我有一个管理单独的串行协议线程的 Java GUI 应用程序。应用程序的性质是,当协议数据线程中的数据发生变化时,我需要刷新文本字段——想想实时数据监视器的一部分,它查看随时间变化的稳定数据帧。我目前处理动画视图的方式是通过自定义 SwingWorker(在下面的示例代码中显示为 ComponentAnimator,它动画实现了 AnimatableComponent 的 Swing 对象列表 - 基本上只是为了我的应用程序的目的的文本字段),它从事件线程绑定协议数据数据变化。SwingWorker 闪烁一个文本组件(在闪烁之间指定的持续时间反转前景和背景文本 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) {}
}