0

0

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

WBOY

WBOY

发布时间:2024-02-22 12:30:17

|

1190人浏览过

|

来源于stackoverflow

转载

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:

Nextcloud Server
Nextcloud Server

Nextcloud服务器是一款免费且开源的服务器软件,它允许您将所有数据存储在您选择的服务器上。通过Nextcloud,您可以轻松访问和存储位于您信任的数据中心的数据,将数据在各种设备之间同步,并共享您的数据以进行协作。它提供了自托管文件同步和共享领域中最佳的安全性,并且可以通过数百个应用进行扩展。

下载
<?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 存储库上发布问题。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Java Maven专题
Java Maven专题

本专题聚焦 Java 主流构建工具 Maven 的学习与应用,系统讲解项目结构、依赖管理、插件使用、生命周期与多模块项目配置。通过企业管理系统、Web 应用与微服务项目实战,帮助学员全面掌握 Maven 在 Java 项目构建与团队协作中的核心技能。

0

2025.09.15

pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1945

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2119

2024.08.01

xml是什么格式的文件
xml是什么格式的文件

xml是一种纯文本格式的文件。xml指的是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。想了解更多相关的内容,可阅读本专题下面的相关文章。

1167

2024.11.28

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

764

2023.08.10

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

99

2025.12.01

github中文官网入口 github中文版官网网页进入
github中文官网入口 github中文版官网网页进入

github中文官网入口https://docs.github.com/zh/get-started,GitHub 是一种基于云的平台,可在其中存储、共享并与他人一起编写代码。 通过将代码存储在GitHub 上的“存储库”中,你可以: “展示或共享”你的工作。 持续“跟踪和管理”对代码的更改。

4037

2026.01.21

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

494

2023.08.14

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

4

2026.03.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号