Java JFrame loading error after loop [duplicate] - java

This question already has answers here:
Create threads in java to run in background
(4 answers)
Closed 5 years ago.
This is my main method where I start my application. The JFrame loads successfully. When I add the WHILE-Loop part to do some background work where I work with some data to show on my JFrame my JFrame doesn't load correctly (see image below).
public static void main(String[] args) throws IOException {
if (Config.checkIfConfigExists() == true) {
/*
* Starten der Anwendung
*/
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main window = new Main();
window.frmServicenowHelper.invalidate();
window.frmServicenowHelper.validate();
window.frmServicenowHelper.repaint();
window.frmServicenowHelper.setVisible(true);
while (true) {
// the part that makes it error
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
} else {
Notifications.alertMSGConfig("Config not found. Create one?");
}
}
As you can see the JFrame freezes and shows its background.
I found out it has something to do with Threads and correct processing (I think I am using something at the wrong point) but I am unable to fix it myself.
Background knowledge:
I want to get a JSON-String from a URL (the methods for that are working - I want to call & show the results on the frame) every 5 minutes (therefore the while-loop).
EDIT:
I tried this which loads the frame correctly but makes the loop (which I need) useless:
while (true) {
Main window = new Main();
window.frmServicenowHelper.invalidate();
window.frmServicenowHelper.validate();
window.frmServicenowHelper.repaint();
window.frmServicenowHelper.setVisible(true);
break;
}

I found the solution:
I simply created a new Thread (background processing) using:
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
runYourBackgroundTaskHere();
}
};
new Thread(r).start();
//this line will execute immediately, not waiting for your task to complete
}
Source: Create threads in java to run in background

Related

Continue executing a thread while another thread is running in java

tl, dr;
I have a GUI thread that creates an object of another class (the seconds class has implemented Runnable, but here we don't execute the run() method, instead, we call a normal method) and calls a method. In that method, the first thread (current thread) is called again (to show sth on the LCD), then sends some data to the Internet, and waits 3 seconds for the server response. The problem is that the information is printed after 3 seconds. I know about the stack and program counter, but I wonder if there is another option that I can do my job.
I have the main method, which runs 3 threads (for short, I just write the requisite code. Tell me to add more, if needed):
public static void main(String[] args) throws UnknownHostException, InterruptedException {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GUI.getInstance().setVisible(true); //GUI is singleton, using swing and JFrame
} catch (Exception e) {
e.printStackTrace();
}
}
});
MQTTConnection.getInstance().tryToConnect(); //It's the connection class, which has a thread (the thread is handled by a library that keeps the connection alive. I have no threads there) and is a singleton too.
Thread t1 = new Thread(new SendDataThread()); //A thread which sends some data every 20 seconds.
t1.start();
}
And in SendDataThread, I have a function that creates some random data and sends them (using the MQTTConnection class).
This is the SendDataThread:
public class SendDataThread implements Runnable {
public void sendLog() {
boolean serverOnline = false;
StringBuilder data = new StringBuilder();
data.append(createData());
GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`
if(MQTTConnection.getInstance().publishLog(MQTTConnection.getInstance().MQTT_PUBLISH_ESP_SEND_LOG, data.toString())) //This line has a 3 second timeout. If the server doesn't respond, it will return false. I've added the 3 seconds timeout too. Please continue reading.
serverOnline = true;
if(serverOnline)
GUI.getInstance().printOK("Server Submitted"); //Prints in GREEN
else
GUI.getInstance().printProblem("Check your connection!"); //Prints in RED
GUI.getInstance().printNeutral("-------------------------------------------------");
}
#Override
public void run() {
while(true) {
sendLog();
try {
Thread.sleep(20000); //sleeps 20 about seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//.....
}
And this is the 3 seconds timeout method, in MQTTConnection:
boolean publishLog(String topic, String data){
mqtt_responds = false;
publish(topic, data);
System.out.println("MQTT is connected");
long lastTime = System.currentTimeMillis();
while(System.currentTimeMillis() - lastTime < callback_timeout) {
if(mqtt_responds){
mqtt_responds = false;
System.out.println("Server submitted");
return true;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Timeout");
return false;
}
Till now, everything work right. The problem starts where I have a button in the GUI class, which the user can manually send random logs:
JButton sendLogBtn = new JButton("Send Log");
sendLogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SendDataThread sdt = new SendDataThread();
sdt.sendLog();
}
});
sendLogBtn.setBounds(10, 331, 89, 23);
panel.add(sendLogBtn);
This button creates an object of SendDataThread and calls the sendLog() method. The issue happens here: after sendLog() is called, sendLog(), calls this GUI thread again:
--> GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`
But the log is printed after 3 seconds (After the sendLog() method has finished working, the timeout!)
How can I fix this?
In the button's actionPerformed you are calling sendLog. sendLog does exactly what you said, ie reports some logs and waits about 3 seconds (assuming callback_timeout is about equal to 3000).
To fix this, you need to make sure that the 3sec blocking is not on the EDT and also to make sure that the logs are instead posted on the EDT.
As a quick workaround you can do:
sendLogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Thread(() -> new SendDataThread().sendLog()).start();
}
});
and then, as always, post your logs in the EDT like for example:
SwingUtilities.invokeLater(() -> GUI.getInstance().printNeutral(...));
AND
SwingUtilities.invokeLater(() -> GUI.getInstance().printProblem(...));
AND
SwingUtilities.invokeLater(() -> GUI.getInstance().printOk(...));
As for the question in your comment, I don't really understand what you are asking, but I should say that (as far as I know) the EDT is a Thread where all the Swing code is (and should be) posted on for execution. This way the Swing code does not have to be synchronized, because all GUI related stuff is executed sequentially (on the EDT). AWT for example was not intended to be single threaded as far as I know. Swing is however single threaded.

javaFX UI crashes when using an infinte loop [duplicate]

This question already has answers here:
javafx animation looping
(3 answers)
Closed 5 years ago.
I am trying to build a clock in javafx but the GUI crashes when I try using an infinite loop.
while (true) {
Date time = new Date();
// mins and hour are labels
if (time.getMinutes() < 10) {
mins.setText("0" + Integer.toString(time.getMinutes()));
} else {
mins.setText(Integer.toString(time.getMinutes()));
}
if (time.getHours() < 10) {
hour.setText(0 + Integer.toString(time.getHours()));
} else {
hour.setText(Integer.toString(time.getHours()));
}
}
I heard I can use something called a thread but I didn't really understand how to properly implement it.
Looks like you are using an infinite loop in the UI thread. You should keep track of time in a background thread, but update the UI in UI thread.
To run in background thread, use:
new Thread(new Runnable(){
public void run(){
//your code here.
}
}).start();
To run in UI thread, use:
Platform.runLater(new Runnable(){
public void run(){
//your code here.
}
});
That is perfectly reasonable. Never block the main thread! Use an additional thread in order to achieve your goal.
Task<Void> workingTask = new Task<Void>() {
#Override
public Void call() {
while (true) {
//yourcode
}
}
and use Platform.runLater(()-> { //yourcode}); in order to send small tasks to main javafx thread. For e.g.
Platform.runLater(() -> {
mins.setText(Integer.toString(time.getMinutes()));
});

Why UI freezes? [duplicate]

This question already has answers here:
What's the difference between Thread start() and Runnable run()
(14 answers)
Closed 5 years ago.
I wont to run my thread in background but it keeps blocking UI.
In methods login() and dostaff() I use selenium webdriver to get data and display it in label, after that I refresh page and thread sleeps for 60000ms;
public static class Moderate implements Runnable {
public void run() {
login();
while (true) {
dostaff();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void login(){....};
private void dostaff(){....};
}
and I call it:
public void ModerateLoop(javafx.scene.control.Label lbl) {
this.displayLabel = lbl;
Moderate thread = new Moderate();
thread.run();
}
because you are calling the method run
thread.run();
so this is blocking the invoking thread until your code in the run method is done.
you need instead to start the thread
thread.start();

UI thread can not start after IDE changed

I changed my IDE from Eclipse to IntelliJ IDEA. The new one started complaining about my code.
public class Controller {
private OknoGlowne frame;
private MenuListener menuListen = new MenuListener(this);
private TabListener tabListener = new TabListener(this);
public OknoGlowne getFrame() {
return frame;
}
public Controller(){
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
frame = new OknoGlowne();
frame.setVisible(true); //error
frame.addMenuListener(menuListen);
frame.addTabListener(tabListener);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
So I commented this line. And add new line to constructor of UI frame.
public OknoGlowne() {
jPanel.setVisible(true);
}
App start but UI doesn't show any more. IDEA create frame in different way than Eclispe. I have to switch.
Main
public class Runner {
public static void main(String[] args) {
new Controller();
}
}
This doesn't really have anything to do with your IDEs. I bet if you ran it 100 times in eclipse, or from the command line, you'd get different results depending on how busy your system is.
The reason you aren't seeing the JFrame pop up is because you're using invokeLater() instead of invokeAndWait().
The invokeLater() method immediately returns, at which point you're in a race condition: will the event thread display the EDT first, or will the main thread exit first? If the main thread exits first, then your program will exit before any windows are shown.
To prevent this, you have to use invokeAndWait() instead of invokeLater().

Wait for Swing Interface to close before proceeding

I've been searching near and far for a solution to my question but I am having difficulty even defining my search terms.
I have a method that creates a Swing GUI using invokeLater where the user completes some task. Once the task is completed, the window closes and the initial calling thread (e.g. the method) should resume execution. To be more specific, here is a summary of the method:
public class dfTestCase extends JFrame{
public dfTestCase{
... //GUI code here
}
public String run()
{
CountDownLatch c = new CountDownLatch(1);
Runnable r = new Runnable()
{
public void run()
{
setVisible(true); //make GUI visible
}
};
javax.swing.SwingUtilities.invokeLater(r);
//now wait for the GUI to finish
try
{
testFinished.await();
} catch (InterruptedException e)
{
e.printStackTrace();
}
return "method finished";
}
public static void main(String args[]){
dfTestCase test = new dfTestCase();
System.out.println(test.run());
}
}
Within the GUI, I have actionListeners for buttons that will close and countDown the CountDownLatch.
While the CountDownLatch works, it is not suitable for my purposes because I need to run this GUI several times and there is no way to increment the latch. I'm looking for a more elegant solution - it is my best guess that I would need to make use of threads but am unsure how to go about this.
Any help would be much appreciated!
Update
Some clarification: What is happening is that an external class is calling the dfTestCase.run() function and expects a String to be returned. Essentially, the flow is linear with the external class calling dfTestCase.run()-->the GUI being invoked-->the user makes a decision and clicks a button-->control to the initial calling thread is returned and run() is completed.
For now my dirty solution is to just put a while loop with a flag to continuously poll the status of the GUI. I hope someone else can suggest a more elegant solution eventually.
public class dfTestCase extends JFrame{
public dfTestCase{
... //GUI code here
JButton button = new JButton();
button.addActionListener{
public void actionPerformed(ActionEvent e){
flag = true;
}
}
}
public String run()
{
Runnable r = new Runnable()
{
public void run(){
setVisible(true); //make GUI visible
};
javax.swing.SwingUtilities.invokeLater(r);
//now wait for the GUI to finish
while (!flag){
sleep(1000);
}
return "method finished";
}
public static void main(String args[]){
dfTestCase test = new dfTestCase();
System.out.println(test.run());
}
}
Modal dialogs and SwingUtilities#invokeAndWait iso invokeLater should allow you to capture user input and only continue the calling thread when the UI is disposed
For an example of using model dialogs you can check out the ParamDialog class I wrote. In particular, check out ParamDialog.getProperties(Properties);
http://tus.svn.sourceforge.net/viewvc/tus/tjacobs/ui/dialogs/

Categories

Resources