My goal is creating a function that waits half second, set the jbutton's background to red for one second, and after this second the jbutton will return to normal. Cant make this work..
This is my Function
private void paint(final int num){
Timer timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (num == 1){
btn.setBackground(Color.black);
}
}
});
timer.start();
}
Start a 500ms timer that will do two things when it goes off:
- change the color to red
- start a 1s timer that will change the color to normal, when it goes off
Well, this would do it (note, you would probably want to put the code from the first sleep onwards into a timer or it's own thread in a real application to avoid blocking the thread running the code):
public static void main(String[] args) throws Exception {
final JFrame jf = new JFrame();
final JButton jButton = new JButton("Hello");
final Color originalBackground = jButton.getBackground();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jf.getContentPane().add(jButton);
jf.pack();
jf.setVisible(true);
}
});
Thread.sleep(500);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jButton.setBackground(Color.RED);
}
});
Thread.sleep(1000);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jButton.setBackground(originalBackground);
}
});
Related
This application has 2 threads the one shown here calls a method that pauses an auto clicker method every 4 seconds(just for ease) to do some mouse movement. I want it to stop the timer when you click the gui stop button.
Right now when you hit stop and then start again it then has two timers that will execute the code; and so on.
Action Listener Stuff.
class MyButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(view.getBtnStart()))
{
autoClick.unTerminate();
bool = true;
getInfo();
}
if (e.getSource().equals(view.getBtnExit()))
{
System.exit(0);
}
if (e.getSource().equals(view.getBtnStop()))
{
bool = false;
autoClick.terminate();
}
}//end of actionPerformed
}//end of inner class
Thread
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
Timer timer = new Timer(4000, new ActionListener() {//301000 5minutes and 1second
#Override
public void actionPerformed(ActionEvent evt) {
autoClick.timeOverload();
}
});
//if (!bool){timer.stop();}
timer.setRepeats(true); //false only repeates once
timer.start();
}
});//end of t2
It calls the timeOverload method repeatedly.
Thanks for your time and helping a newbie out :).
Here is a quick sample of how to declare a instance outside of your thread and be able to control it outside of it.
public static void main(String[] args){
final Timer timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("tick");
}
});
timer.setRepeats(true);
Thread t = new Thread(new Runnable() {
public void run() {
timer.start();
}
});
t.start();
try {
Thread.sleep(2600);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
timer.stop();
}
Basicly, you need to set the instance final to be used in a anonymous class (the ActionListener implementation).
Here, I just start the thread then pause the process for a few seconds and stop the timer.
Note that here, the Thread don't do anything else so it ends directly. You will need to tweek this a bit to match your needs but you have a working example.
EDIT : (DevilsHnd, if you post your answer, notify me, I will remove this part)
Using a flag (here in a Class)
public class Main {
public static void main(String[] args){
new Main();
}
boolean running = true;
public Main(){
final Timer timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(!running){
((Timer)e.getSource()).stop();
} else {
System.out.println("tick");
}
}
});
timer.setRepeats(true);
timer.start();
try {
Thread.sleep(2600);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
stop();
}
public void stop(){
running = false;
}
}
Calling the Main.stop() will set the flag to false, on each action performed, you check this flag, if it is false, you get the timer from the event (in the source) and stop it.
I have a JButton that will not allow me to perform the same action on any subsequent click on it after the first in the same Swing GUI instance.
JButton Run = new JButton("Run");
Run.setLocation(290, 70);
Run.setSize(120, 30);
buttonPanel.add(Run);
Run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Run.isEnabled()) {
errorLabel.setText("");
Result result = JUnitCore.runClasses(Run.class);
errorMessageDisplay(result);
}
}
});
totalGUI.setOpaque(true);
return totalGUI;
}
So far I thought about and tried removing the JPanel and painting all of the buttons back on, and disabling/renabling buttons.
The errorMessageDisplay method is as follows:
public void errorMessageDisplay(Result resultPass) {
if (resultPass.getFailureCount() > 0) {
errorLabel.setForeground(Color.red);
errorLabel.setVisible(true);
errorLabel.setText(" Failed");
}
else {
errorLabel.setForeground(Color.green);
errorLabel.setText(" Passed");
errorLabel.setVisible(true);
}
}
At first glance, the JUnitCore.runClasses(Run.class); call is suspicous. Also, it would be good to know what does the errorMessageDisplay() do. I believe, the problem is with one of these methods.
You can verify this with the following experimental code. Just be careful not to push it into production.
JButton run = new JButton("Run");
run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Run.isEnabled()) {
errorLabel.setText("");
System.out.println("Run action peformed.");
}
}
Update Since the errorMessageDisplay() looks okay, it's probably a Threading problem with JUniCore. Thus I'd try the following code:
final ExecutorService executor = Executors.newFixedThreadPool(5); // this runs stuff in background
JButton run = new JButton("Run");
// ..
run.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Run.isEnabled()) {
executor.execute(new Runnable() { // This is how we run stuff in background. You can use lambdas instead of Runnables.
public void run() {
final Result result = JUnitCore.runClasses(Run.class); // Run.class is different from the current JButton run.
SwingUtilities.invokeLater(new Runnable() { // Now we go back to the GUI thread
public void run() {
errorMessageDisplay(result);
}
});
}
});
}
});
So I'm trying to rotate a line every second using a Timer and a paint method. However, I'm not quite sure whats going on. Here are some of the relevant methods:
public static ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Clock cl = new Clock();
seconds++;
cl.repaint();
}
};
public void paint(Graphics g){
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
for(int c = 0; c<10; c++){
g2.setPaint(Color.BLACK);
g2.drawOval(90-c/2,90-c/2,500+c,500+c); //thick outlined circle
}
g2.setPaint(Color.WHITE);
g2.fillOval(90,90,501,501);
g2.setPaint(Color.BLACK);
g2.rotate(Math.toRadians(seconds*6));
g2.drawLine(340,340,340,90);
}
The line remains stationary. However if I add
System.out.println("tick");
to my actionPerformed method, the command line spits out "tick" 3 times a second. Any ideas as to why these things are happening?
Some context:
public static int seconds = 0;
public static int minutes = 0;
public static int hours = 0;
public static Clock cl = new Clock();
private ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("tick");
seconds++;
cl.repaint();
}
};
public static Timer timer = new Timer(1000,taskPerformer);
public static void main(String[] args){
Clock cl = new Clock();
init();
SwingUtilities.invokeLater(new Runnable(){
public void run() {
createAndShowGUI();
}
});
}
public static void init(){
timer.start();
}
public Clock() {
super("Clock");
timer.addActionListener(taskPerformer);
}
You are creating a new clock at every tick:
public void actionPerformed(ActionEvent e) {
Clock cl = new Clock();
...
Instead you should use an existing instance.
// A field in the class:
Clock cl = new Clock();
...
// removed static so that it can access cl
private ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
seconds++;
cl.repaint();
}
};
You could also make the clock a field in the action listener, if you do not need to access it elsewhere.
Also note that you generally should not be overriding paint(), but should override paintComponent() instead. More about custom painting in swing here.
Edit:
Now that there's more code available, it's possible to say that if you make the clock and action listener static it should work. However, you need to start the timer after the relevant components are ready:
public static void main(String[] args){
// Removed spurious clock here
SwingUtilities.invokeLater(new Runnable(){
public void run() {
createAndShowGUI();
// Start the timer once the components are ready
init();
}
});
}
The above mentioned point about not creating a clock in the action listener still stands.
I have hit another wall. After getting my key input working, I have been racking my brains for hours, i want to create a pause function, so that if the same key is pressed again the timertask stops running (i.e the game is paused)
JPanel component = (JPanel)frame.getContentPane();
component.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "space");
component.getActionMap().put("space", (new AbstractAction(){
public void actionPerformed(ActionEvent e){
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
public void run(){
grid.stepGame();
}
},250, 250);
}}));
}
The problem is i cant use a global boolean isRunning var and switch it each time the key is pressed because the timerTask method in a nested class (so the boolean isRunning would have to be declared final to be accessed...). Any ideas on how to detect if the key is pressed again or if the game is already running so i can pause/cancel my timerTask.
Many Thanks Sam
Since this is a Swing game, you should be using a javax.swing.Timer or Swing Timer and not a java.util.Timer. By using a Swing Timer, you guarantee that the code being called intermittently is called on the EDT, a key issue for Swing apps, and it also has a stop method that pauses the Timer. You can also give your anonymous AbstractAction class a private boolean field to check if the key is being pressed for the first time or not.
Also, kudos and 1+ for using Key Bindings instead of a KeyListener.
e.g.,
JPanel component = (JPanel) frame.getContentPane();
component.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "space");
component.getActionMap().put("space", (new AbstractAction() {
private boolean firstPress = true;
private int timerDelay = 250;
private javax.swing.Timer keyTimer = new javax.swing.Timer(timerDelay , new ActionListener() {
// Swing Timer's actionPerformed
public void actionPerformed(ActionEvent e) {
grid.stepGame();
}
});
// key binding AbstractAction's actionPerformed
public void actionPerformed(ActionEvent e) {
if (firstPress) {
keyTimer.start();
} else {
keyTimer.stop();
}
firstPress = !firstPress;
}
}));
Another useful option is to perform a repeating task on key press and stop it on key release, and this can be done easily by getting the keystrokes for on press and on release:
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true) // for key release
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false) // for key press
For example:
import java.awt.event.*;
import javax.swing.*;
public class SwingTimerEg2 {
private JFrame frame;
private Grid2 grid = new Grid2(this);
private JTextArea textarea = new JTextArea(20, 20);
private int stepCount = 0;
public SwingTimerEg2() {
frame = new JFrame();
textarea.setEditable(false);
frame.add(new JScrollPane(textarea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
setUpKeyBinding();
}
void setUpKeyBinding() {
final int timerDelay = 250;
final Timer keyTimer = new Timer(timerDelay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
grid.stepGame();
}
});
JPanel component = (JPanel) frame.getContentPane();
final int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
final String spaceDown = "space down";
final String spaceUp = "space up";
component.getInputMap(condition).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), spaceDown);
component.getActionMap().put(spaceDown, (new AbstractAction() {
public void actionPerformed(ActionEvent e) {
keyTimer.start();
}
}));
component.getInputMap(condition).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), spaceUp);
component.getActionMap().put(spaceUp, (new AbstractAction() {
public void actionPerformed(ActionEvent e) {
keyTimer.stop();
}
}));
}
public void doSomething() {
textarea.append(String.format("Zap %d!!!%n", stepCount));
stepCount ++;
}
private static void createAndShowGui() {
new SwingTimerEg2();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class Grid2 {
private SwingTimerEg2 stEg;
public Grid2(SwingTimerEg2 stEg) {
this.stEg = stEg;
}
void stepGame() {
stEg.doSomething();
}
}
Easiest and dirty solution:
final boolean[] isRunning = new boolean[1];
You don't want to do that—but it works assuming proper synchronization around.
What would be better is
final AtomicBoolean isRunning = new AtomicBoolean();
What would be even better is to review the design once again: global state usually means, "global problems"
The final qualifier requirement can easily be avoided -- replace your inner method (which has the final requirement) with a call to a class method.
No you got the wrong idea about WHY you need final for anonymous classes! Final is only needed for local variables (well more exactly any variable that might have a live time shorter than the given object).
Hence a static variable in a class is perfectly fine and will work perfectly!
Edit: example:
public class Main {
interface Test {
void call();
}
public static volatile boolean running = true;
public static void main(String[] args) {
Test t = new Test() {
#Override
public void call() {
System.out.println(Main.running);
}
};
t.call();
running = false;
t.call();
}
}
Keep a reference to the Timer somewhere, say in your game class.
When the game is paused cancel the Timer.
This will cancel any currently scheduled tasks.
Then when the game is unpaused schedule the timer again as you have done above.
public class Game {
private Timer timer;
public void pause() {
if (timer != null) {
timer.pause();
}
}
public void startOrResumeGame() {
if (timer == null) {
timer = new Timer();
} else {
// Just in case the game was already running.
timer.cancel();
}
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
grid.stepGame();
}
}, 250, 250);
}
}
I'm new to Swing and I was trying to do this:
On pressing a JButton, the program will start iterating over hundreds of items, taking 1 second to process each one, and after finishing each one he should update a label to show the number of items already processed.
The problem is, the label's text is not updated until the cycle finishes iterating over all the items.
I searched online and apparently it's because this is running in the same thread, so I created a new thread to process the data and to update the variable to be used in the label (number of processed files).
But it didn't work. Then I even made another thread, which I start after the previous one, that just repaints the label. Still nothing works.
The code is like this:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try { SwingUtilities.invokeLater(validateFiles); }
}); }
Runnable validateFiles = new Runnable() {
#Override
public void run() {
while(x_is_not_100) {
processLoadsOfStuff();
label.setText(x); }
}
};
Can you help me with this?
Simple - use a SwingWorker. For more information, read the Tasks that Have Interim Results tutorial.
Here's a pretty generic example that will use a JLabel to display counting from 0 to 30 -
public final class SwingWorkerDemo {
private static JLabel label =
new JLabel(String.valueOf(0), SwingConstants.CENTER);
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
createAndShowGUI();
}
});
JLabelSwingWorker workerThread = new JLabelSwingWorker();
workerThread.run();
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static class JLabelSwingWorker extends SwingWorker<Void, Integer>{
#Override
protected Void doInBackground() throws Exception {
for(int i = 1; i < 31; i++){
Thread.sleep(1000);
publish(i);
}
return null;
}
#Override
protected void process(List<Integer> integers) {
Integer i = integers.get(integers.size() - 1);
label.setText(i.toString());
}
}
}
The background processing must be done in a separate thread. But the label update must be done in the event dispatch thread.
So your code should look like this:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// start a new thread for the background task
new Thread(validateFiles).start();
});
}
Runnable validateFiles = new Runnable() {
#Override
public void run() {
while(x_is_not_100) {
processLoadsOfStuff();
// use SwingUtilities.invokeLater so that the label update is done in the EDT:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
label.setText(x);
}
});
}
};
But you might want to use the SwingWorker class, which is designed to do that in a simpler way. Its documentation is very well done and contains examples.