Delay is affecting entire Block - java

I have a code right below...take a look.
enter.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (enter.getText().length()>0){
addToChat("You: "+enter.getText());
enter.setText("");
delay(1000);
addToChat("oie");
}
}
});
And here is the delay void.
public static void delay(int delayTime){
try
{
Thread.sleep(delayTime);
} catch (InterruptedException ie)
{
}
}
The problem is whoever I type something into the text box and hit enter, it takes one second for not only the one to show up in the text area, but also the "You: " text block to show up, which is before the delay. Why is this delay affecting things BEFORE it and how can I fix this?

The UI does not get a chance to update before your action listener is finished. If you would like to change something after the delay, you should schedule it on a different thread, rather than wait inside the event handler:
addToChat("You: "+enter.getText());
enter.setText("");
new Thread(
new Runnable() {
public void run() {
delay(1000);
addToChat("oie");
}
}
).start();

You're sleep()ing in the Event Dispatch Thread, which means your UI is frozen and can't repaint itself, or accept input, or anything. You should only perform very quick actions in the EDT to avoid this effect. Check out the Graphical User Interfaces and following tutorial trails for the basics of UI programming.

Related

How to utilize sleep method for calculator error

I am trying to set the calculator text to an error message, wait for 2 seconds, then clear the field text. Below is my current code.
public static void wait(int ms) {
try {
Thread.sleep(ms);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
// TODO: 6/30/22 if decimal is clicked multiple times -> setText("Error")
if (field.getText().contains(".") && e.getSource() == decButton) {
field.setText("error text here");
wait(1000);
field.setText("blank here");
} else if (e.getSource().equals(decButton)) {
field.setText(field.getText().concat("."));
}
So far, the field text sets directly to ("blank here") and completely skips the error message. I have tried moving the error message to different areas of the program (within the if statement) but have yet to find a conclusion.
Are you using Swing? Is the code you show running from an event handler (triggered by keypress, mouseclick or something)? Then this cannot work.
The code is running in the Event Dispatcher Thread (EDT). Once you use something like field.setText() you have to exit your code and allow the EDT to fire the updates into the UI. But instead, you 'keep it busy' by waiting a second, then requesting the next update into the UI. Only then your method exits, and the user did not see the first message.
What you need to do is to set the update, then free up the EDT. How do you get the message to disappear one second later? Use a Swing Timer to trigger the action:
field.setText("error text here");
ActionListener errorHider = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
field.setText("blank here");
}
};
Timer t = new Timer(1000, errorHider);
t.setRepeats(false);
t.start();

JTextArea not updating when it should

Hello StackOverflowers,
I'm currently working on my first Client/Server application and facing a problem that doesn't make sense to me at all. Please note that I'm new to network programming and working with runnables/threads.
I'm using the MVC pattern for my application, so I have a ServerController, ServerView and ServerModel.
Now there's a method in my ServerController which basically has 2 tasks.
Update the Server GUI - It is supposed to write a String "Server is starting..." in a JTextArea so the user knows the application did not crash
Invoke the Server
public ActionListener startServerListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
//Update GUI
view.updateServerNotice(new String("Server is starting..."));
//Start Server in new thread
Thread t1 = new Thread(model);
t1.start();
Thread.sleep(1000);
view.showNotification(model.hostAvailabilityCheck() + "");
} catch (Exception ex)
{
view.showNotification("Server is started already!");
}
}
};
My problem is, that the view.updateServerNotice(new String("Server is starting...")); method gets executed but doesn't show up in the GUI before the Server isn't started. So currently it is like the button is clicked, then there's a little delay (due to the sleep()) and THEN, after the server started, the GUI gets updated with "Server is starting...".
This doesn't make sense to me since the GUI updated is definitely executed before the new thread is created.
I hope someone sees something that I don't and can help me. It's not really a big problem, but I'm really curious why this is happening.
Thanks for your help in advance!
Swing (and AWT, and in fact many UI frameworks in most environments, not just Java) is single-threaded: nothing is going to be drawn as long as your ActionListener is running.
What you can do is running your code in a background thread, however in this case another issue kicks in: single-threaded UI frameworks do not really like random interactions from other threads. While direct access may work sometimes, the 'legal' approach is to send actions packed into some Runnable form, using SwingUtilities.invokeLater or invokeAndWait (I am using this latter one here, so your message will be visible for sure):
public ActionListener startServerListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
new Thread(new Runnable({
public void run(){
try{
// Update GUI #1
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
view.updateServerNotice(new String("Server is starting..."));
}
});
//Start Server in new thread
Thread t1 = new Thread(model);
t1.start();
Thread.sleep(1000);
// Update GUI #2
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
view.showNotification(model.hostAvailabilityCheck() + "");
}
});
}catch(Exception ex){/*...*/}
}
})).start();
}catch(Exception ex){/*...*/}
}
};
Beautiful, isn't it?

Java Swing Thread changing UI - complications

I tried this for many hours.. I have a thread that changes a JTextField of my UI, which completely destroys the UI. The Thread (lets call it Thread A) is generated by an ActionListener. The .setText() function call is in a extra thread (B) created by Thread A. Thread B is the Parameter of SwingUtilitis.invokeAll() and/or SwingUtilities.invokeAndWait(). I tried them both. Here's some code to make it more clear.
This is my ActionListener which creates Thread A - shortened of course:
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source == window.getBtn_Search()) {
Refresher refresh = new Refresher();
refresh.start();
}
}
This is my Thread A, which later puts Thread B into the EDT Queue:
public class Refresher extends Thread implements Runnable {
private int counter = 0;
private UI window = null;
private int defRefresh = 0;
#Override
public void run() {
while(true){
-bazillion lines of code-
do {
try {
Refresher.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(window.canceled()) break;
UI.updateCounter(window.getLbl_Status(), (Configuration.getRefreshTime()-counter));
counter++;
} while (counter <= Configuration.getRefreshTime());
- more code-
}
}
}
The UI.updateCounter(...) will queue Thread B into the EDT.
public static void updateCounter(final JLabel label, final int i) {
try {
SwingUtilities.invokeAndWait(
new Runnable() {
public void run() {
label.setText("Refreshing in: " + i + " seconds.");
}
}
);
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Now when the last function gets called, everything gets messed up. I tried different stuff for hours and nothing worked. I also tried using SwingWorker, but the some or nothing at all happened.
The invokeAndWait() tried allows to post a Runnable task to be executed on the EDT, but it blocks the current thread and waits until the EDT is done executing the task.
But there is deadlock potential in invokeAndWait(), as there is in any code that creates a thread interdependency.
If the calling code holds some lock (explicitly or implicitly) that the code called
through invokeAndWait() requires, then the EDT code will wait for the non-
EDT code to release the lock, which cannot happen because the non-EDT code
is waiting for the EDT code to complete, and the application will hang.
As we can see here, modifying the JLabel component passed by the waiting non-
EDT code.
Instead we can use
invokeLater() takes
care of creating and queuing a special event that contains the Runnable. This event is processed on the EDT in the order it was received, just like any other event.
When its time comes, it is dispatched by running the Runnable’s run() method.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Refreshing in: " + i + " seconds.");
}
});
OR
isEventDispatchThread() that returns true if the calling code is currently being executed on the EDT, false otherwise.
Runnable code= new Runnable() {
public void run() {
label.setText("Refreshing in: " + i + " seconds.");
}
}
);
if (SwingUtilities.isEventDispatchThread()) {
code.run();
} else {
SwingUtilities.invokeLater(code);
}
In general, labels are not very good at displaying text which change: their width change, and the layout with it.
Using a read-only JTextField, perhaps with proper changes in style, could be a better solution.
I think the intermediate JPanels you've created may count as validation roots. Therefore the revalidate() that automagically happens when you call setText() does not cause any layout changes higher than the level of the JPanel parent.
I don't think you actually need the panels, since a JLabel can contain both an Icon and text. See the tutorial.
So my advice is to remove the panels or, if they serve a purpose, make sure isValidateRoot() on the panels returns false.
When changing the label's text you should at least call repaint()/revalidate() on the label's topmost container, triggering a relayout, assuming the label calls invalidate()/revalidate() correctly on text change.

How to make the main method wait for input on GUI without using Listener as a direct trigger?

I am working on a webscraping tool that should perform various operations with the scraped data.
Because of this, I need various different GUIs to work in an orderly manner and because of that, I need the main method to wait before each has completed it's purpose.
After searching for a while, I have found the following StackOverflow questions that provided some clues on how to solve the problem, but that I could not implement because they have some differences to my case:
How to wait for input in a text field
How to make main thread wait a different thread to finish
I know I can trigger code using a Listener to a/the GUI's components (a button, for example), but i'm having a hard time making the main-thread wait for that listener to wake it up, while the code for the GUI's thread (when there is one) is initialized by the main thread...
This is an simplified code to demonstrate how the program is supposed to work:
public class Main {
/*
* Waiter is a simple GUI with just an "Start" button in it. Here in place of my actual GUIs.
*/
private static Waiter auth; //Represents my NTLM-authentication form.
private static Waiter status; //Represents a status-feedback GUI that will be displayed during processing.
private static Waiter operation; //Represents a GUI in with the user choses what to do with the gathered data.
public static void main(String[] args) throws InterruptedException {
auth = new Waiter();
auth.setVisible(true);
System.out.println("NTLM Authentication form. Should wait here until user has filled up the GUI and clicked \"Start\".");
System.out.println("Authenticates WebClient's NTLM using data inputed to the GUI...");
auth.dispose();
Thread srt = new Thread(status = new Waiter());
srt.start();
status.setVisible(true);
//Performs webscraping operations...
System.out.println("Prepares the webscraped data here...Things like downloading files and/or parsing text...");
System.out.println("Keeps the user aware of the progress using the \"status\" GUI.");
status.setVisible(false);
//Clears the status GUI.
operation = new Waiter();
operation.setVisible(true);
System.out.println("Operation selection form. Should wait here until user selects an option.");
System.out.println("Starts performing the operation(s)...");
operation.dispose();
status.setVisible(true);
System.out.println("Performs the operation(s), while giving status-feedback to the user.");
status.setVisible(false);
System.out.println("Displays a file-save dialog to save the results.");
System.out.println("And finally, displays a \"End of operations\" dialog before ending.");
}
}
UPDATE 1:
The main difficulty I'm having is to implement something like this (this is what I want to do):
//Main method...code...
Thread srt = new Thread(status = new Waiter());
//Before "srt.start();"...
status.startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
main.continueExecution();
}
});
//Thread's run() being something like "status.setVisible(true); main.waitGUI();"
srt.start();
//continues here after the Listener is triggered...more code...
Instead of this (what is being the solution to most other people, if I'm understanding it right...) (this is what I don't want to do, if possible):
//GUI before this one...
//code...
Thread srt = new Thread(status = new Waiter());
status.startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
/*
* Code that should come after this GUI.
*/
}
});
//Thread's run() being something like "status.setVisible(true);"
srt.start();
//"ends" here...(Initial code or GUI before this "status")
In other words, I'm having trouble implementing the GUIs and Listeners in a way to trigger main's thread's "sleep" and "wake up" actions, instead of triggering actual processing code.
UPDATE 2:
Following #JB_Nizet 's tip on SwingUtilities.invokeLater(), I took a good look at the SwingUtilities docs, and after I found out about how the SwingUtilities.invokeAndWait() method works, and I think I've found how to do it, using a combination of Semaphore and invokeAndWait().
I need someone with a better understanding of multi-threading and/or GUIs to confirm if it's a safe, valid solution or not. (I'll then edit the question and clean it up, and if confirmed, post this in proper "answer format")
Anyways, here goes the modified code, which seems to be working for me:
public class Main_Test {
//Semaphore:
public static Semaphore semaphore;
//GUIs:
private static Waiter auth; //Represents my NTLM-authentication form.
public static void main(String[] args) {
try {
semaphore = new Semaphore(1);
// semaphore.acquire();
auth = new Waiter() {
#Override
public void run() {
try {
System.out.println(Main_Test.getThread() + this.getName() + " has been created and is now running.");
semaphore.acquire(); //Makes main pause.
this.setVisible(true);
} catch (InterruptedException ex) {
Logger.getLogger(Main_Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
auth.jButton1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(getThread() + "NTLM has been hypothetically authenticated.");
semaphore.release(); //Makes main continue after GUI is done.
auth.dispose();
}
});
// semaphore.release();
SwingUtilities.invokeAndWait(auth);
semaphore.acquire(); //<- Where the main effectively gets paused until the permit is released.
/*
* GUI's run() will accquire the semaphore's permit.
* The invokeAndWait() garantees (?) it will happen before main's acquire().
* This causes the main to pause when trying to acquire the permit.
* It stays paused until the actionListener release() that permit.
*/
System.out.println(getThread() + "This message represents the processing, and should come only after the hypothetical NTLM authentication.");
} catch (InterruptedException ex) {
Logger.getLogger(Main_Test.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(Main_Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static String getThread() {
return String.format("%-32s --- ", Thread.currentThread().toString());
}
}
I'm not sure I have completely understood what you want to do, but it seems to me that you have a consumer thread (the main thread, waiting for events from the event dispatch thread), and a producer thread (the event dispatch thread).
The typical way to implement this is to use a blocking queue as a communication mechanism:
Create a blocking queue
Create your GUI and pass it the blocking queue
start a loop which gets data from the queue. Since the queue is blocking, the main thread will be blocked untile there is something in the queue
Have your event listeners, running in the EDT, post data to the blocking queue

Java: Let other threads know if GUI is ready to use

I'm writing an application which parses XML files (continuously) and show the data in a GUI (Swing). The ParseThread is in the CoreProject, and the GUI is in the GUIProject.
The start of the ParseThread is connected to a JCheckBoxMenuItem with an ItemListener. The value of setSelected() is set directly after adding to the Menu. At this time the GUI does not contain the Component which the ParseThread needs to show the parsed Data.
My Solution is, that the ParseThread should wait until the GUI is build completely.
I thought of something like an EventQueue but I have no Idea how to code one.
My Solution is, that the ParseThread should wait until the GUI is build completely. I thought of something like an EventQueue but I have no Idea how to code one.
you have got issue with Concurency in Swing, your hard and long running task should be moved to the Background task, for Swing there are two possibilities
(easy & simple) use Runnable#Thread, output to Swing GUI must be wrapped into invokeLater(), including thread safe methods as are setText, append e.i.
use SwingWorker
EDIT
please to check my visulaizations for Runnable#Thread this is the same thing as you connect server, parse long file e.i.,
with invokeLater() I cannot be sure that the component exists until the call
create GUI,
show GUI,
some (Swing / Util) Timer or user action to invoke code that is/are redirected out of Swing EventDispatchThread, for this reason there are Runnable#Thread or SwingWorker
I'm suggest two easiest of possible ways
Ok, I got my problem...
The GUI is created like this:
EventQueue.invokeAndWait(new Runnable() {
#Override
public void run() {
try {
Mainframe frame = new Mainframe();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
And at construction of the Object Mainframe this code will be executed:
final JCheckBoxMenuItem chckbxmntmParsing = new JCheckBoxMenuItem("Parsing");
chckbxmntmParsing.setName("mainframe.menu.data.parsing");
localeChangedListener.add(chckbxmntmParsing);
chckbxmntmParsing.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (chckbxmntmParsing.isSelected()) {
parseManager.startParsing();
} else {
parseManager.stopParsing();
}
}
});
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
boolean enabled = false;
String prop = PropertyManager.get().getProperty("parser.continuousparsing.enabled");
if (prop != null) {
if (prop.trim().equals("true") || prop.trim().equals("1")) {
enabled = true;
}
}
chckbxmntmParsing.setSelected(enabled);
}
});
So the ParseThread will start after GUI is build.
Sorry for stealing your time

Categories

Resources