java - Thread.sleep() 卡住包含 GraphStream 图形的 JFrame/GUI

标签 java algorithm swing concurrency graphstream

当我尝试在调用 Thread,sleep() 的循环中更新它时,包含嵌入式单个图 (Graphstream) 的 JFrame 卡住了。我已经尝试在独立图上使用相同的更新(单独显示)并且它按预期工作。

我在 JFrame 中嵌入了一个图形,如下所示 (AppGraph.java):

public static ViewPanel init(){

    graph.addAttribute("ui.stylesheet", styleSheet);
    graph.setAutoCreate(true);
    graph.setStrict(false);
    graph.addAttribute("ui.quality");
    graph.addAttribute("ui.antialias");

    initGraph();

    initNodes(graph);

    return attachViewPanel();

}

private static ViewPanel attachViewPanel() {
    Viewer viewer = new Viewer(graph, Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
    viewer.enableAutoLayout();
    return viewer.addDefaultView(false);
}

private static void initGraph(){
    FileSource fs = new FileSourceDOT();
    String graph_filename = "graph.gv";
    String absolute_path = System.getProperty("user.home") + File.separator + graph_filename;
    fs.addSink(graph);
    try {
        fs.readAll(absolute_path);
    } catch (IOException | NullPointerException e) {
        e.printStackTrace();
    } finally {
        fs.removeSink(graph);
    }
}

然后在 JFrame 类中调用如下:

   /*AppWindow.java
    * Set up graph
    */
    GridBagConstraints graphConstraints = new GridBagConstraints();
    graphConstraints.fill = GridBagConstraints.BOTH;
    graphConstraints.gridx = 0;
    graphConstraints.gridy = 1;
    graphConstraints.weightx = 0.5;
    graphConstraints.weighty = 0.5;
    graphConstraints.gridwidth = 4;
    graphConstraints.gridheight = GridBagConstraints.RELATIVE;
    add(AppGraph.init(), graphConstraints);`

JFrame 上是用于不同搜索算法(如 BFS)的按钮。在这些算法的执行过程中,遍历的边以固定的时间间隔着色,以创建一种动画效果,如下所示:

   //BFSAlgorithm.java 
   private void callBFS(Node startNode, Node goalNode) {
            startNode.setAttribute("parent", "null");
            startNode.setAttribute("level", 0);
            startNode.setAttribute("visited?");
            LinkedList<Node> queueFrontier = new LinkedList<>();
            int level = 1;
            queueFrontier.addLast(startNode);
            while (!queueFrontier.isEmpty()) {
                System.out.println("Level: " + (level - 1));
                LinkedList<Node> next = new LinkedList<>();
                for (Node node : queueFrontier) {
                    if (node == goalNode) {
                        System.out.println(node.getId() + ": Found Found Found!!!");
                        if (node != startNode) {
                            colorEdge(node);
                        }
                        return;
                    }
                    System.out.print(node.getId() + " visited \t");
                    if (node != startNode) {
                        colorEdge(node);
                    }
                    for (Edge edge : node.getEdgeSet()) {
                        Node opposite = edge.getOpposite(node);
                        if (!opposite.hasAttribute("visited?")) {
                            System.out.print(opposite.getId() + " enqueued \t");
                            opposite.setAttribute("level", level);
                            opposite.setAttribute("parent", node);
                            opposite.setAttribute("visited?");
                            next.addLast(opposite);
                        }
                    }
                    System.out.print("\n");
                }
                level++;
                queueFrontier = next;
                sleep();
        }
    }

    private void colorEdge(Node node) {
        Edge visitedEdge = node.getEdgeBetween(node.getAttribute("parent", Node.class));
        visitedEdge.setAttribute("ui.color", 0.5);
        sleep();
    }

    private void sleep() {
        try {
            Thread.sleep(AppWindow.speed);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

BFSAlgorithm 实现了DynamicAlgorithm 并扩展了SinkAdapter。我扩展了 SinkAdapter 以使其能够在算法运行时与 View 交互。当我调用 BFSAlgorithm 时,当算法运行并且各种 println 语句被 sleep() 延迟时,GUI 卡住并且没有响应,直到在执行之后,所有访问过的边都会被着色。我尝试在我的 AppGraph.java 中实现 ViewerListener,如 graphstream documentation 中所述但它只会导致应用程序崩溃的无限循环:

/*...init() method from AppGraph.java*/
ProxyPipe fromViewer = viewer.newThreadProxyOnGraphicGraph();
        fromViewer.addSink(graph);
        fromViewer.pump();

while(loop) {
            fromViewer.pump(); //

}

最佳答案

就像@Frakool 和@MadProgrammer 在评论中建议的那样,如果有人遇到类似问题,请使用SwingWorkerSwing Timer将提供所需的结果。根据documentation :

In general, we recommend using Swing timers rather than general-purpose timers for GUI-related tasks because Swing timers all share the same, pre-existing timer thread and the GUI-related task automatically executes on the event-dispatch thread. However, you might use a general-purpose timer if you don't plan on touching the GUI from the timer, or need to perform lengthy processing.

以下是我如何使用它来阻止 gui 卡住。我创建了一个使用 Swing Timer 的私有(private)内部 SwingWorker 类,如下所示:

private class BFSTask extends SwingWorker<LinkedList<Node>, Node>{
    private ArrayList<Node> visitedList;
    private int visitedIndex = 0;
    private boolean traversalDone = false;
    private Timer traversal = new Timer(AppWindow.speed, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            Node lastVisited = visitedList.get(visitedIndex);
            Edge visitedEdge = lastVisited.getEdgeBetween(lastVisited.getAttribute("parent", Node.class));
            visitedEdge.setAttribute("ui.color", 0.5);
            visitedIndex++;
            if(visitedIndex >= visitedList.size()){
                traversal.stop();
                traversalDone = true;
                if(BFSAlgorithm.this.getPathToGoal() != null){
                    startTimer();
                }
            }
        }
    });

     @Override
    protected LinkedList<Node> doInBackground() throws Exception {
        Node found = publishNodeBreadthFirst(getStartNode(), getGoalNode());
        if (found != null) {
            return getPathToGoal(found);
        } else{
            return null;
        }
    }

    @Override
    protected void process(List<Node> list) {
        visitedList = (ArrayList<Node>) list;
        traversal.start();
    }

    @Override
    protected void done() {
        try {
            BFSAlgorithm.this.pathToGoal = get();
            if(traversalDone && BFSAlgorithm.this.getPathToGoal() != null){
                startTimer();
            }
            if(BFSAlgorithm.this.getPathToGoal() == null){
                throw new NullPointerException("Goal Not Found.");
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } catch (NullPointerException e){
            JOptionPane.showMessageDialog(getAppWindow(), "Goal Node Not Found!", "Error", JOptionPane.ERROR_MESSAGE);
            getAppWindow().disableExceptClear();
            getAppWindow().changeStatus("Goal node not found");

        }
    }

    private LinkedList<Node> getPathToGoal(Node found) {
        LinkedList<Node> path = new LinkedList<>();
        Node parent = found.getAttribute("parent");
        path.addLast(found);
        while (parent != getStartNode()){
            path.addLast(parent);
            parent = parent.getAttribute("parent");
        }
        return path;
    }
}

关于java - Thread.sleep() 卡住包含 GraphStream 图形的 JFrame/GUI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35811548/

相关文章:

java - AWT KeyListener react 慢

java.lang.ClassNotFoundException : resources? 异常

java - 将事件从自定义组件传递到父组件

java - 将 DefaultCategoryDataset 转换为 CategoryDataset

java - 带 where 子句的选择查询,其中选择基于参数值

algorithm - 对一组 3D 点进行三角测量

c++ - 一个结构中的多个点的运算符

java - SWING - JTable 单元格中的多个 JCheckBox

计算时间复杂度

java - 在 JButton 上绘制图像?