2011-05-22 78 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()

我希望我的描述有帮助。祝你好运。

相关问题