1

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

我在 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它以使它能够在算法运行时与视图交互。当我调用 时BFSAlgorithm,当算法运行并且各种println语句被延迟时sleep(),GUI 冻结并且没有响应,直到执行之后所有访问的边缘都被着色。我尝试按照graphstream文档ViewerListener中记录的方式实现,但它只会导致导致应用程序崩溃的无限循环:AppGraph.java

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

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

}
4

1 回答 1

1

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

一般来说,我们建议使用 Swing 计时器而不是通用计时器来处理与 GUI 相关的任务,因为 Swing 计时器都共享相同的、预先存在的计时器线程,并且与 GUI 相关的任务会自动在事件调度线程上执行。但是,如果您不打算从计时器触摸 GUI,或者需要执行冗长的处理,则可以使用通用计时器。

这是我用它来阻止gui冻结的方法。我创建了一个私有内部SwingWorker类,它使用Swing Timer如下:

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;
    }
}
于 2016-03-08T16:15:20.000 回答