swing之mvc模式

1 Swing与MVC

  Swing组件设计使用了著名的MVC模型-视图-控制器体系结构。为了了解MVC体系结构与Swing组件的关系,我们来看一下如何设计一个表示按钮的组件,因为按钮的各个部分可以与MVC体系结构的3个部分对应起来。

  按钮在任意给定时刻,可处于启用和无效两种状态之一。很显然,按钮只有处于启用状态时才会响应点击。记录按钮状态是很有用的,视图需要根据按钮的状态进行不同的渲染。按钮的所有状态就是MVC体系结构的模型部分。模型还包括按钮的其他属性。

  你现在了解到按钮在模型中保存其状态,视图是按钮的图形表示,它使用模型来确定如何绘制按钮。按钮的另外一个重要功能是,它的状态可以改变-当你用鼠标点击它,或者当它处于焦点时按空格或回车键,即可激活按钮。显然,必须有某些东西来监控鼠标和键盘以及按钮得到或失去焦点的情况,以便注意到必要的状态改变。组件负责接收和响应输入的部分就是控制器。

  我们用图来表示所有这些。下图说明了在MVC体系结构中按钮的各个部分的表示。

swing之mvc模式_第1张图片

  现在假定用户用鼠标点击按钮。通过控制器可以探测到该操作,并将其解释为点击按钮的请求。一次点击实际上需要两个步骤-首先按钮被按下然后又被释放。当按下鼠标时,控制器告诉模型改变它的状态,以反映按钮已经按下的事实。现在按钮需要重新绘制,这样可以看到按钮被按下了。要使该重新绘制发生,模型需要生成一个事件,通知视图它的状态已经改变,在收到该事件时,视图向模型查询它的新状态并据此重画按钮。当用户释放鼠标时,控制器将探测到它并再次改变模型,以便使按钮的状态改变到并未按下。这使得模型向视图产生另一个事件,结果按钮会重新绘制成弹出状态。这种从压下到弹出的特定状态改变,还使得模型产生另一个事件,可以发送到应用程序代码,表示按钮已经被点击了。

  Swing按钮是JButton,实际上它由几部分组成:

  1、实现模型的类的实例。如果是普通的按钮,该类是DefaultButtonModel。

  2、知道如何绘制按钮的类的实例,它完成视图的任务。对普通的按钮而言是BasicButtonUI。

  3、响应用户输入的类的实例,这时控制器的任务。对于按钮来说,该角色由BasicButtonListener类担任。

  4、一个包装类,提供按钮的编程接口并隐藏其他部分,即JButton。

2 控制器内部实现机制

  现在我们已经了解到MVC的控制器在Swing中用来监控鼠标、键盘以及组件获得失去焦点等。当鼠标被按下时,AWT-Windows线程从底层操作系统捕获到这个消息,然后放入一个EventQueue事件队列中,AWT事件调度线程从该事件队列取出这个消息事件并派发该事件,最终BasicButtonListener在事件处理方法中改变模型中的状态,而模型状态改变会导致视图重新绘制以反映模型的状态改变。

 

swing之mvc模式_第2张图片

  EventQueue的dispatchEvent方法会调用对应的Component对象的dispatchEvent方法,最终会调用不同的xxxListener的不同事件处理方法。当鼠标在按钮上按下时,最终会调用BasicButtonListener的mousePressed( MouseEvent e )方法,该方法会改变DefaultButtonModel的状态以表示按钮已被按下,最后模型发送事件通知视图重画。

3、源代码分析

 

 swing进行事件分发,当按钮按下时,BasicButtonListener进行处理,关键代码如下:

 

[java]   view plain copy print ?
  1.     public void mousePressed(MouseEvent e) {  
  2.        if (SwingUtilities.isLeftMouseButton(e) ) {  
  3.       AbstractButton b = (AbstractButton) e.getSource();  
  4.   
  5.       if(b.contains(e.getX(), e.getY())) {  
  6.           long multiClickThreshhold = b.getMultiClickThreshhold();  
  7.           long lastTime = lastPressedTimestamp;  
  8.           long currentTime = lastPressedTimestamp = e.getWhen();  
  9.           if (lastTime != -1 && currentTime - lastTime < multiClickThreshhold) {  
  10.           shouldDiscardRelease = true;  
  11.           return;  
  12.           }  
  13.     <span style="color:#ff0000;">//改变model层  
  14. </span><span style="color:#ff0000;">         ButtonModel model = b.getModel();  
  15.          if (!model.isEnabled()) {  
  16.             // Disabled buttons ignore all input...  
  17.         return;  
  18.          }  
  19.          if (!model.isArmed()) {  
  20.         // button not armed, should be  
  21.                 model.setArmed(true);  
  22.          }  
  23. </span>      model.setPressed(true);  
  24.          if(!b.hasFocus() && b.isRequestFocusEnabled()) {  
  25.             b.requestFocus();  
  26.          }              
  27.       }   
  28.        }  


 

DefaultButtonModel类

 

[java]   view plain copy print ?
  1. public void setArmed(boolean b) {  
  2.     if(isMenuItem() &&   
  3.             UIManager.getBoolean("MenuItem.disabledAreNavigable")) {  
  4.         if ((isArmed() == b)) {  
  5.             return;  
  6.         }  
  7.     } else {  
  8.         if ((isArmed() == b) || !isEnabled()) {  
  9.             return;  
  10.         }  
  11.     }  
  12.           
  13.     if (b) {  
  14.         stateMask |= ARMED;  
  15.     } else {  
  16.         stateMask &= ~ARMED;  
  17.     }  
  18.         <span style="color:#ff0000;"> fireStateChanged();//发送事件 变更消息,其中包括BasicButtonListener类,触发重新渲染操作  
  19. an>    }  

 BasicButtonListener的状态改变处理逻辑:

[java]   view plain copy print ?
  1. public void stateChanged(ChangeEvent e) {  
  2. tractButton b = (AbstractButton) e.getSource();  
  3.     b.repaint();  
  4. }  


MVC结构图:

 swing之mvc模式_第3张图片

swing之mvc模式_第4张图片

你可能感兴趣的:(swing之mvc模式)