首頁 >Java >GraphStream 的 View 和 JTextField 之間的同步問題

GraphStream 的 View 和 JTextField 之間的同步問題

WBOY
WBOY轉載
2024-02-22 12:30:171064瀏覽

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/7c097a5ed40a8d91afd490263b1062# #xy 屬性來設定節點的座標。但也鼓勵使用屬性 xyz。因此,我嘗試將程式碼更改為: <pre class="brush:php;toolbar:false;">unfixedGraphStreamNode.setAttribute(&quot;xyz&quot;, myUnfixedNode.x, myUnfixedNode.y, 0.0);</pre> <p>并且它有效!我将在项目的 github 存储库上发布问题。</p>

以上是GraphStream 的 View 和 JTextField 之間的同步問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除