Maison >Java >Problèmes de synchronisation entre la vue de GraphStream et JTextField

Problèmes de synchronisation entre la vue de GraphStream et JTextField

WBOY
WBOYavant
2024-02-22 12:30:171065parcourir

PHP Editor Strawberry vous présente les questions et réponses Java sur les problèmes de synchronisation entre View de GraphStream et JTextField dans cet article. Lorsque vous utilisez la bibliothèque GraphStream, vous rencontrez parfois des problèmes de synchronisation des données entre View et JTextField. A travers cet article, vous apprendrez comment résoudre ce problème et rendre vos programmes Java plus fluides et plus efficaces.

Contenu du problème

J'ai publié mon problème sur https://github.com/graphstream/gs-ui-swing/issues/19#issue-2109865450. Mais comme la dernière réponse sur ce référentiel a été publiée le 10 juin 2021 et que d'autres questions ont été publiées sans aucune réponse, je ne sais pas si quelqu'un y prête encore attention. C'est pourquoi je repose ma question ici.

J'ai créé un jframe composé d'une vue et de deux jtextfields :

La vue montre cinq nœuds : quatre ne sont que des points de repère et ne devraient pas être déplacés par l'utilisateur ("fixed_*"), et un sera déplacé par l'utilisateur ("non fixé"). Deux jtextfields affichent les coordonnées des nœuds "non épinglés". View et jtextfield doivent être synchronisés l'un avec l'autre. En fait, lorsque l'utilisateur déplace le nœud "non épinglé" dans la vue, les deux jtextfields doivent être mis à jour en conséquence :

À l'inverse, lorsque l'utilisateur modifie les coordonnées dans l'un des champs jtext, la vue doit également se mettre à jour en conséquence :

Voici quatre cas de test :

  • Cas de test 1 : l'utilisateur exécute l'application et déplace un nœud « non épinglé » dans la vue.
  • Test Case 2 : L'utilisateur exécute l'application et modifie les coordonnées dans l'un des champs jtext.
  • Cas de test 3 : l'utilisateur exécute l'application, modifie les coordonnées dans l'un des champs jtext, puis déplace le nœud "non épinglé" dans la vue.
  • Cas de test 4 : l'utilisateur exécute l'application, déplace un nœud "non épinglé" dans la vue, puis modifie les coordonnées dans l'un des champs jtext.

Les cas de test 1, 2 et 3 fonctionnent correctement mais le cas de test 4 ne fonctionne pas. En fait, dans le scénario de test 4, une fois que l'utilisateur déplace le nœud « non épinglé » dans la vue, les modifications des coordonnées dans l'un des jtextfields ne mettent pas à jour la vue.

J'essaie d'analyser la différence entre l'exécution des cas de test 3 et 4. Pour ce faire, j'ai imprimé le nom du thread actuel à différents endroits du code. Je vois que les modifications via jtextfield sont exécutées sur le thread "awt-eventqueue-0" (le thread de répartition des événements de swing, non ?), tandis que les modifications via view sont exécutées sur le thread "thread-0". Dans mon implémentation, "thread-0" est le thread sur lequel j'exécute la boucle de pompe de graphstream, en attendant les événements qui se produisent dans le thread du visualiseur de graphstream et en les copiant dans "thread-0". D'après ma compréhension de la documentation graphstream :

    La visionneuse de
  • graphstream s'exécute toujours dans le fil de répartition d'événements de swing (edt),
  • Le graphique du graphstream associé au visualiseur du graphstream est accessible depuis l'edt ou un autre thread, selon le modèle de thread du graphstream utilisé,
  • Accéder au graphique de graphstream à partir d'un autre thread est plus puissant que edt car il permet d'exécuter des algorithmes sur le graphique en parallèle avec la visionneuse de graphstream.

Ai-je bien compris la documentation ?

Dans mon implémentation, j'ai choisi d'accéder au graphique de graphstream depuis un autre thread en dehors du thread swing. Je déduis donc des cas de tests 3 et 4 précédemment exécutés :

  • La mise à jour de la vue de graphstream depuis edt n'empêche pas les futures mises à jour de la vue de graphstream depuis "thread-0" (cas de test 3),
  • Mais les mises à jour de la vue graphstream dans "thread-0" empêchent toute mise à jour future de la vue graphstream dans edt (cas de test 4).

J'ai l'impression que je fais la mauvaise chose avec tous ces sujets. Pouvez-vous m'aider?

J'essaie de faire un exemple de travail minimal (mwe) pour reproduire mon problème. Voici le contenu du fichier source 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;
        }
    }
    
}

Voici le fichier pom maven pom.xml utilisé pour construire le pot exécutable avec toutes les dépendances :

<?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>

Pour utiliser ces deux fichiers, créez simplement un dossier mwe/, mettez nodesynctest.java dans mwe/src/main/java/mwe/ et pom.xml dans mwe/, puis exécutez dans mwe/

mvn 编译程序集:single

et

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

Voici le dossier complet du projet : mwe.zip

Solution

Après quelques débogages, j'ai finalement trouvé le problème. J'ai juste besoin de changer la ligne :

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

Par deux lignes :

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

Faire fonctionner correctement.

Pourquoi

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

Ne pas travailler reste un mystère pour moi. En fait, la documentation de https://www.php.cn/link/c305a250710e95cf6bad18c18a1c02f4 et https://www.php.cn/link/7c097a5ed40a8d91afd49026dd3b1062 indique que nous pouvons utiliser xy 属性来设置节点的坐标。但也鼓励使用属性 xyz. J'ai donc essayé de changer le code en :

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

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer