PHP Editor Strawberry stellt Ihnen in diesem Artikel die Java-Fragen und Antworten zu Synchronisierungsproblemen zwischen GraphStream's View und JTextField vor. Bei der Verwendung der GraphStream-Bibliothek treten manchmal Probleme bei der Datensynchronisierung zwischen View und JTextField auf. In diesem Artikel erfahren Sie, wie Sie dieses Problem lösen und Ihre Java-Programme reibungsloser und effizienter gestalten können.
Ich habe meine Ausgabe unter https://github.com/graphstream/gs-ui-swing/issues/19#issue-2109865450 gepostet. Aber da die letzte Antwort in diesem Repository am 10. Juni 2021 veröffentlicht wurde und andere Fragen ohne Antworten gepostet wurden, bin ich mir nicht sicher, ob den Fragen dort noch jemand Aufmerksamkeit schenkt. Deshalb stelle ich meine Frage hier noch einmal.
Ich habe einen JFrame erstellt, der aus einer Ansicht und zwei JTextfeldern besteht:
Die Ansicht zeigt fünf Knoten: Vier sind nur Orientierungspunkte und werden voraussichtlich nicht vom Benutzer verschoben („fixed_*“), und einer wird vom Benutzer verschoben („unfixed“). Zwei Jtextfelder zeigen die Koordinaten von „nicht fixierten“ Knoten an. Sowohl view als auch jtextfield müssen miteinander synchron sein. Tatsächlich müssen beide Jtextfelder entsprechend aktualisiert werden, wenn der Benutzer den „nicht angehefteten“ Knoten in der Ansicht verschiebt:
Umgekehrt muss die Ansicht auch entsprechend aktualisiert werden, wenn der Benutzer die Koordinaten in einem der Jtextfelder ändert:
Hier sind vier Testfälle:
Testfälle 1, 2 und 3 funktionieren einwandfrei, aber Testfall 4 funktioniert nicht. Tatsächlich wird in Testfall 4, sobald der Benutzer den „nicht angehefteten“ Knoten in der Ansicht verschiebt, Änderungen an den Koordinaten in einem der Jtextfelder die Ansicht nicht aktualisieren.
Ich versuche den Unterschied zwischen der Ausführung der Testfälle 3 und 4 zu analysieren. Dazu habe ich an verschiedenen Stellen im Code den Namen des aktuellen Threads gedruckt. Ich sehe, dass Änderungen über jtextfield auf dem Thread „awt-eventqueue-0“ (dem Event-Dispatching-Thread von Swing, nicht wahr?) ausgeführt werden, während Änderungen über view auf dem Thread „thread-0“ ausgeführt werden. In meiner Implementierung ist „thread-0“ der Thread, auf dem ich die Pump-Schleife von Graphstream ausführe, auf Ereignisse warte, die im Viewer-Thread von graphstream auftreten, und sie zurück in „thread-0“ kopiere. Aus meinem Verständnis der Graphstream-Dokumentation:
Habe ich die Dokumentation vollständig verstanden?
In meiner Implementierung habe ich mich dafür entschieden, von einem anderen Thread außerhalb des Swing-Threads auf den Graphen von Graphstream zuzugreifen. Ich schließe also aus den zuvor durchgeführten Testfällen 3 und 4:
Ich habe den Eindruck, dass ich mit all diesen Threads das Falsche mache. Kannst du mir helfen?
Ich versuche, ein minimales Arbeitsbeispiel (mwe) zu erstellen, um mein Problem zu reproduzieren. Das Folgende ist der Inhalt der Java-Quelldatei 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; } } }
Dies ist die Maven-POM-Datei pom.xml, die zum Erstellen der ausführbaren JAR-Datei mit allen Abhängigkeiten verwendet wird:
<?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>
Um diese beiden Dateien zu verwenden, erstellen Sie einfach einen Ordner mwe/, fügen Sie nodesynctest.java in mwe/src/main/java/mwe/ und pom.xml in mwe/ ein und führen Sie es dann in mwe/ aus
mvn 编译程序集:single
und
java -jar 目标/mwe-0.0.1-snapshot-jar-with-dependency.jar
Das ist der komplette Projektordner: mwe.zip
Nach einigem Debuggen habe ich endlich das Problem gefunden. Ich muss nur die Zeile ändern :
unfixedgraphstreamnode.setattribute("xy", myunfixednode.x, myunfixednode.y);
Durch zwei Zeilen:
unfixedgraphstreamnode.setattribute("x", myunfixednode.x); unfixedgraphstreamnode.setattribute("y", myunfixednode.y);
Stellen Sie sicher, dass alles ordnungsgemäß funktioniert.
Warum
unfixedgraphstreamnode.setattribute("xy", myunfixednode.x, myunfixednode.y);
Es ist mir immer noch ein Rätsel, dass es nicht funktioniert. Tatsächlich heißt es in der Dokumentation für https://www.php.cn/link/c305a250710e95cf6bad18c18a1c02f4 und https://www.php.cn/link/7c097a5ed40a8d91afd49026dd3b1062, dass wir xy
属性来设置节点的坐标。但也鼓励使用属性 xyz
verwenden können. Also habe ich versucht, den Code zu ändern:
unfixedGraphStreamNode.setAttribute("xyz", myUnfixedNode.x, myUnfixedNode.y, 0.0);
并且它有效!我将在项目的 github 存储库上发布问题。
Das obige ist der detaillierte Inhalt vonSynchronisierungsprobleme zwischen GraphStreams View und JTextField. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!