【问题标题】:How to observe a JButton from a different class?如何观察来自不同类的 JButton?
【发布时间】:2013-03-08 17:52:12
【问题描述】:

所以我有一个扩展 JPanel 的类,并在构造函数中添加我的 JButtons 以及我需要添加的任何其他内容。我还有一个MainFrame 类,它是容器(JFrame),这个类将从一个名为FrameSwitcher(控制器)的类中获取一个参数,该类将评估点击了哪些按钮,并将信息传递给@987654326 @

我在执行此操作时遇到了麻烦,我找不到合适的方法来执行此操作。我也希望保持 JButtons 的私有和非静态。

JPanel 示例:

public class MainMenu() {

    private JButton btnSinglePlayer, btnMultiPlayer;

    public MainMenu() {
        setLayout(null);

        btnSinglePlayer = new JButton("singlePlayer");
        btnSinglePlayer.setBounds(320, 25, 275, 130);
        add(btnSinglePlayer);

        btnMultiPlayer = new JButton("MultiPlayer");
        btnMultiPlayer.setBounds(320, 170 , 275, 130);
        add(btnMultiPlayer);

   }
}

帧切换器:

public class FrameSwitcher implements panelListener { // panelListener is an interface defined else where.

    public FrameSwitcher(MainFrame frame) {
        // This is irrelevant to the question. 
    } 

    @Override
    public void gamePanel() {
        System.out.println("GamePanel Event: Recieved");
    }
    @Override
    public void mainMenu() {
        System.out.println("mainMenu Event: Recieved");
    }
    @Override
    public void scoreBoardPanel() {
        System.out.println("scoreBoardPanel Event: Recieved");
    }
}

然后是我的 MainFrame:

public class MainFrame extends JFrame implements ActionListener {

    private PanelListener panelListener;
    private JFrame mainContainer = new JFrame("Game");
    private JPanel mainMenu = new MainMenu();

    public void start() {
         mainContainer(mainMenu);
    }

    public MainFrame(JPanel frame) {
        mainContainer.getContentPane().add(frame);
        mainContainer.pack();
        // Other methods to initialize the frame
        return mainContainer;
     }

    public void switchFrames(PanelListener panelListener) {
        this.panelListener = panelListener; // PanelListener is an interface.
    }

    public void actionPerformed(ActionEvent e) {

        JButton source = (JButton)e.getsource();

        if(source == MainMenu.btnSinglePlayer) {
            if(panelListener != null) {
                System.out.println("Recieved the event approriately.");
            }
        }
    }
}

在这个例子中,它确实编译了,但没有做它应该做的事情。另一件事是我目前将 JButtons 作为公共和静态的,我不希望这样。

【问题讨论】:

  • actionPerformedActionListener 接口的一个方法,您的MainFrame 类目前还没有实现它..那么,您期望什么?这整个设计很古怪。回到基础。
  • 在 FrameSwitcher 类中实现 ActionListener,并在 MainMenu 类中为每个按钮添加一个 ActionListener(FrameSwitcher)。

标签: java swing model-view-controller jbutton observer-pattern


【解决方案1】:

在您的MainMenu 类中,您需要添加某种类型的侦听器,相关方可以注册,以便在发生某些事件时通知他们。

最简单的解决方案是提供一个委托给每个按钮的addActionListener 方法。但是,这可能会暴露您未暴露的应用程序部分(监听器现在可以直接访问 JButton 并且可以对它做各种讨厌的事情)。

更好的解决方案是创建类似MainMenuListener 的东西,它具有startSinglePlayerstartMultiPlayer 等方法

然后,您将在 MainMenu 类中提供 add/removeMainMenuListener 方法。

然后每个按钮将在那里注册自己的actionListener 并触发相应的菜单侦听器事件

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventListener;
import javax.swing.JButton;
import javax.swing.JPanel;

public class MainMenu extends JPanel {

    private JButton btnSinglePlayer, btnMultiPlayer;

    public MainMenu() {
        setLayout(null);

        btnSinglePlayer = new JButton("singlePlayer");
        btnSinglePlayer.setBounds(320, 25, 275, 130);
        add(btnSinglePlayer);
        btnSinglePlayer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                fireStartSinglePlayer();
            }
        });

        btnMultiPlayer = new JButton("MultiPlayer");
        btnMultiPlayer.setBounds(320, 170, 275, 130);
        add(btnMultiPlayer);
        btnMultiPlayer.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                fireStartMultiPlayer();
            }
        });

    }

    public void addMainMenuListener(MainMenuListener listener) {
        listenerList.add(MainMenuListener.class, listener);
    }

    public void removeMainMenuListener(MainMenuListener listener) {
        listenerList.remove(MainMenuListener.class, listener);
    }

    public void fireStartSinglePlayer() {
        MainMenuListener[] listeners = listenerList.getListeners(MainMenuListener.class);
        if (listeners != null && listeners.length > 0) {
            for (MainMenuListener listener : listeners) {
                listener.startSinglePlayer();
            }
        }
    }

    public void fireStartMultiPlayer() {
        MainMenuListener[] listeners = listenerList.getListeners(MainMenuListener.class);
        if (listeners != null && listeners.length > 0) {
            for (MainMenuListener listener : listeners) {
                listener.startMultiPlayer();
            }
        }
    }

    public interface MainMenuListener extends EventListener {

        public void startSinglePlayer();
        public void startMultiPlayer();

    }

}

【讨论】:

    【解决方案2】:

    首先你必须像这样创建一个 ActionListener

    class MyActionListener implements ActionListener{
        public void actionPerformed(ActionEvent ae){
            //do your stuff
        }
    }
    

    然后调用,

    yourButton.addActionListener(new MyActionListener());
    

    【讨论】:

    • 这不会强迫我在实际的 MainMenu 类中编写我的 actionListeners 吗?如果没有,它如何允许我以这种方式访问​​另一个班级的按钮?我假设 MyActionListener 将在一个数组中包含 JButtons,我将它们传递给 FrameSwitcher,它在 MainFrame 处返回必要的数据?
    • 您的应用程序的架构非常奇怪——快速阅读后,我无法真正弄清楚什么在与什么对话,或者您想要完成什么。您能否简单描述一下您希望完成的应用程序做什么,我会建议一个简化的设计?
    • 当然,这只是我的应用程序的 GUI。它意味着有一个主菜单,其中有四个按钮,singlePlayer、multiPlayer、scoreBoards 和 quit。每个按钮都会初始化不同的东西。此外,根据单击的按钮,会附带某些逻辑,例如,您单击单人游戏,然后将调用单人游戏逻辑,然后游戏将继续进行。此外,在这些面板中,就像单人游戏一样,会有一个 JMenu 栏,可以将您带到主菜单或记分牌。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 2020-12-26
    • 1970-01-01
    • 2016-08-31
    • 2012-12-05
    • 1970-01-01
    • 2016-06-23
    相关资源
    最近更新 更多