MVC如何使用java swing GUI

Dil*_*Dil 0 java model-view-controller user-interface swing

假设我有一个带有textfeild和按钮的swing GUI.当我单击按钮时,我想将该值保存在db中的文本中并返回joptionpane"success"消息.
我以前的方式是
模型:JDBC类
视图:GUI:在该按钮的" 动作执行 "操作中,我使用参数调用save方法.

   Controller con = new Controller();
   con.save(text1.getText());
Run Code Online (Sandbox Code Playgroud)

控制器:编写保存方法.

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


这就是我的开始.但后来我明白这不应该是这样的,这是完全不安全和愚蠢的.
我真的想学习如何在MVC中正确地做到这一点.请用一个小例子来解释这个问题.感谢您的时间.

Mad*_*mer 7

这是一个很难理解的东西,比如Swing,它已经使用了一种MVC形式,虽然更像VC-M,模型与视图和控制器分开,但视图和控制器的组合.

考虑一下JButton,当用户按下某个键或用鼠标点击它时,你不提供一个控制器来管理它是如何触发的,这是在内部完成的,并且会在发生时通知你.

考虑到这一点,您需要允许视图半自我管理.例如,根据您的要求,视图将具有按钮和文本字段.

视图本身将管理用户与按钮本身之间的交互(ActionListener例如,维护内部),但随后会向控制器提供有关控制器可能感兴趣的任何状态更改的通知.

在更纯粹的MVC意义上,视图和模型将不会彼此了解任何事情,控制器将管理它们.这与Swing的工作方式有点矛盾,因为Swing允许您将模型直接传递给视图,只需查看任何Swing组件.

这并不意味着你无法让事情发挥作用,但你需要知道这个概念可能会动摇或需要"按摩"才能更好地发挥作用.

通常,当我接近这些类型的东西时,我会退后一步,看看更广泛的画面,例如.

  • 您有一个视图,可以接受文本并生成文本或更改它
  • 您有一个可以加载和修改文本的模型,但提供的其他事件很少
  • 您有一个控制器想要从模型中获取文本并将其提供给视图并监视视图对文本的更改并在模型中更新它们

现在,MVC在"代码到接口(不是实现)"的概念下工作得非常好,在这种程度上,我倾向于从合同开始......

查看合同......

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);
}
Run Code Online (Sandbox Code Playgroud)

现在,视图的一个要求是在文本以某种有意义的方式发生变化时生成事件,为此,我使用了一个简单的观察者模式来实现.现在您可以争辩控制器是观察者,但在我看来,控制器可能具有我不想暴露给视图的功能(例如模型)

示范合同......

接下来是模特......

public interface TextModel {
    public String getText();
    public void setText(String text);
}
Run Code Online (Sandbox Code Playgroud)

非常简单.现在,您可以考虑Exception在这些方法中添加某种方法,以允许模型由于某种原因而失败,但Exception应该像您可以做到的那样(甚至是自定义Exception),以便您可以替换实现你需要

控制器合同......

最后,控制器......

public interface TextViewController {

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

}
Run Code Online (Sandbox Code Playgroud)

再次,非常简单.您可能对控制器有更复杂的要求,但对于此示例,这是我们真正需要的.

实现...

视图...

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);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

模型...

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

控制器...

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

把它放在一起...

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);
Run Code Online (Sandbox Code Playgroud)

现在,所有这些只是一个可能解决方案的一个例子.例如,您可以拥有一个控制器实现,该实现具有模型或视图的特定实现或两者.

关键是,你应该不在乎.控制器不关心视图是如何实现的,它只关心它将生成textWasChanged事件.该模型根本不关心视图(反之亦然),控制器不关心模型,只是它会得到并设置一些文本.

有关更复杂的示例,您可以查看Java和GUI - ActionListeners根据MVC模式属于哪里?

思绪过后

  • 这只是解决问题的一种可能方式.例如,您可以将视图限制为单个观察者.
  • 你应该总是在思考"我可以改变MVC的任何一部分并且它仍然可以工作吗?" 这使您可以考虑更改实施的任何一部分可能对周围合同产生的可能问题.你应该明白每个层的实现方式并不重要
  • 视图可以充当另一个子视图的控制器(或充当子视图的另一个控制器的容器).这有时会吓到人,但是视图可以作为一个或多个子控制器/视图的父容器,这允许您开发复杂的UI
  • 不要在合同中公开实现细节,例如,模型不应抛出SQLException,因为另一个实现可能不基于基于SQL的解决方案.不要暴露UI元素,这意味着所有实现都需要实现这些元素.如果我想要一个JComboBox向用户呈现的视图的实现而不是JTextField?这也是我ActionListener在视图合约中不使用a的原因,因为我不知道textWasChanged视图的实现如何实际生成事件