如果B类的实例是A类的成员,那么当按下B类中的按钮时,B类如何调用A类的方法?

时间:2016-04-23 00:10:02

标签: java swing

我正在尝试使用MVC编码实践创建一个GUI来为桌面RPG生成字符。我将有几个“控制面板”类,每个类都有一组特定的按钮来处理角色创建过程的不同方面(滚动属性,购买设备等)。我的Controller类将成为每个“控制面板”类的实例。我的通用代码在这里:

公共类控制器{

private Model m; //class Model not shown
private Viewer v; //class Viewer not shown
private JFrame frame;
private ControlPanelOne cpo;
private ControlPanelTwo cpt; //class ControlPanelTwo not shown

public Controller(){
    m = new Model();
    v = new Viewer();
    frame = new JFrame();
    frame.setLayout(…);
    cpo = new ControlPanelOne();
    cpt = new ControlPanelTwo();
    frame.add(cpo.getPanel());
    frame.add(cpt.getPanel());}

public void update(){
    m.update();
    v.update();}}

公共类ControlPanelOne {

private JPanel panel;
private JButton button;

public ControlPanelOne(){
    panel = new JPanel();
    button = new JButton(“press me”);
    panel.add(button);
    button.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            //do some stuff;
            //call Controller’s update method;}})} //the important bit!

public JPanel getPanel(){
    return panel;}}

公共类测试员{

public static void main(String[] args){

    Controller c = new Controller();}}

当按下ControlPanelOne按钮时,如何让ControlPanelOne看到并调用Controller的update()方法?

我尝试使ControlPanelOne扩展Controller,这样我可以在按下ControlPanelOne按钮时调用super.update(),但是当实例化Controller时(例如在Tester类中),其ControlPanelOne成员也会被实例化,从而两个Controller和ControlPanelOne的构造函数在无限循环构造中被调用。

试图通过使Controller的update()方法静态来欺骗编译器不起作用,因为实例m和v不是静态的。

如果我能帮助它,我不想让ControlPanelOne成为Controller的内部类。将会有其他“控制面板”类(ControlPanelTwo等),我担心它们所有内部类都会使Controller的代码冗长而混乱。我希望每个“控制面板”作为一个单独的类来处理一个特定的功能,以便于整洁,并且易于维护和模块化代码重用。

似乎很明显ControlPanelOne不应该将Controller作为成员变量,因为a)它在概念上是向后的,而b)其他“控制面板”的实例需要它们自己的Controller实例......

我曾经有Controller扩展JFrame和ControlPanelOne扩展JPanel(这样Controller可以直接添加()一个ContollPanelOne实例,而不是调用ControlPanelOne的getPanel()方法),但我读到了让类扩展这些组件而不是制作这样的组件你班上的成员表现不佳。但如果它能以某种方式帮助回到控制器和ControlPanelOne扩展JFrame和JPanel ......

也许我对MVC的想法是错误的......

请告知

4 个答案:

答案 0 :(得分:1)

的确,你并没有坚持MVC模式。该模式的要点是为模型,视图和控制器提供清晰的分离。因此,任何继承或组合彼此的企图都会使其失去效益。

我要做的是AbstractAction如:

public class UpdateAction extends AbstractAction { 

    private Controller controller;

    ...
    @Override
    public void actionPerformed(ActionEvent ae) {
        controller.update();
    }
}

然后,在视图外部初始化并设置按钮,视图无需知道它显示的内容;它只需要知道它的工作就是展示东西。您可以拥有控制器extend JFrame并将JPanel添加到其中。

JButton button = new JButton("Button");
button.setAction(new UpdateAction(this));
... more button set up
... add button to views
... add views to frame

现在,只要单击该按钮,它就会调用控制器的update()方法。

答案 1 :(得分:1)

  

当按下ControlPanelOne按钮时,如何让ControlPanelOne看到并调用Controller的update()方法?

这通常通过使用Observer Pattern来实现,其中控制器将注册对某些事件发生时通知的视图的兴趣,视图将在适当时在事件发生时呼叫每个注册方。这样,视图并不关心控制器,只需要生成适当的事件。

答案 2 :(得分:0)

如果我理解B级是A级的组成部分 B类不知道关于A类,即使它是该类的成员,它也没有参考。 这称为合成 “has -a” 关系。如果你想知道那个类,你也应该在B类中有一个A类实例,或者让A类的方法是静态的。

class B {
    btnPressed() {
        /*To call this method you need or an object of class A, or static method in class A*/
        methodA(); //Method form class A

        op1:
        a = new A();
        a.methodA();

        op2:
        //make methodA static in class A 
        A.methodA();
    }
}

class A {
    b = new B();

    methodA();
}

希望这有帮助。

答案 3 :(得分:0)

您的直接目标是在update构造函数中匿名实施Controller的{​​{1}}方法中的actionPerformed实例上调用ActionListenerControlPanelOneControlPanelOne实例的构造函数组成。实际上,您需要从ControllerController的循环引用,反之亦然。

这是一个直截了当的方法。您可以查看最低限度制定的项目here

首先,您的ControlPanelOne

Controller

接下来,public class Controller { private Model m; //class Model not shown private Viewer v; //class Viewer not shown private JFrame frame; private ControlPanelOne cpo; private ControlPanelTwo cpt; //class ControlPanelTwo not shown public Controller() { m = new Model(); v = new Viewer(); frame = new JFrame(); frame.setLayeredPane(null); // Do something cpo = new ControlPanelOne(this); // Supply self to the instance of ControlPanelOne cpt = new ControlPanelTwo(); frame.add(cpo.getPanel()); frame.add(cpt.getPanel()); } public void update() { m.update(); v.update(); } }

ControlPanelOne

要记住的重要一点是在构造函数中声明提供的public class ControlPanelOne { private JPanel panel; private JButton button; public ControlPanelOne(final Controller controller){ panel = new JPanel(); button = new JButton("press me"); panel.add(button); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //do some stuff; controller.update(); } }); } public Component getPanel() { return null; } } final实例(您可以找出here的原因)。这在Java 8中不是必需的,但它仍然是一个很好的习惯。