This is a part of my java code, in this code there are labels which are counting numbers from 0 up to so on, I want to stop labels to count when I click the button 1st time, and I want to restart the labels to count again when I click the button 2nd time, the problem is that the labels are not restarting there counting when I am clicking the button 2nd time, so please tell how should I notify all the labels to restart there counting???
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
public class Main implements ActionListener {
JButton button = new JButton("Click");
JFrame frame = new JFrame();
boolean wait=false;
public static void main(String arg[]) {
new Main();
}
public Main() {
frame.setLayout(new FlowLayout());
frame.getContentPane().setBackground(Color.BLACK);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
button.addActionListener(this);
frame.add(button);
frame.setVisible(true);
new Producer().execute();
}
public class Producer extends SwingWorker<Void, Void> {
public Void doInBackground() {
for(int infinite=0; infinite!=-1; infinite++) {
new Counter().execute();
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
}
return null;
}
}
public class Counter extends SwingWorker<Void, Void> {
JLabel label = new JLabel();
public Counter() {
label.setForeground(Color.WHITE);
frame.add(label);
}
public Void doInBackground() {
synchronized (this) {
for(int i=0; i!=-1; i++) {
if(wait==true)
try {this.wait();} catch(Exception exp) {exp.printStackTrace();}
label.setText(""+i);
try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
}
}
return null;
}
}
public void actionPerformed(ActionEvent clicked) {
if(wait==false)
wait=true;
else if(wait==true) {
synchronized (this) {
this.notifyAll();
}
}
}
}
I don't see a place where you ever reset wait to false. Try this and see if it gets you unstuck:
public void actionPerformed(ActionEvent clicked) {
if(wait==false) {
wait=true;
} else {
wait=false;
synchronized (this) {
this.notifyAll();
}
}
}
Related
I have to make the timer codes of Java using awt,swing,Thread.
The overview of the eventual app has below 4 features.
The app has just one button.
Firstly the button display the "START"on the button itself.
Dynamic time is displayed on the button as the button is pressed.
As the button pressed while counting the time,the button stop the counting and display "START".
I've written the code such as below.
boolean isCounting = false;
int cnt = 0;
void counter() {
while (isCounting == true) {
btn.setText(Integer.toString(++cnt));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void actionPerformed(ActionEvent e) {
if (isCounting == true) {
isCounting = false;
} else {
isCounting = true;
counter();
}
}
Of course this code doesn't satisfy the conditions because once the button is pressed then
the button is no more able to be pressed again and the counter never works.
In this code,once the button is pressed then the function "counter" is called but the value on the button never changes until the button is unpressed.
I have to make the codes satisfying the above conditions.
How do I implement it?
If I understood your question correctly, then this snippet I quickly put together should work for you.
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Testing {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Testing t = new Testing();
}
});
}
private Timer timer;
private JFrame frame;
private JButton btn;
private int timePassed;
public Testing() {
frame = new JFrame();
timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timePassed++;
updateTimeOnButton();
}
});
btn = new JButton("START");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (timer.isRunning()) {
timer.stop();
btn.setText("START");
} else {
timePassed = 0;
timer.start();
updateTimeOnButton();
}
}
});
frame.getContentPane().add(btn);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(new Dimension(300, 300));
}
private void updateTimeOnButton() {
btn.setText(timePassed + " seconds");
}
}
We are using foxtrot package for stop freeze the swing application.
But in this below code it make a deadlock.
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import foxtrot.Task;
import foxtrot.Worker;
public class FoxtrotExample extends JFrame {
public static void main(String[] args) {
FoxtrotExample example = new FoxtrotExample();
example.setVisible(true);
}
boolean st = true;
public FoxtrotExample() {
super("Foxtrot Example");
final JButton button = new JButton("Take a nap !");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Start..");
button.setText("Sleeping...");
String text = null;
try {
text = (String) Worker.post(new Task() {
public Object run() throws Exception {
System.out.println("Inside Worker 1");
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
System.out.println("Inside invokeLater");
Worker.post(new Task() {
#Override
public Object run()
throws Exception {
System.out.println("Inside Worker 2");
st = false;
return null;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
while (st) {
System.out.println("Inside the loop..");
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
return "Slept !";
}
});
} catch (Exception x) {
}
button.setText(text);
System.out.println("Finished.....");
}
});
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new GridBagLayout());
c.add(button);
setSize(300, 200);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
Dimension size = getSize();
int x = (screen.width - size.width) >> 1;
int y = (screen.height - size.height) >> 1;
setLocation(x, y);
}
}
If use ConcurrentWorker this will work fine.Can any one explane this.
I am bit confuse how EDT behave here ?
This is the result of my program.
Start 1st worker
In the loop
Start invoke later
In the loop
In the loop
In the loop
In the loop
......
It start the 1st worker.Then part of the code is in invokeLater.So request is enqued in the event queue and start the loop.Later execute the invokeLater but not execute the 2nd worker because first worker still doing some work.Since worker are ruining one after another and it runs on a single worker queue 2nd worker cannot execute and deadlock comes.
Thanks to MadProgrammer i understood this.Hope this is correct.
I have Java Swing code that process user's input as follows:
public class UserEntryPane extends JPanel implements DocumentListener {
…
#Override
public void insertUpdate(DocumentEvent e) {
try {
String c = a.getText(...);
if (c.equals("\n")) {
System.out.println(...);
...
}
else {
...
}
} catch (Exception e) {
e.printStackTrace();
}
}
The issue is that this method is not invoked when Backspace is pressed. How can I detect user's Backspace to process it correctly?
Seems you use DocumentListener.
Look at method removeUpdate. It called, when you use backspace.
#Override
public void removeUpdate(DocumentEvent arg0) {
}
import java.awt.FlowLayout;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class UseBackSPace extends JFrame
{
Robot r;
void start()
{
try
{
JFrame f = new JFrame("UseBackSPace");
JTextField txt = new JTextField(20);
f.add(txt);
f.setSize(500, 200);
f.setVisible(true);
f.setLayout(new FlowLayout());
f.setDefaultCloseOperation(EXIT_ON_CLOSE);
// f.setLocation(400, 400);
r = new Robot();
r.setAutoDelay(900);
r.keyPress(KeyEvent.VK_T);
r.keyPress(KeyEvent.VK_H);
r.keyPress(KeyEvent.VK_I);
r.keyPress(KeyEvent.VK_S);
r.keyPress(KeyEvent.VK_SPACE);
r.keyPress(KeyEvent.VK_I);
r.keyPress(KeyEvent.VK_S);
r.keyPress(KeyEvent.VK_SPACE);
r.keyPress(KeyEvent.VK_F);
r.keyPress(KeyEvent.VK_U);
r.keyPress(KeyEvent.VK_N);
r.keyPress(KeyEvent.VK_BACK_SPACE);
} catch (Exception e)
{
}
}
public static void main(String args[])
{
new UseBackSPace().start();
}
}
Ok, so I made a simple program that adds the value to counter each time a button is clicked.
Now, I would like to add "Auto" button feature to increase the value of the counter when the "Auto" button is clicked. I'm having problems with it because it won't render each counter value on the screen, instead the value updates when the loop is done.. Here is my code:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Gui extends JFrame{
private static final long serialVersionUID = 1L;
private JButton uselesButton;
private JButton autoButton;
private FlowLayout layout;
private long counter = 0;
public Gui() {
super("Button");
layout = new FlowLayout(FlowLayout.CENTER);
this.setLayout(layout);
uselesButton = new JButton(String.format("Pressed %d times", counter));
add(uselesButton);
uselesButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter++;
uselesButton.setText(String.format("Pressed %d times", counter));
}
});
autoButton = new JButton("Auto");
add(autoButton);
autoButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for(long i =0; i < 99999999;i++) {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e1) {
System.out.println("ERROR");
}
counter = i;
uselesButton.setText(String.format("Pressed %d times", counter));
}
}
});
}
}
Keep in mind that I'm a beginner... All help appreciated :)
Take a look at the tutorial about How to Use Swing Timer and then look at my solution:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Gui extends JFrame {
private static final long serialVersionUID = 1L;
private JButton uselesButton;
private JButton autoButton;
private FlowLayout layout;
private long counter = 0;
private javax.swing.Timer timer;
public Gui() {
super("Button");
layout = new FlowLayout(FlowLayout.CENTER);
setLayout(layout);
setDefaultCloseOperation(3);
setSize(300, 300);
setLocationRelativeTo(null);
//initialing swing timer
timer = new javax.swing.Timer(100, getButtonAction());
autoButton = new JButton("Auto");
add(autoButton);
autoButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (!timer.isRunning()) {
timer.start();
} else {
timer.stop();
}
}
});
}
private ActionListener getButtonAction() {
ActionListener action = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
autoButton.setText(String.format("Pressed %d times", ++counter));
if (counter > 1000) {
timer.stop();
}
}
};
return action;
}
public static void main(String... args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Gui().setVisible(true);
}
});
}
}
your code block the GUI thread (EDT) when enter inside this loop (GUI will hang, the button will not update until you finish), so you should add your code inside another worker thread:
autoButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Thread(new Runnable() {
#Override
public void run() {
for(long i =0; i < 99999999;i++) {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e1) {
System.out.println("ERROR");
}
counter = i;
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
uselesButton.setText(String.format("Pressed %d times", counter));
}
});
}
}
}).start();
}
});
the problem here is that the system is in the loop, so it can't paint the changes.
in order to do that you need to open a new thread. the new thread will do the loop, and the main thread will repaint the form.
one more thing, you shouldn't do sleep on the main thread. you can use a timer that will tick every 10 millisecond instead of sleep(10)
here is an example
I am trying to make this work. I create a window, with one text field and button, then I run the run() method which should refresh text in textfield, and when I click on button it should iterate number by 1. I want to make this work simultaneously but I am stuck. It just iterates the number but do not refresh a value in textfield.Could you please help me somehow? I thought its easy to learn about Threads but...no :-D Here is the code.
Window class
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
#SuppressWarnings("serial")
public class Okno extends JFrame implements ActionListener,Runnable {
private JFrame o = new JFrame();
private static JTextField t = new JTextField();
private JTextField t2 = new JTextField();
private static int x = 0;
protected JButton b = new JButton("KLIK");
Okno() {
o.setVisible(true);
o.setBounds(0, 0, 300, 200);
o.setLayout(null);
o.setDefaultCloseOperation(EXIT_ON_CLOSE);
t.setBounds(10, 10, 60, 20);
t2.setBounds(80, 10, 60, 20);
b.setBounds(50, 80, 60, 30);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
while (true) {
Okno.work();
System.out.println("Klik");
}
}
});
o.add(t);
o.add(b);
o.add(t2);
}
public static int iter(){
x++;
return x;
}
public static void work(){
try {
iter();
System.out.println(x);
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
}
#Override
public void run() {
while(true){
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.setText(Integer.toString(x));
System.out.println("RUN");
}
}
}
Main Class
public class ThreadDemo {
public static void main(String args[]) {
Okno o = new Okno();
while(true){
o.run();
}
}
}
Swing is single threaded. Calling Thread.sleep prevents UI updates. Use a Swing Timer instead.
From GETah's answer to java stopwatch that updates gui every second:
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.