首页 >Java >GraphStream 的 View 和 JTextField 之间的同步问题

GraphStream 的 View 和 JTextField 之间的同步问题

WBOY
WBOY转载
2024-02-22 12:30:171066浏览

php小编草莓为您介绍本文中关于GraphStream的View和JTextField同步问题的Java问答。在使用GraphStream库时,有时会遇到View和JTextField之间数据同步的挑战。通过本文,您将了解如何解决这个问题,让您的Java程序更加顺畅和高效。

问题内容

我已经在 https://github.com/graphstream/gs-ui-swing/issues/19#issue-2109865450 中发布了我的问题。但由于此存储库上的最后一个答案已于 2021 年 6 月 10 日发布,并且其他问题已发布,但没有任何回复,我不确定是否仍然有人在关注那里的问题。这就是为什么我在这里重新问我的问题。

我创建了一个由一个 view 和两个 jtextfield 组成的 jframe:

视图显示五个节点:四个只是地标,预计不会被用户移动(“fixed_*”),还有一个将被用户移动(“unfixed”)。两个 jtextfield 显示“未固定”节点的坐标。 view 和 jtextfield 都必须彼此同步。事实上,当用户移动视图中的“未固定”节点时,两个 jtextfield 必须相应更新:

相反,当用户修改 jtextfield 之一中的坐标时,视图也必须相应更新:

这里有四个测试用例:

  • 测试用例 1:用户运行应用程序并移动视图中的“未固定”节点。
  • 测试用例 2:用户运行应用程序并修改 jtextfield 之一中的坐标。
  • 测试用例 3:用户运行应用程序,修改其中一个 jtextfield 中的坐标,然后移动视图中的“未固定”节点。
  • 测试用例 4:用户运行应用程序,移动视图中的“未固定”节点,然后修改其中一个 jtextfield 中的坐标。

测试用例 1、2 和 3 工作正常,但测试用例 4 不起作用。实际上,在测试用例 4 中,一旦用户移动了视图中的“未固定”节点,那么对其中一个 jtextfield 中的坐标的修改不会更新视图。

我试图分析测试用例 3 和 4 的执行之间的差异。为此,我在代码的不同位置打印了当前线程的名称。我看到通过 jtextfield 的修改是在线程“awt-eventqueue-0”(swing 的事件调度线程,不是吗?)上运行的,而通过 view 的修改是在线程“thread-0”上运行的。在我的实现中,“thread-0”是我运行 graphstream 的泵送循环的线程,等待 graphstream 的查看器线程中发生的事件并将它们复制回“thread-0”内。根据我对 graphstream 文档的理解:

  • graphstream 的查看器始终在 swing 的事件调度线程 (edt) 中运行,
  • 与 graphstream 的查看器关联的 graphstream 的 graph 可以从 edt 或另一个线程访问,具体取决于所使用的 graphstream 的 threadingmodel,
  • 从另一个线程访问 graphstream 的图比 edt 更强大,因为它允许在图上与 graphstream 的查看器并行运行算法。

我是否充分理解了文档?

在我的实现中,我选择从 swing 线程之外的另一个线程访问 graphstream 的 graph。因此,我从之前运行的测试用例 3 和 4 中推断出:

  • 从 edt 更新 graphstream 的视图不会阻止将来从“thread-0”更新 graphstream 的视图(测试用例 3),
  • 但是“thread-0”中 graphstream 视图的更新会阻止 edt 中 graphstream 视图的任何未来更新(测试用例 4)。

我的印象是我对所有这些线程都做了错误的事情。你能帮我一下吗?

我尝试制作一个最小工作示例(mwe)来重现我的问题。以下是 java 源文件 nodesynctest.java 的内容:

package mwe;

import java.awt.borderlayout;
import java.awt.component;
import java.awt.gridlayout;
import java.awt.event.actionevent;
import java.awt.event.actionlistener;
import java.util.map;

import javax.swing.borderfactory;
import javax.swing.jframe;
import javax.swing.jlabel;
import javax.swing.jpanel;
import javax.swing.jtextfield;
import javax.swing.swingconstants;

import org.apache.commons.lang3.math.numberutils;
import org.graphstream.graph.graph;
import org.graphstream.graph.node;
import org.graphstream.graph.implementations.multigraph;
import org.graphstream.ui.graphicgraph.graphicgraph;
import org.graphstream.ui.graphicgraph.graphicnode;
import org.graphstream.ui.swing_viewer.swingviewer;
import org.graphstream.ui.view.view;
import org.graphstream.ui.view.viewer;
import org.graphstream.ui.view.viewerlistener;
import org.graphstream.ui.view.viewerpipe;

class nodesynctest {
    
    public static void main(string[] args) {
        system.out.println("nodesynctest.main : " + thread.currentthread().getname());
        javax.swing.swingutilities.invokelater(new runnable() {
            @override
            public void run() {
                system.out.println("swingutilities.invokelater.runnable.run : " + thread.currentthread().getname());
                new nodesynctest();
            }
        });
    }
    
    nodesynctest() {
                
        map<string, mynode> mynodes = map.of(
                "fixed_top_left", new mynode(-2, 2),
                "fixed_top_right", new mynode(2, 2),
                "fixed_bottom_left", new mynode(-2, -2),
                "fixed_bottom_right", new mynode(2, -2),
                "unfixed", new mynode(0, 0)
            );

        graphstreamcontrol graphstreamcontrol = new graphstreamcontrol(mynodes);
        
        jtextfieldscontrol jtextfieldscontrol = new jtextfieldscontrol(mynodes);
        
        graphstreamcontrol.jtextfieldscontrol = jtextfieldscontrol;
        jtextfieldscontrol.graphstreamcontrol = graphstreamcontrol;
        
        graphstreamcontrol.fillgraphstreamgraph();
        
        jframe maindialog = new jframe();
        
        maindialog.setdefaultcloseoperation(jframe.exit_on_close);
        maindialog.setsize(300, 300);

        maindialog.getcontentpane().add((component) graphstreamcontrol.view, borderlayout.center);
        maindialog.getcontentpane().add(jtextfieldscontrol.panel, borderlayout.south);
        
        maindialog.setlocationrelativeto(null);
        
        maindialog.setvisible(true);
        
        graphstreamcontrol.startpumploop();
    }
    
     class graphstreamcontrol {
         
         map<string, mynode> mynodes;
         
         mynode myunfixednode;
         
         graph graphstreamgraph;
         
         viewer viewer;
         
         view view;
         
         viewerpipe viewerpipe;
         
         jtextfieldscontrol jtextfieldscontrol;
        
         graphstreamcontrol(map<string, mynode> mynodes) {
             
            this.mynodes = mynodes;
            
            myunfixednode = mynodes.get("unfixed");
                        
            system.setproperty("org.graphstream.ui", "swing");
            
            graphstreamgraph = new multigraph("");
            
            viewer = new swingviewer(graphstreamgraph, viewer.threadingmodel.graph_in_another_thread);
            viewer.disableautolayout();
            view = viewer.adddefaultview(false);
            viewerpipe = viewer.newviewerpipe();
            viewerpipe.addsink(graphstreamgraph);
            
            viewerpipe.addviewerlistener(new viewerlistener() {

                @override
                public void viewclosed(string viewname) {}

                @override
                public void buttonpushed(string id) {}

                @override
                public void buttonreleased(string id) {
                    system.out.println("viewerlistener.buttonreleased : " + thread.currentthread().getname());
                    if ("unfixed".equals(id)) {
                        graphicgraph graphicgraph = viewer.getgraphicgraph();
                        graphicnode unfixedgraphstreamnode = (graphicnode) graphicgraph.getnode("unfixed");
                        myunfixednode.x = unfixedgraphstreamnode.getx();
                        myunfixednode.y = unfixedgraphstreamnode.gety();
                        jtextfieldscontrol.update();
                    }
                }

                @override
                public void mouseover(string id) {}

                @override
                public void mouseleft(string id) {}

            });

        }
         
        public void fillgraphstreamgraph() {
            for (var entry : mynodes.entryset()) {
                string nodeid = entry.getkey();
                mynode mynode = entry.getvalue();
                node graphstreamnode = graphstreamgraph.addnode(nodeid);
                graphstreamnode.setattribute("xy", mynode.x, mynode.y);
                graphstreamnode.setattribute("ui.label", nodeid);
                graphstreamnode.setattribute("ui.style", "text-alignment: under;");
            }
            
        }

        void startpumploop() {
            new thread(() -> {
                system.out.println("graphstreamcontrol.startpumploop : " + thread.currentthread().getname());
                while (true) {
                    try {
                        viewerpipe.blockingpump();
                    } catch (interruptedexception e) {
                        e.printstacktrace();
                    }
                }
            }).start();
        }

        void update() {
            graphicgraph graphicgraph = viewer.getgraphicgraph();
            graphicnode unfixedgraphstreamnode = (graphicnode) graphicgraph.getnode("unfixed");
            unfixedgraphstreamnode.setattribute("xy", myunfixednode.x, myunfixednode.y);    
        }
        
    }
     
    class jtextfieldscontrol {
        
        map<string, mynode> mynodes;
        
        mynode myunfixednode;
        
        jpanel panel;
        
        jtextfield xtextfield;
        
        jtextfield ytextfield;
        
        graphstreamcontrol graphstreamcontrol;
        
        jtextfieldscontrol(map<string, mynode> mynodes) {
            
            this.mynodes = mynodes;
            
            myunfixednode = mynodes.get("unfixed");
                                    
            panel = new jpanel(new gridlayout(1, 4));
            
            jlabel xlabel = new jlabel("x:", swingconstants.right);
            xlabel.setborder(borderfactory.createemptyborder(5, 5, 5, 5));
            panel.add(xlabel);
            xtextfield = new jtextfield(3);
            xtextfield.sethorizontalalignment(swingconstants.right);
            xtextfield.settext(double.tostring(myunfixednode.x));
            xtextfield.getcaret().setdot(0);
            xtextfield.addactionlistener(new actionlistener() {
                public void actionperformed(actionevent event) {
                    system.out.println("jtextfieldscontrol - actionperformed on xtextfield : " + thread.currentthread().getname());
                    string xnodestring = xtextfield.gettext();
                    double xnodedouble = numberutils.todouble(xnodestring);
                    myunfixednode.x = xnodedouble;
                    graphstreamcontrol.update();
                    
                }
            });
            panel.add(xtextfield);
            
            jlabel ylabel = new jlabel("y:", swingconstants.right);
            ylabel.setborder(borderfactory.createemptyborder(5, 5, 5, 5));
            panel.add(ylabel);
            ytextfield = new jtextfield(3);
            ytextfield.sethorizontalalignment(swingconstants.right);
            ytextfield.settext(double.tostring(myunfixednode.y));
            ytextfield.getcaret().setdot(0);
            ytextfield.addactionlistener(new actionlistener() {
                public void actionperformed(actionevent event) {
                    system.out.println("jtextfieldscontrol - actionperformed on ytextfield : " + thread.currentthread().getname());
                    string ynodestring = ytextfield.gettext();
                    double ynodedouble = numberutils.todouble(ynodestring);
                    myunfixednode.y = ynodedouble;
                    graphstreamcontrol.update();
                }
            });
            panel.add(ytextfield);
        }
        
        void update() {
            string xnodestring = double.tostring(myunfixednode.x);
            xtextfield.settext(xnodestring);
            xtextfield.getcaret().setdot(0);
            string ynodestring = double.tostring(myunfixednode.y);
            ytextfield.settext(ynodestring);
            ytextfield.getcaret().setdot(0);
        }
    }
    
    class mynode {
        double x;
        double y;
        mynode(double x, double y) {
            this.x = x;
            this.y = y;
        }
    }
    
}

这是 maven pom 文件 pom.xml,用于构建包含所有依赖项的可执行 jar:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>mwe</groupId>
    <artifactId>mwe</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>MWE</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.14.0</version>
        </dependency>
        <dependency>
            <groupId>org.graphstream</groupId>
            <artifactId>gs-core</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>org.graphstream</groupId>
            <artifactId>gs-ui-swing</artifactId>
            <version>2.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <!-- Build an executable JAR -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <!-- here we specify that we want to use the main
                            method within the App class -->
                            <mainClass>mwe.NodeSyncTest</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>mwe.NodeSyncTest</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

要使用这两个文件,只需创建一个文件夹 mwe/,将 nodesynctest.java 放入 mwe/src/main/java/mwe/ 并将 pom.xml 放入 mwe/,然后在 mwe/ 中运行

mvn 编译程序集:single

java -jar 目标/mwe-0.0.1-snapshot-jar-with-dependency.jar

这是完整的项目文件夹:mwe.zip

解决方法

经过一番调试,终于找到了问题出在哪里。我只需要更换线路:

unfixedgraphstreamnode.setattribute("xy", myunfixednode.x, myunfixednode.y);

通过两行:

unfixedgraphstreamnode.setattribute("x", myunfixednode.x);
unfixedgraphstreamnode.setattribute("y", myunfixednode.y);

让一切正常工作。

为什么

unfixedgraphstreamnode.setattribute("xy", myunfixednode.x, myunfixednode.y);

不起作用对我来说仍然是个谜。事实上,https://www.php.cn/link/c305a250710e95cf6bad18c18a1c02f4https://www.php.cn/link/7c097a5ed40a8d91afd49026dd3b1062 的文档说我们可以使用 xy 属性来设置节点的坐标。但也鼓励使用属性 xyz。因此,我尝试将代码更改为:

unfixedGraphStreamNode.setAttribute("xyz", myUnfixedNode.x, myUnfixedNode.y, 0.0);

并且它有效!我将在项目的 github 存储库上发布问题。

以上是GraphStream 的 View 和 JTextField 之间的同步问题的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文转载于:stackoverflow.com。如有侵权,请联系admin@php.cn删除