Manually invoke actionPerformed of a javax.swing.Timer - java

The following Timer works perfectly.
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// ...
}
});
What I want to do is call the actionPerformed() manually. How can I achieve this?
The question seems unclear to the readers, I'll try to explain more.
Timer does some process hourly. I want to do it whenever I want without interfering the timer's process.

Short answer...
A much simpler (and better designed) solution would be, instead of...
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("OK");
}
});
You should externalise the work the ActionListener does...
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
doReallyImportantWorkEveryHour();
}
});
then you remove the Timer from the equation and you can call doReallyImportantWorkEveryHour when you want and solve the fundamental problem
Long Answer
So, let's start with...
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("OK");
}
});
Creating a Timer this way, automatically registers a ActionListener with the Timer.
You then state:
What I want to do is call the actionPerformed() method inside the timer's ActionListener manually. How can I achieve this?
Which suggest you want try and do something like...
private static final Timer TICK_HOUR = new Timer(3600000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TICK_HOUR.getActionListeners()[0].actionPerformed(null);
}
});
This could cause a NullPointerException, but more importantly, this will have an adverse affect on system performance, as there is no way that the ActionListener will know it shouldn't continuously all itself - basically and infinite loop.
IF however, you wanted to, prematurely, trigger the Timers ActionListeners (outside of any registered listeners)
Then yes, you could use...
ActionEvent evt = new ActionEvent(
TICK_HOUR,
0,
TICK_HOUR.getActionCommand(),
System.currentTimeMillis(),
0);
for (ActionListener listener : TICK_HOUR.getActionListeners()) {
listener.actionPerformed(evt);
}
but make sure you're calling them from within the context of the EDT, as that's one of the guarantees that the Timer makes.
A "simpler" solution might be just to use the functionality that is already provide by the Timer itself...
public class ManuallyTimer extends Timer {
public ManuallyTimer(int delay, ActionListener listener) {
super(delay, listener);
}
public void tigger() {
ActionEvent evt = new ActionEvent(TICK_HOUR, 0, TICK_HOUR.getActionCommand());
fireActionPerformed(new ActionEvent(this, 0, getActionCommand(),
System.currentTimeMillis(),
0));
}
}

Inside a static-initializer-block store ActionListener in a variable instead of passing it directly to the Timer:
private static final Timer TICK_HOUR;
static{
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// ...
}
};
TICK_HOUR = = new Timer(3600000, listener);
listener.actionPerformed(/* someEvent */);
}
You might aswell store the listener variable as a class level static variable and then call it elsewhere from your code:
private static final ActionListener LISTENER = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
// ...
}
};
private static final Timer TICK_HOUR = new Timer(3600000, LISTENER);
And then somewhere in your code
LISTENER.actionPerformed(/* someEvent */);

Use getActionListeners().
Returns an array of all the action listeners registered on this timer.
Returns:
all of the timer's ActionListeners or an empty array if no action listeners are currently registered.
~Java doc~
TICK_HOUR.getActionListeners()[0].actionPerformed(null);
This will throw a ArrayIndexOutOfBoundsException if there are no ActionListeners registered to the timer. So better check the length of the array before using.

Related

Timer works with println but not label using java

I have some labels that become visible when the letter a is pressed.
private void formKeyPressed(java.awt.event.KeyEvent evt) {
// TODO add your handling code here:
if(evt.getKeyCode()==KeyEvent.VK_A){
jLabel7.setVisible(true);
jLabel8.setVisible(true);
jLabel9.setVisible(true);
myBlink();
}
I have Label8 on a timer myBlink()
public void myBlink()
{
new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("begin");
jLabel8.setVisible(false);
jLabel8.setVisible(true);
System.out.println("Timer");
}
}).start();
}
I have placed printlns to see if timer begins and ends and when I press key "a" my output shows begin Timer multiple times but my label does not appear and disappear. What tweak does this code need? What am I missing? Thanks for the extra set of eyes.
This is probably because you call successively setVisible(false) and setVisible(true) which is done too fast to be seen, you should use a variable and modify its value any time the action of the Timer is called as next:
public void myBlink()
{
new Timer(1000, new ActionListener() {
boolean visible = true;
public void actionPerformed(ActionEvent e) {
jLabel8.setVisible(visible = !visible);
}
}).start();
}

Java - Doing something when button clicked, then revert it

Ok, so I'm doing a Java window (a JFrame, doesn't really matter what it is for) and I have a button on it. What I want to approach is when the button is clicked, it changes its text, then the app does something, and when it's finished the button gets its initial text back.
Something like this...
JButton myButton = new JButton("Initial");
myButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
((JButton) e.getSource()).setText("New");
//Do other things
//Do more other things
((JButton) e.getSource()).setText("Initial");
}
});
That's what I've tried so far, but I know it doesn't work as expected (all the code executes. I'm not really an expert and I'm doing this things to learn, so I have no clue if there's a way to do it or not.
I've already looked for a solution to this in the web but I've not found anything (maybe I didn't search properly), so I hope there's someone who can help me with this!
PS: Sorry if my English is not perfect, I know about it. Ask me if something isn't clear about the question. Thanks to all!
Kevin.
EDIT: The app is a sudoku solver, so it takes a while //doing other things. Thats why I'm trying to change the solve button text (so it sais it is solving and when it finished it says solved).
Your logic is not wrong! Take a look at my example below:
public class MainFrame extends JFrame {
public MainFrame() {
setMinimumSize(new Dimension(200, 100));
JButton myButton = new JButton("Initial");
add(myButton);
myButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
final JButton triggerBtn = (JButton) e.getSource();
final String originalValue = triggerBtn.getText();
triggerBtn.setText("New");
JOptionPane.showMessageDialog(null, "Speak softly and carry a big stick and you will go far.");
triggerBtn.setText(originalValue);
}
});
}
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MainFrame mainFrame = new MainFrame();
mainFrame.setVisible(true);
}
});
}
}
If you run this you will see that the button is changed. If you were to change the showMessageDialog line to Thread.sleep(10*1000), you would not see a change! This is because you're running the event on the dispatcher thread and the text, even though it is changed, will not allow the change event to be triggered until your method finishes.
Consider the following alternative if the work you're doing is on the same thread:
myButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
final JButton triggerBtn = (JButton) e.getSource();
final String originalValue = triggerBtn.getText();
triggerBtn.setText("New");
SwingWorker<Void, Void> sw = new SwingWorker<Void, Void>() {
protected Void doInBackground() throws Exception {
Thread.sleep(10*1000);
return null;
}
#Override
protected void done() {
triggerBtn.setText(originalValue);
}
};
sw.execute();
}
});
This sets the text, and launches a SwingWorker to run the job asynchronously. Once finished, the dispatcher thread will update the text without requiring the dispatcher thread to be tied up waiting for it to finish (and so events are therefore handled properly).
Let me know if that works for you!
Have you tried with:
JButton myButton = new JButton("Initial");
myButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myButton.setText("New");
//Do other things
//Do more other things
myButton.setText("Initial");
}
});
In your example you're missing actionPerformed and you're not accessing button directly (I can't say what's e in your example)
Just save your current text in a local variable and set it back after you've performed your other actions.
You should also make sure it's really the button that you clicked or at least check instanceof JButton before casting.
final JButton myButton = new JButton("Initial");
myButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == myButton) {
String initialText = myButton.getText();
myButton.setText("New");
// Do other things
// Do more other things
myButton.setText(initialText);
}
}
});
You were also missing out on your actionPerformed method, the code in the question won't compile - I guess you just wrote it in the editor.

How to work with Swing timer

I'm trying to stop the program for a second using Swing Timer.
Timer timer = new Timer(10000,
new ActionListener(public void actionPerformed(ActionEvent e) {}));
didn't work
public class Card extends JButton implements ActionListener {
int numberClick = 0;
public card() {
addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
numberClick++;
if(numberClick == 2) {
Timer timer = new Timer(10000, );
timer.start();
numberClick = 0;
}
}
}
You seem to lack basic understanding of how the Timer works. Please read How to Use Swing Timers. The concept is fairly simple.
The first argument in the Timer constructor is the delay. Seems you have that part down. The second argument is the ActionListener that listens for the "Timer Events" (actually ActionEvents). An event is fired each delayed time. The callback (actionPerformed) contains what should be performed after that delay (tick). So whatever you want to happen after that second, put it in the actionPerformed of the timer's ActionListener.
Also if you only want it t occur once, you should call timer.setRepeats(false);. Also note, you are using 10000, which is in milliseconds, so it's 10 seconds, not 1. You should change it to 1000
Example Flow
JButton button = new JButton("Press Me");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
Timer timer = new Timer(1000, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Print after one second");
}
});
timer.setRepeats(false);
timer.start();
}
});
Press Button → Wait One Second → Print Statement

Cancel anonymous SwingWorker

I have run into a weird dependency when trying to cancel an anonymous SwingWorker.
My current code:
private static void init() {
if (connected) {
return;
}
//final SwingWorker<Void, Void> initWorker;
final Timer noConnectionTimer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//initWorker.cancel(true);
waitObject.setTimedOut(true);
connected = false;
waitObject.process();
}
});
new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() {
noConnectionTimer.setRepeats(false);
noConnectionTimer.start();
cachedInstance = new Network(Config.HOST_NAME, Config.HOST_PORT);
if (connected) {
noConnectionTimer.stop();
new Thread(cachedInstance).start();
waitObject.setTimedOut(false);
waitObject.process();
}
return null;
}
}.execute();
}
First assumption I want to be verified:
I can kill the new Network(Config.HOST_NAME, Config.HOST_PORT) code by killing (cancelling) the SwingWorker.
So assuming my assumption is correct, I want to cancel the anonymous SwingWorker, but when I try to give it a name initWorker, then it needs to be final such that the timer can reference it. However the SwingWorker itself needs to reference the timer aswell, so the timer also needs to be final.
So I think I managed to create a dependancy between two final variables that need eachother, how can I fix this?
Regards.
You don't have to add an ActionListener upon creation. You could just pass null to the Timer's constructor and add the ActionListener afterwards, using addActionListener.

Referencing issue with ActionListener class

I have problem referencing the Timer to the ActionListener class. I want to stop the timer after Java displays the dialog box that displays the time and starts again after clicking on "Yes".
This is what I currently have:
public class AlarmClock
{
public static void main(String[] args)
{
boolean status = true;
Timer t = null;
ActionListener listener = new TimePrinter(t);
t = new Timer(10000, listener);
t.start();
while(status)
{
}
}
}
class TimePrinter implements ActionListener
{
Timer t;
public TimePrinter(Timer t)
{
this.t = t;
}
public void actionPerformed(ActionEvent event)
{
t.stop(); //To stop the timer after it displays the time
Date now = Calendar.getInstance().getTime();
DateFormat time = new SimpleDateFormat("HH:mm:ss.");
Toolkit.getDefaultToolkit().beep();
int choice = JOptionPane.showConfirmDialog(null, "The time now is "+time.format(now)+"\nSnooze?", "Alarm Clock", JOptionPane.YES_NO_OPTION);
if(choice == JOptionPane.NO_OPTION)
{
System.exit(0);
}
else
{
JOptionPane.showMessageDialog(null, "Snooze activated.");
t.start(); //To start the timer again
}
}
}
However, this code gives a null pointer exception error. Is there any other way I can reference the Timer?
You have a chicken-and-egg problem here, since the constructors of both classes require a reference to each other. You need to break the cycle somehow, the easiest way would be to construct the Timer without a listener, then construct the listener, then add it to the timer:
t = new Timer(10000, null);
ActionListener l = new TimePrinter(t);
t.addActionListener(l);
Alternatively, you could add a setter to TimePrinter instead of passing the Timer to its constructor:
class TimePrinter implements ActionListener
{
Timer t;
public TimePrinter() {}
public setTimer(Timer t)
{
this.t = t;
}
and then do
TimePrinter listener = new TimePrinter();
t = new Timer(10000, listener);
listener.setTimer(t);
Either way the end result is the same.

Categories

Resources