#java #swing #jslider
#java #swing #jslider
Вопрос:
мой вызов JSlider.setValue иногда блокирует поток, что приводит к взаимоблокировке всего приложения.
вот трассировка стека блокирующего потока.
Thread [RenderThread] (Suspended)
JSlider(Component).getMousePosition() line: not available [local variables unavailable]
SynthSliderUI.calculateThumbLocation() line: not available [local variables unavailable]
BasicSliderUI$Handler.stateChanged(ChangeEvent) line: not available
DefaultBoundedRangeModel.fireStateChanged() line: not available [local variables unavailable]
DefaultBoundedRangeModel.setRangeProperties(int, int, int, int, boolean) line: not available
DefaultBoundedRangeModel.setValue(int) line: not available
JSlider.setValue(int) line: not available
TimeLine.setTime(double) line: 422
GLFrame.display() line: 302
GLFrame$2.renderCallback() line: 188
LWJGLBinding$1.paintGL() line: 49
LWJGLBinding$1(AWTGLCanvas).paint(Graphics) line: 314
LWJGLBinding$1(AWTGLCanvas).update(Graphics) line: 343
GLFrame$2(LWJGLBinding).startRendering() line: 78
GLFrame$3.run() line: 267
похоже, это связано с внешним видом nimbus, потому что i не выполняется во внешнем виде по умолчанию.
try
{
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
}
catch (Exception e)
{
e.printStackTrace();
}
Редактировать:
с помощью invokeLater я получаю это исключение:
at javax.swing.plaf.synth.SynthTreeUI.paint(Unknown Source)
at javax.swing.plaf.synth.SynthTreeUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent._paintImmediately(Unknown Source)
at javax.swing.JComponent.paintImmediately(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.awt.EventQueue$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Комментарии:
1. убедитесь, что setValue вызывается в EDT
2. хорошо, спасибо. какой рекомендуемый способ сделать это?
3.
SwingUtilites.invokeLater(new Runnable(){ public void run(){ / *Your code */ }})
4. @Frozen, вы должны перенести это в ответ, чтобы @clamp мог его принять.
5. @MeBigFatGuy Я думал, что @kleopatra сделает это, поэтому я решил подождать 🙂
Ответ №1:
Компоненты Swing не являются потокобезопасными. Все, что изменяет компонент Swing после того, как он уже показан, должно выполняться в так называемом потоке отправки событий (EDT). Для достижения этого Swing предоставляет вам функции:
Два из них служат для выполнения кода:
SwingUtilities.invokeLater(Runnable)
SwingUtilities.invokeAndWait(Runnable)
Их назначение вытекает из их названия. Третий — это
SwingUtilities.isEventDispatchThread()
Если это возвращает true
, значит, вы уже находитесь в EDT и можете выполнять код напрямую.
Обратите внимание, что это invokeAndWait
вызовет исключение, если оно вызывается непосредственно из EDT ( invokeLater
не будет, но это все еще не рекомендуется делать), поэтому код, который может быть вызван как из EDT, так и из побочного потока, следует записать следующим образом:
if (SwingUtilities.isEventDispatchThread()) {
// code
} else {
SwingUtilities.invokeLater(new Runnable () {
public void run () {
// code
}
});
}
В целях простоты и удобочитаемости вы можете извлечь внутренний код из метода.
Комментарии:
1. 1 хороший ответ. Просто обратите внимание, что при использовании SwingUtilities.invokeLater(Runnable) вам не нужно проверять, что он не запускается в EDT, что вы должны сделать при использовании SwingUtilities.invokeAndWait(Runnable) . Исключение будет выдано только invokeAndWait. Это полезно проверить, поскольку вы не приведете к тому, что ваш код попадет в конец очереди.
2. Спасибо. на самом деле я получаю то исключение, о котором вы говорите, при запуске, даже если я использую invokeLater. смотрите мою правку в моем исходном сообщении
3. @Boro Спасибо, исправил это. @clamp Не могли бы вы, пожалуйста, опубликовать само исключение, а не только трассировку стека?
4. ну, само исключение — это просто исключение nullpointer, начинающееся со стека, который я опубликовал.
5. Похоже, что у вас есть другие методы, изменяющие Swing, которые вызываются не из EDT (см. bugs.sun.com/bugdatabase/view_bug.do?bug_id=4524304 ). Пожалуйста, проверьте, верно ли это.