Thread.sleep()冻结包含GraphStream图的JFrame/GUI [英] Thread.sleep() freezes JFrame/GUI containing GraphStream graph

查看:115
本文介绍了Thread.sleep()冻结包含GraphStream图的JFrame/GUI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的JFrame包含嵌入式单个图形( Graphstream )时,当我尝试在其中更新时会冻结调用Thread,sleep()的循环.我已经尝试过在独立图上使用相同的更新(显示为自己),并且按预期运行.

My JFrame containing an embedded single graph (Graphstream) freezes when I try to update it in a loop that calls Thread,sleep(). I have tried using the same update on a standalone-graph (displayed on it's own) and it works as expected.

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

I have a single graph embedded in JFrame as follows (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类中调用此函数,如下所示:

Then this is called in the JFrame class as below:

   /*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)的按钮.在执行这些算法的过程中,以固定的时间间隔对遍历的边缘进行着色,以创建一种动画效果,如下所示:

On the JFrame are buttons for different search algorithms like BFS. During the execution of these algorithms, edges traversed are colored at fixed time intervals to create a sort of animation effect as shown below:

   //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冻结并且无响应,直到执行之后所有被访问的边缘都被着色为止.我尝试按照 graphstream文档所述在AppGraph.java中实现ViewerListener ,但只会导致无限循环,使应用程序崩溃:

This BFSAlgorithm implements DynamicAlgorithm and extends SinkAdapter. I have extended the SinkAdapter to enable it to interact with the View as the algorithm runs. When I call the BFSAlgorithm, while the algorithm runs and the various println statements are delayed by sleep(), the GUI freezes and is unresponsive until after execution before all the visited edges are then colored. I tried implementing ViewerListener in my AppGraph.java as is documented on the graphstream documentation but it only resulted in an infinite loop that crashed the application:

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

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

}

推荐答案

如果有人遇到类似问题,请使用SwingWorker文档:

Like @Frakool and @MadProgrammer suggested in the comments, if anyone is having similar issues, using SwingWorker and Swing Timer will provide the desired results. According to the documentation:

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

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冻结的方式.我创建了一个私有内部SwingWorker类,该类使用Swing Timer如下:

Here's how I used it to stop the gui freezing. I created a private inner SwingWorker class that uses a Swing Timer as below:

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

这篇关于Thread.sleep()冻结包含GraphStream图的JFrame/GUI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆