메서드 호출 후 클래스 변수가 업데이트되지 않음

Dec 01 2020

저는 Java를 처음 접했고 많은 답변을 조사하고 검색하고 읽은 후에야 이것을 게시하고 있습니다. 나는 좀 길을 잃었다. 약간의 안내가 큰 도움이 될 것입니다. 다음은 "ActionListener"인터페이스를 구현하는 클래스의 메소드입니다. 내가하려는 것은 이것입니다. 하나를 클릭하면 두 개의 라디오 버튼 형태로 두 가지 옵션이있는 새 창을 열 수있는 버튼이 있습니다. 내 코드에서 나중에 사용하기 위해 선택된 라디오 버튼을 알아야합니다. "scoreOption"변수를 클래스 변수 및 정적로 선언 한 다음 "actionPerformed"추상 메서드에서 업데이트를 시도합니다. 그러나 그것을 참조하면 (메서드 호출 후) 값은 동일하게 유지됩니다-null 또는 처음에 설정 한 값. 다음은 코드입니다.

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();
                    }
                });
            }
        });
    }

메소드 스코어링 시스템이 호출되는 메인 게임 클래스.

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);
        
    }

}

또한 다음 질문에 대해 알려주세요.

  1. 다른 "ActionListener"내에서 "ActionListener"를 구현하는 것이 좋습니다. 좋은 연습?
  2. "actionPerformed"메소드의 선언이 하나만있을 수 있습니까? 아니면 오버로드 될 수도 있습니까?
  3. "actionPerformed"메서드에서 반환 값을 얻을 수 있습니까?

힌트를 좀 제공해 주시면 정말 감사하겠습니다. 나는 정말 많이 시도한 다음 여기에 게시했습니다. 미리 감사드립니다.

작은 편집 : 내가 "System.out.println" "actioncommand"자체가 콘솔에 인쇄되면 완벽하게 작동합니다. 그러나 클래스 변수를 업데이트하고 메서드 호출 후에 인쇄하려고 할 때가 아닙니다. 이것이 도움이된다면 Dunno.

답변

1 HovercraftFullOfEels Dec 01 2020 at 10:30

JFrame은 모달이 아닙니다. 생성하고 표시하면 코드 흐름을 차단하지 않으므로 JFrame이 표시되고 사용자가 변경할 기회가 있기 전에 scoreOption 권한의 값을 추출 합니다. 모달 대화 상자로 생성 된 JDialog와 같은 모달 대화 상자를 사용하거나 JOptionPane (실제로는 후드 아래의 모달 JDialog입니다)을 사용해야합니다. 이렇게하면 코드 흐름이 차단되어 사용자가 데이터를 변경 한 후에 만 ​​데이터를 추출 할 수 있습니다.

요점을 증명하는 예 :

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());
    }
}

코드를 실행하면 하위 JFrame을 표시 할 때 대화 상자가 처리 되기 전에 테스트 텍스트가 콘솔에 즉시 표시됩니다 . 버튼을 눌러 대화 상자를 표시하면 버튼을 눌렀을 때까지 테스트 텍스트 표시가 지연되어 텍스트가 변경됩니다.

프레임 버튼을 두 번 누르면 텍스트가 처음 표시 될 때 설정되었으므로 마지막으로 올바른 텍스트가 표시됩니다.

1 camickr Dec 01 2020 at 11:00

JDialig는 JFrame과 같습니다. 그것은 당신이 어떤 프레임과 같이 구성 요소를 추가하는 것입니다.

차이점은 JDialog 모달을 만들 수 있다는 것입니다. 이것은 다음을 사용할 때 의미합니다.

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

setVisible (...) 문 뒤의 코드는 대화 상자를 닫을 때까지 실행되지 않습니다. 또한 대화 상자가 닫힐 때까지 부모 JFrame을 클릭 할 수 없음을 의미합니다.

를 만드는 쉬운 방법 modal JDialogJOptionPane. 사용자 입력에 대한 프롬프트를 쉽게 만드는 몇 가지 미리 정의 된 방법이 있습니다.

예를 들어 귀하의 경우 다음과 같이 할 수 있습니다.

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() );
    }
}

위는 "MRE"의 예이기도합니다. 코드는 간단하며 복사 / 붙여 넣기 / 컴파일 및 테스트 할 수있는 단일 클래스에 포함되어 있습니다.

.NET Framework 사용에 대한 더 많은 예제는 대화 상자 사용 방법 에 대한 스윙 자습서의 섹션 을 참조 하십시오JOptionPane .

라디오 버튼을 정말로 사용하려면 라디오 버튼이있는 패널을 만들고 showConfirmDialog(...)방법을 사용하여 옵션 창에 표시 할 수 있습니다 . 대화 상자가 닫히면 .NET Framework에서 작업 명령을 가져와야 ButtonModel합니다 ButtonGroup.

시작하기위한이 접근 방식의 기본 예제는 JOptionPane의 레이아웃을 설정 및 관리하는 방법을 참조하십시오 .