我编写了一些程序来监视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
。