Jtable_Swing part 9


Trong phần này chúng ta sẽ tìm hiểu về cách thêm và xóa dữ liệu ở trong một bảng. Để thay đổi dữ liệu trong bảng, chúng ta cần thay đổi TableModel của chúng ta và sau đó thông báo cho listener của nó (hay nói cách khác chính là JTable) rằng dữ liệu đã bị thay đổi.

Đoạn mã dưới đây là ví dụ minh họa cho một bảng có 1 cột. Có một ô chữ để cho phép chúng ta thêm những dòng mới vào trong bảng.

  1. public class RowAdder extends JFrame{
  2.     protected SimpleModel tableData;
  3.     protected JTable table;
  4.     protected JTextField textField;
  5.     public static void main(String[ args) {
  6.         RowAdder ra = new RowAdder();
  7.         ra.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  8.         ra.setSize(400, 300);
  9.         ra.setVisible(true);
  10.     }
  11.     public RowAdder(){
  12.         Container pane = getContentPane();
  13.         pane.setLayout(new BorderLayout());
  14.         tableData = new SimpleModel();
  15.         table = new JTable(tableData);
  16.         table.getColumnModel().getColumn(0).setPreferredWidth(300);
  17.         JScrollPane jsp = new JScrollPane(table);
  18.         pane.add(jsp, BorderLayout.CENTER);
  19.         textField = new JTextField();
  20.         textField.addActionListener(new ActionListener() {
  21.             public void actionPerformed(ActionEvent event) {
  22.                 addLineToTable();
  23.             }
  24.         });
  25.         pane.add(textField, BorderLayout.SOUTH);
  26.     }
  27.     protected void addLineToTable(){
  28.         tableData.addText(textField.getText());
  29.         textField.setText(“”);
  30.     }
  31.     class SimpleModel extends AbstractTableModel{
  32.         protected Vector textData = new Vector();
  33.         public void addText(String text){
  34.             textData.addElement(text);
  35.             fireTableDataChanged();
  36.         }
  37.         public int getRowCount(){
  38.             return textData.size();
  39.         }
  40.         public int getColumnCount(){
  41.             return 1;
  42.         }
  43.         public Object getValueAt(int row, int column){
  44.             return textData.elementAt(row);
  45.         }
  46.     }
  47. }

Khi chạy chương trình, chúng ta nhập chữ vào trong ô chữ sau đó nhấn Enter. Một dòng mới trong sẽ được thêm vào JTable của chúng ta như hình dưới đây:

Khi chúng ta nhấn phím Enter vào ô chữ, một sự kiện sẽ được sinh ra và xử lý sự kiện đó sẽ gọi phương thứcfireTableDataChanged để cập nhật lại dữ liệu trong bảng. Tuy nhiên phương thức này chỉ được cài đặt trước trong lớp AbstractTableModel, còn nếu cái model của chúng ta mà không phải kế thừa từ lớp AbstractTableModel thì chúng ta sẽ không có phương thức này để mà dùng. Lúc đó chúng ta sẽ phải tự tạo ra một phương thức trong model giống như là phương thức fireTableDataChanged của lớp AbstractTableModel. Ví dụ dưới đây minh họa trong trường hợp model của chúng ta cài đặt interface TableModel thì chúng ta sẽ làm như sau:

  1. public class RowAdder extends JFrame{
  2.     protected SimpleModel tableData;
  3.     protected JTable table;
  4.     protected JTextField textField;
  5.     public static void main(String[ args) {
  6.         RowAdder ra = new RowAdder();
  7.         ra.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  8.         ra.setSize(400, 300);
  9.         ra.setVisible(true);
  10.     }
  11.     public RowAdder(){
  12.         Container pane = getContentPane();
  13.         pane.setLayout(new BorderLayout());
  14.         tableData = new SimpleModel();
  15.         table = new JTable(tableData);
  16.         table.getColumnModel().getColumn(0).setPreferredWidth(300);
  17.         JScrollPane jsp = new JScrollPane(table);
  18.         pane.add(jsp, BorderLayout.CENTER);
  19.         textField = new JTextField();
  20.         textField.addActionListener(new ActionListener() {
  21.             public void actionPerformed(ActionEvent event) {
  22.                 addLineToTable();
  23.             }
  24.         });
  25.         pane.add(textField, BorderLayout.SOUTH);
  26.     }
  27.     protected void addLineToTable(){
  28.         tableData.addText(textField.getText());
  29.         textField.setText(“”);
  30.     }
  31.     class SimpleModel implements TableModel{
  32.         protected Vector textData = new Vector();
  33.         protected EventListenerList listenerList = new EventListenerList();
  34.         public void addText(String text){
  35.             textData.addElement(text);
  36.             notifyListenersOfDataChange();
  37.         }
  38.         public void notifyListenersOfDataChange(){
  39.             TableModelEvent event= new TableModelEvent(this);
  40.             Object[ listeners = listenerList.getListenerList();
  41.             for(int i = 0; i< listeners.length; i++){
  42.                 if(listeners<img src=”http://hp-aptech.edu.vn/emoticons/emotion-55.gif” alt=”Idea” /> == TableModelListener.class){
  43.                     TableModelListener listener = (TableModelListener) (listeners[i+1]);
  44.                     listener.tableChanged(event);
  45.                 }
  46.             }
  47.         }
  48.         public int getRowCount(){
  49.             return textData.size();
  50.         }
  51.         public int getColumnCount(){
  52.             return 1;
  53.         }
  54.         public Object getValueAt(int row, int column){
  55.             return textData.elementAt(row);
  56.         }
  57.         public String getColumnName(int columnIndex) {
  58.             return “A”;
  59.         }
  60.         public Class getColumnClass(int columnIndex) {
  61.             return String.class;
  62.         }
  63.         public boolean isCellEditable(int rowIndex, int columnIndex) {
  64.             return false;
  65.         }
  66.         public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
  67.             textData.setElementAt(aValue, rowIndex);
  68.         }
  69.         public void addTableModelListener(TableModelListener l) {
  70.             listenerList.add(TableModelListener.class, l);
  71.         }
  72.         public void removeTableModelListener(TableModelListener l) {
  73.             listenerList.remove(TableModelListener.class, l);
  74.         }
  75.     }
  76. }

Trong đoạn mã trên, chúng ta tạo ra phương thức notifyListenersOfDataChange và phương thức này tương đương với phương thức fireTableDataChanged khi mà chúng ta dùng AbstractTableModel. Bản chất vẫn là gọi phương thức tableChanged của các listener và truyền vào đó một đối tượng của TableModelEvent. Các listener sẽ được đăng kí với một model qua phương thức addTableModelListener của model đó. Listener trong trường hợp này của chúng ta chính là cái JTable đang tham chiếu đến cái model SimpleModel.

Hiển thị một dòng trong bảng
Trong ví dụ bên trên, khi mà chúng ta nhập chữ vào ô chữ rồi ấn phím Enter, một dòng mới sẽ được thêm vào bảng. Khi một vài dòng đầu được thêm vào, chúng ta sẽ nhìn thấy chúng ngay lập tức. Tuy nhiên, khi số dòng nhiều vượt quá kích thước thì sẽ dẫn đến sự xuất hiện của thanh cuộn dọc. Và đến đây, vấn đề của chúng ta chính là không thể nhìn thấy được dòng vừa được thêm vào bảng trừ khi chúng ta phải cuộn thanh cuộn xuống dưới. Hình dưới đây minh họa cho việc khi mà chúng ta nhập quá 14 dòng vào bảng, nếu không cuộn thanh cuộn xuống dưới, thì từ dòng 15 trở xuống, chúng ta sẽ không nhìn thấy được.

Như vậy, chúng ta phải tìm cách nào đó để cho thanh cuộn tự cuộn xuống khi mà một dòng mới được thêm vào bảng. Chúng ta có làm điều này bằng cách lấy ra đối tượng JViewport của cửa sổ cuộn và sau đó đặt lại vị trí cho nó sao cho dòng cuối cùng của bảng luôn được hiện lên trong cửa sổ cuộn. Chúng ta sửa lớp RowAdder như sau:

  1. public class RowAdder extends JFrame{
  2.     protected SimpleModel tableData;
  3.     protected JTable table;
  4.     protected JTextField textField;
  5.     public static void main(String[ args) {
  6.         RowAdder ra = new RowAdder();
  7.         ra.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  8.         ra.setSize(400, 300);
  9.         ra.setVisible(true);
  10.     }
  11.     public RowAdder(){
  12.         Container pane = getContentPane();
  13.         pane.setLayout(new BorderLayout());
  14.         tableData = new SimpleModel();
  15.         table = new JTable(tableData);
  16.         table.getColumnModel().getColumn(0).setPreferredWidth(300);
  17.         table.addComponentListener(new TableScroller());
  18.         JScrollPane jsp = new JScrollPane(table);
  19.         pane.add(jsp, BorderLayout.CENTER);
  20.         textField = new JTextField();
  21.         textField.addActionListener(new ActionListener() {
  22.             public void actionPerformed(ActionEvent event) {
  23.                 addLineToTable();
  24.             }
  25.         });
  26.         pane.add(textField, BorderLayout.SOUTH);
  27.     }
  28.     protected void addLineToTable(){
  29.         tableData.addText(textField.getText());
  30.         textField.setText(“”);
  31.     }
  32.     class SimpleModel implements TableModel{
  33.         […]
  34.     }
  35.     class TableScroller extends ComponentAdapter{
  36.         public void componentResized(ComponentEvent event){
  37.             int lastRow = tableData.getRowCount() -1;
  38.             int cellTop = table.getCellRect(lastRow, 0, true).y;
  39.             JScrollPane jsp  = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, table);
  40.             JViewport jvp = jsp.getViewport();
  41.             int portHeight = jvp.getSize().height;
  42.             int position = cellTop – (portHeight – table.getRowHeight() – table.getRowMargin());
  43.             if(position >= 0){
  44.                 jvp.setViewPosition(new Point(0, position));
  45.             }
  46.         }
  47.     }
  48. }

Phương thức componentResized lấy về kích thước và tọa độ của một dòng trong bảng bằng việc gọi phương thứcgetCellRect. Sau đó nó sử dụng vị trí thẳng đứng của dòng, kích thước của viewport, và chiều cao của dòng để điều chỉnh vị trí nhìn của viewport sao cho chúng ta có thể luôn nhìn thấy được dòng cuối cùng của bảng. Sau khi chạy chương trình, bây giờ chúng ta thêm dòng đến đâu, thanh cuộn sẽ tự động cuộn xuống tới đó như hình dưới đây:

Như vậy, trong phần này chúng ta đã biết cách để thêm một dòng mới vào bảng như thế nào. Thêm vào đó, chúng ta cũng biết cách để hiển thị một dòng tại đúng vị trí mà chúng ta mong muốn. Loạt bài “Cách sử dụng JTable của Swing trong java” sẽ dừng ở đây với hi vọng cung cấp cho bạn đọc những kiển thức cơ bản về cách sử dụng JTable – một thành phần rất hay được sử dụng trong các ứng dụng viết bằng java.

2 Responses to “Jtable_Swing part 9”

  1. Swing in Java « Thái Hoàng Hải Says:

    […] 1 Part 2 Part 3 Part 4 Part 5 Part 6 Part 7 Part 8 Part 9 Share this:TwitterFacebookLike this:LikeBe the first to like this post. Comments RSS […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: