我有一个管理单独的串行协议线程的Java GUI应用程序。应用程序的性质是,当协议数据线程中的数据发生更改时,我需要刷新文本字段-考虑一下实时数据监视器的一部分,该监视器查看随时间变化的稳定数据帧。我目前处理动画视图的方式是通过自定义的SwingWorker(在下面的示例代码中显示为ComponentAnimator,该动画对实现AnimatableComponent的Swing对象列表进行动画处理-就我的应用程序而言,实际上只是文本字段)而已事件线程绑定的协议数据数据发生更改。 SwingWorker会闪烁一个Text组件(以两次闪烁之间的指定持续时间将前景和背景文本反转N次)。这是动画的一种粗略形式,当协议中的数据变化缓慢时,效果很好。
当后台协议线程中的数据快速更改时,我需要帮助解决的问题是,ComponentAnimator启动(通过Executor服务,我限于三个并发线程池)以快速排队,并且动画持续的时间比更改的时间长数据。我想知道GUI线程中是否有某种方式(我可以触发ComponentAnimator)可以加入一个现有的活动动作,取消其动画动作并将其替换为新动作,而不是在启动后排队另一个定时动画。当前的一个。任何帮助或指导将不胜感激。
/**
* Handles bound Frame Info property. For this particular panel,
* the frameInfo may be associated with this Simulator (Panel)
* or from frames received from the Prosim737 translated TCP
* strings.
*
* @param aNewFrameInfo
* new frame of 429 words
* @param aOldFrameInfo
* old frame of 429 words - if this is null
* then this represents the first time
* callback of that frame. This is particularly
* important when processing the first Prosim737
* Frame for the indicator bits as we must ensure
* that we update all indicator bits. For
* subsequent frames we are only interested in
* deltas.
*/
private void handleNewFrameData(
final ProsimLabelInfo aNewFrameInfo,
final ProsimLabelInfo aOldFrameInfo) {
// log the event to the log area (this is done in the EVT queue)
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// log changes, don't need a verbose date
// SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss:SSS");
java.util.Date lastLogTimeStamp = (aOldFrameInfo == null)?
aNewFrameInfo.getTimeStamp() : aOldFrameInfo.getTimeStamp();
// Code added to handle updating the widgets to default when
// this is the first callback to handleNewFrameData (i.e
// when aOldFrameInfo null)
java.util.Date deltaT = new java.util.Date(
aNewFrameInfo.getTimeStamp().getTime() -
lastLogTimeStamp.getTime());
StringBuilder sb = new StringBuilder(
"DT" + gTimeFormat.format(deltaT));
// make sure we behave like tail -f by setting the caretPosition
// to the end of the stream of data
StyledDocument doc = jEventLogTextPane.getStyledDocument();
// only print changed label details
boolean bFromPanel = aNewFrameInfo.isFromPanel();
for (Base429Word newWord : aNewFrameInfo.getDataWords().values()) {
List<AnimatableComponent> flashingText = new ArrayList<>();
// get the corresponding label from
// the previous frame update if any
Base429Word oldWord = (aOldFrameInfo == null)? null :
aOldFrameInfo.get429Word(newWord.getUniqueKey());
// update GUI elements - if first time word encountered
if (oldWord == null || !oldWord.equals(newWord)) {
processUpdatedWord(bFromPanel, oldWord, newWord);
if ((oldWord == null) || !newWord.equals(oldWord)) {
JTextComponent textField = bFromPanel?
gTXLabelCompInfo.get(newWord.getUniqueKey()):
gRXLabelCompInfo.get(newWord.getUniqueKey());
if (textField != null) {
flashingText.add(new TextFieldAnimator(
textField,
Color.BLACK, Color.WHITE, // final colors
Color.YELLOW, Color.RED)); // animating colors
}
}
if (flashingText.size() > 0) {
// flash first time or changed received words
mExecutorService.execute(
new ComponentAnimator(flashingText, 1, 70));
}
}
}
// red for changed areas, blue for timestamp prefix
try {
doc.insertString(doc.getLength(), sb.toString(), gBlueTextAttrs);
jEventLogTextPane.setCaretPosition(doc.getLength());
if ( !jSaveLogButton.isEnabled() ) {
jSaveLogButton.setEnabled(true);
jClearEventLogButton.setEnabled(true);
}
} catch (BadLocationException ex) {}
}
最佳答案
如何加入现有的SwingWorkerSwingWorker
是不可共享的,因为它被指定为作为单个实例运行,所以没有non_hacky方式将值从一个实例传递到另一个实例(意思是publish()
,process()
,setProgress()
),因为没有实现getProgress()
这是标准线程的工作
使用信号量进行线程化,但是必须将所有输出到已经可见的Swing GUI中的输出包装到invokeLater
中,仅包装到在AWT,Swing中实现的方法,而不是整个方法都生成此输出
您可以从SwingWorker
调用Executor
并开始第二。 (任意数量的实例)实例,该实例具有从SwingWorker
实例中以done()
结尾的传递值
例如
1)对于信号量,您将need to naming SwingWorkers instances
2)another reference code
3)注意添加PropertyChangeListener,....没有实现任何AWT,Swing Listener