Change Java Swing Thread UI

I have tried this for hours. I have a thread that changes the JTextField of my user interface, which completely destroys the user interface. Thread (lets call it Thread A) is generated by an ActionListener. The .setText () function call is located in the auxiliary stream (B) created by thread A. Thread B is the SwingUtilitis.invokeAll () and / or SwingUtilities.invokeAndWait () parameter. I tried both of them. Here is some code to make it more understandable.

This is my ActionListener that creates Thread A - in short, 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 places Thread B on 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- } } } 

UI.updateCounter (...) will put thread B in 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 is called, everything becomes spoiled. I tried different things for hours and nothing worked. I also tried using SwingWorker, but some or nothing happened.

+4
source share
4 answers

In general, labels do not display text that is changing very well: changing their width and layout with it.

Using a JTextField for reading, perhaps with proper style changes, might be a better solution.

0
source

I think the intermediate JPanel that you created can be considered the roots of validation. Therefore, revalidate() , which automatically occurs when setText() is called, does not cause any layout changes that exceed the level of the JPanel parent.

I don’t think you really need panels, since JLabel can contain both an icon and text. See the tutorial .

So my advice is to remove the panels, or if they serve the purpose, make sure that isValidateRoot() on the panels returns false.

0
source

The invokeAndWait() allows you to publish a Runnable job that must be run on the EDT, but blocks the current thread and waits for the EDT to complete the task.

But there is a deadlock potential in invokeAndWait (), since thread code is created in any code. If the calling code contains some lock (explicitly or implicitly) that the code calls through invokeAndWait () is required, then the EDT code will wait for the EDT to release the lock, which cannot be because the non-EDT code is waiting for the completion of the EDT code, and the application will hang.

As we can see here, a change in the JLabel component passed to the pending non-EDT.

Instead, we can use

invokeLater() takes care of creating and invokeLater() special event that contains Runnable. This event is processed on the EDT in the order in which it was received, like any other event. When the time comes, it is sent by running the Runnables run () method.

 SwingUtilities.invokeLater(new Runnable() { public void run() { label.setText("Refreshing in: " + i + " seconds."); } }); 

OR

isEventDispatchThread() , which returns true if the calling code is currently executing in EDT, otherwise false.

 Runnable code= new Runnable() { public void run() { label.setText("Refreshing in: " + i + " seconds."); } } ); if (SwingUtilities.isEventDispatchThread()) { code.run(); } else { SwingUtilities.invokeLater(code); } 
0
source

When changing label text, you should at least call repaint()/revalidate() in the top label container, causing a relay, assuming the label calls invalidate() / revalidate() correctly when changing the text.

-1
source

All Articles