user1387622
user1387622

Reputation: 187

SwingUtilities.invokeLater on full speed thread

I have a thread that does display updates on my JFrame by using SwingUtilities.invokeLater. The thread's speed is adjustable, and when it set to full speed (no sleeping between updates), my program gets slowed down badly. I guess the problem is my thread is generating too much SwingUtilities.invokeLater events that JFrame's thread can not consume. So is there anything I can do on my thread to remove previously added but not consumed events? Or should I use some other ways to update JFrame without using SwingUtilities.invokeLater?

Thanks in advance.

Upvotes: 2

Views: 1079

Answers (3)

user949300
user949300

Reputation: 15729

Can you use a simple repaint()? The advantage of that is that multiple calls are merged into one.

(Elaboration added)

Let's say you are constantly updating your GPS location and displaying it in two text fields. Your thread to do the updating:

run() {
  while (keepGoing) {
    Point myLocation = computeMyLocation();
    locationModel.setLocation(myLocation);
    locationComponent.repaint();
  }
}

then, in MyLocationComponent

@Override
public void paintComponent(Graphics g) {
   Point myLocation = locationModel.getLocation();

   // you'd really want a NumberFormat
   latitudeTextArea.setText(String.valueOf(myLocation.y));
   longitudeTextArea.setText(String.valueOf(myLocation.x));

   super.paintComponent(g);
}

The advantage is that this splits the model from the view (if you think of the thread as the controller, this is MVC), and all the threading should work - no need for any invokeLater(). One disadvantage is that your thread needs to know all of the JComponents that need to be updated. In a "real" scenario you'd probably fire events to listeners that trigger the repaints, either from the "controller" (your thread) or from the model.

NOTE: As pointed out by @trashgod, in LocationModel, the getLocation() and setLocation() methods should be synchronized so that updates appear immediately.

Upvotes: 1

trashgod
trashgod

Reputation: 205785

It sounds like you want to avoid saturating the event dispatch thread. The class javax.swing.Timer, discussed in How to Use Swing Timers, includes setCoalesce(), which "coalesces multiple pending ActionEvent firings." It may an alternative way to pace your updates.

As mentioned here, SwingWorker is limited to 33 Hz.

Upvotes: 3

Mark Peters
Mark Peters

Reputation: 81074

This might be a perfect job for SwingWorker. You can publish incremental updates, and SwingWorker will batch them to solve the performance problem:

Because the process method is invoked asynchronously on the Event Dispatch Thread multiple invocations to the publish method might occur before the process method is executed. For performance purposes all these invocations are coalesced into one invocation with concatenated arguments.

The code you want to run on the EDT, you add by implementing process(). The list of updates is passed to you in the argument.

Upvotes: 4

Related Questions