I would like to create a JButton that changes its text periodically after the first click. I'm not really familiar with Swing library. What would be a good starting point? May I update its text without an action?
Thank you.
for all periodical events in Swing I only suggest javax.swing.Timer
output by using Timer should be, for example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.Timer;
public class CrazyButtonTimer {
private JFrame frame = new JFrame(" Crazy Button Timer");
private JButton b = new JButton("Crazy Colored Button");
private Random random;
public CrazyButtonTimer() {
b.setPreferredSize(new Dimension(250, 35));
frame.getContentPane().add(b);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
javax.swing.Timer timer = new Timer(500, new TimerListener());
timer.setInitialDelay(250);
timer.start();
}
private class TimerListener implements ActionListener {
private TimerListener() {
}
#Override
public void actionPerformed(final ActionEvent e) {
Color c = b.getForeground();
if (c == Color.red) {
b.setForeground(Color.blue);
} else {
b.setForeground(Color.red);
}
}
}
public static void main(final String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
CrazyButtonTimer crazyButtonTimer = new CrazyButtonTimer();
}
});
}
}
If you to change it on every fixed amount of time then you can use Swing Timer or Thread to do this. But for this you have to listen at least one action so that you can initialize and start it.
You can also use TimerTask class from java.util like follow:
java.util.TimerTask timerTask = new java.util.TimerTask() {
#Override
public void run() {
//change button text here using button.setText("newText"); method
}
};
java.util.Timer myTimer = new java.util.Timer();
myTimer.schedule(timerTask, 3 * 1000, 3* 1000); // This will start timer task after 3 seconds and repeat it on every 3 seconds.
I suggest you to create a timer (here you can find some doc)
Timer timer = new Timer(100,this);
Your class has to extend action listener ed implements the following method which allow you to change the text of your JButton(I called it ``button).
public void actionPerformed(ActionEvent e) {
if(e.getSource.equals(timer)){
button.setText("newText");
}
}
Luca
All the other answers fail to mention how to update non-periodically. If you need it to update irregularly, you can make a method in your GUI class called something like: updateButton(); and just call that every time you want it to change your text.
public void updateButton(String newText)
{
Button.setText(newText);
}
Just thought I'd add this in case someone wanted to set it irregularly.
If you want to change it periodically (e.g. every 5th second) you could create a new Thread which sets the text of the button to the desired value and repaints it (if necessary).
Related
I simply want this program to wait for a timer. All I want is for the program to pause for two seconds. I want this program to do is display "Start," wait for two seconds until the timer has finished, then display "Start, Finished Waiting, Finished." How can I make this program wait for the timer to finish? I believe that it currently creates the timer in a separate thread, not pausing the main thread, so it displays,"Start, Finished" then waits for two seconds and then displays "Start, Finished, Finished Waiting." This is not the order that I want things to happen in, and I have looked all over for a simple timer example when running a GUI and have found none. Thank you for your help, here is the code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;
public class GUI extends JFrame {
private static final long serialVersionUID = 3560258176733156660L;
public static void main(String[] args) {
new GUI().setVisible(true);
}
private Timer timer;
private JTextArea area;
private String text;
public GUI() {
setLayout(null);
setSize(500, 120);
setTitle("Timer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
text = "";
area = new JTextArea(text);
area.setBounds(0, 0, 500, 120);
add(area);
doThings();
}
public void doThings() {
text += "Start, ";
area.setText(text);
// Want program to wait for two seconds
waitForTwoSeconds();
text += "Finished ";
area.setText(text);
}
public void waitForTwoSeconds() {
timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
text += "Finished Waiting, ";
area.setText(text);
timer.stop();
}
});
timer.start();
}
}
Take the code from after you call waitForTwoSeconds and place within the actionPerformed method...
public void doThings() {
area.setText("Start, ");
// Want program to wait for two seconds
waitForTwoSeconds();
}
public void waitForTwoSeconds() {
timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
area.append("Finished Waiting, ");
area.append("Finished ");
timer.stop();
}
});
timer.setRepeats(false);
timer.start();
}
This will cause Finished Waiting, Finished to be append to the JTextArea 2 seconds after you click the button...
You DO NOT want to perform any long running/blocking operations within the context of the Event Dispatching Thread, this WILL make it look like your program as hang, cause it has.
See, Concurrency in Swing and How to use Swing Timers for more details
Updated...
Swing (and most UIs) are event driven, that is, something happens and you respond to it. For instance, with the Timer, the timer tripped and you responded to the event. You can't block/wait within the Event Dispatching Thread, it will simply cause the UI to stop responding and painting, this is the way the framework works, you can learn to live with it or continue to be frustrated by it (remember, wanting something and getting it to work, are two different things)
There are, however, things you can do, the Timer is one example, another is the SwingWorker
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
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();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
public TestPane() {
setLayout(new BorderLayout());
ta = new JTextArea(10, 20);
JButton btn = new JButton("Make it so");
add(new JScrollPane(ta));
add(btn, BorderLayout.SOUTH);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
btn.setEnabled(false);
ta.append("Start, ");
SwingWorker<String, String> worker = new SwingWorker<String, String>() {
#Override
protected String doInBackground() throws Exception {
Thread.sleep(2000);
publish("Finished waiting, ");
return null;
}
#Override
protected void process(List<String> chunks) {
for (String text : chunks) {
ta.append(text);
}
}
#Override
protected void done() {
ta.append("Finished");
btn.setEnabled(true);
}
};
worker.execute();
}
});
}
}
}
What this basically does is, in a background thread, it waits two seconds and then (via the publish/process methods), prints "Finished Waiting", then after the doInBackground returns, done is (eventually) called and "Finished" is printed.
This is all done so that the UI updates occur from within the context of the Event Dispatching Thread, meeting the single thread requirements of Swing
Ok, so I guess my question should really look like this then:
How do i make the program wait until the waitForTwoSeconds() method is complete before doing area.append("Finished "); ? This is really what I want to accomplish.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;
public class GUI extends JFrame {
private static final long serialVersionUID = 3560258176733156660L;
public static void main(String[] args) {
new GUI().setVisible(true);
}
private Timer timer;
private JTextArea area;
public GUI() {
setLayout(null);
setSize(500, 120);
setTitle("Timer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
area = new JTextArea("");
area.setBounds(0, 0, 500, 120);
add(area);
doThings();
}
public void doThings() {
area.setText("Start, ");
// Want program to wait for two seconds
waitForTwoSeconds();
// Don't want to do this until waitForTwoSeconds() has finished...
area.append("Finished ");
}
public void waitForTwoSeconds() {
timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
area.append("Finished Waiting, ");
timer.stop();
}
});
timer.setRepeats(false);
timer.start();
}
}
I have:
A JFrame with a JButton on it.
A separate Canvas subclass to show animations.
And I wish to, at the press of the JButton bring up a new JFrame displaying the Canvas subclass as it animates.
The problem I face right now is that the new JFrame appears, however it doesn't get a chance to render anything and the JButton on the main frame stays depressed. The logic I figure behind this is that the EDT hasn't finished doing it's jobs such as showing the JButton as released and so does not get a chance to run the animation method and ends up in deadlock.
This logic treated me well in the past as I made this work by creating a new thread, but having learned more about Java, threads and Swing lately I've come to know that all Swing related events must be handled on one thread: the EDT.
This confuses me as to how I got it working before but lead me to believe that using invokeLater would help the problem; as the job of making the JFrame visible and showing animation would be placed at the end of the queue allowing the JButton to unrelease etc. I've had no luck however; have I completely misunderstood something?
Thanks!
(Also please no comments on my use of the Canvas class as opposed to JPanel, I have my reasons).
Sample code:
Test5 (class with main method).
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*
public class Test5 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Test5().setup();
}
});
}
private void setup() {
JFrame frame = new JFrame("Test");
JButton button = new JButton("Click here");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
newFrame();
}
});
}
});
frame.getContentPane().add(button);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
private void newFrame() {
JFrame newFrame = new JFrame("The new frame");
newFrame.setVisible(true);
newFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
CanvasClass canvas = new CanvasClass();
newFrame.getContentPane().add(canvas);
newFrame.pack();
canvas.runAnimation();
}
}
CanvasClass (Canvas subclass)
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
public class CanvasClass extends Canvas {
int x;
public CanvasClass() {
setSize(new Dimension(550,550));
this.x = (int) (Math.random() * 255);
}
//#Override
public void paint(Graphics g) {
g.setColor(new Color(x, x, x));
g.fillOval(0,0,500,500);
}
void runAnimation() {
while (true) {
randomise();
repaint();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
void randomise() {
x = (int) (Math.random() * 255);
}
}
You actualy invoke it in EDT but it's blocked in the canvas.runAnimation();
Place the code to be executed in a separate Thread (where you can call sleep) but call the repaint() in SwingUtilities.invokeLater()
Or even better to define a javax.swing.Timer and call the runAnimation() in the Timer's actionPerformed()
UPDATE:
int delay = 20; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
canvasInstance.randomise();
canvasInstance.repaint();
}
};
new Timer(delay, taskPerformer).start();
to be called instead of the runAnimation()
I'm using a Swing Timer to execute animations in my program. In many instances, there are several different calls made to the animate() method at once, with a separate Timer created for each. I know that, because of the way Swing timers are designed, these all get executed together - all my animations occur at the same time. However, there are some instances where I need to wait for one animation to complete to execute another.
Is there a way to make Swing timers execute sequentially - one after the other, rather than all at once? Or is there an alternative mechanism to the Swing timer that might better match my use case?
EDIT: I'm afraid I oversimplified my use case a bit. #peeskillet's suggestion would work perfectly if I knew at each "scene transition" what animations would need to be executed, or if the same sequence of animations occurred each time. Unfortunately that's not the case -- each transition requires a different set of animations, with different sets of components moving onto, off of and around on the panel.
What I want is to execute the animations of items off the screen first, and then (after that completes) animate the components on the screen. It's not a problem to distinguish between these "types" of animations at runtime - they're initiated from different methods, and thus its easy to imagine adding them to two different "queues" - a queue of outgoing items and a queue of incoming items. Having done so, I could then implement the basic strategy of calling a
That said - that all only makes sense to me intuitively, heuristically - I haven't figured out how to implement it in practice. What would those "queues" actually be, and what class would hold and later execute them?? Presumably one that implements Runnable, creating a second thread that can execute the animations with tighter control on how they proceed? Or does the event-dispatch thread give me the ample control here, if only I fully grasped how to use it? In which case - please help me do that.
(PS I realize that I've changed the question significantly here, essentially turning it into a new question, and that #peetskillet answered it as previously worded perfectly well, so I accepted that answer and posted a new question here.
"Is there a way to make Swing timers execute sequentially - one after the other, rather than all at once? "
Just use a `boolean of some sort, telling when the first timer when it should stop and when the second timer should start. Something like
Timer timer1 = new Timer(delay, null); <---- initialize
Timer timer2 = new Timer(delay, null);
boolean something = false;
public Constructor() {
timer1 = new Timer(delay, new Action Listener(){
public void actionPerformed(ActionEvent e) {
if (something) { ------
timer2.start(); |
timer1.stop(); |---- some code should lead to
} esle { | `something` being true. Maybe
animateFirstSomething(); | another if statement inside the
} | else. Like if x equals y
} ------ something = true, else,
}); animateFirstSomething()
timer1.start();
timer2 = new Timer(delay, new ActionListener(){
public void actionPerformed(ActionEvent e) {
animationSecondSomething();
}
});
}
Here's simple example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TestTwoTimers extends JPanel {
int rectOneX = 0;
int rectTwoX = 0;
Timer timer1 = new Timer(100, null);
Timer timer2 = new Timer(100, null);
boolean rectOneGo = true;
public TestTwoTimers() {
timer1 = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (rectOneGo) {
if (rectOneX >= 225) {
timer2.start();
timer1.stop();
} else {
rectOneX += 10;
repaint();
}
}
}
});
timer2 = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (rectTwoX < 225) {
rectTwoX += 10;
repaint();
} else {
timer2.stop();
}
}
});
final JButton button = new JButton("Start First Timer");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
timer1.start();
}
});
setLayout(new BorderLayout());
add(button, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(rectOneX, 50, 75, 75);
g.setColor(Color.BLUE);
g.fillRect(rectTwoX, 150, 75, 75);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
JFrame frame = new JFrame("Double Timers");
frame.add(new TestTwoTimers());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I want to set setDissmissDelay() method multiple times, but I could not set it for a specific value again and again. I also tried to use an infinite loop, and tried to override (ToolTipManager Constructor is on default modifier).
I know for sure the code is working properly as I can see it's printing the e.getsource() in console. I was trying to solve this issue asked by someone (This Question) and while solving that I became stumped at this point. What is the reason behind that? And if I can set the value how can it be? Is there any other way to achieve this?
Here is my code snippet:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class Hello {
static JButton button;
private static void createAndShowGUI() {
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button = new JButton("Hello World");
button.setToolTipText("Its a tool tip Experiment!");
frame.getContentPane().add(button);
button.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
if (e.getSource() == button) {
ActionListener tt = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ToolTipManager.sharedInstance().setDismissDelay(
1000);
System.out.println(e.getSource());
}
};
new Timer(100, tt).start();
}
}
});
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Please guide me through this.
Calling setDismissDelay() is a global setting to indicate how long should a Tooltip remain on the display before it is removed. It does not reset the time until when the current tooltip is removed. As suggested in your linked question setting the dismiss delay, once and for all, to Integer.MAX_VALUE should do the trick.
I'm a Java beginner and I'm trying to build a simple stopwatch program that displays the time on a swing GUI. Making the stopwatch is easy, however I cannot find a way to make the GUI update every second and display the current time on the stopwatch. How can I do this?
Something along these lines should do it:
import java.awt.EventQueue;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JLabel;
/** #see https://stackoverflow.com/a/11058263/230513 */
public class Clock {
private Timer timer = new Timer();
private JLabel timeLabel = new JLabel(" ", JLabel.CENTER);
public Clock() {
JFrame f = new JFrame("Seconds");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(timeLabel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
timer.schedule(new UpdateUITask(), 0, 1000);
}
private class UpdateUITask extends TimerTask {
int nSeconds = 0;
#Override
public void run() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
timeLabel.setText(String.valueOf(nSeconds++));
}
});
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
final Clock clock = new Clock();
}
});
}
}
The timeLabel will always display the number of seconds the timer has been running.
You will need to correctly format it to display "hh:mm:ss"; one approach is shown here.
Create a container and add the label to it so that you can display it as part of the GUI.
Compare the result to this alternate using javax.swing.Timer.