控制器創建一個帶有按鈕的新 JFrame。使用 actionListener 可以正確獲取訂單,但在不作業后要求執行該操作。被要求更改視圖上的按鈕名稱文字,但它永遠不會發生。否則,除錯該功能似乎可以運行,但視圖沒有變化。
使用 Java 實作了以下類:
public class Window extends JFrame {
JButton bGoFile;
public static final String FILE = "FILE";
public Window(ActionListener actionListener) {
this.actionListener = actionListener;
setupButtons();
setupView();
}
private void setupButtons() {
bGoFile = new JButton("Button");
bGoFile.addActionListener(actionListener);
bGoFile.setActionCommand(GO_FILE);
}
private void setupView() {
setTitle("Cover pdf to img");
setBounds(300, 90, 900, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
ImageIcon icon = new ImageIcon("./src/resources/logo.jpg");
setIconImage(icon.getImage());
JPanel jp = new JPanel;
jp.add(bGoFile);
add(jp);
}
public void changeButtonName(String name) {
bGoFile.setText(name);
System.out.println("Name should be changed.");
// Here I already tried to user repaint() but with no result.
}
public class WindowController implements ActionListener {
Window window;
public WindowController() {
this.window = new Window(this);
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Action performed");
switch (e.getActionCommand()) {
case GO_FILE -> {
synchronized (this) {
window.changeButtonName("New name");
break;
}
}
}
}
關鍵是顯示了終端上的兩個列印件,但正在運行的視窗上的按鈕名稱沒有改變。
uj5u.com熱心網友回復:
您不應該在控制器中創建視圖的實體。這應該傳遞給控制器??(AKA 使用依賴注入)。
您還應該使用interfaces,因為控制器不應該系結到視圖(或模型)的實作,而應該通過一系列既定的合同和觀察者作業。
所以,讓我們從一些基礎知識開始......
public interface View {
public JComponent getView();
}
public interface Controller<V extends View> {
public V getView();
}
我說的是基本的。但是,interface直接使用這些 s 會變得非常乏味,所以讓我們添加一些助手......
public abstract class AbstractController<V extends View> implements Controller<V> {
private V view;
public AbstractController(V view) {
this.view = view;
}
@Override
public V getView() {
return view;
}
}
public abstract class AbstractView extends JPanel implements View {
@Override
public JComponent getView() {
return this;
}
}
沒什么特別的,但這可以解決很多鍋爐電鍍問題。
接下來,我們要定義我們的視圖的契約......
public interface MainView extends View {
public interface Observer {
public void didPerformGoFile(MainView view);
}
public void addObserver(Observer observer);
public void removeObserver(Observer observer);
public void setDescription(String description);
}
這很簡單。但請注意,這并沒有描述任何型別的實作細節。合約不關心如何didPerformGoFile生成,只關心相關方可以觀察到該行為
接下來,我們要定義或實作MainView...
public class DefaultMainView extends AbstractView implements MainView {
private List<Observer> observers = new ArrayList<>(8);
private JButton goFileButton;
private JLabel descriptionLabel;
public DefaultMainView() {
goFileButton = new JButton("Make it so");
descriptionLabel = new JLabel("...");
descriptionLabel.setHorizontalAlignment(JLabel.CENTER);
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
add(goFileButton, gbc);
add(descriptionLabel, gbc);
goFileButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireDidPerformGoFile();
}
});
}
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
protected void fireDidPerformGoFile() {
for (Observer observer : observers) {
observer.didPerformGoFile(this);
}
}
@Override
public void setDescription(String description) {
descriptionLabel.setText(description);
}
}
和MainController....
public class MainViewController extends AbstractController<MainView> {
public MainViewController(MainView view) {
super(view);
view.addObserver(new MainView.Observer() {
@Override
public void didPerformGoFile(MainView view) {
view.setDescription("Go file!");
}
});
}
}
現在,我們可以將它們放在一起并運行它們...

JFrame frame = new JFrame();
Controller controller = new MainViewController(new DefaultMainView());
frame.add(controller.getView().getView());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
現在,您可能正坐在那里想,“這是為了獲得微薄的收益而做的很多作業”,而實際上您會……錯了。
假設您想goFileAction根據某種狀態(例如用戶的憑據或其他內容)更改控制器回應的方式。您可以將大量邏輯放入其中MainViewController來處理它,或者更簡單的是,完全創建一個不同的控制器(注意:這是“Model-View-Controller”中的模型的用武之地,但由于沒有在你的例子中,我做了“不同”的模型)
public class OverlordController extends AbstractController<MainView> {
public OverlordController(MainView view) {
super(view);
view.addObserver(new MainView.Observer() {
@Override
public void didPerformGoFile(MainView view) {
view.setDescription("Your overload has spoken!");
}
});
}
}
然后,通過簡單地改變...
Controller controller = new MainViewController(new DefaultMainView());
至
Controller controller = new OverlordController(new DefaultMainView());
你改變輸出!
“模型-視圖-控制器”在 Swing 中并不像在其他 API/框架中那樣直接,這是因為 Swing 已經基于 MVC,因此您實際上是將 MVC 包裝在 MVC 上。如果您了解這一點,您可以使其更輕松地作業。
例如,在上面,我沒有ActionListener向控制器公開,而是創建了自己的觀察者,它描述了可能由視圖的實作觸發的實際操作。實際的動作處理發生在視圖本身的實作中。
這很好,因為我們已經解耦了作業流,這也意味著視圖可以自由地以它認為合適的任何方式實作這些操作的觸發器。
您可能還想看看:
- 在 Java Swing 中實作 MVC 的 Controller 部分
- MVC 如何與 java swing GUI 一起作業
- Java 和 GUI - 根據 MVC 模式,ActionListeners 屬于哪里?
- MVC中類之間訊息傳遞的正確方法是什么?
- 遵循傳統(非中介)MVC 模式的監聽器放置
- JTextField 輸入無法更新 MVC 中 TextView 中的輸出
- 多執行緒 MVC 使用多個獨立儀表重新創建平面儀表板
- 在 MVC 設計中將模型物件存盤在哪里?
可運行的示例...
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
Controller controller = new OverlordController(new DefaultMainView());
frame.add(controller.getView().getView());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface View {
public JComponent getView();
}
public interface Controller<V extends View> {
public V getView();
}
public abstract class AbstractController<V extends View> implements Controller<V> {
private V view;
public AbstractController(V view) {
this.view = view;
}
@Override
public V getView() {
return view;
}
}
public abstract class AbstractView extends JPanel implements View {
@Override
public JComponent getView() {
return this;
}
}
public interface MainView extends View {
public interface Observer {
public void didPerformGoFile(MainView view);
}
public void addObserver(Observer observer);
public void removeObserver(Observer observer);
public void setDescription(String description);
}
public class MainViewController extends AbstractController<MainView> {
public MainViewController(MainView view) {
super(view);
view.addObserver(new MainView.Observer() {
@Override
public void didPerformGoFile(MainView view) {
view.setDescription("Go file!");
}
});
}
}
public class OverlordController extends AbstractController<MainView> {
public OverlordController(MainView view) {
super(view);
view.addObserver(new MainView.Observer() {
@Override
public void didPerformGoFile(MainView view) {
view.setDescription("Your overload has spoken!");
}
});
}
}
public class DefaultMainView extends AbstractView implements MainView {
private List<Observer> observers = new ArrayList<>(8);
private JButton goFileButton;
private JLabel descriptionLabel;
public DefaultMainView() {
goFileButton = new JButton("Make it so");
descriptionLabel = new JLabel("...");
descriptionLabel.setHorizontalAlignment(JLabel.CENTER);
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
add(goFileButton, gbc);
add(descriptionLabel, gbc);
goFileButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireDidPerformGoFile();
}
});
}
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
protected void fireDidPerformGoFile() {
for (Observer observer : observers) {
observer.didPerformGoFile(this);
}
}
@Override
public void setDescription(String description) {
descriptionLabel.setText(description);
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/491722.html
