我有一个管理单独的串行协议线程的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) {}
        }

最佳答案

如何加入现有的SwingWorker



SwingWorker是不可共享的,因为它被指定为作为单个实例运行,所以没有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

10-08 19:03