问题
I write some program for monitoring processes on unix server. The main part of my code is looking like this:
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();
As you could see from code above I use two SwingWorkers. In one of them I make request to server to check which processes is running, in another worker
I try to emulate envTree.setCellRenderer(new DefaultTreeCellRenderer()
action by calling envTree.setSelectionRow(0)
, to mark running and downing processes by GREEN and RED colours in JTree. The main problem here that this action doesn't work properly for me, it could fire only one or two times, but when I manually clicked on JTree it always executed. Could please someone advise on this. Thanks in advance.
回答1:
If I understood your question correctly, you obtain some sort of process list using the shell. This list is stored in a field and used to create a TreeModel
. You want to periodically repaint the JTree
using the newly available info to the TreeModel
.
The JTree
, like all Swing components, has a built-in mechanism to trigger a repaint when the underlying data has changed. You alter the model, the model fires a change event and this event is picked up by the view. The view then knows that it has to repaint.
So, I would propose a solution like this:
- The
SwingWorker
which retrieves the process list (and which currently updates a field in a loop) no longer uses the field. Instead, it uses theSwingWorker#publish
method to publish the intermediate result. You then override theSwingWorker#process
method to handle those results. This method is called on the EDT, and can update theTreeModel
with the new information. Make sure that the correct events are fired when altering theTreeModel
. - The
TreeModel
should contain all info which is relevant for the correct rendering of the data - Due to the changes made to the
TreeModel
and the corresponding event, theJTree
will schedule a repaint. No need for the secondSwingWorker
. And since the model contains all info needed for the renderer, the renderer can return aComponent
in the correct state.
来源:https://stackoverflow.com/questions/26524209/defaulttreecellrenderer-execute-periodically