Update Swing GUI from other thread - java

I have two classes, one of them is my thread in which I read outputs from a device through TCP/IP:
public static controlPanel cp = new controlPanel();
void startListenForTCP (final String ipaddress){
Thread TCPListenerThread;
TCPListenerThread = new Thread(new Runnable() {
#Override
public void run() {
Boolean run = true;
String serverMessage = null;
InetAddress serverAddr = null;
BufferedWriter out = null;
try
(Socket clientSocket = new Socket(ipaddress, 7420)) {
cp.updateGUI("Connection initiated... waiting for outputs!"+"\n");
char[] buffer = new char[2];
int charsRead = 0;
out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while ((charsRead = in.read(buffer)) != -1)
{
String message = new String(buffer).substring(0, charsRead);
switch (message) {
case "o,":
cp.updateGUI("Čekanje da loptica prođe RFID čitač!");
break;
case "y,":
cp.updateGUI("Hardverski problem!");
break;
case "Y,":
cp.updateGUI("Loptica nije izažla, hardverski problem!");
break;
case "I,":
cp.updateGUI("Uređaj u stanju mirovanja!!");
break;
default:
String m = message;
m = m.replaceAll("[^\\d.]", "");
try{
int i = Integer.parseInt(m);
System.out.println("Is int: "+i);
int izasao=Integer.parseInt(m);
if (redni>34){
redni=0;
}
if (izasao>0 && izasao<49){
redni =redni+1;
m=m;
ur.updateResults(redni, m);
bs.testAuto(m, redni);
System.out.println(m+ "\n");
}
} catch(NumberFormatException e){
} break;
}
}}
catch(UnknownHostException e) {
System.out.println("Unknown host..."+"\n");
} catch(IOException e) {
System.out.println("IO Error..."+"\n");
}
}
});
TCPListenerThread.start();
}
The other one is swing form in which i want to set jLabel text from the class above:
Public class controlPanel extends javax.swing.JFrame {
public static gameControler gc = new gameControler();
public controlPanel() {
initComponents();
}
public void updateGUI(final String text) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
updateGUI(text);
}
});
}jLabel5.setText(text);
System.out.println(text);
}
The message gets printed out in console but i can't set it's value to jLabel.
I need a quick way to achieve this, so any workarounds will be most helpfull.
Thank you,

Your code only updates the GUI if current thread is not the EDT:
if (!SwingUtilities.isEventDispatchThread()) {
// you call SwingUtilities.invokeLater();
}
The GUI update should also happen if the current thread happens to be the EDT. So you should change it to somehting like this:
if (SwingUtilities.isEventDispatchThread())
jLabel5.setText(text);
else
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
jLabel5.setText(text);
}
});
Note that invokeLater() is not executed immediately but asynchronously some time later. If you need the update to happen before it returns, use SwingUtilities.invokeAndWait().
Also note that you may consider using the SwingWorker class to perform lengthy GUI-interaction tasks in a background thread.
Making it utility method
If you have to do this many times, it is profitable to make a utilitiy method for this:
public void callFromEdt(Runnable task) {
if (SwingUtilities.isEventDispatchThread())
task.run();
else
SwingUtilities.invokeLater(task); // You might want to consider
// using invokeAndWait() instead
}

Related

Kill thread when it called twice

I made thread that send String back to main thread periodically.
and I put this thread on some function.
When I press some button, than function will be called and do the work.
The problem is when I press that button twice.
That two threads are sending their String to main thread.
(They do the exactly same thing, but different string.)
But I don't need the first thread when thread started again.
Is their any way to kill the first thread?
here's the code.
private void speller_textbox(final String string){
final int strlen = string.length();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
int cursor= 0;
while(cursor != strlen){
try{
Message message = Message.obtain();
message.obj = string.subSequence(0,cursor);
txt_handler.sendMessage(message);
cursor++;
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
}
}
});
thread.start();
}
txt_handler is on the main thread.
First replace your working thread from method. Than:
private Thread workingThread;
//.....
private void speller_textbox(final String string){
if (workingThread != null && workingThread.isAlive()) {
workingThread.interrupt();
}
final int strlen = string.length();
workingThread = new Thread(new Runnable() {
#Override
public void run() {
int cursor= 0;
while(cursor != strlen){
try{
Message message = Message.obtain();
message.obj = string.subSequence(0,cursor);
txt_handler.sendMessage(message);
cursor++;
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
}
}
});
thread.start();
}

Java async problems

So my code works just the way I want it the only issue I'm having is this.. Basically I am having a main class which controls gates on a railroad track, when a train is approaching or crossing the track from either 1 of two tracks the gates should close. The only issue I'm having is the statements for when a gate opens or closes spam like 3-5 times everytime it does something so if the gate is closing it will go..
GATE: Closing
GATE: Closing
GATE: Closing
GATE: Closing
GATE: Closing
GATE: Closed
I'm wondering why this is occuring, here is my code for the Gate class and Main class
public class Gate {
private boolean isClosed = false;
private boolean closing = false;
private boolean opening = false;
public Gate(){
}
public void close(){
if(!(isClosing() == true)){
Runnable task = new Runnable() {
public void run() {
try {
setClosing(true);
setOpening(false);
System.out.println("GATE: Closing");
Thread.sleep(400);
System.out.println("GATE: Closed");
setClosed(true);
setClosing(false);
}catch(Exception ex){
}
}
};
new Thread(task, "closeThread").start();
}
}
public void open(){
if(!(isOpening() == true)){
Runnable task = new Runnable() {
public void run() {
try {
setOpening(true);
System.out.println("GATE: Opening");
Thread.sleep(400);
setOpening(false);
if(closing == false){
setClosed(false);
System.out.println("GATE: Opened");
}
}catch(Exception ex){
}
}
};
new Thread(task, "openThread").start();
}
}
public boolean isClosed(){
return isClosed;
}
public boolean isClosing(){
return closing;
}
public boolean isOpening(){
return opening;
}
public synchronized void setClosing(boolean t){
closing = t;
}
public synchronized void setOpening(boolean t){
opening = t;
}
public synchronized void setClosed(boolean t){
isClosed = t;
}
}
public class Controller {
public static void main(String[] args){
Track t1 = new Track("Track 1");
Track t2 = new Track("Track 2");
Gate g = new Gate();
t1.simulateTrack();
t2.simulateTrack();
do{
System.out.print("");
if((t1.isApproaching() || t1.isCrossing()) || (t2.isApproaching() || t2.isCrossing())){
if(!g.isClosed() && !g.isClosing()){
g.close();
}
}else if(g.isClosed() && !g.isOpening()){
g.open();
}
}while((t1.isSimulating() || t2.isSimulating()));
}
}
Also the code for Track
import java.security.SecureRandom;
public class Track {
private static final SecureRandom gen = new SecureRandom() ;
private boolean approaching = false;
private boolean atCrossing = false;
private boolean simulating = false;
private String trackName = "";
public Track(String n){
trackName = n;
}
public void simulateTrack(){
Runnable task = new Runnable() {
public void run() {
try {
setSimulating(true);
for(int i = 0; i < 10; i++){
Thread.sleep((gen.nextInt(5000) + 2500));
setApproaching(true);
System.out.println(trackName + ": Train is now approaching.");
Thread.sleep((gen.nextInt(5000) + 3500));
setCrossing(true);
setApproaching(false);
System.out.println(trackName + ": Train is now crossing.");
Thread.sleep((gen.nextInt(1000) + 1000));
setCrossing(false);
System.out.println(trackName + ": Train has left.");
}
setSimulating(false);
} catch (Exception ex) {
}
}
};
new Thread(task, "simulationThread").start();
}
public boolean isApproaching(){
return approaching;
}
public boolean isCrossing(){
return atCrossing;
}
public boolean isSimulating(){
return simulating;
}
public synchronized void setSimulating(boolean t){
simulating = t;
}
public synchronized void setApproaching(boolean t){
approaching = t;
}
public synchronized void setCrossing(boolean t){
atCrossing = t;
}
}
This is just an idea:
By shooting the close() logic on a background thread you lose the atomicity. The main's do loop can go around 5 times before it gives up the control of the main thread and one of the "closeThread"s start executing. Don't you see multiple "GATE: Closed"s as well?
Try this (not tested, sorry):
public synchronized void close() { // added synchornized
if (!isClosing()) { // read: "if not closing"
setClosing(true); // set closing so next time close() is called it is a no op
setOpening(false); // close other loopholes so the state is correct
System.out.println("GATE: Closing");
// we're in closing state now, because the close method is almost finished
// start the actual closing sequence
Runnable task = new Runnable() {
public void run() {
try {
Thread.sleep(400);
System.out.println("GATE: Closed");
setClosed(true);
setClosing(false);
}catch(Exception ex){
}
}
};
new Thread(task, "closeThread").start();
}
}
You'll need to modify open() the same way, so that the invariants are always kept. Checking and setting the closing and opening flags are mutually exclusive, that's what you get by placing synchronized on both of them.

JScrollPanel is not responding initially

I wanted to make a chat server client with GUI. Any new messages will be added as a JPanel. Initially messages added to my JScrollPanel is updating smoothly. However when i implemented the server and client to work with the GUI, the first few new messages added are never updated. Messages will only be updated to the JScrollPanel after the third add onward. Some times the adding of components ended prematurely. The client implements runnable so any new messages will be updated to the JScrollPanel via a Thread.
It seems like the GUI did not fully initialise.
this is the Client code
public static void main(String[] args) {
new Thread(new MessageClient("htf0001")).start();
MessageGUI dialog = new MessageGUI(collaID);
}
#Override
public void run() {
//loop read from server
// The default port.
int portNumber = 50000;
// The default host.
String host = "localhost";//"54.169.62.79";
/*
* Open a socket on a given host and port. Open input and output streams.
*/
try {
clientSocket = new Socket(host, portNumber);
oos = new ObjectOutputStream(clientSocket.getOutputStream());
oos.flush();
ois = new ObjectInputStream(clientSocket.getInputStream());
Staff staff = new Staff();
sendToServer(staff.connectToMessageServer(collaID));
sendToServer(staff.getMessageLog(collaID));
while(!close){
ArrayList<String> input = new ArrayList<String>();
Object o = ois.readObject();
input = (ArrayList<String>) o;
if(input.get(0).compareTo("end")!=0){
for(int i=0;i<input.size();i=i+5){
MessageGUI.addMessage(input.get(i),input.get(i+1), input.get(i+2),
input.get(i+3),input.get(i+4));
}
}
else close = true;
}
oos.close();
ois.close();
clientSocket.close();
}
catch (UnknownHostException uhe) {
JOptionPane.showMessageDialog(null,uhe.getMessage());
}
catch (IOException ioe) {
JOptionPane.showMessageDialog(null,ioe.getMessage());
}
catch (ClassNotFoundException ex) {
JOptionPane.showMessageDialog(null,ex.getMessage());
}
}
this is the GUI code part that add in the component
public static void addMessage(String date, String firstName, String lastName,
String message, String time){
String newUser = firstName + " " + lastName;
if(recentDate.compareTo(date)!=0){
JLabel newDate = new JLabel(date);
newDate.setHorizontalAlignment(SwingConstants.CENTER);
addComponent(newDate,nextLine,0,3,1);
recentDate = date;
nextLine++;
}
if(recentUser.compareTo(newUser)==0 && recentTime.compareTo(time)==0){
recentJTextArea.append("\n\n"+message);
}
else{
if(recentUser.compareTo(newUser)==0) newUser = recentUser;
JTextArea temp = new JTextArea();
temp.setFocusable(false);
temp.setBorder(BorderFactory.createTitledBorder(newUser));
temp.setLineWrap(true);
temp.setWrapStyleWord(true);
temp.setEditable(false);
temp.setText(message);
recentJTextArea = temp;
recentUser = newUser;
JLabel newTime = new JLabel(time);
newTime.setHorizontalAlignment(SwingConstants.RIGHT);
recentTime = time;
addComponent(temp,nextLine,0,2,1);
nextLine = nextLine + 1;
addComponent(newTime,nextLine,1,1,1);
nextLine = nextLine + 1;
}
invokeLater(new Runnable() {
public void run() {
ChatLogJScrollPane.getVerticalScrollBar().setValue(ChatLogJScrollPane.getVerticalScrollBar().getMaximum());
}
});
}
Seems like you are updating (ie adding the chat text) to your text areas on a thread that is not the GUI thread. Instead, you should call
SwingUtilities.invokeLater(new Runnable() {
temp.setText(message);
temp.repaint();
});
I've found the solution. I need to validate the JPanel in my JScrollPanel.
JPanel container
JScrollPanel(container)
SwingUtilities.invokeLater(new Runnable(){
container.validate();
});

making pop up window by using SwingUtilities.invokeLater

I am writing a turn-based game on the internet. I try to pop up a window that should be in front until the input stream is ready. I created smth like this, but it seems that it does not work.
class CustomBlockerDialog extends JDialog {
/**
*
*/
private static final long serialVersionUID = 1L;
public CustomBlockerDialog(Frame owner, String text) {
super(owner, true);
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
setSize(300, 100); // Adjust if needed
setTitle("");
add(new JLabel(text, SwingConstants.CENTER));
}
}
final CustomBlockerDialog block = new CustomBlockerDialog(null, "Not your turn");
SwingUtilities.invokeLater(new Runnable() {//A
#Override
public void run() {
System.out.println("show");
block.setVisible(true);
}
});
boolean one_write_only = true;
while(in.ready()){ /* C*/
if(one_write_only){
System.out.println("waiting server");
one_write_only = false;
}
};
System.out.println("suppose to hide");
SwingUtilities.invokeLater(new Runnable() {//B
#Override
public void run() {
System.out.println("hide");
block.setVisible(false);
}
});
It looks like "A" and "B" are executed after "C" and I have no idea why.
Your problem must be due to "C" being called on the Swing event thread and not in a background thread, since it sounds like "C" is blocking the event thread from running "A". Solution: be sure that "C" is not called on the Swing event thread. Also if this is the case, and this can be tested by running the SwingUtilities.isEventDispatchThread() method, then you don't need all those other runnables.
// note that this all must be called on the Swing event thread:
final CustomBlockerDialog block = new CustomBlockerDialog(null, "Not your turn");
System.out.println("show");
// block.setVisible(true); // !! no this will freeze!
final SwingWorker<Void, Void> worker = new SwingWorker<>() {
public void doInBackground() throws Exception {
boolean one_write_only = true;
while(in.ready()){ /* C*/
if(one_write_only){
System.out.println("waiting server");
one_write_only = false;
}
}
}
}
worker.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChanged(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
System.out.println("hide");
block.setVisible(false);
// call worker's get() method here and catch exceptions
}
}
});
worker.execute();
// moved to down here since the dialog is modal!!!
block.setVisible(true);
Caveat: code not compiled nor tested. There may be errors present as it was typed off the cuff.
Thanks to Hovercraft Full Of Eels, I created a little different solution which works in my case:
final SwingWorker<Object,Object> worker2 = new SwingWorker<Object, Object>() {
public Object doInBackground() throws Exception {
boolean one_write_only = true;
while(!in.ready()){ /* C*/
if(one_write_only){
System.out.println("waiting server");
one_write_only = false;
}
}
return one_write_only;
}
protected void done() {
try {
block.setVisible(false);
} catch (Exception ignore) {}
}
};
worker2.execute();
block.setVisible(true);

Handle socket termination in android

I am connected to a device using following code.
Using this socket code I cam perfom all the tasks, but now I need to perform some functions when server is going to be down. I am not able to find suitable method to do so please help.
EDIT
I want to detect when server is disconnected with this client , means after doing transactions server will be disconnected so that i can disable the buttons ,
void sendRequest(){
try {
this.clientSocket=new Socket("192.168.1.11",2000);
this.os=new DataOutputStream(this.clientSocket.getOutputStream());
this.in=new DataInputStream(this.clientSocket.getInputStream());
sendFirtCommand();
Client t=new Client();
t.start();
}catch(Exception e){
e.printStackTrace();
}
}// end of the sendRequest
My Thread code
private class Client extends Thread{
int time;
public void run(){
try{
while(true){
//if(in.read()==-1) break;
int size =in.available();
if(size>0){
byte data[]=new byte[size];
in.readFully(data);
String str=new String(data);
// System.out.println(data);
//char c[]=str.toCharArray();
str=toHex(data);
System.out.println(str);
/*
if(str.equalsIgnoreCase("050D00E7F0E1000101581D4A1D01FF")){
System.out.println("Start Left 3");
}
*/
if(str.equalsIgnoreCase("050d00e7f0e1000101601d4a1d01ff")){
stopAll();
handler.post(new Runnable() {
#Override
public void run() {
enableAll();
}
});
}
}
Try this if it helps
try{
while(true){
if(str.equalsIgnoreCase("050d00e7f0e1000101601d4a1d01ff")){
stopAll();
handler.post(new Runnable() {
#Override
public void run() {
enableAll();
}
});
}
}
}catch(IOException e)
{
handler.post(new Runnable() {
#Override
public void run() {
enableAll();
}
});
}
It seems as if Exception handling is not there in the code you have posted, let me know if i am missing something ...

Categories