我使用JGraph进行了可视化。该图由不同的线程更新为实例化Visualization的线程。
图表应该由各种工作线程更新。线程调用以更新图形的函数是syncronized
,因此工作线程不会导致它们之间的并发问题。
绘制时,AWT-EventQueue线程中抛出异常( ocassionally )。有时它是一个空指针,有时它是一个超出范围的索引。这是一个堆栈跟踪:
线程“AWT-EventQueue-0”中的异常java.lang.NullPointerException 在com.mxgraph.shape.mxConnectorShape.translatePoint(未知来源) 在com.mxgraph.shape.mxConnectorShape.paintShape(未知来源) 在com.mxgraph.canvas.mxGraphics2DCanvas.drawCell(未知来源) at com.mxgraph.view.mxGraph.drawState(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.drawCell(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.drawChildren(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.drawCell(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.drawChildren(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.drawCell(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.drawChildren(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.drawCell(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.drawFromRootCell(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.drawGraph(Unknown Source) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.paintComponent(Unknown Source) 在javax.swing.JComponent.paint(JComponent.java:1029) at com.mxgraph.swing.mxGraphComponent $ mxGraphControl.paint(Unknown Source) 在javax.swing.JComponent.paintChildren(JComponent.java:866) 在javax.swing.JComponent.paint(JComponent.java:1038) 在javax.swing.JViewport.paint(JViewport.java:764) 在javax.swing.JComponent.paintToOffscreen(JComponent.java:5138) 在javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:302) 在javax.swing.RepaintManager.paint(RepaintManager.java:1188) 在javax.swing.JComponent._paintImmediately(JComponent.java:5086) 在javax.swing.JComponent.paintImmediately(JComponent.java:4896) 在javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:783) 在javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:735) 在javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:677) 在javax.swing.RepaintManager.access $ 700(RepaintManager.java:58) 在javax.swing.RepaintManager $ ProcessingRunnable.run(RepaintManager.java:1593) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:226) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:647) at java.awt.EventQueue.access $ 000(EventQueue.java:96) at java.awt.EventQueue $ 1.run(EventQueue.java:608) at java.awt.EventQueue $ 1.run(EventQueue.java:606) at java.security.AccessController.doPrivileged(Native Method) at java.security.AccessControlContext $ 1.doIntersectionPrivilege(AccessControlContext.java:105) at java.awt.EventQueue.dispatchEvent(EventQueue.java:617) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177) 在java.awt.EventDispatchThread.run(EventDispatchThread.java:138)
它似乎不会对应用程序的运行产生负面影响。一个新的AWT-EventQueue产生,在某个阶段将不可避免地遇到同样的问题。
我认为它必须通过在单独的线程中将图形更新为JFrame实例化的图形来引起。在paint方法试图绘制它们时,需要绘制的东西正在被更改。
如何解决此问题?我能以某种方式将paint方法与更新图形的方法同步吗?
package ui;
import javax.swing.JFrame;
import com.mxgraph.layout.mxOrganicLayout;
import com.mxgraph.layout.mxStackLayout;
import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGraphModel;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.view.mxGraph;
import core.Container;
import core.Node;
import core.WarehouseGraph;
public class Visualisation extends JFrame{
private static final long serialVersionUID = 8356615097419123193L;
private mxGraph graph = new mxGraph();
Object parent = graph.getDefaultParent();
mxOrganicLayout graphlayout = new mxOrganicLayout(graph);
mxStackLayout containerLayout = new mxStackLayout(graph, true, 10);
public Visualisation(WarehouseGraph model){
super("Warehouse Simulator");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(800, 600);
graph.getModel().beginUpdate();
try{
for(Node node : model.getNodes().values()){
mxCell cell = (mxCell)graph.insertVertex(parent, node.getId(), node.getId(), 0, 0, 60, 30);
Object prev = null;
for(Container container : node.getContainers()){
Object newCont = graph.insertVertex(cell, container.getId(), container.getId(), 0, 0, 60, 20);
if(prev != null) graph.insertEdge(cell, null, null, prev, newCont);
prev = newCont;
}
}
for(Node node : model.getNodes().values()){
for(Node toNode : node.getDownstreamNodes()){
Object fromCell = ((mxGraphModel)graph.getModel()).getCell(node.getId());
Object toCell = ((mxGraphModel)graph.getModel()).getCell(toNode.getId());
graph.insertEdge(parent, null, null, fromCell, toCell);
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
graph.getModel().endUpdate();
}
graphlayout.execute(parent);
Object[] nodes = mxGraphModel.getChildVertices(graph.getModel(), parent);
for(Object cell : nodes){
containerLayout.execute(cell);
graph.updateCellSize(cell);
}
mxGraphComponent graphComponent = new mxGraphComponent(graph);
getContentPane().add(graphComponent);
this.setVisible(true);
}
//CALLED FROM SYNCHRONIZED FUNCTION
public void moveContainer(Container container, Node to){
graph.getModel().beginUpdate();
mxCell toCell = (mxCell)((mxGraphModel)graph.getModel()).getCell(to.getId());
mxCell containerCell = (mxCell)((mxGraphModel)graph.getModel()).getCell(container.getId());
mxCell fromCell = (mxCell)containerCell.getParent();
try{
Object[] edges = mxGraphModel.getEdges(graph.getModel(), containerCell);
graph.removeCells(edges);
containerCell.removeFromParent();
graph.addCell(containerCell, toCell);
Object[] containers = mxGraphModel.getChildVertices(graph.getModel(), toCell);
if(containers.length >= 2)
graph.insertEdge(toCell, null, null, containerCell, containers[containers.length-2]);
containerLayout.execute(toCell);
containerLayout.execute(fromCell);
}catch(Exception e){
e.printStackTrace();
}finally{
graph.getModel().endUpdate();
}
}
}
package core;
import serialisation.JsonUtil;
import ui.Visualisation;
public class Controller{
private WarehouseGraph graph;
Visualisation viz;
public static void main(String[] args){
Controller.getInstance();
}
private Controller(){
graph = JsonUtil.initFromJson(); //graph has many worker threads running which can call containerMoved
viz = new Visualisation(graph);
}
private static class SingletonHolder{
private static final Controller INSTANCE = new Controller();
}
public static Controller getInstance(){
return SingletonHolder.INSTANCE;
}
public synchronized void containerMoved(Container container, Node from, Node to){
viz.moveContainer(container, to);
}
}
答案 0 :(得分:4)
不回答你的问题,只是注意你的概念。
您能告诉我们您的public static void main(String[] args) {...}
方法吗?我希望有一些看起来像:
public static void main(String [] args){ SwingUtilities.invokeLater(new Runnable(){
public void run() {
Visualisation vis = new Visualisation();
}
});
}
this.setSize(800, 600);
应为this.setpreferredSize(new Dimension(800, 600));
然后在最后一行(this.pack();
)之前添加this.setVisible(true);
编辑:
mxGraphComponent graphComponent = new mxGraphComponent(graph);
,因为如果是基于JPanel的自定义组件,那么 getContentPane().add(graphComponent);
应为add(graphComponent);
来自backGround线程/任务的所有输入都必须包含在invokeLater()中。如果它是闪烁或冻结,那么你必须寻找invokeAndWait()
。我个人认为那里存在invokeAndWait()
,但对于这种方法,我无法给你一些正确的建议。或者:
如果您要在某些期刊基础上运行任务,那么您必须查找Runnable(输出必须包装到invokeLater中)或SwingWorker。