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 和 3 工作正常,但測試案例 4 不起作用。實際上,在測試案例 4 中,一旦使用者移動了視圖中的「未固定」節點,那麼對其中一個 jtextfield 中的座標的修改不會更新視圖。
我試著分析測試案例 3 和 4 的執行之間的差異。為此,我在程式碼的不同位置列印了當前線程的名稱。我看到透過 jtextfield 的修改是在線程“awt-eventqueue-0”(swing 的事件調度線程,不是嗎?)上運行的,而通過 view 的修改是在線程“thread-0”上運行的。在我的實作中,「thread-0」是我運行 graphstream 的泵送循環的線程,等待 graphstream 的檢視器線程中發生的事件並將它們複製回「thread-0」內。根據我對 graphstream 文件的理解:
我是否充分理解了文件?
在我的實作中,我選擇從 swing 線程之外的另一個線程存取 graphstream 的 graph。因此,我從之前運行的測試案例 3 和 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/c305a250710e95cf6bad18c18a1c02f4 和https://www.php.cn/link/7c097a5ed40a8d91afd490263b1062# #xy 屬性來設定節點的座標。但也鼓勵使用屬性 并且它有效!我将在项目的 github 存储库上发布问题。 以上是GraphStream 的 View 和 JTextField 之間的同步問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!xyz
。因此,我嘗試將程式碼更改為:
unfixedGraphStreamNode.setAttribute("xyz", myUnfixedNode.x, myUnfixedNode.y, 0.0);