Klassenvariable wird nach Methodenaufruf nicht aktualisiert

Dec 01 2020

Ich bin ziemlich neu in Java und erst nachdem ich viele Antworten recherchiert, gegoogelt und gelesen habe, poste ich dies. Ich bin irgendwie verloren. Eine kleine Anleitung wäre eine große Hilfe. Das Folgende ist eine Methode aus einer Klasse, die die "ActionListener" -Schnittstelle implementiert. Ich versuche Folgendes zu tun: Es gibt eine Schaltfläche, auf die geklickt werden sollte, um ein neues Fenster mit zwei Optionen in Form von zwei Optionsfeldern zu öffnen. Ich muss das Optionsfeld kennen, das für die weitere Verwendung in meinem Code ausgewählt wurde. Ich habe die Variable "scoreOption" als Klassenvariable und statisch deklariert und dann versucht, sie in der abstrakten Methode "actionPerformed" zu aktualisieren. Wenn ich jedoch darauf verweise (nach dem Methodenaufruf), bleibt der Wert gleich - null oder was auch immer ich ursprünglich festgelegt habe. Hier ist der Code:

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class StartEvents implements ActionListener {
    StartPanel startingPanel;
    static String scoreOption;
    
    public StartEvents(StartPanel startPanel) {
        startingPanel = startPanel;
    }
    // Scoring System Window - 1
    public void scoringSystem() {
        startingPanel.scoringSystem.addActionListener(new ActionListener () {
            @Override
            public void actionPerformed(ActionEvent e) {
                Panel scoringSystemPanel = new Panel();
                JFrame scoreSystemFrame  = scoringSystemPanel.frame(150, 250, "Scoring System", 2, true);
                JPanel scoreSystemPanel = scoringSystemPanel.panel(Color.lightGray);
                JButton confirmSelection = scoringSystemPanel.button(40, 20, "Confirm");
                JRadioButton scoreSystem1 = scoringSystemPanel.radioButton("Option 1: Same Points Per Hit");    
                scoreSystem1.setActionCommand("Option 1");
                JRadioButton scoreSystem2 = scoringSystemPanel.radioButton("Option 2: Unique Points Per Hit");
                scoreSystem2.setActionCommand("Option 2");
                ButtonGroup scoreSys = new ButtonGroup();
                scoreSys.add(scoreSystem1);
                scoreSys.add(scoreSystem2);
                scoreSystemFrame.getContentPane().add(scoreSystemPanel);
                scoreSystemPanel.add(scoreSystem1);
                scoreSystemPanel.add(scoreSystem2);
                scoreSystemPanel.add(confirmSelection);
                
                // Get Selection Event
                // Option 1
                scoreSystem1.addActionListener(new ActionListener () {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (scoreSystem1.isSelected()) {
                            scoreOption = scoreSystem1.getActionCommand();
                        }
                    }
                });
                // Option 2
                scoreSystem2.addActionListener(new ActionListener () {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (scoreSystem2.isSelected()) {
                            scoreOption = scoreSystem2.getActionCommand();
                        }
                    }
                });
                // Confirm Event 
                confirmSelection.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        scoreSystemFrame.dispose();
                    }
                });
            }
        });
    }

Hauptspielklasse, in der das Methoden-Scoring-System aufgerufen wird.

import java.util.ArrayList;

public class Game {

    public static void main(String[] args) {
        StartPanel startingPanel = new StartPanel();
        startingPanel.makeStartPanel();
        StartEvents starter = new StartEvents(startingPanel);
        starter.rulesButton();
        starter.exitButton();
        starter.highScoresButton();
        ArrayList<Integer> dimensions = starter.boardSizeSelector();
        
        // Problem Zone
        System.out.println(StartEvents.scoreOption);
        starter.scoringSystem();
        System.out.println(StartEvents.scoreOption);
        // The two values of scoreOption should be different
        
        String[] playPanelDetails = {"970", "Player 1", "450"};
        
        // Final Start of the Game
        starter.startGameButton(playPanelDetails, dimensions);
        
    }

}

Könnten Sie mich bitte zu folgenden Fragen informieren:

  1. Es wird empfohlen, "ActionListener" in einem anderen "ActionListener" zu implementieren. Gute Übung?
  2. Kann es nur eine Deklaration der Methode "actionPerformed" geben oder kann sie auch überladen werden?
  3. Ist es möglich, einen Rückgabewert von der "actionPerformed" -Methode zu erhalten?

Ich wäre sehr dankbar, wenn auch nur einige Hinweise gegeben werden könnten. Ich habe wirklich viel versucht und erst dann hier gepostet. Vielen Dank im Voraus.

Kleine Bearbeitung: Wenn ich dort "System.out.println" den "Aktionsbefehl" selbst "gebe", funktioniert es einwandfrei und druckt in der Konsole. Aber nicht, wenn ich versuche, die Klassenvariable zu aktualisieren und sie dann nach dem Methodenaufruf zu drucken. Keine Ahnung, ob das hilft.

Antworten

1 HovercraftFullOfEels Dec 01 2020 at 10:30

JFrames sind nicht modal - Sie erstellen einen und zeigen ihn an, blockieren den Codefluss nicht und extrahieren den Wert von scoreOption direkt während der Anzeige des JFrames und bevor der Benutzer die Möglichkeit hatte, ihn zu ändern. Sie müssen einen modalen Dialog verwenden, z. B. einen JDialog, der als modaler Dialog erstellt wird, oder einen JOptionPane (der eigentlich nur ein modaler JDialog unter der Haube ist). Dadurch wird der Codefluss blockiert, sodass Sie die Daten erst extrahieren, nachdem sie vom Benutzer geändert wurden.

Ein Beispiel, das den Punkt beweist:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class FooGui01 extends JPanel {
    private String frameTest = "";
    private String dialogTest = "";
    private JFrame mainFrame = new JFrame("Main GUI");
    
    private JFrame subFrame;
    private JDialog dialog;

    
    public FooGui01() {
        JButton showFrameBtn = new JButton("Show JFrame");
        showFrameBtn.addActionListener(e -> {
            changeTest1WithJFrame();
            System.out.println("frameTest: " + frameTest);
        });
        
        JButton showDialogBtn = new JButton("Show JDialog");
        showDialogBtn.addActionListener(e -> {
            changeTest2WithModalDialog();
            System.out.println("dialogTest: " + dialogTest);
        });
        
        JPanel panel = new JPanel();
        panel.add(showDialogBtn);
        panel.add(showFrameBtn);
        
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.add(panel);
        mainFrame.pack();
        mainFrame.setLocationByPlatform(true);
        mainFrame.setVisible(true);
        
    }
    
    public void changeTest1WithJFrame() {

        if (subFrame == null) {
            subFrame = new JFrame("Frame");
            JButton button = new JButton("Press me");
            button.addActionListener(e -> {
                frameTest = "Hello World and frameTest";
                subFrame.setVisible(false);
            });

            JPanel panel = new JPanel();
            panel.add(button);
            
            subFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
            subFrame.add(panel);
            subFrame.pack();
            subFrame.setLocationByPlatform(true);
        }
        subFrame.setVisible(true);
    }
    
    public void changeTest2WithModalDialog() {
        
        if (dialog == null) {       
            dialog = new JDialog(mainFrame, "Dialog", Dialog.ModalityType.APPLICATION_MODAL);
            JButton button = new JButton("Press me");
            button.addActionListener(e -> {
                dialogTest = "Hello World and dialogTest";
                dialog.setVisible(false);
            });

            JPanel panel = new JPanel();
            panel.add(button);
            
            dialog.add(panel);
            dialog.pack();
            dialog.setLocationByPlatform(true);
        }
        dialog.setVisible(true);
    }
        
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new FooGui01());
    }
}

Wenn Sie den Code ausführen und den Sub-JFrame anzeigen, wird der Testtext sofort in der Konsole angezeigt, bevor der Dialog behandelt wurde. Wenn Sie die Taste drücken, um den Dialog anzuzeigen, wird die Anzeige des Testtextes verzögert, bis die Taste gedrückt wurde und der Text geändert wird.

Durch zweimaliges Drücken der Rahmentaste wird schließlich der richtige Text angezeigt, da der Text beim ersten Anzeigen festgelegt wurde.

1 camickr Dec 01 2020 at 11:00

Ein JDialig ist wie ein JFrame. Das heißt, Sie fügen Komponenten hinzu, wie Sie es bei jedem Frame tun.

Der Unterschied besteht darin, dass Sie einen JDialog modal machen können. Dies bedeutet, dass wenn Sie verwenden:

dialog.setVisible(true);
System.out.println("here");

Der Code nach der Anweisung setVisible (...) wird erst ausgeführt, wenn der Dialog geschlossen wird. Dies bedeutet auch, dass Sie nicht auf den übergeordneten JFrame klicken können, bis der Dialog geschlossen wird.

Eine einfache Möglichkeit, ein zu erstellen, modal JDialogist die Verwendung von a JOptionPane. Es gibt einige vordefinierte Methoden, die die Eingabe von Benutzereingaben vereinfachen.

In Ihrem Fall könnten Sie beispielsweise Folgendes tun:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SSCCE extends JPanel
{
    private int scoringOption = -1;

    public SSCCE()
    {
        JButton button = new JButton("Change Points Option");
        add(button);

        button.addActionListener((e) -> displayOptionDialog());
    }

    private void displayOptionDialog()
    {
        Window window = SwingUtilities.windowForComponent( this );

        // Custom button text

        Object[] options = {"Option 1: Same Points Per Hit", "Option 2: Unique Points Per Hit"};

        scoringOption = JOptionPane.showOptionDialog(
            window,
            "Select your scoring option:",
            "Scoring Option",
            JOptionPane.YES_NO_CANCEL_OPTION,
            JOptionPane.QUESTION_MESSAGE,
            null,
            options,
            null);

        System.out.println( scoringOption );
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new SSCCE());
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args) throws Exception
    {
        java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
    }
}

Das Obige ist auch ein Beispiel für ein "MRE". Der Code ist einfach und in einer einzelnen Klasse enthalten, die Sie kopieren / einfügen / kompilieren und testen können.

Weitere Beispiele für die Verwendung von a finden Sie im Abschnitt aus dem Swing-Lernprogramm zur Verwendung von DialogenJOptionPane .

Wenn Sie wirklich Optionsfelder verwenden möchten, können Sie ein Bedienfeld mit den Optionsfeldern erstellen und diese mithilfe der showConfirmDialog(...)Methode im Optionsbereich anzeigen . Wenn der Dialog geschlossen wird, müssen Sie den Aktionsbefehl von der ButtonModelaus abrufen ButtonGroup.

Siehe: Wie einstellen und das Layout der JOptionPane verwalten für ein einfaches Beispiel für diesen Ansatz zum Einstieg.