Java / Swing: problem with fast / slow UI

I need a way to bind UI indicators to fast-changing values.

I have a NumberCruncher class that does a ton of heavy processing in a non-UI critical thread, thousands of iterations of a cycle per second, and some of them lead to changes in the set of parameters that concern me (think of them as a keystore)

I want to display them at a lower speed in the user interface thread; 10-20 Hz will be fine. How can I add an MVC-style notification so that my NumberCruncher code NumberCruncher not need to know the UI / binding code?

+4
source share
4 answers

The idiomatic way to do this is to use the SwingWorker class and use publish(V...) calls to notify about the event. The dispatch thread periodically causes the user interface to be updated.

In the example below, taken from Javadoc, the crunching number occurs in the workflow in the doInBackground () method, which causes publication at each iteration. This call causes the process method (V ...) to call asynchronously in the Dispatch stream of events , allowing it to update the user interface. Please note that this ensures that the user interface is always updated from the Event Manager thread . Also note that you can choose to publish every N iterations to reduce the refresh rate of the user interface.

Example from Javadoc

  class PrimeNumbersTask extends SwingWorker<List<Integer>, Integer> { PrimeNumbersTask(JTextArea textArea, int numbersToFind) { //initialize } @Override public List<Integer> doInBackground() { while (! enough && ! isCancelled()) { number = nextPrimeNumber(); publish(number); setProgress(100 * numbers.size() / numbersToFind); } } return numbers; } @Override protected void process(List<Integer> chunks) { for (int number : chunks) { textArea.append(number + "\n"); } } } 
+5
source

SwingWorker proposed by @Adamski is preferred; but the javax.swing.Timer instance is a convenient alternative for this, since "action event handlers for timers perform [on] dispatching thread events."

+3
source

You have one object that your NumberCrucher changes / continues to change depending on the numerous operations that you perform. Let it work in a separate thread. Have a swing user interface that uses the same Object as NumberCruncher. This thread will only read values ​​in the specified time period, so this should not be a problem of deadlocked threads.

NumberCruncher

 public class NumberCruncher implements Runnable{ CommonObject commonObj; public NumberCruncher(CommonObject commonObj){ this.commonObj = commonObj; } public void run() { for(;;){ commonObj.freqChangeVal = Math.random(); } } } 

CommonObject:

 public class CommonObject { public double freqChangeVal; } 

interface:

 import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class UI extends JFrame implements Runnable{ private CommonObject commonObj = new CommonObject(); JLabel label ; public static void main(String args[]){ UI ui = new UI(); ui.begin(); Thread t2 = new Thread(ui); t2.start(); } private void begin(){ JPanel panel = new JPanel(); label = new JLabel("Test"); panel.add(label); Thread thread = new Thread(new NumberCruncher(commonObj)); thread.start(); this.add(panel); this.setSize(200,200); this.setVisible(true); } public void run() { for(;;){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } label.setText(commonObj.freqChangeVal+""); this.repaint(); } } } 
+2
source

It looks like you might want to take a β€œlistener” approach. Allow your cruncher number to register listeners, then every 100-200 cycles (customizable) (or in some conditions changes), notify listeners of an update that they should be aware of.

The listener may be another class that has a wait () thread, and when it receives a notification, it simply updates its internal variable and then notifies the waiting thread. Then, the quick loop class has a quick way to update the external value and does not worry about accessing the fast-changing internal state.

In another thread, wait () s can also be wait () in a timer thread that is set to 10-20HZ (configurable) to wait on the timer until it waits () the next time it updates from your synchronized class.

+2
source

Source: https://habr.com/ru/post/1305597/


All Articles