ActionListener führt falsche Funktion aus

Elmishelmi

Mitglied
Hi,

ich bin neu in der Java Programmierung und habe ein Problem. In der Sufu habe ich leider nichts passendes gefunden.

Ich möchte durch einen Button eine Funktion ausführen in einer anderen Klasse.

Die Funktion copy(). Diese wird auch aufgerufen, doch es wird nicht richtige valueChanged Listener ausgeführt. Der wird in der Methode path() ausgeführt. Ich habe nun ein Problem, wie ich kann ich einen Entscheidungsfall treffen, indem der Anweisungsblock des valueChanged Listeners in der copy() Funktion ausgeführt wird?

Hier ein Code Ausschnitt.

Java:
public class XMLEditor {

    private JFrame frame;
    private JMenuBar menuBar = new JMenuBar();
    private JMenu mnMen = new JMenu("Men\u00FC");
    private JMenuItem mntmLaden = new JMenuItem("Laden");

   
   
    private DefaultMutableTreeNode root = new DefaultMutableTreeNode();
    private DefaultTreeModel treeModel = new DefaultTreeModel(root);
    private JTree tree1 = new JTree(treeModel);
    @SuppressWarnings("unused")
    private TreeCellEditor editor;
    private JPanel panel1;
    private CardLayout cl;
    private cardEmpty cEmpty;
   
    private card4 c4;
   
   
    // Starten der Applikation
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    XMLEditor window = new XMLEditor();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    // Erstellen der Applikation
    public XMLEditor() {
        initialize();
    }

    // Initialisieren des Frameinhalts
    private void initialize() {

        // Frame erstellen
        frame = new JFrame();
        frame.setSize(706, 645);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel();
        frame.getContentPane().add(panel, BorderLayout.CENTER);

        // Frame in zwei Hälften teilen, mittels linkem und rechtem Pane
        JSplitPane splitPane = new JSplitPane();
        GroupLayout gl_panel = new GroupLayout(panel);
        gl_panel.setHorizontalGroup(gl_panel.createParallelGroup(Alignment.TRAILING).addComponent(splitPane,
                Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 606, Short.MAX_VALUE));
        gl_panel.setVerticalGroup(gl_panel.createParallelGroup(Alignment.LEADING).addComponent(splitPane,
                GroupLayout.DEFAULT_SIZE, 389, Short.MAX_VALUE));
        JScrollPane scrollPane = new JScrollPane();
        splitPane.setLeftComponent(scrollPane);
       
        JScrollPane scrollPane_1 = new JScrollPane();
        splitPane.setRightComponent(scrollPane_1);
       
        panel.setLayout(gl_panel);
       
        splitPane.setDividerLocation(0.35);
        splitPane.setResizeWeight(0.35);
        // Menübar erstellen mit Unterverzeichnissen und Buttons
        frame.setJMenuBar(menuBar);

        menuBar.add(mnMen);
       
        mnMen.add(mntmLaden);
   
        // ActionListener wird als anonyme Klasse eingebunden
        mntmLaden.addActionListener(new ActionListener() {

            // Beim Drücken des Menüpunktes wird actionPerformed aufgerufen
            public void actionPerformed(ActionEvent e) {

                try {

                    // Dateiauswahldialog wird erzeugt und vorgegebener Pfad
                    // gesetzt.
                    JFileChooser fc = new JFileChooser();
                    fc.setCurrentDirectory(new File("C:/Users/langec/workspace"));
                    fc.showOpenDialog(frame);

                    // Holen des Pfads der dem Filechooser übergeben wurde.
                    // Danach übergabe an die Funktion "load", um den Baum zu
                    // erstellen.
                    File path;
                    path = fc.getSelectedFile();
                    load(path);
                   
                   
                    // Des Weiteren wird der Baum an die Scrollbar gehängt.
                    scrollPane.setViewportView(tree1);
                    scrollPane_1.setViewportView(panel1);
                   
                } catch (Exception e1) {

                    e1.printStackTrace();
                    System.out.println("Fehler");

                }
            }
        });
    }
    public void load(File path) {

        // Funktion zum erstellen des Baums.
        // Der Baum wird mit jeder Datei die geladen wird neu erstellt.
        // Die Datei wird als Paremeter aus vom Objekt mntmLaden übergeben.
       
        //Der TreeListener ermöglicht durch anklicken des Baums die richtigen Karten zu öffnen.
        MyTreeModel model = new MyTreeModel();
        model.synchronizeXmlWithModel(path, root);
       
        //TreeModel übergeben, um die Möglichkeit der Editierung des Baums zu realisieren.
        //Die Veränderungen des Baums werden mit dem Befehl updateUI() ausgegeben.
        tree1.setEditable(true);
        tree1.updateUI();
       
        //Der Renderer ermöglicht das Bearbeiten der Knoten und Blätter im Baum hinsichtlich des Designs
        DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) tree1.getCellRenderer();
        @SuppressWarnings("unused")
        TreeCellEditor editor = new LeafCellEditor(tree1, renderer);
        tree1.setCellEditor(null);
       
        //Erstellt die Karten(JPanel) der einzelnen Seiten die mit Formularen befüllt werden.
        //Nach Erstellung der Karten werden sie dem KartenLayout hinzugefügt.
        cl = new CardLayout();
        panel1 = new JPanel(cl);
        cEmpty = new cardEmpty();
        c4 = new card4();
       
        panel1.setLayout(cl);
       
        panel1.add(cEmpty, "0");
        panel1.add(c4, "4");
        panel1.updateUI();
       
        path();

    }
   
    public void copy() {
    System.out.println("a1");   
        tree1.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
           
            public void valueChanged(TreeSelectionEvent tse) {
            // Selektiert den aktuellen Knoten oder das aktuelle Blatt
                DefaultMutableTreeNode selNode = (DefaultMutableTreeNode) tree1.getLastSelectedPathComponent();
                System.out.println("a2");
                if (selNode.isLeaf() == true && (selNode.toString() == "ECU-Version")) {

                    // Erstellt eine Kopie des selektierten Knoten oder Blatts
                    // auf der gleichen hierarchischen Ebene wie das Original
                    Object befSelNode;
                    befSelNode = selNode.getUserObject();
                    DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) selNode.getParent();
                    treeModel.insertNodeInto(new DefaultMutableTreeNode(befSelNode), parentNode, 0);
                    tree1.setCellEditor(null);
                   
                } else if (selNode.isLeaf() == false) {

                    // Ruft einen Fehlerdialog auf, falls ein falscher Knoten
                    // kopiert wurde
                    JDialog meinJDialog = new JDialog();
                    meinJDialog.setTitle("Fehler");
                    meinJDialog.setSize(320, 60);
                    meinJDialog.setLocationRelativeTo(frame);
                    meinJDialog.setModal(true);
                    meinJDialog.add(new JLabel("Ordner können nicht kopiert werden, nur Textdateien."));
                    meinJDialog.setVisible(true);
                    }   
           
            }
        });
    }
   
    public void path() {
       
    tree1.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
       
        public void valueChanged(TreeSelectionEvent e) {
        // Selektiert den aktuellen Knoten oder das aktuelle Blatt
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree1.getLastSelectedPathComponent();
            System.out.println("a");
            if (node == null) {

                cl.show(cEmpty, "0");

            } else if (node.isLeaf() == false && node.toString() == "ECU-Version") {
               
                cl.show(panel1, "4");
               
            }    
       
        }
    });
    }
   
}

Java:
public class card4 extends JPanel implements ActionListener{
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    JPanel p;
    JLabel lblAddECU, lblECU;
    JTextField txtECU;
    public JButton btnAddECU;
   
    @SuppressWarnings("deprecation")
    public
    card4() {
       
        p = new JPanel(new SpringLayout());
        lblECU = new JLabel("ECU-Version");
        txtECU = new JTextField();
        lblAddECU = new JLabel("ECU kopieren: ");
        btnAddECU = new JButton("Ok");
       
        btnAddECU.addActionListener(this);
        p.add(lblECU);
        p.add(txtECU);
        p.add(lblAddECU);
        p.add(btnAddECU);
           
        txtECU.hide();

        // Lay out the panel.
        SpringUtilities.makeCompactGrid(p, 2, 2, // rows, cols
                6, 6, // initX, initY
                6, 6); // xPad, yPad

        // Set up the content pane.
        p.setOpaque(true); // content panes must be opaque
        p.setBounds(-100, 10, 10, 10);
        add(p);       
       
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        XMLEditor e = new XMLEditor();
        e.copy();
       
    }
}

MFG
 
Du hast hier (meiner Meinung) nach einen Denkfehler:
Deine Methoden "copy" und "path" machen nichts anderes als dem JTree Object einen SelectionListener hinzuzufügen.

Du drückst deinen Button, es wird ein XMLEditor Objekt erstellst, danach rufst du von diesem Objekt die Methode "copy" auf, das JTree Objekt bekommt einen SelectionListener hinzugefügt.
Sobald du über das Menü etwas ladest, rufst du auch die Methode "path" auf und hängst dem JTree Objekt einen weiteren Listener an.

Sobald du nun im JTree deine Auswahl änderst wird dann eben der aktuelle Listener angesprochen. Ich weiß nicht ob es möglich ist, dass das JTree Object 2 unterschiedliche Listener hat, oder der neue den alten überschreibt.
 
Hi, danke für die Antwort.

Ja das habe ich mir auch genauso gedacht. Ich habe leider keine Lösung für das Problem gefunden. Wie müsste ich denn vorgehen, um das Problem zu lösen? Gibt es überhaupt eine Lösung ohne ein Objekt der Klasse XMLEditor zu erstellen, so wie ich das bisher implementiert habe? Oder sollte die Logik von der View komplett getrennt werden?

Ist mein erstes Projekt und verlaufe mich noch an einigen Stellen.
 
Naja wenn du die Auswahl im JTree änderst soll ja etwas passieren.

Laut "path()" Methode soll das Panel gewechselt werden, laut "copy()" Methode soll etwas kopiert werden.
Versuche doch einfach die beiden SelectionListener zu einem zusammenzufassen -> if/else
 
Vielleicht beschreibst du erstmal etwas ausführlicher, was dein Code genau machen soll? In der aktuellen Form ist für mich so manches unklar:

- XMLEditor hat einen JFrame, der im Konstruktor von XMLEditor ein paar Komponenten verpasst bekommt, u.a. eine JSplitPane mit je einer JScrollPane links und rechts. So weit, so gut.
- Es gibt ein Menü, über das eine Datei geladen werden kann. Der Inhalt der Datei wird in der load-Methode in eine neue Instanz von MyTreeModel geladen. Diese neue Instanz wird dem existierenden JTree tree1 aber offenbar nicht als model gesetzt. Siehst du tatsächlich neue Daten, wenn du eine neue Datei lädst?
- Es wird eine neue Instanz von LeafCellEditor erstellt, die den aktuellen TreeCellRenderer von tree1 und tree1 im Konstruktor übergeben bekommt. Was LeafCellEditor mit den übergebenen Referenzen macht, ist unklar. Der LeafCellEditor (ein TreeCellEditor) wird dann aber nicht explizit als TreeCellEditor des tree1 gesetzt, ganz im Gegenteil, der TreeCellEditor von tree1 wird danach auf jeden Fall explizit auf null gesetzt. Ich halte das für ziemlich verwirrend.
- In der load-Methode bekommt ausserdem das panel im rechten Teil der JSplitPane ein neues Layout und ein paar Komponenten verpasst. Unter anderen wird dabei eine neue Instanz der Klasse card4 erstellt. card4 enthält dabei ein JPanel und ist dabei auch selber eins als auch ein ActionListener. In seiner actionPerformed Methode erzeugt card4 dann eine neue Instanz von XMLEditor und ruft darauf die copy-Methode auf. Es sollte genügen, das panel einfach mit den neuen Daten aus dem neuen Model zu aktualisieren, anstatt es komplett neu aufzubauen.
-Ganz am Ende der load-Methode wird die path-Methode aufgerufen. Die macht aber nix anderes als dem JTree einen neuen TreeSelectionListener zu verpassen. In einem anderen Kontext wird die Methode path offenbar nicht aufgerufen.

Ich würde dir raten, das ganze nochmal von Grund auf neu zu schreiben. Hier eine ungefähre Struktur:

-Die grobe Struktur von XMLEditor kann erhalten bleiben: JSplitPane mit 2 JScrollPanes. Die linke JScrollPane enthält den JTree, die rechte JScrollPane ein JPanel mit einem CardLayout
Der JTree tree1 bekommt als TreeModel eine Instanz MyTreeModel.
-In der load-Methode aktualisierst nur das MyTreeModel und setzt es erneut als Model von tree1. Der JTree tree1 sollte sich dann neu zeichnen. tree1 selber sollte zu diesem Zeitpunkt bereits fertig konfiguriert sein, d. h. TreeCellRenderer, TreeCellEditor und ein TreeSelectionListener der bei Auswahl eines Knotens im o.g. JPanel mit CardLayout ein JPanel einblendet welches zum Knotentyp passt, sollten bereits gesetzt sein.
-Ich halte es nicht für sinnvoll, die copy Funktion an einen TreeSelectionListener zu hängen. Dann würde die copy-Funktion nämlich bei jedem Klick ausgeführt werden, und zwar auf dem gerade ausgewählten Knoten. Ich kann mir nicht vorstellen, dass das so beabsichtigt ist. Ich würde eher einen MouseListener auf dem JTree registrieren. Dann kannst du z.B. zwischen Einfach- und Doppelklick unterscheiden und auf gedrückte Zusatztasten wie Alt, Ctrl und Shift abfragen. An den Knoten auf den geklickt wurde, kommst du ran wie hier beschrieben: http://docs.oracle.com/javase/7/docs/api/index.html?javax/swing/JTable.html

Zu guter Letzt zwei Hinweise zu dieser Zeile

Java:
selNode.isLeaf() == true && (selNode.toString() == "ECU-Version")

selNode.isLeaf() == true schreibt man einfach als selNode.isLeaf(), und String werden mit equals verglichen.
 
Hi, erstmal danke für die Antworten!

1. Zu Joose:
Das habe ich versucht, leider klappt das jedoch nicht.

2. Zu Harry Kane
1. Ich schreibe einen XML Editor und versuche mit der Methode copy() einen Treenode zu kopieren.
2. Ja, der JTree baut sich immer neu auf, je nach geladener Datei. Das funktioniert problemlos.
3. Der LeafCellEditor sorgt dafür das nur Leafs editierbar sind.
4. Den TreeCellEditor habe ich explizit auf Null gesetzte weil ich einen Bug im Programm habe und noch keine Lösung gefunden habe. Wenn ich einen bestimmten Knoten mit einer ComboBox editieren will, taucht die ComboBox nach dem editieren bei jedem selektierten Knoten auf. Ist natürlich keine Lösung die so bestehen bleiben soll.
5. Danke für den Hinweis den Tree einfach zu aktualisieren, da hatte ich wohl Tomaten auf den Augen, gar nicht daran gedacht.
6. Muss ich die path() Methode nicht nutzen, um dem Tree mitzuteilen wo der selektierte Knoten der copy() Methode eingefügt werden soll oder ist die überflüssig?

Ich habe mir eure Anmerkungen durchgelesen und schreibe den Code nun neu. Danke für die Hilfestellungen!
 
2. Ja, der JTree baut sich immer neu auf, je nach geladener Datei. Das funktioniert problemlos.
Jo, jetzt sehe ich es. Du behältst in deinem XMLEditor eine Referenz auf den root node des JTree. Je nachdem was in
Java:
model.synchronizeXmlWithModel(path, root);
passiert, ist es deshalb durchaus möglich nach dem Laden einer Datei das alte TreeModel mit neuen Kindkoten zu versehen.
6. Muss ich die path() Methode nicht nutzen, um dem Tree mitzuteilen wo der selektierte Knoten der copy() Methode eingefügt werden soll oder ist die überflüssig?
Nein, die path-Methode macht nichts dergleichen. In der path-Methode und auch in der copy-Methode wird nur auf demTreeSeelctionModel des JTree ein TreeSeelctionListener registriert. Dabei "passiert" zunächst mal gar nix. Der Code in der valueChanged-Methode wird erst ausgeführt, wenn du auf einen Knoten klickst bzw. den ausgewählten Knoten änderst.
 

Neue Themen


Zurück
Oben