gpt4 book ai didi

java - JGraph AWT EventQueue 绘画异常(多线程)

转载 作者:行者123 更新时间:2023-11-30 07:32:15 27 4
gpt4 key购买 nike

情况

我有一个可视化使用 JGraph .该图由与实例化可视化的线程不同的线程更新。

预期行为

图形应由各种工作线程更新。线程调用以更新图形的函数是同步的,因此工作线程不会在它们之间引起并发问题。

实际行为

在绘制时(偶尔)在 AWT-EventQueue 线程中抛出异常。有时是空指针,有时是索引越界。这是堆栈跟踪:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at com.mxgraph.shape.mxConnectorShape.translatePoint(Unknown Source) at com.mxgraph.shape.mxConnectorShape.paintShape(Unknown Source) at com.mxgraph.canvas.mxGraphics2DCanvas.drawCell(Unknown Source) 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) at javax.swing.JComponent.paint(JComponent.java:1029) at com.mxgraph.swing.mxGraphComponent$mxGraphControl.paint(Unknown Source) at javax.swing.JComponent.paintChildren(JComponent.java:866) at javax.swing.JComponent.paint(JComponent.java:1038) at javax.swing.JViewport.paint(JViewport.java:764) at javax.swing.JComponent.paintToOffscreen(JComponent.java:5138) at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:302) at javax.swing.RepaintManager.paint(RepaintManager.java:1188) at javax.swing.JComponent._paintImmediately(JComponent.java:5086) at javax.swing.JComponent.paintImmediately(JComponent.java:4896) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:783) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:735) at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:677) at javax.swing.RepaintManager.access$700(RepaintManager.java:58) at 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) at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)

它似乎不会对应用程序的运行产生不利影响。一个新的 AWT-EventQueue 产生,它将在某个阶段不可避免地遇到同样的问题。

原因

我认为这一定是由于在单独的线程中将图形更新为实例化 JFrame 的线程引起的。需要绘制的东西在 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();
}
}
}

Controller 代码

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);
}
}

最佳答案

不是回答你的问题,只是对你的概念的一些通知。

  1. 您能向我们展示您的public static void main(String[] args) {...} 方法吗?我希望有一些东西看起来像:

    public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() {

            public void run() {
    Visualisation vis = new Visualisation();
    }
    });
    }
  2. this.setSize(800, 600); 应该是 this.setpreferredSize(new Dimension(800, 600));

    <
  3. 然后在最后一行之前添加this.pack(); (this.setVisible(true);)

编辑:

  1. 什么类型的组件返回 mxGraphComponent graphComponent = new mxGraphComponent(graph); 因为如果是基于 JPanel 的自定义组件那么

getContentPane().add(graphComponent); 应该是 add(graphComponent);

  1. 来自后台线程/任务的所有输入都必须包装到 invokeLater() 中.如果它闪烁或卡住,那么您必须寻找 invokeAndWait()。我个人讨厌那里存在invokeAndWait(),但是对于这个方法我不能给你一些正确的建议。或者:

  2. 如果您将在某些周期性基础上运行您的任务,那么您必须寻找 Runnable(输出必须包装到 invokeLater 中)或 SwingWorker .

关于java - JGraph AWT EventQueue 绘画异常(多线程),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6692674/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com