我编写了一些程序来监视UNIX服务器上的进程。我的代码的主要部分看起来像这样:

Class FeedMonitor {
    //.............
    private volatile boolean monitor = true;
    private volatile String feedShRez;
    private volatile DefaultMutableTreeNode envNode;
    //.............
    public void prepareGUI() {
       //..............
       //
       SwingWorker worker = new SwingWorker<Void, Void>() {
          @Override
          protected Void doInBackground() throws Exception {
            sh = new Shell(env);
            System.out.println("Swing worker for check feed statuses started...");
            while (monitor) {
              // get running feeds
              feedShRez = sh.getFeedsStatus(rez);
              System.out.println(feedShRez);
              Thread.sleep(15000);
              System.out.println("Swing worker for check feed statuses is waking up...");
            }
            return null;
          }
          @Override
          protected void done() {
            System.out.println("Swing worker completed.");
            super.done();
            System.out.println("Set monitor object to false");
            feedShRez = "";
          }
        };
        worker.execute();
        //......
        // This action I would like to execute in thread periodically
        envTree.setCellRenderer(new DefaultTreeCellRenderer() {
            public Component getTreeCellRendererComponent(JTree pTree,
                    Object pValue, boolean pIsSelected, boolean pIsExpanded,
                    boolean pIsLeaf, int pRow, boolean pHasFocus) {

                    System.out.println("Node is " + pValue.toString());
                    super.getTreeCellRendererComponent(
                            pTree, pValue, pIsSelected,
                            pIsExpanded, pIsLeaf, pRow,
                            hasFocus);

                    // we are under environment tree
                    if ( envNode !=null && ((DefaultMutableTreeNode)pValue).getParent() == envNode
                        && feedShRez != null && !feedShRez.isEmpty()){
                          if (feedShRez.contains(pValue.toString())) {
                            System.out.println("Found feed " + pValue.toString() + " in strings");
                            setForeground(Color.GREEN);
                              } else {
                            setForeground(Color.RED);
                          }
                    }

                    return (this);
                }
        });

        // In this thread I would like to execute action above
        // but it works only one or two times
        SwingWorker worker2 = new SwingWorker<Void, Void>() {
                @Override
                protected Void doInBackground() throws Exception {
                    while (monitor) {
                            //System.out.println("enter to second swing worker");
                            //envTree.repaint();
                            //mainFrame.repaint();
                            // should fire DefaultTreeCellRenderer action
                            envTree.setSelectionRow(0);
                            //envTree.setFont(null);
                            Thread.sleep(3000);
                    }
                    return null;
                }
                @Override
                protected void done() {
                    super.done();
                    monitor = false;
                    System.out.println("Done in second swing worker");
                    //progressBar.setVisible(false);
                }
        };
        worker2.execute();


从上面的代码中可以看到,我使用了两个SwingWorker。在其中一个中,我向服务器发出请求,以检查另一个工作器中正在运行的进程
我尝试通过调用envTree.setCellRenderer(new DefaultTreeCellRenderer()来模拟envTree.setSelectionRow(0)动作,以在JTree中用GREEN和RED颜色标记正在运行和中断的进程。这里的主要问题是,该操作对我而言无法正常运行,它只能触发一两次,但是当我手动单击JTree时,它始终会执行。请有人对此提出建议。提前致谢。

最佳答案

如果我正确理解了您的问题,则可以使用Shell获得某种进程列表。此列表存储在字段中,并用于创建TreeModel。您想使用对JTree的新可用信息定期重绘TreeModel

与所有Swing组件一样,JTree具有内置的机制,可在基础数据发生更改时触发重新绘制。您更改模型,模型将触发一个change事件,并且该事件由视图拾取。这样,视图便知道必须重新绘制。

所以,我会提出这样的解决方案:


检索进程列表(并且当前在循环中更新字段)的SwingWorker不再使用该字段。而是使用SwingWorker#publish方法发布中间结果。然后,您覆盖SwingWorker#process方法以处理那些结果。在EDT上调用此方法,并且可以使用新信息更新TreeModel。确保更改TreeModel时触发了正确的事件。
TreeModel应包含与正确呈现数据有关的所有信息
由于对TreeModel和相应事件进行的更改,JTree将安排重新绘制。不需要第二个SwingWorker。并且由于模型包含渲染器所需的所有信息,因此渲染器可以返回正确状态的Component

10-04 18:12