I have strange problem when running my Java program.
It's designed to:
run external app specified in bat file and display fullscreen wallpaper
"hide" wallpaper for some time when buttons combination pressed
warn user that 5sec left so he can save work
when timeout occures display again fullscreen wallpaper and do some other stuff from bats
quit program when button combination pressed
warinng user is realized as displaying fullscreen red box for 200ms
I'm using visible function to do this.
It shows standard fullscreen frame discaring color settings. but only when I comment frame.setUndecorated(true). when uncommented I see only icon in taskbar.
On the other hand when I launch (Using BlueJ) only function visible
the red frame is displayed for specified amount of time. Simply standalone function works perfectly (in my oppinion) even if frame.setUndecorated(true) is used .
what can be wrong that I can't launch that red frame in fullscreen?
olympicApp class:
import java.awt.*;
import java.awt.Color;
import java.awt.event.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Graphics;
import java.awt.image.*;
import java.io.*;
import java.io.IOException;
import javax.imageio.*;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JComponent;
public class olympicApp extends JComponent {
alertApp alert;
BufferedImage img;
public olympicApp()
{
try
{
img = ImageIO.read(new File("wallpaper.jpg"));
}
catch (IOException e)
{
}
}
public void paint(Graphics g)
{
g.drawImage(img, 0, 0, null);
}
public Dimension getPreferredSize()
{
if (img == null)
{
return new Dimension(200,200);
}
else
{
return new Dimension(img.getWidth(null), img.getHeight(null));
}
}
public static void visible()
{
JFrame frame = new JFrame();
frame.getContentPane().setBackground(Color.red);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.dispose();
//frame.setUndecorated(true);
frame.setAlwaysOnTop(true);
frame.pack();
frame.setVisible(true);
try
{
frame.setVisible(true);
Thread.sleep(500);
frame.setVisible(false);
}
catch(Exception ex)
{
}
frame.setAlwaysOnTop(false);
frame.setVisible(false);
}
public static void main(String[] args)
{
//alertApp reminder = new alertApp();
try
{
Process process = Runtime.getRuntime().exec("start-lv.bat");
Thread.sleep(500);
}
catch (IOException | InterruptedException e)
{
}
JFrame f = new JFrame("olympic");
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
f.setUndecorated(true);
f.setAlwaysOnTop(true);
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
f.add(new olympicApp());
f.pack();
f.setVisible(true);
f.addKeyListener(new KeyListener()
{
public void keyPressed(KeyEvent kevt)
{
if(kevt.getKeyChar()=='l')
{
if(kevt.isAltDown())
{
f.setAlwaysOnTop(false);
f.setVisible(false);
try
{
Thread.sleep(5*1000);
visible();
Thread.sleep(5*1000);
//Process process = Runtime.getRuntime().exec("saving.bat");
Thread.sleep(500);
f.setAlwaysOnTop(true);
f.setVisible(true);
Process process2 = Runtime.getRuntime().exec("kopia.bat");
}
catch(IOException | InterruptedException e)
{
}
}
}
if(kevt.getKeyChar()=='q')
{
if(kevt.isAltDown())
{
System.exit(0);
}
}
}
public void keyTyped(KeyEvent kevt)
{
}
public void keyReleased(KeyEvent kevt)
{
}
});
}
}
I would imagine that you're going to have to do something in here...
public class alertApp {
public static void main(String[] args) {
// Sample loop to flash every 2 seconds
}
}
This is called when your program starts and where you should put the code to get the program running
I would also strogly recommend that you take a look at Code Conventions for the Java TM Programming Language, it will make it easier for people to read your code and for you to read others
As well as Concurrency in Swing and How to use Swing Timers which will help you solve other potential issues
I put neccessary code in visible funciton. I can see the frame but color information is discarted. Thanks for Concurrency and Timers, but I think the problem isn't connected to thread.sleep()
Then you didn't read the links...
public void keyPressed(KeyEvent kevt) {
if (kevt.getKeyChar() == 'l') {
if (kevt.isAltDown()) {
f.setAlwaysOnTop(false);
f.setVisible(false);
try {
Thread.sleep(5 * 1000);
visible();
Thread.sleep(5 * 1000);
//Process process = Runtime.getRuntime().exec("saving.bat");
Thread.sleep(500);
f.setAlwaysOnTop(true);
f.setVisible(true);
Process process2 = Runtime.getRuntime().exec("kopia.bat");
} catch (IOException | InterruptedException e) {
}
}
}
keyPressed is executed within the context of the Event Dispatching Thread, so when you call Thread.sleep, it prevents the EDT from processing the Event Queue, preventing it from painting or responding to other events
Related
https://github.com/terryaa/KOSTA_MAC/tree/master/Java/NetBeans/day13_01_15/src/ex1
What I'm trying to do is to draw circles, but one circle on a canvas at a time and then moving on to drawing next circle using Runnable join. It should draw a circle using .start() and the other .start() shouldn't start until formal .start()'s drawing circle is done.
In linked page's package, Ex3_Canvas1 class has main and use Runnable MyThread0 class to draw a circle using basic .start() and .join() and it does perfectly what I want.
I created NetBean's automatic JFrame class Ex2_CanvasDemo and tried to do the same and failed. JFrame window pops up after drawing a full circle and then shows creating of next circle. What I want is that the window should first appear and it shows creation of both circles ,not simulataneously but sequently, like Ex3_Canvas1.
I guess it's because main thread waits for th(Ex2_CanvasDemo) to finish so window doesn't apply for changes. But shouldn't Ex1_Canvas1 should do the same? Is this differences due to automatically generated code by netbeans? How can I do the same as Ex1_Canvas1 in Ex2_CanvasDemo.
I tried making a Runnable class and used in Ex2_CanvasDemo but failed also..
Any help?
I'm using jdk 8 and netbeans8 on mac.
--Thread part of Ex2_CanvasDemo--
public Ex2_CanvasDemo() {
initComponents();
Thread th=new Thread(new Runnable() {
#Override
public void run() {
for(int i=0;i<370;i+=10){
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
}
arcNUm=i;
System.out.println("circle"+arcNUm);
canvas1.repaint();
}
}
});
th.start();
try {
th.join();
} catch (InterruptedException ex) {
Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
}
th=new Thread(new Runnable() {
#Override
public void run() {
for(int i=0;i<370;i+=10){
System.out.println("circle"+i);
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
}
arcNum2=i;
canvas2.repaint();
}
}
});
th.start();
// try {
// th.join();
// } catch (InterruptedException ex) {
// Logger.getLogger(Ex2_CanvasDemo.class.getName()).log(Level.SEVERE, null, ex);
// }
}
Caveat
Animation is hard, good animation is really hard. You need to repeat this to yourself, because animation done right is, really hard.
What you need to know...
Animation is basically the illusion of change over time. Very rarely do you want to perform linear animation, animation is normally done over a period of time, as it allows for performance difference in the platform to be smoothed out in away which is not as harsh to the user.
Swing is single threaded and not thread safe. This means that you should not block the event dispatching thread and that you must only update the UI from within the context of the event dispatching thread.
See Concurrency in Swing for more details
This makes life a little difficult, as you can't simply run a linear loop in the EDT, as this will block the UI and it's difficult to do it from a Thread because it's a mess of synchronisation.
One of the simplest solutions is to make use of the available API and use a Swing Timer, which acts as a pseudo loop, putting in a small delay between call backs, in which you can perform some operations
Example...
While there are a number of ways you might approach this, I've set up a simple List which contains a bunch of Animatables which "do stuff" and then simply run one after the other in serial.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane testPane = new TestPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(testPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
testPane.play();
}
});
}
});
}
public class TestPane extends JPanel {
private List<Animatable> animations;
private Animatable animation;
private Timer timer;
public TestPane() {
animations = new ArrayList<>(25);
animations.add(new CircleAnimation(Color.RED));
animations.add(new CircleAnimation(Color.BLUE));
timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (animation == null) {
animation = animations.remove(0);
}
if (animation.update(getBounds())) {
if (animations.isEmpty()) {
((Timer)e.getSource()).stop();
} else {
animation = animations.remove(0);
}
}
repaint();
}
});
}
public void play() {
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (animation != null) {
Graphics2D g2d = (Graphics2D) g.create();
animation.paint(g2d);
g2d.dispose();
}
}
}
public interface Animatable {
public boolean update(Rectangle bounds);
public void paint(Graphics2D g2d);
}
public class CircleAnimation implements Animatable {
private Color color;
private Ellipse2D circle;
private double delta = -1;
public CircleAnimation(Color color) {
this.color = color;
}
#Override
public boolean update(Rectangle bounds) {
if (circle == null) {
circle = new Ellipse2D.Double(bounds.width, (bounds.height / 2) - 10, 20, 20);
}
Rectangle rect = circle.getBounds();
rect.x += delta;
circle.setFrame(rect);
return rect.x + 20 < bounds.x;
}
#Override
public void paint(Graphics2D g2d) {
if (circle == null) {
return;
}
g2d.setColor(color);
g2d.fill(circle);
}
}
}
I'm trying to make a basic click counter using mouse events in Java. I understand the tutorials everyone has but their programs are semi automatic and it registers one increment per click.
public void mouseClicked(MouseEvent e)
{
clicks++;
}
I'm trying to do a fully automatic version of that where it will continually increment until you release the button, but the release method doesn't switch the boolean to false and stop the loop. Any advice?
public class example{
private boolean fire = false;
public void mousePressed(MouseEvent e)
{
if(e.getButton()== e.BUTTON1){fire = true};
while(fire) {clickCounter++; }
}
}
public void mouseReleased(MouseEvent e){
fire = false;
}
}
Just to be clear, a "click" is what typically happens between the mouse been pressed and released, the idea that there are more "clicks" during this period is an artificial construct.
First, you need to go read Concurrency in Swing to better understand while "sleep" and while-loop won't work in this context. You're blocking the Event Dispatching Thread, preventing any new events from been processed.
The following example simply attempts to calculate the time between the mouse pressed and released event and applies a artificial multiplier to the result to create the "click" count
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.time.Duration;
import java.time.LocalDateTime;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JLabel label = new JLabel("...");
add(label);
addMouseListener(new MouseAdapter() {
private LocalDateTime clickTime;
#Override
public void mouseClicked(MouseEvent e) {
clickTime = LocalDateTime.now();
}
#Override
public void mouseReleased(MouseEvent e) {
if (clickTime == null) {
return;
}
Duration between = Duration.between(clickTime, LocalDateTime.now());
long seconds = between.getSeconds();
long clicks = seconds * 3;
label.setText("Held for " + seconds + "s = " + clicks + " clicks");
clickTime = null;
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Another solution might be to start a Swing Timer on mouse pressed and stop it on mouse released, allowing it to increment a value
You set fire= true then enter into an infinite while(true) loop.
To fix this, modify the boolean statement of the while loop inside the loop itself.
while(fire) {
count++;
if (mouseReleased(eventMouseIsReleased))
fire= false;
} // Check while(fire) but now it is false! Move on!
Hope this helps!
I have a problem with a task that seemed to be pretty easy. I have to create a program that will show images (.jpg,.png and .gif) consecutively. Images have to be the contents of some files, that is given as an argument to the program. When I have to load the images separately, it works, but the issue occurs when I load them one after another with a sleep between them.
Here is my code:
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new MyFrame(args[0],Integer.parseInt(args[1]));
//First argument is path to file with images, second - amount of time (in seconds) which every image has to stay on the screen until the next one appears
}
});
}
}
import java.io.File;
import javax.swing.*;
public class MyFrame extends JFrame{
public MyFrame(String path, int time){
super("Obrazki");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
MyPanel panel = new MyPanel();
panel.setVisible(true);
this.add(panel);
pack();
File file = new File(path);
String[] tabs = file.list();
for(int i=0; i<tabs.length; i++)
{
panel.loadImage(path+"\\"+tabs[i]);
this.repaint();
try {
Thread.sleep(time*1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import javax.swing.JPanel;
public class MyPanel extends JPanel
{
Image img;
public void loadImage(String s)
{
img = Toolkit.getDefaultToolkit().getImage(s);
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(img, 1);
while(!tracker.checkID(1)) {
try {
tracker.waitForID(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.repaint();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.drawImage(this.img, 0, 0, this.getSize().width, this.getSize().height, this);
}
}
but the issue is when i load them one after another with sleep time between them.
You are causing the Event Dispatch Thread (EDT) to sleep, which means the GUI can't respond to events or repaint itself. Read the section from the Swing tutorial on Concurrency for more information.
Don't use Thread.sleep() when code is executing on the EDT.
For animation you can:
use a SwingWorker (with Thread.sleep())and publish the Icon you want to paint, or
use a Swing Timer. The tutorial also has a section on How to Use Swing Timers.
I'm using a JFrame and I wanted to display an image and pause the code until the user presses ANY key. After that key being pressed the image would close and the code would continue running.
What I did:
Created a flag
final boolean[] flag = {true};
Added a addKeyListener to the JFrame object that would change the flag
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
frame.setVisible(false);
frame.dispose();
flag[0] = false;
}
});
Wait loop until flagged
while (flag[0]){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
This is working, but I understand that it is a bit resourceful.
Is there any other way of making the wait loop? Is there any listener of the listener?
2nd try, using CountDownLatch:
Set the latch
final CountDownLatch latch = new CountDownLatch(1);
CountDown
for (JFrame frame : framesList) {
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
frame.setVisible(false);
frame.dispose();
latch.countDown();
}
});
Wait
latch.await();
So, you want to display an image and have the execution stop until the window is closed. This just screams modal dialog to me. A modal dialog will stop the code execution from where it is made visible, it will do it in such away so as not to block the Event Dispatching Thread and make your entire problem come to a screaming halt and hang the program. See How to use dialogs for more details...
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Image;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
BufferedImage img = ImageIO.read(...);
ImageShower.show(null, img);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public static class ImageShower extends JPanel {
private JLabel label = new JLabel();
public ImageShower() {
setLayout(new BorderLayout());
add(label);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "close");
am.put("close", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
Window window = SwingUtilities.windowForComponent(ImageShower.this);
if (window != null) {
window.dispose();
}
}
});
}
public void setImage(Image img) {
label.setIcon(new ImageIcon(img));
}
public static void show(Component owner, Image img) {
Window parent = null;
if (owner != null) {
parent = SwingUtilities.windowForComponent(owner);
}
JButton close = new JButton("Close");
close.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
Window window = SwingUtilities.windowForComponent(btn);
if (window != null) {
window.dispose();
}
}
});
JDialog dialog = new JDialog(parent, Dialog.ModalityType.APPLICATION_MODAL);
ImageShower shower = new ImageShower();
shower.setImage(img);
dialog.add(shower);
dialog.add(close, BorderLayout.SOUTH);
dialog.getRootPane().setDefaultButton(close);
dialog.pack();
dialog.setLocationRelativeTo(owner);
dialog.setVisible(true);
}
}
}
"But wait, may images are large and take time to load and I don't want to freeze the UI while the load"...
Okay, for that, I'd look towards using a SwingWorker, which can load the image in the background but which provides simple methods for ensuring the the image is displayed within the context of the EDT properly...
public class ImageLoadAndShow extends SwingWorker<Void, Image> {
#Override
protected Void doInBackground() throws Exception {
BufferedImage img = ImageIO.read(...);
publish(img);
return null;
}
#Override
protected void process(List<Image> chunks) {
Image img = chunks.get(chunks.size() - 1);
ImageShower.show(null, img);
}
}
Not, if the image fails to load, you won't know about it, as the doInBackground method will pass the Exception out of the method. You'd need to use a combination of a PropertyChangeListener and the SwingWorkers get method to trap it, just remember, get is blocking, so calling it inside the context of the EDT will block until the worker completes
"But I need to carry out other operations when the dialog is closed"
There are a few ways you might be able to achieve this, depending on what it is you want to do, for this example, I've stuck with the SwingWorker, because it was easy to copy and paste the basic structure, but you could use a Runnable wrapped in a Thread
public class ImageLoadShowAndWait extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
BufferedImage img = ImageIO.read(...);
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
ImageShower.show(null, img);
}
});
return null;
}
}
Now, if none of that does what you want...then I'd like to know what it is you're actually doing :P, have a look at Foxtrot which provides an API which allows you to execute code asynchronisly within the EDT without blocking it (entirly), but which will stop the code execution at the point it's called until it completes
The thing is that I wanted it to close the JFrame when ANY key is pressed
KeyListener is going to give you issues, maybe not today, maybe not tomorrow, but it will blow up in your face eventually. The example I've provide binds the Escape key to dispose of the window. It also makes the "Close" button the default button, which provides Space and/or Enter keys as well and a nice visual queue to the user.
If you want to use KeyListener, that's up to you, but your core problem doesn't seem to revolve around it, but the ability to display a window and pause the code execution till it's closed
JFrames not displaying properly in loop.
Code:-
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class SwingDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run()
{
final JFrame jfrm= new JFrame("A Simple Swing Application");
final JFrame jfrm2= new JFrame("A Simple Swing Application 2");
jfrm.setSize(275,100);
jfrm.setLocation(100,100);
jfrm2.setLocation(50,50);
jfrm2.setSize(275,100);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfrm2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel jlab = new JLabel("Swing means powerful GUIs.");
jfrm.add(jlab);
JButton button0= new JButton("loop");
jfrm.add(button0);
jfrm.setLayout(new FlowLayout());
JLabel jlab2 = new JLabel("Swing means powerful GUIs again");
jfrm2.add(jlab2);
//jfrm2.setVisible(true);
jfrm.setVisible(true);
button0.addActionListener(new ActionListener() {
private boolean confirmAction;
#Override
public void actionPerformed(ActionEvent e) {
confirmAction = true;
if (confirmAction) {
try {
while(true)
{
jfrm.setVisible(false);
jfrm2.setVisible(true);
try{
Thread.sleep(15000);
}
catch(InterruptedException ie)
{
System.out.println("nothing");
}
jfrm2.setVisible(false);
jfrm.setVisible(true);
}
} catch (Throwable t) {
t.printStackTrace(System.out);
}
}
}
});
}
});
}
}
If the problem is that they are not updating correctly (this is my only thought since you didn't explain the issue), you should try to include these methods in the loop:
validate();
repaint();
If your issue is different, please inform us.
The method
#Override
public void actionPerformed(ActionEvent e) {
...
}
is executed in the EDT. Once you have implemented an infinite loop inside EDT it will stop processing any farther events and your GUI will stop responding.
A possible solution may be to start a timer and on every timer tick post relevant events to EDT, using SwingUtilities.invokeLater() or invokeAndWait():
Replace the contents of actionPerformed(ActionEvent e) with the following:
Timer timer = new Timer(15000, new ActionListener() {
boolean flip = false;
#Override
public void actionPerformed(ActionEvent actionEvent) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jfrm.setVisible(flip);
jfrm2.setVisible(!flip);
flip =! flip;
}
});
}
});
timer.start();