Java – Kiến trúc Swing và mô hình MVC

Swing MVCCác component của Swing, bạn có thể nhận ra rằng chúng được thiết kế để tách riêng hai phần giao diện và dữ liệu. Cụ thể hơn các thành phần này được thiết kế dựa trên mô hình MVC (Model-View-Controller). Việc áp dụng mô hình này giúp cho việc quản lý dữ liệu và thay đổi giao diện của các component hiệu quả hơn.

Mô hình MVC

Một ứng dụng thiết kế theo mô hình MVC sẽ được chia thành 3 phần tương ứng như hình sau:

MVC Model

–      Model: lưu trữ hoặc làm cầu nối với dữ liệu.

–      View: hiển thị giao diện và nhận các thông điệp người dùng. View có thể truy vấn dữ liệu từ Model để hiển thị lên màn hình.

–      Controller: làm trung gian chuyển các thông điệp người dùng từ View đến Model và cập nhật lại View khi cần thiết.

Trong Swing, theo quy mô của component, mô hình được thay đổi để phù hợp cho việc áp dụng cho các component.  Cụ thể phần View và Controller sẽ được gộp chung lại trong một UI Object.

Swing MVC

Trong hình minh họa trên, UI Manager được dùng để quản lý giao diện của các component (tính năng look and feel).

GUI-state Model và Application-data Model

Tất cả component trong Swing đều sử dụng một trong hai mô hình là GUI-state hoặc Application-data.

  • GUI-state: lưu giữ trạng thái của component, ví dụ như button có được nhấn xuông hay không, phần tử nào được chọn trong một list,…
  • Application-data: chứa dữ liệu để hiển thị lên component. Dữ liệu này thường nằm ở mức ứng dụng như một table, danh sách phần tử của list.

Không phải tất cả component đều phân biệt rõ ràng mô hình được sử dụng. Ví dụ như JSlider và JprogressBar. Bạn có thể nhận thấy điều này trong bảng liệt kê mô hình mà các component của Swing sử dụng sau:

Component

Model Interface

Model Type

JButton
ButtonModel
GUI

JToggleButton
ButtonModel
GUI/data

JCheckBox
ButtonModel
GUI/data

JRadioButton
ButtonModel
GUI/data

JMenu
ButtonModel
GUI

JMenuItem
ButtonModel
GUI

JCheckBoxMenuItem
ButtonModel
GUI/data

JRadioButtonMenuItem
ButtonModel
GUI/data

JComboBox
ComboBoxModel
data

JProgressBar
BoundedRangeModel
GUI/data

JScrollBar
BoundedRangeModel
GUI/data

JSlider
BoundedRangeModel
GUI/data

JTabbedPane
SingleSelectionModel
GUI

JList
ListModel
data

JList
ListSelectionModel
GUI

JTable
TableModel
data

JTable
TableColumnModel
GUI

JTree
TreeModel
data

JTree
TreeSelectionModel
GUI

JEditorPane
Document
data

JTextPane
Document
data

JTextArea
Document
data

JTextField
Document
data

JPasswordField
Document
data

Thông báo sự thay đổi của Model

Việc thông báo khi model của các component thay đổi là một điều cần thiết để cập nhật lại các trạng thái, giao diện của các đối tượng liên quan. Swing cung cấp hai cách thức để làm điều này:

  • Lightweight: thông báo sự thay đổi trạng thái của model. Sự kiện được sử dụng cho kiểu thông báo này là ChangeEvent. Cách này được dùng cho những component đơn giản và có thể quản lý nhiều thay đổi của model trong một sự kiện.

Ví dụ:

checkbox.addChangeListener(new ChangeListener() {
	public void stateChanged(ChangeEvent e) {

		JCheckBox checkbox=(JCheckBox)e.getSource();
		DefaultButtonModel model = (DefaultButtonModel)checkbox.getModel();
		System.out.println("Selected: "+model.isSelected());
	}
});
  • Stateful: Sử dụng cho các component phức tạp và cho mỗi sự thay đổi cụ thể.

Ví dụ:

String items[] = {"One", "Two", "Three", "Four"};
JList<String> list = new JList<String>(items);
this.add(list);

list.addListSelectionListener
       (new ListSelectionListener() {
   public void valueChanged(ListSelectionEvent e) {

	  JList list=(JList)e.getSource();
	  ListSelectionModel model=(ListSelectionModel)list.getSelectionModel();

      if (!e.getValueIsAdjusting()) {
         System.out.println("Selection index: " + model.getLeadSelectionIndex());
      }
   }
});

Tạo Custom Model

Ví dụ sau tạo một custom model cho JList bằng cách tạo một lớp con của lớp AbstractListModel. Khi kế thừa lớp abtract này, cần hiện thực hai phương thức là getElementAt(index) và getSize().

import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.AbstractListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

class MyListModel extends AbstractListModel {
	String[] data = { "1st","2nd","3rd","4th" };

	public Object getElementAt(int index) {
		return "Item "+data[index];
	}

	public int getSize() {
		return data.length-1;
	}
}

public class CustomModelDemo extends JFrame {

	public CustomModelDemo(){
		super("Custom Model Demo");
		setLayout(new FlowLayout());
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLocationRelativeTo(null);

		setSize(300, 200);
		JList<String> list = new JList<String>(new MyListModel());
		list.setPreferredSize(new Dimension(80, 100));

		list.addListSelectionListener(new ListSelectionListener() {

			@Override
			public void valueChanged(ListSelectionEvent e) {
				if(!e.getValueIsAdjusting())
				{
					JList list=(JList)e.getSource();
					System.out.println(list.getSelectedValue());
				}
			}
		});

		add(list);
	}

	public static void main(String[] a){
		new CustomModelDemo().setVisible(true);
	}

}

Bạn có thể thấy ảnh hưởng của lớp MyListModel trong ví dụ trên đến việc hiển thị dữ liệu lên trên JList khi chạy ví dụ.

Java Swing Custom Model Demo

Cụ thể:

–      Trong phương thức getElementAt() được dùng để lấy giá trị của một phần tử tại vị trí xác định, tôi sẽ nối thêm chuỗi “Item “ phía trước.

–      Bất kì JList khi sử dụng model này đã có sẵn dữ liệu mà không cần thêm vào. Dữ liệu này chính là mảng String[] data trong lớp MyListModel.

–      Mặc dù mảng data có 4 phần tử nhưng khi hiển thị lên JList chỉ có 3 phần tử, nguyên nhân là do phương thức getSize() trả về giá trị data.length-1.

https://yinyangit.wordpress.com

Đánh giá:

Share this:

Thích bài này:

Thích

Đang tải…