【问题标题】:How MVC work with java swing GUIMVC 如何与 java swing GUI 一起工作
【发布时间】:2015-10-13 02:59:45
【问题描述】:

假设我有一个带有 textfeild 和按钮的摇摆 GUI。当我单击按钮时,我想将该值保存在 db 中的文本中并返回 joptionpane“成功”消息。
我以前这样做的方式是
模型:JDBC 类
查看:GUI:在该按钮的“执行的操作”操作中,我使用参数调用保存方法。

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

控制器:写一个保存方法。

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


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

【问题讨论】:

  • "But later I understood this is not how this should be and this is utterly unsafe and stupid...." -- 请详细说明:什么是完全不安全和愚蠢的?
  • sql 注入,这不是真正使用 mvc 的方式
  • 看看我的Retro Snake Game 文章,了解如何在相当复杂的 Swing 应用程序中使用 MVC 模式。
  • 谢谢@GilbertLeBlanc.. 我会调查的..

标签: java swing user-interface model-view-controller


【解决方案1】:

这是一个难以掌握的主题,例如 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);
}

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

合同范本...

接下来是模型...

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

真的很简单。现在,您可能会考虑在这些方法中添加某种Exception 以允许模型因某种原因失败,但Exception 应该尽可能通用(甚至是自定义Exception) ,以便您可以在需要时替换实现

控制器合约...

最后,控制器...

public interface TextViewController {

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

}

再次,非常简单。您可能对控制器有更复杂的要求,但对于本示例,这就是我们真正需要的全部内容。

实现...

查看...

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

}

型号...

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

}

控制器...

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

把它放在一起......

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

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

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

更复杂的例子可以看Java and GUI - Where do ActionListeners belong according to MVC pattern?

经过思考

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

【讨论】:

  • 我不会称其为完美,这只是实现的一种可能方式;)。很高兴它有帮助
  • 请注意,在 Swing 中,模型和视图部分都有事件,而您的示例仅在视图部分中有它们。我认为您也需要在模型方面进行更改。您如何在多个视图之间共享您的模型,并在通过一个特定视图更改模型时让所有视图自行更新
  • @Robin 我的例子很简单,我没有看到模型需要生成事件,在这个例子中。这并不意味着它不能,只是我没有'看不出有必要为这个例子添加一个。我相信我所做的链接示例
  • @Robin 您同样可以争辩说生成这些事件是控制器的责任,作为父控制器,我可能无法(或不想)直接监听模型,但这是一种设计选择;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-01
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多