Multithreading with one JTextBox - java

I have some code here that causes an issue for me. I am creating an application that will change the humidity of a greenhouse and then put it in a JTextBox. I have two classes, one to change the humidity and another class that takes care of ambient humidity. The two classes share one text box and the problem is that sometimes two values get printed on one another. How can I do this so that the threads do not overlap with their text box input?
private class humidControl implements Runnable {
public void run() {
try {
screen.setField(String.valueOf(calc.getHumid()), 21);
Thread.sleep(1000*humidTime);
while(on == true) {
calc.changeHumid();
screen.setField(String.valueOf(calc.getHumid()), 21);
if(calc.getHumidifier())
screen.setField("Humidifier is on", 24);
else if (!calc.getHumidifier());
screen.setField("Humidifier is off", 24);
Thread.sleep(1000*humidTime);
}
}
catch (InterruptedException e) {
return;
}
}
}
private class AmbientHumid implements Runnable {
public void run() {
try {
while(on == true) {
calc.ambientHumid();
screen.setField(String.valueOf(calc.getHumid()), 21);
Thread.sleep(1000*AhumidTime);
}
}
catch (InterruptedException e) {
return;
}
}
}

Never ever modify or access any Swing component from any thread other than the event dispatch thread. Swing components are NOT thread safe and are confined to the EDT. Use SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait() from other Threads. SwingWorker also comes in handy when having to do work off the EDT and then modify some Swing component in the end.

Simple, in the humid runnable, you output at 21 and the AmbientHumid outputs at 21 as well, i suggest outputting the AmbientHumid at, say 27, so the overlap won't occur.

Related

How to stop JButton from performing an endless loop

Basically what I'm trying to do is continuously append a string of text into a JTextPane when the user clicks a button. The loop will only stop when the user clicks on the button again. This is in my button's actionPerformed method:
StyledDocument xpInfo = txtXPInfo.getStyledDocument();
if (btnGo.getText().equals("Go Adventure!")) {
btnGo.setText("Stop Adventure");
try {
do {
xpInfo.insertString(xpInfo.getLength(), "Some string\n", null);
txtXPInfo.update(txtXPInfo.getGraphics());
Thread.sleep(1000);
} while (btnGo.getText().equals("Stop Adventure"));
} catch (BadLocationException e) {
System.out.println(e);
} catch (InterruptedException ex) {
Logger.getLogger(FrmPlay.class.getName()).log(Level.SEVERE, null, ex);
}
} else if (btnGo.getText().equals("Stop Adventure")) {
btnGo.setText("Go Adventure!");
}
The code I wrote seemed to be an endless loop. I thought it might be because I did all those in the button's actionPerformed method, but I have no idea how else to make it. I'm sorry if this is such a stupid question. I give my thanks in advance to anyone who's willing to answer this question!
You could use ScheduledExecutorService as its main purpose is executing tasks on separate thread with some specified time interval. But you need to keep in mind that all UI-related operations must be done from EDT, so you should wrap txtXPInfo updating operations with SwingUtilities.invokeLater():
private final ScheduledExecutorService xpInfoScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> xpInfoUpdatingFuture;
public void actionPerformed() {
StyledDocument xpInfo = txtXPInfo.getStyledDocument();
if (btnGo.getText().equals("Go Adventure!")) {
btnGo.setText("Stop Adventure");
xpInfoUpdatingFuture = xpInfoScheduledExecutor.scheduleAtFixedRate(
new XpInfoUpdater(), 0, 1, TimeUnit.SECONDS);
} else if (btnGo.getText().equals("Stop Adventure")) {
xpInfoUpdatingFuture.cancel(true);
btnGo.setText("Go Adventure!");
}
}
private class XpInfoUpdater implements Runnable {
#Override
public void run() {
SwingUtilities.invokeLater(() -> {
try {
xpInfo.insertString(xpInfo.getLength(), "Some string\n", null);
txtXPInfo.update(txtXPInfo.getGraphics());
} catch (BadLocationException e) {
System.out.println(e);
}
});
}
}
I think your issue is that you're blocking the Event Thread. In Swing, there's only a single thread that the OS uses to dispatch UI events (like a button press).
In your case, It appears that you're looping infinitely on that thread. If you are, then the other button presses will never register, because that thread is busy with your do/while loop.
What you really want to do is start a different thread (there are lots of examples of this) that do the append loop, and leave the Event Thread for dispatching UI events.

creat flashing text by using java multithread method sleep()

hi im creating a flashing text frame by using threading handling method, here is my code:
import javax.swing.*;
public class FlashingText extends JApplet implements Runnable {
/**
*
*/
private static final long serialVersionUID = 1L;
private JLabel jlblText = new JLabel("welcome",JLabel.CENTER);
public FlashingText() {
add(jlblText);
new Thread(this).start();
}
#Override
public void run() {
try {
while(true) {
if(jlblText.getText() == null) {
jlblText.setText("Welcome");
Thread.sleep(2000);
} else
jlblText.setText(null);
}
} catch(InterruptedException ex) {
}
}
}
after i compiled and ran it, it seems the text does not flashing at all
is there anything wrong with my code?
thanks a lot!
There's a better solution, which updates the UI in Event Dispatcher Thread and does not block it.
final JLabel label = new JLabel("Some text");
final Runnable updater = new Runnable() {
#Override
public void run() {
label.setVisible(!label.isVisible());
}
};
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
executorService.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
SwingUtilities.invokeLater(updater);
}
}, 2, 2, TimeUnit.SECONDS);
From the code, it does not really seem that you are flashing anything. Some issues I see with your code:
If the label has no text, the getText() method will yield an empty string ("") and not null.
When updating visual components, you would need to go through the Event Dispatcher Thread (EDT). This is exposed to you through the SwingUtilities.invokeLater(Runnable runnable) class.
It is usually a bad idea to sleep() threads. If you make the changes through the EDT, you would be hanging the ED Thread which will cause the application UI to freeze, which is not desired.
You are swallowing exceptions. In your exception handling, you are not doing anything. It is considered bad practice to not handle exceptions (sometimes a simple log message will do).
According to me there is a problem in the following code block:
try {
while(true) {
if(jlblText.getText() == null) {
jlblText.setText("Welcome");
Thread.sleep(2000);
} else
jlblText.setText(null);
}
}
Because see at the first time the value is welcome, so it will enter the loop and go to else and set it null and then immediately it will check again, as there is no sleep in else so it will check again and enter the if block and set it to welcome, and this whole process will be done at a great speed so you would not be able to see the flashing effect. So I think that you should try putting a sleep at the end of the else block and see, according to me it should work then.
You should change:
else
jlblText.setText(null);
to
else{
jlblText.setText(null);
Thread.sleep(500);
}
or something like this

100% cpu because of this thread java

i have just attempted to add something to my game where if one player is hit by a bullet his health goes down. problem is when i am checking for this, CPU is at 100% and everything sooo laggy. This is a problem. here is the thread i am using:
package Graphics;
import java.util.logging.Level;
import java.util.logging.Logger;
public class BulletCollision implements Runnable {
Player1 player1 = new Player1();
Player2 player2 = new Player2();
public Thread checkBulletCollision = new Thread(this);
public void checkPlayerBulletCollide() {
if (player2.getBulletX() > player1.getX() &&
player2.getBulletX() < player1.getX() - 50) {
player2.decHealth(50);
}
}
#Override
public void run() {
while(true) {
checkPlayerBulletCollide();
try {
checkBulletCollision.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(BulletCollision.class.getName()).log(
Level.SEVERE, null, ex);
}
}
}
}
i am pretty sure this is where the problem is. there are no errors when compiled or ran. if anyone could help that would be amazing! and i just make this class so the code is not perfect. i have tried a lot to fix this, the Threads start() method is being called in my Display class which only displays the JFrame. i previously had the start method in one of my player classed.
The problem is not in this code. There are one or two flaws, but nothing in this code that would result in laggyness ... as far as I can tell.
FWIW, the flaws are as follows:
1) This is bad style:
checkBulletCollision.sleep(100);
The Thread.sleep method is static, so you should invoke it as:
Thread.sleep(100);
2) Your thread run() method should return if it receives an interrupt. You have coded it to keep going ... which would defeat the purpose of interrupting it.
In my opinion, using this block free running in a separate thread is not correct in this case.
while(true) {
checkPlayerBulletCollide();
try {
checkBulletCollision.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(BulletCollision.class.getName()).log(Level.SEVERE, null, ex);
}
}
I'd only do this once each frame, I'd call the checkPlayerBulletCollide() from the drawing logic.
Also note that Thread.sleep() is a static function, so you can't make a specific Thread instance sleep from another Thread, a Threac can just put itself to sleep...
EDIT If you would like to code nice and clean (which is very good), I'd advise using the locking mechanisms we have from Java 1.5 on.
Even though this is (in the current context of 2 users with 1 bullet each) not lightweight ebough, I'd use a BlockingQueue. The checking thread would have to issue a queue.take(), but the actual Integer value wouldn't matter (later on e.g. with more bullets or players, you could put objects in the queue that specify which bullets and which users to check...). The drawing logic - or the logic controlling the drawing would do queue.offer(0). The checking Thread would look like this:
public class BulletCollision implements Runnable{
Player1 player1 = new Player1();
Player2 player2 = new Player2();
public BlockingQueue<Integer> checkQueue = new LinkedBlockingQueue<Integer>();
public void checkPlayerBulletCollide() {
if(player2.getBulletX() > player1.getX() && player2.getBulletX() < player1.getX() -50) {
player2.decHealth(50);
}
}
#Override
public void run() {
while(true) {
try {
queue.take();
checkPlayerBulletCollide();
} catch (InterruptedException ex) {
Logger.getLogger(BulletCollision.class.getName()).log(Level.SEVERE, null, ex);
break; //I'd put this here. If we were interrupted, the hread should stop gracefully.
}
}
}
}
Also, when you're done with drawing a frame, you should issue a queue.offer(0);

GUI Threading in Java (and SwingUtilities)

I'm making a simple game in Java using swing and am having problems with my GUI freezing up sporadically (due to threading issues most probably) after a button press that is supposed to trigger a switch in JPanels.
I posted a related thread here, which has more details about the actual code I'm currently using (although I did update the countdown and get that working fine). From answers to that thread, it seems like usingSwingUtilities.invokeLater() or invokeAndWait() might be what I need to solve the problem, but I'm not sure where in my code it is necessary or exactly how to implement it.
I don't know that much about threading and could use any help (preferably somewhat detailed and with some sample code) that I can get. Let me know if any further details would be useful.
See: Tutorial: Concurrency in Swing
Generally speaking, the Event Dispatch Thread is a single thread, chugging through the event queue, processing one at a time.
SwingUtilities.invokeLater(..)
puts a Runnable on this queue. So it will be processed by the EDT when the EDT finishes everything on the queue before it (This is why sleeping on the queue blocks other events like repainting). It's relatively unusual to call invokeLater(..) from the EDT itself, though there are situations where it is useful (usually as a hack). I don't think I have had a legitimate use for SwingUtilities.invokeAndWait(..) in the last 6 years. Maybe once.
javax.swing.Timer can be configured to fire once or periodically. When it fires, it puts an event on the EDT queue. If you have computationally-intensive processing that need to be done, consider using javax.swing.SwingWorker to do the computation on another thread, and give you back the result in a thread-safe manner (this is also comparatively rare).
A good point to look is the docs. In your case, this explains how SwingUtilities.invokeLater() works and where to use it:
Causes doRun.run() to be executed asynchronously on the AWT event
dispatching thread. This method should be used when an application
thread needs to update the GUI.
So, in your actions that modifies the GUI you must use the invokeLater method to assure that the GUI wont freeze.
Another good resource is the Java tutorials. They cover concurrency in Swing.
I have create a WorkerThread class which take care of Threads and GUI current/main thread . i have put my GUI application in construct() method of WorkerThread when an event fire to start XXXServer then all threads are activate and GUI work smoothlly wihout freeze. have a look.
/**
* Action Event
*
* #see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent ae) {
log.info("actionPerformed begin..." + ae.getActionCommand());
try {
if (ae.getActionCommand().equals(btnStart.getText())) {
final int portNumber = 9990;
try {
WorkerThread workerThread = new WorkerThread(){
public Object construct(){
log.info("Initializing the XXXServer ...");
// initializing the Socket Server
try {
XXXServer xxxServer = new XXXServer(portNumber);
xxxServer.start();
btnStart.setEnabled(false);
} catch (IOException e) {
// TODO Auto-generated catch block
log.info("actionPerformed() Start button ERROR IOEXCEPTION..." + e.getMessage());
e.printStackTrace();
}
return null;
}
};workerThread.start();
} catch (Exception e) {
log.info("actionPerformed() Start button ERROR..." + e.getMessage());
e.printStackTrace();
}
} else if (ae.getActionCommand().equals(btnStop.getText())) {
log.info("Exit..." + btnStop.getText());
closeWindow();
}
} catch (Exception e) {
log
.info("Error in ServerGUI actionPerformed==="
+ e.getMessage());
}
}
In order to invoke an action in the existing WorkerThread, one would intuitively send a user defined event using SwingUtilities.invokeLater() to a JFrame's actionPerformed() method as
class TestFrame extends JFrame implements ActionListener
{
...
private class Performer implements Runnable
{
ActionEvent event;
Performer(ActionEvent event)
{
this.event = event;
}
#Override
public void run()
{
actionPerformed(event);
}
}
synchronized protected void invokeLater(ActionEvent event)
{
SwingUtilities.invokeLater(new Performer(event));
}
public void actionPerformed(ActionEvent event)
{
...
}
}
Now, TestFrame.invokeLater() called in any Thread will be processed in TestFrame.actionPerformed() in existing WorkerThread .

Get and send messages with Java Threads

I want to make a thread, which runs, computes something with the data i give it, and returns a few values, or an object. The thread is a part of a Swing GUI.
My question: How can I make a method that runs when I make the thread, and returns an object (or whatever I want it to return)?
My code:
private void nextTurn () {
// do something
if (turn == white) {
try {
Engine e = new Engine(); // Engine is implemented by runnable
e.start();
Move m = e.getBestMove (board);
// thread should work, next code should be excecuted immediately
}
catch (Exception e) {}
}
// end of Main class
}
This is the first time I am working with Threads, and I know you should avoid them if possible, but I need it this time for my GUI.
The info on the Oracle site on Threads did not help me out. I am able to make a program with multiple Threads that runs indefinately, but I can't make it work with functions.
Since this is with a Swing GUI, consider using a SwingWorker object which creates a background thread (all the code run in the doInBackground method), and then can return a final result and/or interim results. Information on how to use this is well documented in the tutorials here:
Concurrency in Swing
SwingWorkers have property change support and thus will allow listeners to observe its state (as a SwingWorker.StateValue) via a PropertyChangeListener. This is one way your program can determine that the thread has completed its processing, get the returned result and go from there.
On an unrelated note, this isn't in your production code is it?:
catch (Exception e) {}
If so, you will likely want to fix this as ignored exceptions can bite you in the tail big time.
e.g.,
if (turn == white) {
try {
final SwingWorker<Move, Void> mySwingWorker = new SwingWorker<Move, Void>() {
#Override
protected Move doInBackground() throws Exception {
Engine e = new Engine(); // Engine is implemented by runnable
e.start();
Move m = e.getBestMove(board);
return m;
}
};
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (StateValue.DONE == mySwingWorker.getState()) {
try {
Move m = mySwingWorker.get();
// TODO: insert code to run on the EDT after move determined
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
});
mySwingWorker.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
I suggest you use an ExecutorService. It allows you to create a thread pool, you can pass tasks to it and get the results later.
http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html

Categories