简体   繁体   English

MVC如何与Java Swing GUI一起使用

[英]How MVC work with java swing GUI

Lets say I have a swing GUI which has textfeild and button. 可以说我有一个带有textfeild和button的swing GUI。 When I click button I want to save that value in text in db and return joptionpane "success" message. 当我单击按钮时,我想将该值保存在db中的文本中,并返回joptionpane“成功”消息。
The way I used to do this is 我以前这样做的方式是
Model : JDBC class 型号 :JDBC类
View : GUI : In that button's ' action performed ' action I call save method with parameter. 视图 :GUI :在该按钮的“ 操作已执行 ”操作中,我使用参数调用保存方法。

   Controller con = new Controller();
   con.save(text1.getText());

Controller : Write a save method. 控制器 :编写保存方法。

   JDBC db = new                             
   public void save(jTextfeild text){     
   text= text1.getText();
   boolean b= db.putData("insert into .. values(text)");
   if(b){
   JOptionPane("Success"); 
   }
 }


This is how I started. 这就是我开始的方式。 But later I understood this is not how this should be and this is utterly unsafe and stupid. 但是后来我知道这不是应该的样子,这是完全不安全和愚蠢的。
I really want to learn how to do this in MVC properly. 我真的很想学习如何在MVC中正确执行此操作。 Please be kind enough to explain this to with a small example. 请通过一个小例子对此加以说明。 Thank you for your time. 感谢您的时间。

This is a difficult subject to grasp in something like Swing, which already uses a form of MVC, albeit more like VC-M, where the model is separated from the view and controller, but where the view and controller are combined. 这对于使用Swing之类的东西已经很难理解了,它已经使用了MVC的形式,尽管更像VC-M,其中模型与视图和控制器是分离的,但是视图和控制器是结合在一起的。

Think about a JButton , you don't supply a controller to manage how it's triggered when a user presses a key or clicks on it with the mouse, this is done internally and you are notified about the actions when the occur. 考虑一下JButton ,您没有提供控制器来管理用户按下键或用鼠标单击键时如何触发它,这是在内部完成的,并且在发生操作时会收到通知。

With this in mind, you need to allow the view to be semi self managed. 考虑到这一点,您需要允许视图是半自我管理的。 For instance, based on your requirements, the view would have a button and text field. 例如,根据您的要求,该视图将具有一个按钮和文本字段。

The view itself would manage the interactions between the user and the button itself (maintain a internal ActionListener for example), but would then provide notifications to the controller about any state changes that the controller might be interested in. 视图本身将管理用户和按钮本身之间的交互(例如,维护一个内部ActionListener ),但是随后将向控制器提供有关控制器可能感兴趣的任何状态更改的通知。

In a more pure sense of a MVC, the view and model won't know anything about each other and the controller would manage them. 从MVC的角度来看,视图和模型彼此之间一无所知,而控制器将对其进行管理。 This is a little contradictive to how Swing works, as Swing allows you to pass the model directly to the view, see just about any Swing component. 这与Swing的工作方式有点矛盾,因为Swing允许您将模型直接传递到视图,几乎可以看到任何Swing组件。

This doesn't mean that you can't make things work, but you need to know where the concept can falter or needs to be "massaged" to work better. 这并不意味着您无法使事情起作用,而是您需要知道该概念在何处会动摇或需要“按摩”以使其更好地工作。

Normally, when I approach these type of things, I take step back and look at much wider picture, for example. 通常,当我处理这类事情时,我会退后一步,例如看更广阔的前景。

  • You have a view which can accept text and produce text or changes to it 您有一个可以接受文本并产生文本或对其进行更改的视图
  • You have a model which can load and modify text, but provides little other events 您有一个可以加载和修改文本,但几乎不提供其他事件的模型
  • You have a controller which wants to get text from the model and supply it to the view and monitor for changes to the text by the view and update them within the model 您有一个控制器,该控制器希望从模型中获取文本并将其提供给视图,并监视视图对文本的更改并在模型中更新它们

Now, MVC works REALLY well with the concept of "code to interfaces (not implementation)", to that extent, I tend to start with the contracts... 现在,MVC在“代码到接口(不是实现)”的概念上工作得非常好,在某种程度上,我倾向于从合同开始。

View contract... 查看合同...

public interface TextView {

    public void setText(String text);
    public String getText();
    public void addTextViewObserver(TextViewObserver observer);
    public void removeTextViewObserver(TextViewObserver observer);

}

public interface TextViewObserver {
    public void textWasChanged(TextView view);
}

Now, one of the requirements of the view is to generate events when the text has changed in some meaningful way, to this end, I've used a simple observer pattern to implement. 现在,视图的要求之一是当文本以某种有意义的方式更改时生成事件,为此,我使用了一种简单的观察者模式来实现。 Now you could argue that the controller is the observer, but to my mind, the controller may have functionality that I don't want to expose to the view (like the model for instance) 现在您可以争辩说控制器是观察者,但是在我看来,控制器可能具有我不想公开给视图的功能(例如模型)

Model contract... 示范合同...

Next comes the model... 接下来是模型...

public interface TextModel {
    public String getText();
    public void setText(String text);
}

pretty simple really. 真的很简单。 Now, you might consider adding some kind of Exception to these methods to allow the model the ability to fail for some reason, but the Exception should be as generic as you can make it (or even a custom Exception ), so that you can replace the implementation should you need to 现在,您可以考虑向这些方法添加某种Exception ,以允许模型由于某种原因而失败,但是Exception应该与您可以做到的一样通用(甚至是自定义Exception ),以便可以替换您需要执行的操作

Controller contract... 控制器合同...

And finally, the controller... 最后,控制器...

public interface TextViewController {

    public TextView getTextView();
    public TextModel getTextModel();

}

again, pretty simple. 再次,非常简单。 You might have a more complex requirement for your controller, but for this example, this is about all we really need. 您可能对控制器有更复杂的要求,但是对于本示例,这就是我们真正需要的。

Implementations... 实施...

View... 视图...

public class TextViewPane extends JPanel implements TextView {

    private JTextField textField;
    private JButton updateButton;
    private List<TextViewObserver> observers;

    public TextViewPane() {
        observers = new ArrayList<>(25);
        textField = new JTextField(25);
        updateButton = new JButton("Update");
        updateButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                fireTextWasChanged();
            }
        });

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        add(textField, gbc);
        add(updateButton, gbc);
    }

    @Override
    public void setText(String text) {
        textField.setText(text);
    }

    @Override
    public String getText() {
        return textField.getText();
    }

    @Override
    public void addTextViewObserver(TextViewObserver observer) {
        observers.add(observer);
    }

    @Override
    public void removeTextViewObserver(TextViewObserver observer) {
        observers.remove(observer);
    }

    protected void fireTextWasChanged() {
        for (TextViewObserver observer : observers) {
            observer.textWasChanged(this);
        }
    }

}

Model... 模型...

public class SimpleTextModel implements TextModel {

    private String text = "This is some text";

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

    @Override
    public void setText(String text) {
        this.text = text;
    }

}

Controller... 控制器...

public class SimpleTextController implements TextViewController, TextViewObserver {

    private TextView view;
    private TextModel model;

    public SimpleTextController(TextView view, TextModel model) {
        this.view = Objects.requireNonNull(view, "TextView can not null");
        this.model = Objects.requireNonNull(model, "TextModel can not be null");
        view.addTextViewObserver(this);
    }

    @Override
    public TextView getTextView() {
        return view;
    }

    @Override
    public TextModel getTextModel() {
        return model;
    }

    @Override
    public void textWasChanged(TextView view) {
        getTextModel().setText(view.getText());
    }
}

Putting it together... 把它放在一起...

TextViewPane view = new TextViewPane();
TextModel model = new SimpleTextModel();
TextViewController controller = new SimpleTextController(view, model);

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(view);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

Now, all this is just an example of one possible solution. 现在,所有这些只是一个可能解决方案的示例。 You could have a controller implementation which has a particular implementation of the model or view or both, for example. 例如,您可以具有一个控制器实现,该控制器实现具有模型或视图或两者的特定实现。

The point is, you just shouldn't care. 关键是,您根本不在乎。 The controller doesn't care how the view is implemented, it only cares that it will generate textWasChanged events. 控制器不在乎视图的实现方式,只在乎它将生成textWasChanged事件。 The model doesn't care about the view at all (and visa-versa) and the controller doesn't care about model, only that it will get and set some text. 模型根本不关心视图(反之亦然),控制器也不关心模型,只是它会获取并设置一些文本。

For a more complex example, you can have a look at Java and GUI - Where do ActionListeners belong according to MVC pattern? 对于更复杂的示例,您可以看一下Java和GUI-根据MVC模式,ActionListeners在哪里?

After thoughts 经过思考

  • This is just ONE possible way to approach the problem. 这只是解决问题的一种可能方法。 For example, you could limit the view to a single observer. 例如,您可以将视图限制为单个观察者。
  • You should always be thinking "can I change any one part of the MVC and will it still work?" 您应该一直在思考“我可以更改MVC的任何一部分,并且它仍然可以工作吗?” This makes you think about the possible issues that changing any one part of the implementation might have on the surrounding contracts. 这使您考虑更改实施的任何一部分对周围合同可能产生的问题。 You should get to the point that it simply doesn't matter how each layer is implemented 您应该指出,每一层的实现方式都无关紧要
  • A view may act as a controller for another sub-view (or act as a container for another controller of a sub-view). 视图可以充当另一个子视图的控制器(或充当子视图的另一个控制器的容器)。 This can scare people sometimes, but it's possible for a view to act as parent container for one or more sub controllers/views, this allows you to develop complex UIs 有时这可能使人们感到恐惧,但是视图有可能充当一个或多个子控制器/视图的父容器,这使您可以开发复杂的UI
  • Don't expose implementation details in your contracts, for example, the model shouldn't throw a SQLException , as another implementation might not be based on a SQL based solution. 不要在合同中公开实现的详细信息,例如,该模型不应抛出SQLException ,因为另一个实现可能不基于基于SQL的解决方案。 Don't expose UI elements, this means that ALL implementations would then need to implement those elements. 不要公开UI元素,这意味着所有实现都需要实现那些元素。 What happens if I want a implementation of the view that presents a JComboBox to the user instead of JTextField ? 如果我想实现将JComboBox呈现给用户而不是JTextField的视图的实现,该怎么办? This is also the reason I don't use a ActionListener in the view contract, because I have no idea how a textWasChanged event might actually be generated by an implementation of the view 这也是我在视图协定中不使用ActionListener的原因,因为我不知道如何通过视图的实现实际生成textWasChanged事件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM