JAVA MVC_以MVC架構來進行Java GUI程式開發(一)_介面層邏輯和業務層邏輯的拆分
JAVA MVC架構實作
在一些現今程式應用中
很常聽到和使用到的MVC(Model-View-Controller)
最早於1978年的 特里夫·林斯高格 (Trygve Reenskaug) 所提出的軟體工程三層架構
其主張介面層邏輯要跟業務層邏輯分離
不應該混在一塊
使程式各自類可以各司其職(符合單一職責原則)
利於後續程式增多後的維護
Model : 負責儲存及維護一些來自前端使用者介面資料的流程邏輯
(使用者輸入了資料後進行捨麼計算....)
View : 舉凡使用者和前端介面互動的相關流程邏輯接歸屬於View來做控制
(捨麼時候要跳窗,當按下捨麼按鈕做....)
Controller : 介於Model和View兩者之間的溝通橋樑
主要接收View使用者於前端介面的資料後再傳遞給Model並接收來自Model回傳結果
再丟還給View進行介面渲染(更新顯示)的流程。
這樣就不會於系統維護到後期時發生
因為過去都將Model data處理邏輯部分的Code內嵌至View而造成的
因為後續有需要用多個不同的View要來顯示某些同一資料部分
而導致出現重複黏貼Model data code 處理的區塊
開發規格與工具
新增好專案後
建置好三個java package
資源package下存著一張400*200的底圖
針對View 新增一個繼承JFrame的可視化class 及設計面板
首先將預設新增的View JFrame中進入點程式移動至main中
於此的main區塊可先暫時註解掉(留著做針對該類中的 unit test也可以)
程式運行時會自動找main進入點於哪個class的java檔案去運行
針對View 類別
起初預設的程式碼
我們進行介面端的邏輯設計規劃
Defalt View.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.kuanyu.view; /** * * @author chous */ public class View extends javax.swing.JFrame { /** * Creates new form View */ public View() { initComponents(); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code"> private void initComponents() { setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 400, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 300, Short.MAX_VALUE) ); pack(); }// </editor-fold> // Variables declaration - do not modify // End of variables declaration } |
針對JFrame Form設置
在View Form上拖曳一個JPanel (先保有後續調動的彈性不要直接在Form上設置)
JPanel的設置
設置完寬高後會發現沒有自動對齊
這時可以往上拖曳會自動做類似WinForm當中的介面屬性 Dock -> Fill
這裡會發現寬高的即時呈現跑掉
在去改為Default即可
於JPanel上設置AbsoluteLayout (會依以所想要的絕對座標位置來安排)
大致上把前端控制項位置布局完成
JLabel(for 底圖載入)
MVC當中的 Model起手式
Model package添加完後再新建Model.java
Model.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | * and open the template in the editor. */ package com.kuanyu.model; /** * * @author chous */ public class Model { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } //toString() overrite @Override public String toString() { return "Model{" + "name=" + name + '}'; } } |
此段功能之單元測試
MVC 當中的View起手式
針對 View.java先完成初步的程式撰寫
UI 初始化時位置
當UI被拖曳時位置移動更新 (先點擊取得UI位置 再滑鼠拖曳按著不放移動並更新位置)
UI關閉事件
View.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.kuanyu.view; import java.awt.Toolkit; /** * * @author chous */ public class View extends javax.swing.JFrame { private int MouseX; private int MouseY; private int x , screenW; private int y , screenH; /** * Creates new form View Set location center * https://codingnote.blogspot.com/2008/04/java.html */ public View() { initComponents(); this.setLocationRelativeTo(null); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code"> private void initComponents() { jPanel1 = new javax.swing.JPanel(); lblClose = new javax.swing.JLabel(); lblName = new javax.swing.JLabel(); txtName = new javax.swing.JTextField(); btnEnter = new javax.swing.JButton(); btnClear = new javax.swing.JButton(); lblResult = new javax.swing.JLabel(); lblBG = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); setUndecorated(true); setPreferredSize(new java.awt.Dimension(400, 200)); setResizable(false); jPanel1.setMinimumSize(new java.awt.Dimension(400, 200)); jPanel1.setPreferredSize(new java.awt.Dimension(400, 200)); jPanel1.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); lblClose.setFont(new java.awt.Font("新細明體", 1, 18)); // NOI18N lblClose.setForeground(new java.awt.Color(0, 0, 204)); lblClose.setText("X"); lblClose.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { lblCloseMouseClicked(evt); } }); jPanel1.add(lblClose, new org.netbeans.lib.awtextra.AbsoluteConstraints(380, 0, -1, -1)); lblName.setText("Enter your name:"); jPanel1.add(lblName, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 40, -1, -1)); lblName.getAccessibleContext().setAccessibleName(""); jPanel1.add(txtName, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 70, 190, -1)); btnEnter.setText("ENTER"); jPanel1.add(btnEnter, new org.netbeans.lib.awtextra.AbsoluteConstraints(280, 40, -1, -1)); btnClear.setText("CLEAR"); jPanel1.add(btnClear, new org.netbeans.lib.awtextra.AbsoluteConstraints(280, 90, -1, -1)); lblResult.setText("_____"); jPanel1.add(lblResult, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 110, -1, -1)); lblBG.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/kuanyu/resources/bg.png"))); // NOI18N lblBG.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { public void mouseDragged(java.awt.event.MouseEvent evt) { lblBGMouseDragged(evt); } }); lblBG.addMouseListener(new java.awt.event.MouseAdapter() { public void mousePressed(java.awt.event.MouseEvent evt) { lblBGMousePressed(evt); } }); jPanel1.add(lblBG, new org.netbeans.lib.awtextra.AbsoluteConstraints(0, 0, -1, -1)); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); pack(); }// </editor-fold> private void lblBGMouseDragged(java.awt.event.MouseEvent evt) { // TODO add your handling code here: int x = evt.getXOnScreen(); int y = evt.getYOnScreen(); this.setLocation(x - MouseX, y - MouseY); } private void lblBGMousePressed(java.awt.event.MouseEvent evt) { // TODO add your handling code here: MouseX = evt.getX(); MouseY = evt.getY(); } private void lblCloseMouseClicked(java.awt.event.MouseEvent evt) { // TODO add your handling code here: System.exit(0); } // Variables declaration - do not modify private javax.swing.JButton btnClear; private javax.swing.JButton btnEnter; private javax.swing.JPanel jPanel1; private javax.swing.JLabel lblBG; private javax.swing.JLabel lblClose; private javax.swing.JLabel lblName; private javax.swing.JLabel lblResult; private javax.swing.JTextField txtName; // End of variables declaration } |
MVC 當中的Controller起手式
我們說 Controller是 View 以及 Model兩者之間的溝通中介
在定義完對應物件屬性後
進行Ctrl + Shift + I 可自動做缺失對應Package的 import
這裡我們要在main主程式進入點地方
去實體化我們的Controller時 傳入 model , view
因此定義我們的建構子
將原本main主程式區塊稍稍改寫成呼Controller的版本
於Controller中再去針對呼叫的View參數去做面板顯示
最後大致補上一些中介層 View和Model溝通傳輸資料
相關事件即可
Controller.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.kuanyu.controller; import com.kuanyu.model.Model; import com.kuanyu.view.View; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JOptionPane; /** * * @author chous */ public class Controller implements ActionListener { private Model m; private View v; //Constructor public Controller(Model m, View v) { this.m = m; this.v = v; this.v.setVisible(true); //Set Action Commands this.v.getBtnEnter().setActionCommand("ENTER"); this.v.getBtnClear().setActionCommand("CLEAR"); //Add Action Listener this.v.getBtnEnter().addActionListener(this); this.v.getBtnClear().addActionListener(this); } @Override public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); switch (command) { case "ENTER": System.out.println("Enter...."); String name = v.getTxtName().getText(); System.out.println(name); if (!name.equals("")) { m.setName(name); //Send objects from the Model section to View section v.showResult(m); v.getTxtName().setText(""); } else { JOptionPane.showMessageDialog(v, "不可為空", "輸入錯誤", 0); } break; case "CLEAR": System.out.println("Clear...."); v.getTxtName().setText(""); v.getLblResult().setText(""); break; } } } |
最後版的
View.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.kuanyu.view; import com.kuanyu.model.Model; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JTextField; /** * * @author chous */ public class View extends javax.swing.JFrame { private int MouseX; private int MouseY; private int x , screenW; private int y , screenH; /** * Creates new form View Set location center * https://codingnote.blogspot.com/2008/04/java.html */ public View() { initComponents(); this.setLocationRelativeTo(null); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code"> private void initComponents() { jPanel1 = new javax.swing.JPanel(); lblClose = new javax.swing.JLabel(); lblName = new javax.swing.JLabel(); txtName = new javax.swing.JTextField(); btnEnter = new javax.swing.JButton(); btnClear = new javax.swing.JButton(); lblResult = new javax.swing.JLabel(); lblBG = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); setUndecorated(true); setPreferredSize(new java.awt.Dimension(400, 200)); setResizable(false); jPanel1.setMinimumSize(new java.awt.Dimension(400, 200)); jPanel1.setPreferredSize(new java.awt.Dimension(400, 200)); jPanel1.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout()); lblClose.setFont(new java.awt.Font("新細明體", 1, 18)); // NOI18N lblClose.setForeground(new java.awt.Color(0, 0, 204)); lblClose.setText("X"); lblClose.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { lblCloseMouseClicked(evt); } }); jPanel1.add(lblClose, new org.netbeans.lib.awtextra.AbsoluteConstraints(380, 0, -1, -1)); lblName.setText("Enter your name:"); jPanel1.add(lblName, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 40, -1, -1)); lblName.getAccessibleContext().setAccessibleName(""); jPanel1.add(txtName, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 70, 190, -1)); btnEnter.setText("ENTER"); jPanel1.add(btnEnter, new org.netbeans.lib.awtextra.AbsoluteConstraints(280, 40, -1, -1)); btnClear.setText("CLEAR"); jPanel1.add(btnClear, new org.netbeans.lib.awtextra.AbsoluteConstraints(280, 90, -1, -1)); lblResult.setText("_____"); jPanel1.add(lblResult, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 110, -1, -1)); lblBG.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/kuanyu/resources/bg.png"))); // NOI18N lblBG.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { public void mouseDragged(java.awt.event.MouseEvent evt) { lblBGMouseDragged(evt); } }); lblBG.addMouseListener(new java.awt.event.MouseAdapter() { public void mousePressed(java.awt.event.MouseEvent evt) { lblBGMousePressed(evt); } }); jPanel1.add(lblBG, new org.netbeans.lib.awtextra.AbsoluteConstraints(0, 0, -1, -1)); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); pack(); }// </editor-fold> //Getter for Cnntroller using public JButton getBtnClear() { return btnClear; } public JButton getBtnEnter() { return btnEnter; } public JLabel getLblResult() { return lblResult; } public JTextField getTxtName() { return txtName; } //Getter for Cnntroller using public void showResult(Model m){ lblResult.setText("Hi !! " + m.getName() + " This is MVC test"); } private void lblBGMouseDragged(java.awt.event.MouseEvent evt) { // TODO add your handling code here: int x = evt.getXOnScreen(); int y = evt.getYOnScreen(); this.setLocation(x - MouseX, y - MouseY); } private void lblBGMousePressed(java.awt.event.MouseEvent evt) { // TODO add your handling code here: MouseX = evt.getX(); MouseY = evt.getY(); } private void lblCloseMouseClicked(java.awt.event.MouseEvent evt) { // TODO add your handling code here: System.exit(0); } // Variables declaration - do not modify private javax.swing.JButton btnClear; private javax.swing.JButton btnEnter; private javax.swing.JPanel jPanel1; private javax.swing.JLabel lblBG; private javax.swing.JLabel lblClose; private javax.swing.JLabel lblName; private javax.swing.JLabel lblResult; private javax.swing.JTextField txtName; // End of variables declaration } |
Reference link:
https://www.javacodegeeks.com/2017/09/mvc-delivery-mechanism-domain-model.html
留言
張貼留言