2011-05-22 77 views
5

我只想知道關於swing的一些問題 1)如何在swing中使用MVC模型? 2)說我有一個主窗口,我需要做菜單作爲單獨的類,所有組件作爲單獨的類和.which將是最好的方法來集成它如何與多個類的swing一起工作

+1

將問題發佈在示例程序的上方,我們可以幫助您解決問題。 – 2011-05-22 11:48:55

回答

9

好的,這叫做回答過度殺手,所以很抱歉,但是這裏有一個我試圖用簡單的MVC模式來做一件小事的簡單例子:按下一個按鈕並改變文本一個JTextField。這太浪費了,因爲你可以在幾行代碼中做同樣的事情,但它確實在單獨的文件中說明了一些MVC以及模型如何控制狀態。如果有任何疑問,請提出問題!

,所有一起提出,並得到主類的東西開始:

import javax.swing.*; 

public class SwingMvcTest { 
    private static void createAndShowUI() { 

     // create the model/view/control and connect them together 
     MvcModel model = new MvcModel(); 
     MvcView view = new MvcView(model); 
     MvcControl control = new MvcControl(model); 
     view.setGuiControl(control); 

     // EDIT: added menu capability 
     McvMenu menu = new McvMenu(control); 

     // create the GUI to display the view 
     JFrame frame = new JFrame("MVC"); 
     frame.getContentPane().add(view.getMainPanel()); // add view here 
     frame.setJMenuBar(menu.getMenuBar()); // edit: added menu capability 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    // call Swing code in a thread-safe manner per the tutorials 
    public static void main(String[] args) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowUI(); 
     } 
     }); 
    } 
} 

視圖類:

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

public class MvcView { 
    private MvcControl control; 
    private JTextField stateField = new JTextField(10); 
    private JPanel mainPanel = new JPanel(); // holds the main GUI and its components 

    public MvcView(MvcModel model) { 
     // add a property change listener to the model to listen and 
     // respond to changes in the model's state 
     model.addPropertyChangeListener(new PropertyChangeListener() { 
     public void propertyChange(PropertyChangeEvent evt) { 
      // if the state change is the one we're interested in... 
      if (evt.getPropertyName().equals(MvcModel.STATE_PROP_NAME)) { 
       stateField.setText(evt.getNewValue().toString()); // show it in the GUI 
      } 
     } 
     }); 
     JButton startButton = new JButton("Start"); 
     startButton.addActionListener(new ActionListener() { 
     // all the buttons do is call methods of the control 
     public void actionPerformed(ActionEvent e) { 
      if (control != null) { 
       control.startButtonActionPerformed(e); // e.g., here 
      } 
     } 
     }); 
     JButton endButton = new JButton("End"); 
     endButton.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      if (control != null) { 
       control.endButtonActionPerformed(e); // e.g., and here 
      } 
     } 
     }); 

     // make our GUI pretty 
     int gap = 10; 
     JPanel buttonPanel = new JPanel(new GridLayout(1, 0, gap, 0)); 
     buttonPanel.add(startButton); 
     buttonPanel.add(endButton); 

     JPanel statePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); 
     statePanel.add(new JLabel("State:")); 
     statePanel.add(Box.createHorizontalStrut(gap)); 
     statePanel.add(stateField); 

     mainPanel.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap)); 
     mainPanel.setLayout(new BorderLayout(gap, gap)); 
     mainPanel.add(buttonPanel, BorderLayout.CENTER); 
     mainPanel.add(statePanel, BorderLayout.PAGE_END); 
    } 

    // set the control for this view 
    public void setGuiControl(MvcControl control) { 
     this.control = control; 
    } 

    // get the main gui and its components for display 
    public JComponent getMainPanel() { 
     return mainPanel; 
    } 

} 

控制:

import java.awt.event.ActionEvent; 

public class MvcControl { 
    private MvcModel model; 

    public MvcControl(MvcModel model) { 
     this.model = model; 
    } 

    // all this simplistic control does is change the state of the model, that's it 
    public void startButtonActionPerformed(ActionEvent ae) { 
     model.setState(State.START); 
    } 

    public void endButtonActionPerformed(ActionEvent ae) { 
     model.setState(State.END); 
    } 
} 

該模型使用的PropertyChangeSupport對象允許其他對象(在這種情況下視圖)監聽狀態的變化。因此,該模型實際上是我們的「可觀察」,而認爲是「觀察員」

import java.beans.*; 

public class MvcModel { 
    public static final String STATE_PROP_NAME = "State"; 
    private PropertyChangeSupport pcSupport = new PropertyChangeSupport(this); 
    private State state = State.NO_STATE; 

    public void setState(State state) { 
     State oldState = this.state; 
     this.state = state; 
     // notify all listeners that the state property has changed 
     pcSupport.firePropertyChange(STATE_PROP_NAME, oldState, state); 
    } 

    public State getState() { 
     return state; 
    } 

    public String getStateText() { 
     return state.getText(); 
    } 

    // allow addition of listeners or observers 
    public void addPropertyChangeListener(PropertyChangeListener listener) { 
     pcSupport.addPropertyChangeListener(listener); 
    } 

} 

一個簡單枚舉,國家,封裝國家的概念:

public enum State { 
    NO_STATE("No State"), START("Start"), END("End"); 
    private String text; 

    private State(String text) { 
     this.text = text; 
    } 

    @Override 
    public String toString() { 
     return text; 
    } 

    public String getText() { 
     return text; 
    } 
} 

編輯:我看你上面提到的菜單也是如此,所以我添加了這個類並添加了SwingMcvTest類中的幾行菜單支持。請注意,由於代碼分離,因此所有菜單需要執行的都是呼叫控制方法,因此對GUI進行此更改很簡單。它需要什麼都不知道的模型或視圖:

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

public class McvMenu { 
    private JMenuBar menuBar = new JMenuBar(); 
    private MvcControl control; 

    @SuppressWarnings("serial") 
    public McvMenu(MvcControl cntrl) { 
     this.control = cntrl; 

     JMenu menu = new JMenu("Change State"); 
     menu.add(new JMenuItem(new AbstractAction("Start") { 
     public void actionPerformed(ActionEvent ae) { 
      if (control != null) { 
       control.startButtonActionPerformed(ae); 
      } 
     } 
     })); 
     menu.add(new JMenuItem(new AbstractAction("End") { 
     public void actionPerformed(ActionEvent ae) { 
      if (control != null) { 
       control.endButtonActionPerformed(ae); 
      } 
     } 
     })); 

     menuBar.add(menu); 
    } 

    public JMenuBar getMenuBar() { 
     return menuBar; 
    } 
} 

上帝,這是一個很大的代碼做保單的一個微不足道的一點!我提名自己和我的代碼爲本週的計算器Rube Goldberg獎。

+0

@MByD:謝謝!! :) – 2011-05-22 15:09:39

+0

鼓舞人心的(一如既往):)(修正了錯字) – MByD 2011-05-22 15:51:49

+0

不是Rube Goldberg;也許[卡爾韋克](http://en.wikipedia.org/wiki/Loose_coupling)鬆散耦合。 – trashgod 2011-05-22 16:07:07

4

Swing已建立機制,簡化MVC實現。它具有Actions框架。 負責構建視圖的類應該關心JComponent子類的實例化並將它們放置到面板上。應對用戶活動作出反應的每個組件都應具有相應的操作(b.setAction(myAction))。 我通常會創建包com.myapp.actions並將所有操作放在那裏。有時我也會創建抽象動作,但它是特定於應用程序的。動作允許您將表示層的邏輯分開。將行動視爲「模型」的切入點。

典型的應用比操作有更多的控制。一些控件重用相同的操作。例如,你可以通過輸入Ctrl-S,點擊菜單項或工具欄按鈕,使用上下文菜單等來保存文件。但是所有這些控件都會調用相同的動作SaveFileAction

關於你的第二個問題有兩種不同的方法。首先是基於繼承。有些人在需要框架並將所有佈局實現到這個特殊類時擴展JFrame。

其他方法是創建一組生成佈局的實用程序方法。我個人比較喜歡這個。我認爲應該使用繼承,如果你真的需要某個子類的時候,例如當你想重寫某個超類方法時(例如paint()

我希望我的描述有幫助。祝你好運。

相關問題