我正在创建一个带有rootNode的Jtree,而不是创建另一个异步更新根节点的线程。
如果我在一些JPanel中独立运行这个Jtree,它甚至可以在项目的某个地方工作,但是我被要求在一些新的swing组件中使用这个Jtree。
在新的Swing Panel中,它不会完全填充,它只会填充在屏幕上呈现Jtree之前插入的节点(在启动时几毫秒)。一旦呈现Jtree,它就不会更新。 现在有趣的部分我也在节点上创建了一个鼠标监听器,这样我就可以通过右键单击创建节点功能来创建一个新节点,并创建新节点并添加到Jtree根节点上。
添加i的重要一点是使用newThread(){void run})。start()方法创建一个在Jtree上添加节点的线程,因为我以前从未觉得需要SwingUtilities.invokeLater方法。但是现在如果我使用SwingUtilities.invokeLater方法而不是主窗口也没有打开它只是在启动期间暂停,我只是检查SwingUtilities.invokeLater也可以正常使用旧组件和当然工作正常。
我确实调用了model.nodeStructureChanged(changedNode);添加节点后,为什么它之前工作正常。
请asist, 代码难以提取和Jtree代码之前工作正常,可能是某些组件阻止包含小部件来刷新自己的异步?
修改 更新以包含一些代码,我正在使用由Nick提供的Temp类: -
public BasicGraphEditor(String appTitle, mxGraphComponent component)
{
// Stores and updates the frame title
this.appTitle = appTitle;
// Stores a reference to the graph and creates the command history
graphComponent = component;
final mxGraph graph = graphComponent.getGraph();
undoManager = createUndoManager();
// Do not change the scale and translation after files have been loaded
graph.setResetViewOnRootChange(false);
// Updates the modified flag if the graph model changes
graph.getModel().addListener(mxEvent.CHANGE, changeTracker);
// Adds the command history to the model and view
graph.getModel().addListener(mxEvent.UNDO, undoHandler);
graph.getView().addListener(mxEvent.UNDO, undoHandler);
// Keeps the selection in sync with the command history
mxIEventListener undoHandler = new mxIEventListener()
{
@Override
public void invoke(Object source, mxEventObject evt)
{
List<mxUndoableChange> changes = ((mxUndoableEdit) evt
.getProperty("edit")).getChanges();
graph.setSelectionCells(graph
.getSelectionCellsForChanges(changes));
}
};
undoManager.addListener(mxEvent.UNDO, undoHandler);
undoManager.addListener(mxEvent.REDO, undoHandler);
// Creates the graph outline component
graphOutline = new mxGraphOutline(graphComponent);
// Creates the library pane that contains the tabs with the palettes
libraryPane = new JTabbedPane();
/////////////////////////////////////////////////
// Only change i have done here: start
////////////////////////////////////////////////
Temp tempExplorer = new Temp();
libraryPane.add("new Explorere", tempExplorer);
/////////////////////////////////////////////////
// Only change i have done here: End
////////////////////////////////////////////////
// Creates the inner split pane that contains the library with the
// palettes and the graph outline on the left side of the window
JSplitPane inner = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
libraryPane, graphOutline);
inner.setDividerLocation(320);
inner.setResizeWeight(1);
inner.setDividerSize(6);
inner.setBorder(null);
// Creates the outer split pane that contains the inner split pane and
// the graph component on the right side of the window
JSplitPane outer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, inner,
graphComponent);
outer.setOneTouchExpandable(true);
outer.setDividerLocation(200);
outer.setDividerSize(6);
outer.setBorder(null);
// Creates the status bar
statusBar = createStatusBar();
// Display some useful information about repaint events
installRepaintListener();
// Puts everything together
setLayout(new BorderLayout());
add(outer, BorderLayout.CENTER);
add(statusBar, BorderLayout.SOUTH);
installToolBar();
// Installs rubberband selection and handling for some special
// keystrokes such as F2, Control-C, -V, X, A etc.
installHandlers();
installListeners();
updateTitle();
}
以上类来自Jgraph库https://github.com/jgraph/jgraphx 我只是添加如上所述的jtree组件,没有其他更改。 请帮忙。
答案 0 :(得分:2)
除非明确说明,否则Swing不是线程安全的。在the JavaDocs for JTree中,它明确表示这不是线程安全的。如果你在EDT之外的一个主题中更新它,那么没有任何保证可以工作。因此,如果要从不同的线程更新JTree,则需要使用SwingUtilities.invokeLater(Runnable run);
将请求放在EDT上。
我建议使用数据结构来存储JTree的信息,并且只使用JTree进行用户交互(而非数据存储)。
修改强>
以下是在组件模型中使用SwingUtilities.invokeLater()
更新JTree的示例。没有你发布任何代码,这是我必须使用的最好的。请尝试使用此方法重新创建您的问题(在此示例中添加代码片段,直到您缩小问题范围为止)。
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
public class Temp extends JPanel{
JTree tree = new JTree();
public Temp(){
JScrollPane jsp = new JScrollPane(tree);
// Creates the library pane that contains the tabs with the palettes
JTabbedPane libraryPane = new JTabbedPane();
libraryPane.add("new Explorere", jsp);
// Creates the inner split pane that contains the library with the
// palettes and the graph outline on the left side of the window
JSplitPane inner = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
libraryPane, new JPanel());
inner.setDividerLocation(320);
inner.setResizeWeight(1);
inner.setDividerSize(6);
inner.setBorder(null);
// Creates the outer split pane that contains the inner split pane and
// the graph component on the right side of the window
JSplitPane outer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, inner,
new JPanel());
outer.setOneTouchExpandable(true);
outer.setDividerLocation(200);
outer.setDividerSize(6);
outer.setBorder(null);
// Puts everything together
setLayout(new BorderLayout());
add(outer, BorderLayout.CENTER);
}
public static void main(String[] args) {
final Temp temp = new Temp();
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(temp);
frame.pack();
frame.setVisible(true);
}});
Thread updater = new Thread(temp.new CustomThread());
updater.start();
}
public class CustomThread implements Runnable{
@Override
public void run() {
for(int i = 0; i < 1000; i++){
updateTree("New Item "+ i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void updateTree(final String nodeToAdd){
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
DefaultMutableTreeNode child = new DefaultMutableTreeNode(nodeToAdd);
model.insertNodeInto(child, root,root.getChildCount());
tree.scrollPathToVisible(new TreePath(child.getPath()));
}});
}
}
}