问题
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.
回答1:
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.
回答2:
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.
回答3:
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.
来源:https://stackoverflow.com/questions/13114097/swingutilities-invokelater-on-full-speed-thread