How can I smoothly move the JButton if action performed (eg the button is pushed). Here's my example but it doesnt work propely:
public void actionPerformed(ActionEvent event) {
for(int i = 0; i<50; i++){
ww.button.setLocation(ww.button.getLocation().x+1, ww.button.getLocation().y);//ww is a JFrame child
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
After action performed I get a delay in 20*50 ms and button location set in previous loc + 50px, without intermediate locations.
Always try to avoid Thread while working with Swing. In your code it will make main EDT thread to sleep and that's why you are not able to view intermediate locations. Try this with using Swing Timer and you will get it working as intended. Take a look here: How to Use Swing Timers and also try using Swing workers.
Related
this is how I'm trying to accomplish this:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Hello there");
Thread.sleep(1000);
panel.updateUI();
}
});
I set Enter button as the default button so when I keep pressing it the button press maybe 100 times or more but because I'm using Thread.sleep(1000) it takes some time so I have time to type in my JtextField or even close the window but can't do anything.
also, I tried to put btnNewButton.addActionListener() in the run method of a thread but no difference.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Hello there");
Thread.sleep(1000);
panel.updateUI();
}
});
}
});
thread.start();
// I used try catch block in real code
can anyone help me to solve the issue?
**I'm creating this application in eclipse using windowsBuilder.
This is because of something that is called EDT - the Event Dispatch Thread.
This special purpose thread is responsible for all the events in your GUI - including drawing (refreshing) and interactions (button click). This means, that exactly the same thread is used to draw your application as the one that is used to execute actionPerformed code. Since you are literally halting that thread for some amount of time, your application will be non responsive for that exact period of time.
Whatever is being executed on user interactions should be short and execute fast for the reason of not blocking the application. If you need to do some heavy stuff, there is a facility for that purpose called SwingWorker that allows you to easily do some processing in the background thread (pool) and schedule UI updates during execution (like update of progress bar)
In your second "thread" snippet, your thread is not doing anything beside adding actionListener to the button, and then it terminates (probably after less than 1ms ;)) - action callback is still executed by the EDT. If you would start that custom thread from inside of run method - then it would be indeed in parallel and GUI would not be frozen - but again, SwingWorker is the way to go here.
Not entirely sure what your code is supposed to do, but if you want to press the button and then 1000ms later it will check your field you should do something like this:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("before 1000ms");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after 1000ms");
System.out.println("Reading the text field ...");
}
});
thread.start();
System.out.println("after the thread");
Output:
after the thread
before 1000ms
after 1000ms
Reading the text field ...
I have an array of strings which I'm trying to display (one by one) as a slideshow in a Java Swing component. I am also trying to add a delay time between the iterations.
I attempted to do this by using a JTextArea, with an action listener added to it. Here is the code I have right now:
private class myActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// A BUNCH OF TEXT PROCESSING
//NOTE: myInfo.getContents() returns an ArrayList<myType>.
Iterator<myType> iterator = myInfo.getContents().iterator();
int i = 0;
while (iterator.hasNext()) {
myTextArea.setText(iterator.next().toString());
// to add time betweeen iterations i wanted to use the thread
// delay method.
}
}
}
My code is not working because JTextArea doesn't have an action listener.
UPDATE
NOTE: Many replies stated that I should use an ActionListener for the JTextArea; However, Eclipse is not showing me that JTextArea has a method called addActionListener.
I'm kind of stuck here, which Java Swing component do you think would be the most suitable in this scenario?
The text in my array may be long, so a one lined label would not be a good choice.
What other alternatives or approaches do I have?
Thank you very much, any help and suggestions are appreciated.
This is basic example is based on the suggestion posted by #Robin
public class TestDisplayString {
public static void main(String[] args) {
new TestDisplayString();
}
public TestDisplayString() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea textArea;
private List<String> content;
private Iterator<String> iterator;
public TestPane() {
readText();
setLayout(new BorderLayout());
textArea = new JTextArea(10, 40);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
add(new JScrollPane(textArea));
iterator = content.iterator();
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (iterator.hasNext()) {
textArea.setText(iterator.next());
} else {
((Timer)e.getSource()).stop();
}
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
protected void readText() {
content = new ArrayList<>(25);
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/Text.txt")));
String text = null;
while ((text = reader.readLine()) != null) {
if (text.trim().length() > 0) {
content.add(text);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception e) {
}
}
}
}
}
This is the contents of the "Text.txt" file.
How to Use Swing Timers
A Swing timer (an instance of javax.swing.Timer) fires one or more
action events after a specified delay. Don't confuse Swing timers with
the general-purpose timer facility that was added to the java.util
package in release 1.3. This page describes only Swing timers.
In general, we recommend using Swing timers rather than
general-purpose timers for GUI-related tasks because Swing timers all
share the same, pre-existing timer thread and the GUI-related task
automatically executes on the event-dispatch thread. However, you
might use a general-purpose timer if you don't plan on touching the
GUI from the timer, or need to perform lengthy processing.
You can use Swing timers in two ways:
To perform a task once, after a delay.
For example, the tool tip manager uses Swing timers to determine when to show a tool tip and when to hide it.
To perform a task repeatedly.
For example, you might perform animation or update a component that displays progress toward a goal.
Swing timers are very easy to use. When you create the timer, you
specify an action listener to be notified when the timer "goes off".
The actionPerformed method in this listener should contain the code
for whatever task you need to be performed. When you create the timer,
you also specify the number of milliseconds between timer firings. If
you want the timer to go off only once, you can invoke
setRepeats(false) on the timer. To start the timer, call its start
method. To suspend it, call stop.
Note that the Swing timer's task is performed in the event dispatch
thread. This means that the task can safely manipulate components, but
it also means that the task should execute quickly. If the task might
take a while to execute, then consider using a SwingWorker instead of
or in addition to the timer. See Concurrency in Swing for instructions
about using the SwingWorker class and information on using Swing
components in multi-threaded programs.
Let's look at an example of using a timer to periodically update a
component. The TumbleItem applet uses a timer to update its display at
regular intervals. (To see this applet running, go to How to Make
Applets. This applet begins by creating and starting a timer:
timer = new Timer(speed, this); timer.setInitialDelay(pause);
timer.start();
The speed and pause variables represent applet parameters; as
configured on the other page, these are 100 and 1900 respectively, so
that the first timer event will occur in approximately 1.9 seconds,
and recur every 0.1 seconds. By specifying this as the second argument
to the Timer constructor, TumbleItem specifies that it is the action
listener for timer events.
After starting the timer, TumbleItem begins loading a series of images
in a background thread. Meanwhile, the timer events begin to occur,
causing the actionPerformed method to execute:
public void actionPerformed(ActionEvent e) {
//If still loading, can't animate.
if (!worker.isDone()) {
return;
}
loopslot++;
if (loopslot >= nimgs) {
loopslot = 0;
off += offset;
if (off < 0) {
off = width - maxWidth;
} else if (off + maxWidth > width) {
off = 0;
}
}
animator.repaint();
if (loopslot == nimgs - 1) {
timer.restart();
} }
Until the images are loaded, worker.isDone returns false, so timer
events are effectively ignored. The first part of the event handling
code simply sets values that are employed in the animation control's
paintComponent method: loopslot (the index of the next graphic in the
animation) and off (the horizontal offset of the next graphic).
Eventually, loopslot will reach the end of the image array and start
over. When this happens, the code at the end of actionPerformed
restarts the timer. Doing this causes a short delay before the
animation sequence begins again.
Use your ActionListener in combination with a javax.Swing.Timer. The ActionListener assigned to the Timer will be called on regular intervals with the specified delay.
See the timer tutorial for more information
The problem that I have in my code is that when it runs the button.setVisible(true); it won't set the button to visible until all the other if statements are passed through which really confuses me.
I'm trying to make simon says, and what this try-catch does is that it makes the button in the sequence order blink so that the user can know which button it is that follows.
I'm new to programming so any tips and advises are welcome.
Thank you for taking a look!
try {
inputOrder.clear();
// System.out.println("THIS IS INPUT" + inputOrder);
Sequence.add(randomNumber());
int f = 0;
for (; f < Sequence.size(); f++) {
//Thread.sleep(2000);
if (Sequence.get(f) == 1) {
try {`
btnNewButton.setVisible(false);
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
Thread.sleep(1000);
System.out.println("it ran here");
btnNewButton.setVisible(true);
}
if (Sequence.get(f) == 2) {
try {
btnBlue.setVisible(false);
Thread.sleep(1000);
} catch (InterruptedException e1) {
}Thread.sleep(1000);
System.out.println("it ran here");
btnBlue.setVisible(true);
}
if (Sequence.get(f) == 3) {
try {
btnYellow.setVisible(false);
Thread.sleep(1000);
} catch (InterruptedException e1) {
}Thread.sleep(1000);
System.out.println("it ran here");
btnYellow.setVisible(true);
}
if (Sequence.get(f) == 4) {
try {
btnGreen.setVisible(false);
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
Thread.sleep(1000);
System.out.println("it ran here");
btnGreen.setVisible(true);
}
System.out.println(Sequence);
// Order.add(getColor(Sequence.get(f)));
System.out.println(Order);
text.setText(String.valueOf(Order.size()));
}
btnNextRound.setVisible(false);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
Looks like this happens because you are doing this operation in the UI thread, and it does not have time to execute EventQueue since you force to sleep the UI thread, due to this thread gets chance to actually do the paint once it finish all the sleep calls.
In order to get desired output, I think you should move the sleep logic into a separate thread or to a SwingWorker. If you moved the logic to a separate thread you need to use the EventQueue.InvokeLater to enable buttons.
The way that the Java Swing GUI works is that everything happens one after another. Only when the entire method you posted is finished will the next GUI events (such as the repainting events that need to occur to show that the button's not visible anymore). Doing a Thread.sleep just makes your method take longer to finish. The result is that your UI is frozen because no other events (such as mouse, keyboard, or repainting events) are able to run until after all of your sleep calls.
To perform animation in Java, you should use the javax.swing.Timer class rather than using Thread.sleep. Below I've posted a quick example of a timer that, when started, will cause a button to flash. This doesn't completely solve your problem (you're also looping, but you really need another timer to actually schedule when the buttons will flash so that they don't all happen at once).
import javax.swing.Timer
/**
* Timer that causes a button to flash (become invisible for 1 second, and then become visible again).
*/
public class ButtonFlashTimer extends Timer {
private final JButton buttonToFlash;
public ButtonFlashTimer(JButton button) {
super(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// This method is called every 1000 ms (until we tell
// it to stop). This allows us to perform the next "step"
// in the animation.
boolean isVisible = buttonToFlash.isVisible();
if (isVisible) {
buttonToFlash.setVisible(false);
} else {
buttonToFlash.setVisible(true);
// Once we've flashed, stop the timer (don't keep flashing).
stop();
}
}
});
buttonToFlash = button;
// Become invisible immediately; the 1000 ms will be the time between the first
// call to the actionPerformed (which will set it as invisible) and the second
// call (which makes it visible again).
setInitialDelay(0);
setRepeats(true);
}
}
In the code below I am running my method which adds text to a JTextArea, then i wait 4 seconds and add more text. However it simply waits four seconds then puts all the text down at once. How can I make it so it adds the first text, waits then adds the second block of text?
public static void configuresettings() {
GUI.add("To Begin, Go to www.opionsxo.com");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
GUI.add("Welcome to Configure Settings!");
}
I figured it out, if anyone is interested in how. Then view the code below...
public static void configuresettings() {
GUI.add("To Begin, Go to www.opionsxo.com");
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
GUI.add("Welcome to Configure Settings!");
}
};
Timer timer = new Timer( 4000, actionListener );
timer.setRepeats(false);
timer.start();
}
You shouldn't use Thread.sleep with swing, or it will block your application. For instance, if you resize your window or move a window in front of your application, it won't repaint as needed, because you stopped it. Instead, you should be using Swing Timers.
Your problem is probably because you should revalidate() your JTextArea before sleep or something, but as said, you should change the implementation of it.
Read more here: http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
Don't do anything within the context of the Event Dispatching Thread that might cause it to stop, like calling Thread.sleep.
Instead, trying using a javax.swing.Timer or SwingWorker
Take a look at:
Concurrency in Swing
Worker Threads and SwingWorker
How to Use Swing Timers
For more details
For example:
java for-loop in GUI TextArea
Displaying contents of String array in Swing component as iterations using Time delay. JAVA
I cant run JTextArea multiple times?
I have an array of strings which I'm trying to display (one by one) as a slideshow in a Java Swing component. I am also trying to add a delay time between the iterations.
I attempted to do this by using a JTextArea, with an action listener added to it. Here is the code I have right now:
private class myActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// A BUNCH OF TEXT PROCESSING
//NOTE: myInfo.getContents() returns an ArrayList<myType>.
Iterator<myType> iterator = myInfo.getContents().iterator();
int i = 0;
while (iterator.hasNext()) {
myTextArea.setText(iterator.next().toString());
// to add time betweeen iterations i wanted to use the thread
// delay method.
}
}
}
My code is not working because JTextArea doesn't have an action listener.
UPDATE
NOTE: Many replies stated that I should use an ActionListener for the JTextArea; However, Eclipse is not showing me that JTextArea has a method called addActionListener.
I'm kind of stuck here, which Java Swing component do you think would be the most suitable in this scenario?
The text in my array may be long, so a one lined label would not be a good choice.
What other alternatives or approaches do I have?
Thank you very much, any help and suggestions are appreciated.
This is basic example is based on the suggestion posted by #Robin
public class TestDisplayString {
public static void main(String[] args) {
new TestDisplayString();
}
public TestDisplayString() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea textArea;
private List<String> content;
private Iterator<String> iterator;
public TestPane() {
readText();
setLayout(new BorderLayout());
textArea = new JTextArea(10, 40);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
add(new JScrollPane(textArea));
iterator = content.iterator();
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (iterator.hasNext()) {
textArea.setText(iterator.next());
} else {
((Timer)e.getSource()).stop();
}
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
protected void readText() {
content = new ArrayList<>(25);
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/Text.txt")));
String text = null;
while ((text = reader.readLine()) != null) {
if (text.trim().length() > 0) {
content.add(text);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception e) {
}
}
}
}
}
This is the contents of the "Text.txt" file.
How to Use Swing Timers
A Swing timer (an instance of javax.swing.Timer) fires one or more
action events after a specified delay. Don't confuse Swing timers with
the general-purpose timer facility that was added to the java.util
package in release 1.3. This page describes only Swing timers.
In general, we recommend using Swing timers rather than
general-purpose timers for GUI-related tasks because Swing timers all
share the same, pre-existing timer thread and the GUI-related task
automatically executes on the event-dispatch thread. However, you
might use a general-purpose timer if you don't plan on touching the
GUI from the timer, or need to perform lengthy processing.
You can use Swing timers in two ways:
To perform a task once, after a delay.
For example, the tool tip manager uses Swing timers to determine when to show a tool tip and when to hide it.
To perform a task repeatedly.
For example, you might perform animation or update a component that displays progress toward a goal.
Swing timers are very easy to use. When you create the timer, you
specify an action listener to be notified when the timer "goes off".
The actionPerformed method in this listener should contain the code
for whatever task you need to be performed. When you create the timer,
you also specify the number of milliseconds between timer firings. If
you want the timer to go off only once, you can invoke
setRepeats(false) on the timer. To start the timer, call its start
method. To suspend it, call stop.
Note that the Swing timer's task is performed in the event dispatch
thread. This means that the task can safely manipulate components, but
it also means that the task should execute quickly. If the task might
take a while to execute, then consider using a SwingWorker instead of
or in addition to the timer. See Concurrency in Swing for instructions
about using the SwingWorker class and information on using Swing
components in multi-threaded programs.
Let's look at an example of using a timer to periodically update a
component. The TumbleItem applet uses a timer to update its display at
regular intervals. (To see this applet running, go to How to Make
Applets. This applet begins by creating and starting a timer:
timer = new Timer(speed, this); timer.setInitialDelay(pause);
timer.start();
The speed and pause variables represent applet parameters; as
configured on the other page, these are 100 and 1900 respectively, so
that the first timer event will occur in approximately 1.9 seconds,
and recur every 0.1 seconds. By specifying this as the second argument
to the Timer constructor, TumbleItem specifies that it is the action
listener for timer events.
After starting the timer, TumbleItem begins loading a series of images
in a background thread. Meanwhile, the timer events begin to occur,
causing the actionPerformed method to execute:
public void actionPerformed(ActionEvent e) {
//If still loading, can't animate.
if (!worker.isDone()) {
return;
}
loopslot++;
if (loopslot >= nimgs) {
loopslot = 0;
off += offset;
if (off < 0) {
off = width - maxWidth;
} else if (off + maxWidth > width) {
off = 0;
}
}
animator.repaint();
if (loopslot == nimgs - 1) {
timer.restart();
} }
Until the images are loaded, worker.isDone returns false, so timer
events are effectively ignored. The first part of the event handling
code simply sets values that are employed in the animation control's
paintComponent method: loopslot (the index of the next graphic in the
animation) and off (the horizontal offset of the next graphic).
Eventually, loopslot will reach the end of the image array and start
over. When this happens, the code at the end of actionPerformed
restarts the timer. Doing this causes a short delay before the
animation sequence begins again.
Use your ActionListener in combination with a javax.Swing.Timer. The ActionListener assigned to the Timer will be called on regular intervals with the specified delay.
See the timer tutorial for more information