2011-04-29 104 views
12

我想以有意義的方式使用Swing將MVC設計應用於我的Java應用程序。因此我的問題是,控制器如何在Java Swing中構造?Java Swing中的控制器是什麼?

我心裏有兩個選擇:

  1. 每個組件監聽器是一個自己的類,作爲控制器封裝的一部分
  2. 每個組件監聽器視圖包,它代表了調用內部的匿名類一個帶控制器方法的類。

既可能嗎?這是一個偏好問題,還是它有明確的定義?

+0

另請參閱此[答案](http://stackoverflow.com/questions/3066590/gui-problem-after-rewriting-to-mvc/3072979#3072979)。 – trashgod 2011-04-29 11:28:39

+0

請注意,MVC可能適用於低級組件(例如JTextField),但在應用程序級別,其他模式通常更好;想到2種模式:MVP和PresentationModel(我稱之爲第二種模式MVPM,但這不是官方術語)。 – jfpoilpret 2011-04-29 11:50:41

回答

23

控制器構成組件接口的另一半 ,主要是 交互的一半。控制器需要 保護鼠標和鍵盤事件。

在Swing組件如JButton等是控制器。和所有的監聽器類重定向事件模型,有你的業務邏輯

例如:

主程序

import javax.swing.*; 

public class CalcMVC { 
    //... Create model, view, and controller. They are 
    // created once here and passed to the parts that 
    // need them so there is only one copy of each. 
    public static void main(String[] args) { 

     CalcModel  model  = new CalcModel(); 
     CalcView  view  = new CalcView(model); 
     CalcController controller = new CalcController(model, view); 

     view.setVisible(true); 
    } 
} 

查看

import java.awt.*; 
import javax.swing.*; 
import java.awt.event.*; 

class CalcView extends JFrame { 
    //... Constants 
    private static final String INITIAL_VALUE = "1"; 

    //... Components 
    private JTextField m_userInputTf = new JTextField(5); 
    private JTextField m_totalTf  = new JTextField(20); 
    private JButton m_multiplyBtn = new JButton("Multiply"); 
    private JButton m_clearBtn = new JButton("Clear"); 

    private CalcModel m_model; 

    //======================================================= constructor 
    /** Constructor */ 
    CalcView(CalcModel model) { 
     //... Set up the logic 
     m_model = model; 
     m_model.setValue(INITIAL_VALUE); 

     //... Initialize components 
     m_totalTf.setText(m_model.getValue()); 
     m_totalTf.setEditable(false); 

     //... Layout the components.  
     JPanel content = new JPanel(); 
     content.setLayout(new FlowLayout()); 
     content.add(new JLabel("Input")); 
     content.add(m_userInputTf); 
     content.add(m_multiplyBtn); 
     content.add(new JLabel("Total")); 
     content.add(m_totalTf); 
     content.add(m_clearBtn); 

     //... finalize layout 
     this.setContentPane(content); 
     this.pack(); 

     this.setTitle("Simple Calc - MVC"); 
     // The window closing event should probably be passed to the 
     // Controller in a real program, but this is a short example. 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 

    void reset() { 
     m_totalTf.setText(INITIAL_VALUE); 
    } 

    String getUserInput() { 
     return m_userInputTf.getText(); 
    } 

    void setTotal(String newTotal) { 
     m_totalTf.setText(newTotal); 
    } 

    void showError(String errMessage) { 
     JOptionPane.showMessageDialog(this, errMessage); 
    } 

    void addMultiplyListener(ActionListener mal) { 
     m_multiplyBtn.addActionListener(mal); 
    } 

    void addClearListener(ActionListener cal) { 
     m_clearBtn.addActionListener(cal); 
    } 
} 

控制器

import java.awt.event.*; 

public class CalcController { 
    //... The Controller needs to interact with both the Model and View. 
    private CalcModel m_model; 
    private CalcView m_view; 

    //========================================================== constructor 
    /** Constructor */ 
    CalcController(CalcModel model, CalcView view) { 
     m_model = model; 
     m_view = view; 

     //... Add listeners to the view. 
     view.addMultiplyListener(new MultiplyListener()); 
     view.addClearListener(new ClearListener()); 
    } 


    ////////////////////////////////////////// inner class MultiplyListener 
    /** When a mulitplication is requested. 
    * 1. Get the user input number from the View. 
    * 2. Call the model to mulitply by this number. 
    * 3. Get the result from the Model. 
    * 4. Tell the View to display the result. 
    * If there was an error, tell the View to display it. 
    */ 
    class MultiplyListener implements ActionListener { 
     public void actionPerformed(ActionEvent e) { 
      String userInput = ""; 
      try { 
       userInput = m_view.getUserInput(); 
       m_model.multiplyBy(userInput); 
       m_view.setTotal(m_model.getValue()); 

      } catch (NumberFormatException nfex) { 
       m_view.showError("Bad input: '" + userInput + "'"); 
      } 
     } 
    }//end inner class MultiplyListener 


    //////////////////////////////////////////// inner class ClearListener 
    /** 1. Reset model. 
    * 2. Reset View. 
    */  
    class ClearListener implements ActionListener { 
     public void actionPerformed(ActionEvent e) { 
      m_model.reset(); 
      m_view.reset(); 
     } 
    }// end inner class ClearListener 
} 

型號

import java.math.BigInteger; 

public class CalcModel { 
    //... Constants 
    private static final String INITIAL_VALUE = "0"; 

    //... Member variable defining state of calculator. 
    private BigInteger m_total; // The total current value state. 

    //============================================================== constructor 
    /** Constructor */ 
    CalcModel() { 
     reset(); 
    } 

    //==================================================================== reset 
    /** Reset to initial value. */ 
    public void reset() { 
     m_total = new BigInteger(INITIAL_VALUE); 
    } 

    //=============================================================== multiplyBy 
    /** Multiply current total by a number. 
    *@param operand Number (as string) to multiply total by. 
    */ 
    public void multiplyBy(String operand) { 
     m_total = m_total.multiply(new BigInteger(operand)); 
    } 

    //================================================================= setValue 
    /** Set the total value. 
    *@param value New value that should be used for the calculator total. 
    */ 
    public void setValue(String value) { 
     m_total = new BigInteger(value); 
    } 

    //================================================================= getValue 
    /** Return current calculator total. */ 
    public String getValue() { 
     return m_total.toString(); 
    } 
} 
+1

http://www.leepoint.net/notes-java/GUI/structure/40mvc.html – 2014-03-20 08:55:10

0

我心裏有兩個選擇:

  1. 每個組件監聽器是一個自己的類,如控制器 包
  2. 每個組件監聽器的一部分,是認爲 封裝內部的匿名類使用控制器方法將其呼叫委託給 類。是否可以使用 ?

都可以,但我更喜歡寫類,它實現了所有actionListioner並分配相同的所有組件在您的應用程序。通過這種方式,您可以在單點上跟蹤應用中的所有操作。 也可以用這種方法使您的視圖與控制器區分開來。

0

對於視圖和控制器能夠清晰的分離,你可以做這樣的:

public class MyView extends SomeSwingComponent { 

    private Controller controller; 
    public View(Controller controller) { 
    this.controller = controller; 
    JButton saveButton = new JButton("Save"); 
    button.addActionListner(controller.getSaveButtonListener()); 
    } 
} 

public class MyController implements Controller { 
    private ActionListener saveButtonListener; 
    @Override 
    public ActionListener getSaveButtonListener() { 
    if (saveButtonListener == null) { 
     saveButtonListener = new ActionListener() { 
     // ... 
     } 
    } 
} 

現在我們可以實現不同的控制器可能是方便,如果我們要使用查看不同模型的組件。該控制器是實際視圖實例的策略

在大多數情況下,將偵聽器定義爲匿名類就足夠了,因爲他們通常只是在控制器實例上調用方法。我通常使用監聽器作爲簡單的調度器 - 他們收到通知並將消息發送到另一個對象。一個監聽者類應該實現太多的業務邏輯,這超出了它的責任。

8

Platzhirsch,

好傢伙,這是一個SERIOUSLY重量級的問題......其中一個沒有人會在論壇帖子中充分回答。這個artice Java SE Application Design With MVCRobert Eckstein(Java神之一)詳細討論了這個問題。個人而言,我最終使用MVC的「變體」,我稱之爲MBVC(模型業務視圖控制器),它實際上非常接近MVVMC ... MVVM廣泛用於.NET循環;添加一個對我有意義的控制器,因爲我有一些Web MVC的經驗。我希望在閱讀上面的文章之前,我會介紹MVC-ise我的應用程序。你仍然可以在Sun的(現在是甲骨文的)Java論壇上閱讀我相當困惑的帖子。

乾杯。基思。

1

該視圖將包含GUI設計。視圖的actionPerformed方法應標識事件,並根據事件調用ControllerInterface上的各個方法。控制器的實現將實現這個ControllerInterface,並且在這裏實現由視圖調用的方法。這些方法可能會以某種方式與模型進行交互。模型本身將有一種方法來註冊觀察者(在這種情況下,視圖,順便說一下,甚至控制器都可以註冊),並且每次模型更改時都會更新觀察者。這基本上就是你如何構建應用程序。有關MVC的詳細信息,你也可以參考: here!

4

雖然搖擺框架已經實現了MVC的形式(顯性模型; JXyz & UI類=控制器&視圖),這種嚴格的分離應用很少使用水平,看起來很奇怪。

首先,我建議遵循以下設計:

  • 實現使用POJO客戶端業務邏輯
  • 包裹的POJO用在需要的地方自定義的Swing模型(ListModel的,TableModel的)
  • 使用一個GUI Builder設計的GUI
  • 使用Mediator模式偵聽事件(自定義父JPanel的,如果需要它的孩子和更新其他的孩子或自己火災事件的事件監聽)

如果您想更進一步,請使用NetBeans平臺等RCP(非常推薦)。