【问题标题】:class variable not updating after method call方法调用后类变量不更新
【发布时间】:2021-03-13 00:04:03
【问题描述】:

我对 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”本身时,它可以完美地工作,在控制台中打印。但是当我尝试更新类变量然后在方法调用后尝试打印它时不会。不知道这是否有帮助。

【问题讨论】:

  • 查看minimal reproducible example 链接,因为这是其他人了解当前代码为何无法按预期工作的最佳方式。该链接将解释这是什么、如何创建以及为什么它可以帮助您和我们。请注意,这不是对您的整个程序或不可运行的 sn-ps 的请求(就像您现在提供的那样),而是一个我们可以运行的新的小型演示程序,它向我们展示了问题。
  • 在我看来,我们无法从上面的代码中看到为什么 scoreOption 保持为空,除了 JFrame 不是模式窗口,而且您当然不想在应用程序中显示多个 JFrame。也许您需要一个模态对话框窗口,例如模态 JDialog 而不是 JFrame。变量为空还有其他原因,例如变量阴影,但是这是否发生仍然是任何人的猜测。
  • 你能不能至少给我们看一下scoreOption的声明?
  • 关于ActionListener中的ActionListener,一般来说这样是可以的,但实际上这段代码应该被大量重构为不同的类,更不用说不同的方法了。
  • @DawoodibnKareem 我添加了完整的课程。这就是你要找的东西吗?

标签: java swing interface radio-button


【解决方案1】:

JDialig 就像 JFrame。也就是说,您可以像添加任何框架一样向其中添加组件。

不同之处在于您可以制作 JDialog 模式。这意味着当您使用:

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

setVisible(...) 语句之后的代码在对话框关闭之前不会执行。这也意味着在对话框关闭之前您不能单击父 JFrame。

创建modal JDialog 的一种简单方法是使用JOptionPane。它有一些预定义的方法,使提示用户输入变得容易。

例如,在您的情况下,您可以执行以下操作:

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”的一个例子。代码很简单,包含在一个类中,您可以复制/粘贴/编译和测试。

阅读 How to Use Dialogs 上的 Swing 教程部分,了解更多使用 JOptionPane 的示例。

如果你真的想使用单选按钮,那么你可以创建一个带有单选按钮的面板,并使用showConfirmDialog(...) 方法将它们显示在选项面板上。当对话框关闭时,您需要从ButtonGroupButtonModel 获取操作命令。

有关此方法的基本示例,请参阅:how to set & manage the layout of JOptionPane

【讨论】:

  • 非常感谢您的回答、代码和最后的 cmets - 也会尝试一次 :)
【解决方案2】:

JFrames 不是模态的——您创建一个并显示它,它不会阻塞代码流,因此您在显示 JFrame 时和 之前提取 scoreOption 的值strong> 用户有机会改变它。您需要使用模态对话框,例如创建为模态对话框的 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 时,测试文本会立即显示在控制台中对话框被处理之前。如果您按下按钮显示对话框,则测试文本显示会延迟到按下按钮后,更改文本。

按两次框架按钮最终会显示正确的文本,因为文本是在第一次显示时设置的。

【讨论】:

  • 您能否以更具描述性的方式在此上下文中解释“模态”。我相信我可以看到我哪里出错了,你仍然是专业人士可以肯定地给我更多的见解:)
  • @fattypanda 等一下
  • 小更新 - 它仍然不适用于 JDialog。我刚试过。同样的问题。我相信问题出在其他地方还是?
  • 不,一点也不。
猜你喜欢
  • 2019-10-21
  • 2014-07-11
  • 2023-03-19
  • 2018-09-13
  • 2021-01-12
  • 2018-03-06
  • 1970-01-01
  • 1970-01-01
  • 2021-06-08
相关资源
最近更新 更多