当前位置: 首页 > 知识库问答 >
问题:

线sleep()冻结包含GraphStream图形的JFrame/GUI

任飞龙
2023-03-14

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

我在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();
        }
    }

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

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

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

}

共有1个答案

刘意
2023-03-14

就像@Frakool和@MadProgrammer在评论中建议的那样,如果任何人有类似的问题,使用< code>SwingWorker和Swing Timer将会提供想要的结果。根据文件:

一般来说,我们建议对GUI相关任务使用Swing计时器而不是通用计时器,因为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;
    }
}
 类似资料:
  • 问题内容: 我开发汽车管理系统程序。然后,我想在汽车进出时将邮件发送给该公司的所有者。我的代码可以成功发送邮件,但是我注意到在发送邮件时,其他JFrame窗口被冻结(我无法在所有JFrame窗口上执行任何操作),直到完成邮件发送为止。这通常用于Javamail还是有办法使其他JFrame仍然正常工作? 在我的程序中,大约需要10秒钟才能完成发送一封邮件。 问题答案: 当您执行繁重的任务时,应在另一

  • 如果注释掉,框架显示得很好。 我还应该做什么来显示文件选择器?

  • 在我的java项目中,我将图形与这个库“图形流”一起使用。 我需要将我的图形保存在一个类型文件“Graphviz Dot”中,即:节点、边、节点属性、边属性。我通常用这种方式把我的图形保存在文件中: 问题:当我打开或加载文件时,我看不到边缘属性。有人知道“图形流”并且知道我可以保存这个文件吗? 感谢您的帮助。

  • 问题内容: 嘿,我只需要回答一个问题…我将如何使以下代码不冻结整个JFrame? 问题答案: 使用其他线程来执行此任务。如果在主UI线程中执行此操作,则它将冻结。例如,您可以执行以下操作 更新 在对Robin和Marko提出明智建议之后,我正在用更好的解决方案来更新答案。

  • 我试图改变graphstream中图形的大小,但它失败了,甚至变得很小。 这是我的代码。起初,我无法设置窗口标题,所以我唯一的选择是创建一个JFRAMe并将视图嵌入其中。因此,如果有一个选项可以设置图表的标题,我将不胜感激。 这是我的代码。 编辑 即使应用了提议的改变,它也不起作用。 public Clicks()抛出中断异常{System.setProperty(“org.graphstream

  • 使用Java图形,我试图画一个简单的矩形。 作为它运行良好,但当我使用它在上显示时,矩形来了,但有一些不寻常的背景 这是编码: 然后我尝试使用使用这两个类,但在这种情况下,矩形根本不显示。 和DisplayItems。java: 任何人都可以帮助我在任何摆动容器上显示图形组件,例如JPanelJTextArea'等。