这个问题困扰我很久了,一直没有找到一个简捷的方法来解决。如题所述,如果有两个窗口,P1和P2,在P1里有一个按钮,点击按钮将在P2上进行操作,比如说显示一行字。传统的方法是把P2的实例输入到P1里,然后在按钮点击事件里对P2的实例进行操作,像这样:
public class MainWindow extends JPanel {
   private P1 p1 = new P1();
   private P2 p2 = new P2();   public void constructGUI() {
      this.add(p1);
      this.add(p2);
      
      p1.setP2(p2);
   }
}
public class P1 extends JPanel {
   private P2 p2;   public void setP2(P2 p2){
      this.p2 = p2;
   }
......
   
   public void buttonClicked(...){
      p2.displayText();
   }
}public class P2 extends JPanel {
   public void displayText(){
      ......
   }
}
这个方法在简单的界面设计下没有任何问题,但在复杂情况下就有些力不从心了。还有一种方法是在上面例子的MainWindow里定义事件处理,这样需要P1定义一个getButton的方法来返回需要添加事件的按钮,这个方法个人认为也不是很好。在我去年的一个工程里,就遇到了这个问题,这种方法在工作中已经不能胜任,所以我用到了一个中间类来传递事件。在这种方式里,我定义一个中间类,比如说叫做MiddleActionHandler,在这个类里有P1的实例和P2的实例,然后有一个方法是p1ButtonAction(),在这个方法里执行P2上的操作。这个工程在去年完成了,事件操作上没有任何问题,代码看起来也规整得多,应该说这个方法还是可以。但是我觉得自己似乎没有找到最好的事件操作方法,所以就在这发个帖子,大家讨论一下,看看你有什么高招可以说出来让大家借鉴的。

解决方案 »

  1.   

    你这种方法和前面的方法从本质上没什么区别。
    我认为最好的方法应该是UI与Controller分离。两个窗口有各自的Controller,事件都在Controller之间交互。这样代码结构更清晰。
      

  2.   

    实际上需要你自己维护一个dispatcher
      

  3.   

    就是让View与Controller分离,让View只处理UI的工作,让Controller处理相关的事件。
    尽量多采用MVC的设计模式。
      

  4.   


    不好意思,我还是不太明白MVC的模式在Swing的GUI中能怎样的被运用。就拿我上面的例子来说吧,如果像你所说的VC分离,那应该怎么处理呢?代码将会是什么样?
      

  5.   

    以下是我个人的见解:
    其实从swing本身我们可以得到一些启发。
    比如JButton例子。
    我们看到很多下面的情况。
    public class ButtonDemo extends JPanel
                            implements ActionListener
    b1 = new JButton("Disable middle button", leftButtonIcon);
    b1.addActionListener(this);
    对于swing的组件来说,可以看到都有一个add...Listener和fire...Change的函数。
    从而我可以得出一个结论,swing的组件都是一个被观察者。
    b1.addActionListener(this);这句告诉被观察者有一个什么的监听器。此例是ButtonDemo的实例。
    注意ButtonDemo类实现了ActionListener监听器,并且重写了actionPerform方法.
    可以想象一下,组件是一个发布命令的领导,而监听器是领导手下的兵。
    那么ButtonDemo的实例和b1是两个不同的类实例。
    注意:当点击按钮的时候,我们触发的是ButtonDemo实例的函数。
    所以对于此例。我们可以套用swing的做法使用observer模式来实现解耦。
    就象下面这样:
    import java.beans.*;//PropertyChangeListener;public class MainWindow extends javax.swing.JPanel {
       private P1 p1 = new P1();
       private P2 p2 = new P2();
       public void constructGUI() {
          //this.add(p1);
          //this.add(p2);
          //p1.setP2(p2);
          p1.addPropertyChangeListener(p2);
       }
       public static void main(String[]args){
           MainWindow main=new MainWindow();
           main.constructGUI();
           args=new String[]{"call function"};
           if (args[0]=="call function"){
               main.p1.event();
           }
       }
    }
    class P1 extends javax.swing.JPanel {
       //private P2 p2;
       //public void setP2(P2 p2){
       //   this.p2 = p2;
       //}
       public void event(){
         System.out.println("call out.");
         firePropertyChange("if your get this message,please do yourself event",1,0);
       }
    }class P2 extends javax.swing.JPanel implements PropertyChangeListener{
       public void displayText(){
           System.out.println("for me,i got the message so i need to do work.");
       }
       public void propertyChange(PropertyChangeEvent evt) {
                    if (evt.getPropertyName().equals("if your get this message,please do yourself event"))
                    {
                        displayText();
                    }
       }
    }
    p1和p2没有出现套用关系。可以看到和swing做法是多么的相象。
    使用中间对象listener实现解耦。在这里p1是被观察者,p2是监听者。