Why is my looping GUI timer not showing up? - java

I'm trying to make a GUI timer without using javax.swing.Timer(kind of a strange task), but I am having trouble making it work. It's supposed to sleep the thread for 1 second, add 1 to seconds, and repeat(infinitely). When I run my program, the icon shows up, but the window does not appear. I'm guessing my error is in the Thread.sleep(1000); line or in that area, but I'm not sure why it doesn't work. Is Thread.sleep(millis)not compatible with swing applications? Do I have to multithread? Here's my program:
import java.awt.*;
import javax.swing.*;
public class GUITimer extends JFrame {
private static final long serialVersionUID = 1L;
private int seconds = 0;
public GUITimer() {
initGUI();
pack();
setVisible(true);
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void initGUI(){
JLabel title = new JLabel("Timer");
Font titleFont = new Font(Font.SERIF, Font.BOLD, 32);
title.setFont(titleFont);
title.setHorizontalAlignment(JLabel.CENTER);
title.setBackground(Color.BLACK);
title.setForeground(Color.WHITE);
title.setOpaque(true);
add(title, BorderLayout.NORTH);
JLabel timeDisplay = new JLabel(Integer.toString(seconds));//this label shows seconds
add(timeDisplay, BorderLayout.CENTER);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
seconds++;
initGUI();
}
public static void main(String[] args) {
try {
String className = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(className);
}
catch (Exception e) {}
EventQueue.invokeLater(new Runnable() {
public void run() {
new GUITimer();
}
});
}
}
EDIT:
I noticed when I print seconds in my method initGUI() to console, it prints them incrementally by one second correctly. So when it looks like:
private void initGUI() {
System.out.println(seconds);
//...
it prints the value of seconds after every second(How the JLabel should). This shows that my loop is working fine, and my Thread.sleep(1000) is OK also. My only problem now, is that the frame is not showing up.

Your main window does not appear, because you called infinite recursion inside constructor. GUITimer will not be created and this lock main thread.
You need use multithreading for this aim. Main thread for drawing time, second thread increment and put value to label
For example:
import javax.swing.*;
import java.awt.*;
public class GUITimer extends JFrame
{
private static final long serialVersionUID = 1L;
private int seconds = 0;
private Thread timerThread;
private JLabel timeDisplay;
public GUITimer()
{
initGUI();
pack();
setVisible(true);
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void initGUI()
{
JLabel title = new JLabel("Timer");
Font titleFont = new Font(Font.SERIF, Font.BOLD, 32);
title.setFont(titleFont);
title.setHorizontalAlignment(JLabel.CENTER);
title.setBackground(Color.BLACK);
title.setForeground(Color.WHITE);
title.setOpaque(true);
add(title, BorderLayout.NORTH);
timeDisplay = new JLabel(Integer.toString(seconds));//this label shows seconds
add(timeDisplay, BorderLayout.CENTER);
}
public void start()
{
seconds = 0;
timerThread = new Thread(new Runnable()
{
#Override
public void run()
{
while(true)
{
timeDisplay.setText(Integer.toString(seconds++));
try
{
Thread.sleep(1000L);
}
catch(InterruptedException e) {}
}
}
});
timerThread.start();
}
public void stop()
{
timerThread.interrupt();
}
public static void main(String[] args)
{
try
{
GUITimer timer = new GUITimer();
timer.start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}

The core issue is, you're blocking the UI by continuously calling initGUI, which will eventually fail with a StackOverFlowException, as the method calls never end
The preference would be to use a Swing Timer, but since you've stated you don't want to do that, a better solution would be to use a SwingWorker, the reason for this - Swing is NOT thread safe and SwingWorker provides a convenient mechanism for allowing us to update the UI safely.
Because both Swing Timer and Thead.sleep only guarantee a minimum delay, they are not a reliable means for measuring the passage of time, it would be better to make use of Java 8's Date/Time API instead
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label = new JLabel("00:00:00");
private TimeWorker timeWorker;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(label, gbc);
JButton button = new JButton("Start");
add(button, gbc);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (timeWorker == null) {
timeWorker = new TimeWorker(label);
timeWorker.execute();
button.setText("Stop");
} else {
timeWorker.cancel(true);
timeWorker = null;
button.setText("Start");
}
}
});
}
}
public class TimeWorker extends SwingWorker<Void, Duration> {
private JLabel label;
public TimeWorker(JLabel label) {
this.label = label;
}
#Override
protected Void doInBackground() throws Exception {
LocalDateTime startTime = LocalDateTime.now();
Duration totalDuration = Duration.ZERO;
while (!isCancelled()) {
LocalDateTime now = LocalDateTime.now();
Duration tickDuration = Duration.between(startTime, now);
publish(tickDuration);
Thread.sleep(500);
}
return null;
}
#Override
protected void process(List<Duration> chunks) {
Duration duration = chunks.get(chunks.size() - 1);
String text = format(duration);
label.setText(text);
}
public String format(Duration duration) {
long hours = duration.toHours();
duration = duration.minusHours(hours);
long minutes = duration.toMinutes();
duration = duration.minusMinutes(minutes);
long millis = duration.toMillis();
long seconds = (long)(millis / 1000.0);
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
}
}
}

Related

Need assistance java Thread slot machine

I need to make a slot machine that implements thread in java and jframe
this is what iv'e done so far kindly tell me what i need to do in order make the images change per .5 seconds when i press the the play and stop when i press stop. If all the three images are the same it'll say you won. This is what iv'e got so far how will i change this numbers or text to images in jlabel.
public class MySlotNumber extends JFrame{
private MyJLabel x;
private MyJLabel y;
private MyJLabel z;
private JButton btn;
public MySlotNumber(){
super("ABC");
setLayout(new FlowLayout());
Font font = new Font("arial",Font.ITALIC,50);
x = new MyJLabel();
x.setFont(font);
y = new MyJLabel();
y.setFont(font);
z = new MyJLabel();
z.setFont(font);
btn = new JButton("PLAY");
btn.setFont(font);
add(x);
add(y);
add(z);
add(btn);
final Thread thx = new Thread(x);
final Thread thy = new Thread(y);
final Thread thz = new Thread(z);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("PLAY")){
if(thx.isAlive()){
thx.resume();
thy.resume();
thz.resume();
} else {
thx.start();
thy.start();
thz.start();
}
btn.setText("STOP");
} else {
thx.suspend();
thy.suspend();
thz.suspend();
btn.setText("PLAY");
System.out.println(x.getText());
}
}
});
}
- - - - - - --
public class MyJLabel extends JLabel implements Runnable{
private Random r;
private int ctr;
private final int T = 500;
public MyJLabel(){
setText("0");
ctr = 0;
r= new Random();
}
#Override
public void run() {
while(true){
try {
Thread.sleep(T);
} catch (InterruptedException ex) {
Logger.getLogger(MyJLabel.class.getName()).log(Level.SEVERE, null, ex);
}
//ctr++;
ctr = r.nextInt(9)+1;
setText(String.valueOf(ctr));
}
}
}
Here is one way to put a picture on a JLabel and change it when you click a button. (I am using window builder for eclipse, so it may look a little odd.) It is not recommended you use absolute paths because when you move your project or the file, it breaks (I did this just for proof of concept).
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.BorderLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Test {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Test window = new Test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Test() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 1379, 643);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel lblNewLabel = new JLabel("");
lblNewLabel.setIcon(new ImageIcon("C:\\Users\\Andrew\\Pictures\\Random Pictures\\Capture.JPG"));
frame.getContentPane().add(lblNewLabel, BorderLayout.CENTER);
JButton btnClickMe = new JButton("click me");
btnClickMe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
lblNewLabel.setIcon(new ImageIcon("C:\\Users\\Andrew\\Pictures\\Random Pictures\\I'm pretty sure he did.JPG"));
}
});
frame.getContentPane().add(btnClickMe, BorderLayout.EAST);
}
}

Refresh jTextField following a timer

I'm working on an assignment for Java subject. I'm using NetBean IDE. My assignment requests me to make a word game. The game I'm designing involves a timer with delay of 1000 ms. The timer decrements a variable from 30 to 0. The timer itself is working. It is placed in the main function of GUI class. The problem I'm facing that I don't know how I'm supposed to update a jTextfield with everytime the variable is decremented.
public static void main(String args[]) {
Time counter=new Time();
ActionListener actListner = new ActionListener() {
public void actionPerformed(ActionEvent event) {
counter.decTime();
jTime.setText("Time left: " + counter.getTime());
}
};
Timer timer = new Timer(1000, actListner);
timer.start();
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new StartGUI().setVisible(true);
}
});
}
I'm not sure how to implement this properly
jTime.setText("Time left: " + counter.getTime());
Not sure what you're doing wrong (that's why you should always provide a short example that we can copy-paste-compile-run that demonstrates the problem. When I make the code runnable, it works fine. That's why we need to be able to run your code to see where you're going wrong.
Here's the runnable version:
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.Timer;
public class StartGUI extends JFrame {
static JTextField jTime = new JTextField(10);
public StartGUI() {
jTime.setEditable(false);
add(jTime);
setLayout(new GridBagLayout());
setSize(200, 200);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
}
static class Time {
int time = 1000;
void decTime() {
time--;
}
int getTime() {
return time;
}
}
public static void main(String args[]) {
Time counter = new Time();
ActionListener actListner = new ActionListener() {
public void actionPerformed(ActionEvent event) {
counter.decTime();
jTime.setText("Time left: " + counter.getTime());
}
};
Timer timer = new Timer(1000, actListner);
timer.start();
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new StartGUI().setVisible(true);
}
});
}
}
Here is the code refactored a bit with some better practices
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.Timer;
public class StartGUI extends JFrame {
private JTextField jTime = new JTextField(10);
private Timer timer = createTimer(1000);
public StartGUI() {
jTime.setEditable(false);
add(jTime);
setLayout(new GridBagLayout());
pack();
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
}
private Timer createTimer(int delay) {
Timer timer = new Timer(delay, new ActionListener(){
Time counter = new Time(30);
public void actionPerformed(ActionEvent e) {
if (counter.getTime() == 0) {
((Timer)e.getSource()).stop();
jTime.setText("Times up!");
} else {
jTime.setText("Time left: " + counter.getTime());
counter.decTime();
}
}
});
timer.setInitialDelay(0);
return timer;
}
private Timer getTimer() {
return timer;
}
static class Time {
int time = 1000;
public Time(int time) {
this.time = time;
}
void decTime() {
time--;
}
int getTime() {
return time;
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
StartGUI start = new StartGUI();
start.setVisible(true);
start.getTimer().start();
}
});
}
}

Swing Countdown from 5 to 0

I am creating a Java Swing game and before every new game I would like to have a frame show up and countdown from 5 to 0 seconds.
While this is happening I would like the game in the background to wait until the countdown is complete. What would be the best way to make the game in the background wait?
I have tried Thread.sleep but this causes the The Event Dispatch Thread to sleep and the GUI not to update. However, it works the first time i run it but not the second.
Thankful for your help.
public class CountdownPresenterPanel {
JFrame mainFrame;
int currentNumber = 5;
JLabel textLabel;
CountdownPresenterPanel() {
mainFrame = new JFrame();
textLabel = new JLabel(String.valueOf(currentNumber), SwingConstants.CENTER);
textLabel.setFont(new Font("Arial", Font.BOLD, 55));
textLabel.setVerticalAlignment(SwingConstants.CENTER);
mainFrame.add(textLabel);
mainFrame.setUndecorated(true); // Remove bar including close, minimize
mainFrame.setSize(600,300);
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(currentNumber > 0) {
currentNumber--;
textLabel.setText(String.valueOf(currentNumber));
} else {
mainFrame.setVisible(false);
mainFrame.dispose();
}
}
});
timer.setRepeats(true);
timer.start();
}
}
Solution
import java.awt.*;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.Timer;
public class CountdownPresenterPanel {
private int currentNumber = 5;
private JLabel textLabel;
private final JDialog dialog;
CountdownPresenterPanel() {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(currentNumber > 0) {
currentNumber--;
textLabel.setText(String.valueOf(currentNumber));
} else {
dialog.dispose();
}
}
});
Frame window = new Frame();
dialog = new JDialog(window, "Alert", true);
textLabel = new JLabel(String.valueOf(currentNumber), SwingConstants.CENTER);
textLabel.setFont(new Font("Arial", Font.BOLD, 55)); // Increase the font-size
dialog.add(textLabel);
dialog.setSize(400, 200);
dialog.setLocationRelativeTo(null);
timer.setRepeats(true);
timer.start();
dialog.setUndecorated(true);
dialog.setVisible(true);
}
}
Don't use a JFrame, use some kind of modal dialog
Take a look at How to Make Dialogs for more details
Seems that you want something like a SplashScreen. Have you looked to the SplasScreen Tutorial from Oracle? There Thread.sleep() is used safely and it updates the graphics correctly. I think it to be your unique solution. The only way to let the undergoing application to wait is to use the same thread. The reason your Timer didn't work is because it creates another thread to run itself.
Another option is to use a SwingWorker:
import java.awt.*;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.beans.*;
import javax.swing.*;
public class CountdownPresenterPanel2 {
public static void main(String[] args) {
final JFrame frame = new JFrame();
final JDialog splashScreen = new JDialog(null, Dialog.ModalityType.DOCUMENT_MODAL);
final JLabel textLabel = new JLabel(String.valueOf(5), SwingConstants.CENTER);
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
textLabel.setFont(new Font("Arial", Font.BOLD, 55));
textLabel.setVerticalAlignment(SwingConstants.CENTER);
splashScreen.setUndecorated(true);
splashScreen.getContentPane().add(textLabel);
splashScreen.setSize(600, 300);
splashScreen.setLocationRelativeTo(null);
splashScreen.setVisible(true);
}
});
(new GamePanelInitTask() {
#Override protected void process(java.util.List<Integer> chunks) {
for (Integer value : chunks) {
textLabel.setText(value.toString());
}
}
#Override public void done() {
splashScreen.dispose();
try {
MainGamePanel p = get();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(p);
frame.setSize(320, 240);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
}
}).execute();
}
}
class GamePanelInitTask extends SwingWorker<MainGamePanel, Integer> {
#Override public MainGamePanel doInBackground() {
int currentNumber = 5;
MainGamePanel game = new MainGamePanel();
while (currentNumber > 0 && !isCancelled()) {
currentNumber--;
publish(currentNumber);
game.add(new JLabel(String.format("Label: %d", currentNumber)));
try {
Thread.sleep(1000); //dummy task
} catch (InterruptedException ie) {
ie.printStackTrace();
return null;
}
}
return game;
}
}
class MainGamePanel extends JPanel {
public MainGamePanel() {
super();
try {
Thread.sleep(1000); //dummy task
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

Multithreading program not working

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.

How to update the JTextField when the variable value is changed?

I have two Java(.java) files. One has a JButton and JTextField and the other has a Thread. In first Java file, I have added an ActionListener to the JButton so that, when the button is pressed, a thread (object for 2nd .java file in created and thread is initiated) runs which modifies an integer variable continuously. How to display the value of that integer variable (of 2nd .java file) in the JTextField (of 1st .java file) ?
Detection.java
package sample;
public class Detection implements Runnable
{
public String viewers;
public int count;
public void run()
{
try
{
while (true)
{
// i have written code for displaying video.
// and it say how many no. of people in the video
// the no of people is stored in a variable "count"
viewers=""+count; //storing count as string so as to display in the JTextField
}
}
catch (Exception e)
{
System.out.println("Exception: "+e);
}
}
}
UsrInterfac.java
//build using WindowBuilder eclipse juno
package sample;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextField;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class UsrInterfac
{
private JFrame frame;
private JTextField textField;
Detection dd = new Detection();
Thread th = new Thread(dd);
/**
* Launch the application.
*/
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
UsrInterfac window = new UsrInterfac();
window.frame.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public UsrInterfac()
{
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize()
{
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton btnStartThread = new JButton("Start Thread");
btnStartThread.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
th.start();
}
});
btnStartThread.setBounds(59, 133, 117, 23);
frame.getContentPane().add(btnStartThread);
textField = new JTextField();
textField.setBounds(270, 134, 104, 20);
frame.getContentPane().add(textField);
textField.setColumns(10);
}
}
Starting from the basics, while using Swing, it is always best to use LayoutManagers, which can make your work much more easier, in comparison to using Absolute Positioning.
Whenever one needs to change something in the View from some another thread, it is always advisable to do that using EventQueue.invokeLater(...)/EventQueue.invokeAndWait(...).
This small sample program, might be able to help you get an idea, how to accomplish what you so desire :-)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ThreadCounter
{
private CustomThread cThread;
private JTextField tField;
private JButton button;
private int counter;
public ThreadCounter()
{
counter = 0;
}
private void displayGUI()
{
JFrame frame = new JFrame("Thread Counter Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
tField = new JTextField(10);
tField.setText("0");
button = new JButton("Start");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
if (counter == 0)
{
cThread = new CustomThread(tField);
cThread.setFlagValue(true);
cThread.start();
counter = 1;
button.setText("Stop");
}
else
{
try
{
cThread.setFlagValue(false);
cThread.join();
}
catch(InterruptedException ie)
{
ie.printStackTrace();
}
counter = 0;
button.setText("Start");
}
}
});
contentPane.add(tField);
contentPane.add(button);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
new ThreadCounter().displayGUI();
}
});
}
}
class CustomThread extends Thread
{
private int changingVariable;
private JTextField tField;
private boolean flag = true;
public CustomThread(JTextField tf)
{
changingVariable = 0;
tField = tf;
}
public void setFlagValue(boolean flag)
{
this.flag = flag;
}
#Override
public void run()
{
while (flag)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
tField.setText(
Integer.toString(
++changingVariable));
}
});
try
{
Thread.sleep(1000);
}
catch(InterruptedException ie)
{
ie.printStackTrace();
}
}
System.out.println("I am OUT of WHILE");
}
}
Ideally you should post your code. Anyway, when you are calling the thread code, either pass the instance of the first class (object) or an instance of JTextField, so that the thread can set the new value in the text field.

Categories