Java 如何添加触发别处定义的函数的actionEvent?

Java 如何添加触发别处定义的函数的actionEvent?,java,swing,Java,Swing,我正在开发Java,添加了一个按钮,当点击时会触发一个函数。这是从主类执行的GUI文件,用于制作游戏窗口。我找到的唯一方法是: package Kingdomino; import java.awt.BorderLayout; ... public class createAndShowGUI extends JPanel { static public JComboBox createNumPlayersMenu(){ String[] lista = {"2 p

我正在开发Java,添加了一个按钮,当点击时会触发一个函数。这是从主类执行的GUI文件,用于制作游戏窗口。我找到的唯一方法是:

package Kingdomino;

import java.awt.BorderLayout;
...

public class createAndShowGUI extends JPanel {

    static public JComboBox createNumPlayersMenu(){
        String[] lista = {"2 players","3 players","4 players"};
        JComboBox numPlayersMenu = new JComboBox(lista);
        numPlayersMenu.setSelectedIndex(2);
        numPlayersMenu.setMaximumSize(new Dimension(200,30));
        return numPlayersMenu;
    }

    static public JComboBox createPlayerColorMenu(){
        String[] lista = {"blue","green","red","pink"};
        JComboBox playerColor = new JComboBox(lista);
        playerColor.setSelectedIndex(2);
        playerColor.setMaximumSize(new Dimension(200,30));
        return playerColor;
    }   

    static public JButton createPlayButton()  {
        JButton createPlayButton = new JButton();
        createPlayButton.setText("Play");
        return createPlayButton;
    }

    static public void main() throws IOException {
        JFrame frame = new JFrame("FrameDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setJMenuBar(createMenuBar());

        JPanel jpanel = new JPanel();

        frame.getContentPane().add(jpanel, BorderLayout.CENTER);

        Box verticalBox = Box.createVerticalBox();      
        jpanel.add(verticalBox, BorderLayout.CENTER);

        JLabel label = new JLabel();
        label.setText("Hi");
        verticalBox.add(label);

        Box horizontalBox = Box.createHorizontalBox();
        horizontalBox.setMaximumSize(new Dimension(700,50));

        JComboBox numPlayersMenu = createNumPlayersMenu();
        horizontalBox.add(numPlayersMenu);

        JComboBox playerColor = createPlayerColorMenu();
        horizontalBox.add(playerColor);

        verticalBox.add(horizontalBox);

        JButton btnNewButton = createPlayButton();
        btnNewButton.addActionListener( 
            new ActionListener() {          
            public void actionPerformed(ActionEvent e)  {
                String num1 =  numPlayersMenu.getSelectedItem().toString();
                String num2 = playerColor.getSelectedItem().toString();
                label.setText( "Selected number of players: "+num1 + " // selected color: " + num2 );
        }
        });
        verticalBox.add(btnNewButton);

        frame.pack();
        frame.setVisible(true);

    }
}
问题是,如果我想要实现的函数比几行代码更复杂,我希望用不同的方法实现它,而不是在main的代码中

我已经尝试了很多方法来做到这一点,但没有一个有效。这个方法看起来最简单、最干净,但我不喜欢在main方法中定义函数,我宁愿将它放在外部,并在action侦听器中引用它


我相信一定有办法做到这一点,但我一直没能想出办法。有什么帮助吗?谢谢大家!

同样,我在评论中的建议似乎过于复杂化了,建议您重新思考代码,努力使其更符合面向对象,短期内这可能是正确的,但从中期和长期来看,情况正好相反,因为现在您的游戏非常简单,你只是试着设置两个属性,int和Color,但是一旦你把它变得更复杂一点,把所有东西都放在静态领域所带来的复杂性就会变得难以承受

既然如此,我的建议是什么?首先从view GUI代码中提取出模型的非GUI状态,这里的模型非常简单,一个包含int和Color的类,一个包含构造函数、字段、getter/setter以及其他所需的任何东西,类似这样:

import java.awt.Color;

// class that holds the non-GUI "state" of the game
// Also holds non-GUI behaviors as well via its methods
public class Game {
    // fields to hold state
    private int numberOfPlayers;
    private Color color;

    public Game() {
        this(0, Color.WHITE);
    }

    public Game(int numberOfPlayers, Color color) {
        this.numberOfPlayers = numberOfPlayers;
        this.color = color;
    }

    public int getNumberOfPlayers() {
        return numberOfPlayers;
    }

    public void setNumberOfPlayers(int numberOfPlayers) {
        this.numberOfPlayers = numberOfPlayers;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    // other behavior methods here
}
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class MainGamePanel extends JPanel {
    private static final int PREF_W = 600;
    private static final int PREF_H = 450;
    private UserSelectionPanel userSelectionPanel = new UserSelectionPanel();
    private Game game;
    private JLabel numberOfPlayersLabel = new JLabel("0");

    public MainGamePanel(Game game) {
        JPanel topPanel = new JPanel();
        topPanel.setOpaque(false); // so color shows through

        // display the number of players here
        topPanel.add(new JLabel("Number of Players:"));
        topPanel.add(numberOfPlayersLabel);

        // to hold button that displays dialog
        JPanel middlePanel = new JPanel(new GridBagLayout());
        middlePanel.setOpaque(false); // same reason
        middlePanel.add(new JButton(new AbstractAction("Set-Up Game") {

            @Override
            public void actionPerformed(ActionEvent e) {
                setUpGameActionPerformed();
            }
        }));

        setPreferredSize(new Dimension(PREF_W, PREF_H));
        this.game = game;
        setBackground(game.getColor());
        setLayout(new BorderLayout());
        add(topPanel, BorderLayout.PAGE_START);
        add(middlePanel);
    }

    private void setUpGameActionPerformed() {
        // set up the JOptionPane
        Component parentComponent = MainGamePanel.this;
        UserSelectionPanel message = userSelectionPanel; // *** our all-imporant JPanel
        String title = "Set-up Game";
        int optionType = JOptionPane.OK_CANCEL_OPTION;
        int messageType = JOptionPane.PLAIN_MESSAGE;

        // display the JOptionPane
        int result = JOptionPane.showConfirmDialog(parentComponent, message, title,
                optionType, messageType);

        // if the user pressed "OK" then make the changes
        if (result == JOptionPane.OK_OPTION) {
            // update the state of the GUI
            int numberOfPlayers = userSelectionPanel.getNumberOfPlayers();
            Color color = userSelectionPanel.getSelectedColor();

            // and update our Game field, game:
            game.setNumberOfPlayers(numberOfPlayers);
            game.setColor(color);

            numberOfPlayersLabel.setText(String.valueOf(numberOfPlayers));
            setBackground(color);
        }
    }
}
import javax.swing.*;

public class SimpleGameMain {
    private static void createAndShowGui() {
        Game game = new Game();
        MainGamePanel mainPanel = new MainGamePanel(game);

        JFrame frame = new JFrame("OOP Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}
然后,让我们创建一个JPanel,它保存并显示两个JComboxes,如UserSelectionPanel:

public class UserSelectionPanel extends JPanel {
    private static final String[] NUMBER_OF_PLAYERS_ITEMS = {
            "2 Players", "3 Players", "4 Players"};

    // using "parallel arrays" below, not a good thing long-term
    private static final String[] COLOR_ITEMS = {
            "Blue", "Green", "Red", "Pink"
    };
    private static final Color[] COLORS = {
            Color.BLUE, Color.GREEN, Color.RED, Color.PINK
    };
    private static final Color DEFAULT_COLOR = Color.WHITE;
    JComboBox<String> numberOfPlayersCombo = new JComboBox<>(NUMBER_OF_PLAYERS_ITEMS);
    JComboBox<String> colorsCombo = new JComboBox<>(COLOR_ITEMS);
我们可以这样做:

import java.awt.Color;

// class that holds the non-GUI "state" of the game
// Also holds non-GUI behaviors as well via its methods
public class Game {
    // fields to hold state
    private int numberOfPlayers;
    private Color color;

    public Game() {
        this(0, Color.WHITE);
    }

    public Game(int numberOfPlayers, Color color) {
        this.numberOfPlayers = numberOfPlayers;
        this.color = color;
    }

    public int getNumberOfPlayers() {
        return numberOfPlayers;
    }

    public void setNumberOfPlayers(int numberOfPlayers) {
        this.numberOfPlayers = numberOfPlayers;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    // other behavior methods here
}
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class MainGamePanel extends JPanel {
    private static final int PREF_W = 600;
    private static final int PREF_H = 450;
    private UserSelectionPanel userSelectionPanel = new UserSelectionPanel();
    private Game game;
    private JLabel numberOfPlayersLabel = new JLabel("0");

    public MainGamePanel(Game game) {
        JPanel topPanel = new JPanel();
        topPanel.setOpaque(false); // so color shows through

        // display the number of players here
        topPanel.add(new JLabel("Number of Players:"));
        topPanel.add(numberOfPlayersLabel);

        // to hold button that displays dialog
        JPanel middlePanel = new JPanel(new GridBagLayout());
        middlePanel.setOpaque(false); // same reason
        middlePanel.add(new JButton(new AbstractAction("Set-Up Game") {

            @Override
            public void actionPerformed(ActionEvent e) {
                setUpGameActionPerformed();
            }
        }));

        setPreferredSize(new Dimension(PREF_W, PREF_H));
        this.game = game;
        setBackground(game.getColor());
        setLayout(new BorderLayout());
        add(topPanel, BorderLayout.PAGE_START);
        add(middlePanel);
    }

    private void setUpGameActionPerformed() {
        // set up the JOptionPane
        Component parentComponent = MainGamePanel.this;
        UserSelectionPanel message = userSelectionPanel; // *** our all-imporant JPanel
        String title = "Set-up Game";
        int optionType = JOptionPane.OK_CANCEL_OPTION;
        int messageType = JOptionPane.PLAIN_MESSAGE;

        // display the JOptionPane
        int result = JOptionPane.showConfirmDialog(parentComponent, message, title,
                optionType, messageType);

        // if the user pressed "OK" then make the changes
        if (result == JOptionPane.OK_OPTION) {
            // update the state of the GUI
            int numberOfPlayers = userSelectionPanel.getNumberOfPlayers();
            Color color = userSelectionPanel.getSelectedColor();

            // and update our Game field, game:
            game.setNumberOfPlayers(numberOfPlayers);
            game.setColor(color);

            numberOfPlayersLabel.setText(String.valueOf(numberOfPlayers));
            setBackground(color);
        }
    }
}
import javax.swing.*;

public class SimpleGameMain {
    private static void createAndShowGui() {
        Game game = new Game();
        MainGamePanel mainPanel = new MainGamePanel(game);

        JFrame frame = new JFrame("OOP Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

那为什么要经历这一切呢?因为您当前的游戏设置非常简单,一旦您尝试使其更复杂和有趣,就很难进行调试和增强。如果您以这种方式分离关注点,如果您使用OOP发挥优势,您就有更好的机会创建可以增长和改进的东西。

静态方法中的代码太多,没有创建真正符合OOP的对象的代码,就好像您是以意识流的方式创建此程序一样。不要。在编码之前规划类,使它们成为行为良好的对象,具有状态和行为的对象,然后重新开始。这将如何帮助我解决问题?只是真诚地问一下,我不认为有必要做一些不能改善或解决我的问题的事情,只是让代码变得更复杂。如果它真的有用的话,我会去做。就是这样,你所做的就是让你的代码变得不必要的复杂和不起作用。所以,是的,你应该放弃这个代码,重新开始。同样,意识流类型的代码也不值得这么做。例如,您发布的代码没有字段-那么除了通过参数之外,您如何在方法之间共享状态?这个状态在程序运行时是如何保持和改变的?感谢你发表了大量的评论,这些评论根本没有回答这个问题。welp谢谢,我将回顾这些代码,并尝试以一种更面向对象的方式编写它。到目前为止,当我只需要运行一次类时,我并不认为有必要建立类。这就是为什么我只使用静态方法和对象,我不需要特定的实例。问题:我不明白为什么只写add而不写topPanel.add有效。您是否应该指定要添加面板的位置?