当前位置: 首页 > 面试题库 >

MVC如何与Java Swing GUI一起工作

殳毅
2023-03-14
问题内容

可以说我有一个带有textfeild和button的swing
GUI。当我单击按钮时,我想将该值保存在db中的文本中,并返回joptionpane“成功”消息。
我过去这样做的方式是
Model :JDBC class
View :GUI:在该按钮的“ action执行 ”操作中,我调用带参数的save方法。

   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中正确执行此操作。请以一个小例子对此加以解释。感谢您的时间。


问题答案:

这对于使用Swing之类的东西已经很难理解了,它已经使用了MVC的形式,尽管更像VC-M,其中模型与视图和控制器是分离的,但是视图和控制器是结合在一起的。

考虑一下a 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应尽可能地通用(甚至是custom
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和GUI-根据MVC模式,ActionListeners在哪里?

经过思考

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


 类似资料:
  • 问题内容: 继续我提出的问题,我试图在我的代码库中使用ThreadPoolExecutor。即使反复尝试从Java API文档中理解,我也无法清楚地理解keepAliveTime要在构造函数中传递的参数的功能/目的。希望有人可以通过一些很好的例子向我解释。 Java文档摘录: keepAliveTime-当线程数大于内核数时,这是多余的空闲线程将在终止之前等待新任务的最长时间。 问题答案: 假设您

  • 我想知道是否有人可以帮助我理解如何将转换表合并到Hypermax算法中。任何示例、伪代码、技巧或实现参考都将不胜感激! 一点背景: Hypermax是一种递归游戏树搜索算法,用于n人游戏,通常用于3人游戏。它是最小最大和α-β修剪的扩展 通常,在游戏树中的每个节点,当前玩家(选择者)将查看其可以做出的所有移动,并选择一个最大化其自身效用的移动。不同于最小值/最大值 我理解换位表是如何工作的,但我不

  • 我已经在Angular 2上使用ImmutableJS有一段时间了,因为它在变化检测方面的性能优势。看这里。 然而,我不太清楚,为什么Immutable在默认情况下与Angular 2一起工作。当没有显式数组时,它如何知道如何迭代值并显示它们?它是否每次访问集合的值时都调用?它实现了Angular 2自动调用的某种方法吗? 如果是这样的话,有没有一种方法可以定义您自己的集合来实现这个方法? 例如:

  • 我试图在一个我的组件中使用Tesseract来执行文件上的ocr。 .ts: .html 我遵循了这个,但是这个错误显示了 我应该怎么做才能让这个工作成功?

  • 我只是很难让我的控制器单元测试正常工作,因为在我看来,如果使用OAuth,SpringDoc中的内容是不够的。在我的例子中,是Oauth2和JWT。 我尝试使用,,甚至使用和自定义定义我自己的注释,但在计算安全表达式时,总是在UserSecurityContext中获得匿名用户,无论我在工厂中设置测试上下文的是什么。。。 我提出了我刚刚想到的解决方案,但由于我不确定嘲笑令牌服务是最有效/干净的方法

  • 我的pom。xml如下所示 我已经尝试了三天,使用REdhat入门指南让这个简单的示例代码与Infinispan一起使用,并下载了快速入门zip来运行它,但仍然不起作用!我一直收到Spring JMS的错误“无法连接到foo: 11222”或“池未打开”,然后是关于混合Uber和Jars版本的警告。我开始使用ehcache,这很难实现,因为只有有限的简单示例展示了如何从rest调用等中存储、检索和