Hướng dẫn Sử dụng JTable để hiển thị dữ liệu từ Database

Nhưng chúng ta đã biết, JTable là component thuộc swing pakage dùng để cho phép hiển thị thông tin ở dạng hàng, cột. Có thể nói với những thông tin phức tạp, khối lượng thông tin nhiều thì việc sử dụngJTable để thể hiện thông tin theo dạng bảng là cách thể hiện trực quan và thân thiện nhất dành cho người dùng chương trình của chúng ta.

Một số tình huống sử dụng JTable để thể hiện thông tin dạng bảng có thể kể đến như danh sách nhân viên, bảng điểm của học sinh, danh sách hàng hóa trong siêu thị …


Hình minh họa thông tin dạng bảng sử dụng JTable

Việc ứng dụng JTable trong chương trình của chúng ta để hiện thực hóa 1 ResultSet là điều rất nên làm. Trong phạm vi của bài viết này tôi sẽ giới thiệu với các bạn cách sử dụng JTable trong chương trình của mình để thể hiện dữ liệu đọc được từ Database với kết quả là 1 ResultSet.

Để trình bày thông tin dạng bảng (Gồm nhiều hàng, cột) bạn phải thực hiện thông qua các bước như sau :

-          Bước 1: Khai báo 1 đối tượng JTable để thể hiện thông tin dạng bảng và gắn vào container

-          Bước 2: Xây dựng 1 class có tên rsTableModel (Bạn có thể đặt tên khác cũng được) thừa kế từ lớp ảo AbstractTableModel thuộc Pakage javax.swing.table để đọc thông tin từResultSet chuyển thành đối tượng Vector và gắn vào JTable đã tạo ở bước 1.

Đồng thời cũng tại bước này ta sẽ định nghĩa lại 1 số phương thức để sử dụng cho các thuộc tính cơ bản cho đối tượng JTable đã tạo, ví dụ: phương thức cho phép đọc số cột của bảng -getColumnCount(); phương thức cho phép đọc số dòng dữ liệu có trong bảng –getRowCount(); đọc dữ liệu của 1 ô có trong bảng dựa vào vị trí của hàng, cột –getValueAt(int row, int col); Đọc tên của cột tại vị trí nào đó thuộc bảng – getColumnName(int col)

-          Bước 3: tạo 1 đối tượng của lớp rsTableModel vừa định nghĩa ở bước 2, sau đó gắn vàoJTable đã tạo thông qua phương thức setModel của đối tượng JTable

Ba bước này tương đối đơn giản, tuy nhiên nếu không quen thì bạn có thể sẽ thấy hơi rối khi thực hiện bước thứ 2. Bây giờ chúng ta sẽ bắt tay vào tạo 1 JTable để thể hiện danh sách người quen có trong table ttNguoiQuen của database qlLichHen (Tôi vẫn sử dụng cơ sở dữ liệu qlLichHen quen thuộc của chúng ta để minh họa cho phần này, nếu bạn quên cấu trúc của Database này thì có thể mở bài viết này để tham khảo lại “Làm việc với Statement, PreparedStatement và CallableStatement”)

Để cho đơn giản, tôi minh họa cho việc tạo JTable bằng phương pháp kéo thả trong 1 ứng dụng dạng “Java Desktop Application”. Như vậy sau khi đã tạo ra 1 project bằng cách chọn new\Project và chọn loại chương trình là “Java Desktop Application

Bạn lại tiếp tục chọn new/File và tạo 1 JDialog Form cho giao diện “Swing GUI Form” của chúng ta rồi đặt tên cho cửa sổ này là dsNguoiQuen

Bước 1: Bây giờ hãy chọn biểu tượng Table có trong nhóm Swing controls trên thanh công cụ Palleteở màn hình thiết kế của Netbean

và định vị trí cho nó trên cửa sổ đã tạo ở bước trước. JTable này bạn hãy đặt tên cho nó làbangDL. Đến đây, bạn có kết quả thu đước như hình mô tả sau

Vậy là bạn đã thực hiện xong bước thứ nhất. Rất dễ đúng không.

Bước 2: Đây là bước quan trọng nhất, có thể xem bước 1 là tạo ra hình thức cho JTable còn bước 2 là tạo ra nội dung của nó. Như đã nói đến trong phần lý thuyết ở trên, tại bước này bạn phải tạo ra 1 class thừa kết từ lớp AbstractTableModel, sau định nghĩa dữ liệu và các phương thức cơ bản để dùng cho JTable của ta. Bạn hãy thực hiện như sau

-          Tạo 1 class và đặt tên cho nó là rsTableModel, trong phần code của class này, bạn điều chỉnh lại ở phần khai báo để lớp này thừa kế từ AbstractTableModel


public class rsTableModel extends AbstractTableModel 


Như bạn biết 1 Table cần phải có tiêu đề mô tả cho thông tin mà nó chứa trong bảng và dữ liệu để thiể hiện bên trong bảng đó. Chính vì thế, trong lớp rsTableModel tôi cần định nghĩa 2 biến thành viên là 2 object của lớp Vector lần lượt là
          private  Vector colHeaders;        //-- Chứa thông tin là tên của các Field dùng làm ColumnHeader  
          private  Vector tbData;              //-- Phần chứa dữ liệu của JTable

Tiếp theo, chúng ta sẽ định nghĩa constructor cho lóp này với 1 tham số truyền vào là 1ResultSet chứa dữ liệu cần hiển thị cho bảng. Constructor của lớp như sau:
public rsTableModel(ResultSet rsData) throws SQLException {
        ResultSetMetaData rsMeta = rsData.getMetaData();     //-- Đọc MetaData của ResultSet
        int count = rsMeta.getColumnCount();                         //-- Xác định số Field trong ResultSet

        tbData = new Vector();
        colHeaders = new Vector(count);
                  //--- Lặp tương ứng với số phần tử của columnHeaders để lấy tên của từng cột trong bảng
        for (int i = 1; i <= count; i++) {

            colHeaders.addElement(rsMeta.getColumnName(i));
        }
           //--- Lặp từ Record đầu tiên đến cuối ResultSet để lấy dữ liệu và Add vào Table
        while (rsData.next()) {

            //--- Khai báo 1 Object Vector có tên là rowData để chứa dữ liệu đọc từ Table
            Vector dataRow = new Vector(count);

                        //-- Lặp dựa theo số cột của bảng để lấy thông tin của từng đối tượng bỏ vào trong dataRow
            for (int i = 1; i <= count; i++) {

                dataRow.addElement(rsData.getObject(i));
            }
            tbData.addElement(dataRow);
        }
    }

Trong hàm khởi tạo ờ trên, tôi muốn viết 1 hàm tương đối tổng quát để bạn có thể sử dụng nó đọc thông tin cho bất kỳ bảng nào của cơ sở dữ liệu. Chính vì thế tôi đã dùng kỹ thuật truy xuất đến dữ liệu thuộc dạng MetaData của ResultSet. Như bạn đã biết, MetaData là dạng dữ liệu dùng để mô tả những thông tin đặc trưng của bảng (Nói một cách tổng quát thì MetaData là những thông tin mô tả những đặc điểm, những đặc trưng của những loại thông tin khác, trong tình huống này, tôi gọi là những thông tin đặc trưng của bảng cho gần gũi), như vậy trong 1ResultSet bất kỳ, nếu bạn sử dụng phương thức getMetaData() bạn sẽ nhận được kết quả chứa trong 1 ResultSetMetadata là những thông tin đại loại như tên của các cột trongResulset đó cũng như kiểu dữ liệu của cột …

          Quán sát 2 dòng đầu
        ResultSetMetaData rsMeta = rsData.getMetaData();     //-- Đọc MetaData của ResultSet
        int count = rsMeta.getColumnCount();                         //-- Xác định số Field trong ResultSet

 

Vì tôi chẳng biết ResultSet sẽ truyền vào bao gồm bao nhiêu cột ?, các cột tên là gì ?, cho nên tôi đã đọc thông tin dạng MetaData vào trong rsMeta, mục đích là thông qua MetaData đọc được, tôi sẽ tạo ra số cột cũng như đặt tên cho các cột của JTable sẽ sử dụng.

Để ý đoạn code sau bạn sẽ thấy tôi tạo ra cột tiêu đề để dùng cho bảng với kích thược đọc được từ MetaData và lặp trên rsMeta để lấy tên của các cột trong ResultSetMetaData làm tiêu đề cho JTable sẽ sử dụng trên giao diện
        colHeaders = new Vector(count);
                  //--- Lặp tương ứng với số phần tử của columnHeaders để lấy tên của từng cột trong bảng
        for (int i = 1; i <= count; i++) {

            colHeaders.addElement(rsMeta.getColumnName(i));
        }

Đoạn code của vòng lặp While thì chắc các bạn hiểu rồi, chẳng qua tôi tiến hành lặp từ dòng đầu tiên đến dòng cuối cùng của ResultSet để lấy từng dòng dữ liệu gắn vào trong đối tượng Vectorchứa dữ liệu của bảng.

 

Phương thức khởi tạo ở trên là quan trọng nhất, ngoài ra, bạn cũng nên viết thêm 1 số phương thức khác như sau :

Phương thức trả về số cột của JTable
    public int getColumnCount() {
          return colHeaders.size();
    }

Phương thức trả về số hàng dữ liệu có trong JTable
    public int getRowCount() {
        return tbData.size();
    }

          Phương thức đọc về tên của cột bằng cách chỉ ra vị trí của nó
    public String getColumnName(int column) {
        return (String) (colHeaders.elementAt(column));
    }

          Phương thức đọc giá trị của 1 ô thuộc dòng, cột được chỉ định
    public Object getValueAt(int row, int column) {
        Vector rowData = (Vector) (tbData.elementAt(row));
        return rowData.elementAt(column);
    }

          Toàn bộ code của class rsTableModel tôi cung cấp cho các bạn như sau

/**
* @author Nguyen Mai Huy
* Định nghĩa 1 lớp thừa kế từ AbstractTableModel
* để nạp thông tin cho JTable
*/
public class rsTableModel extends  AbstractTableModel {

    //-- Khai báo 2 Vector Object để sử dụng cho JTable
    private  Vector colHeaders;        //-- Chứa thông tin là tên của các Field dùng làm ColumnHeader

    private  Vector tbData;              //-- Phần chứa dữ liệu của JTable
/**
* Constructor truyền vào1 ResultSet để gán dữ liệu cho JTable có Model tham chiếu tới
* @param rset - ResultSet chứa dữ liệu đọc từ Database
* @throws SQLException
*/
    public rsTableModel(ResultSet rsData) throws SQLException {

        ResultSetMetaData rsMeta = rsData.getMetaData();    //-- Đọc MetaData của ResultSet
        int count = rsMeta.getColumnCount();              //-- Xác định số Field trong ResultSet

        colHeaders = new Vector(count);
        tbData = new Vector();
                  //--- Lặp tương ứng với số phần tử của columnHeaders để lấy tên của từng cột trong bảng
        for (int i = 1; i <= count; i++) {

            colHeaders.addElement(rsMeta.getColumnName(i));
        }
           //--- Lặp từ Record đầu tiên đến cuối ResultSet để lấy dữ liệu và Add vào Table
        while (rsData.next()) {

                      //--- Khai báo 1 Object Vector có tên là rowData để chứa dữ liệu tương ứng với mỗi dòng đọc từ Table
            Vector dataRow = new Vector(count);

                      //-- Lặp dựa theo số cột của bảng để lấy thông tin của từng đối tượng
            for (int i = 1; i <= count; i++) {

                dataRow.addElement(rsData.getObject(i));
            }
            tbData.addElement(dataRow);
        }
    }
    /**
* Định nghĩa phương thức lấy số cột của JTable
* @return
*/
    public int getColumnCount() {

        return colHeaders.size();
    }
    /**
* Định nghĩa phương thức lấy số hàng có trong JTable
* @return
*/
    public int getRowCount() {

        return tbData.size();
    }
    /**
* Định nghĩa phương thức lấy dữ liệu tại 1 ô nào đó của bảmg
* @param row - Vị trí của hàng chứa ô dữ liệu cần lấy
* @param column - Vị trí của cột chứa ô dữ liệu cần lấy
* @return Giá trị trả về cho nơi gọi là 1 Object chứa giá trị, để dùng phải Cast lại
*/
    public Object getValueAt(int row, int column) {

        Vector rowData = (Vector) (tbData.elementAt(row));
        return rowData.elementAt(column);
    }
    /**
* Định nghĩa lại hàm lấy tên của cột thứ n trong JTable
* @param column - Vị trí của cột muốn lấy tên
* @return - Kết quả trả về là tên của cột ở dạng chuỗi ký tự
*/
    @Override

    public String getColumnName(int column) {
        return (String) (colHeaders.elementAt(column));
    }
}

Bước 3: Sau khi đã có JTable để thể hiện trên giao diện, đã có rsTableModel để cung cấp dữ liệu, bây giờ ta sẽ thực hiện bước cuối cùng để sử dụng JTable của chúng ta. Hãy quay về cửa sổ mà bạn đã tạo ra ở bước 1, cửa sổ JDialog Form mà bạn đã tạo ra với tên làdsNguoiQuen, hãy mở phần Source code viết thêm 1 hàm làm nhiệm vụ kết nối xuống cơ sở dữ liệu để đọc về ResultSet kết quả, sau đó khai báo 1 đối tượng của lớp rsTableModel với hàm khởi tạo truyền vào ResultSet đã đọc rồi gắn đối tượng này cho JTable thông qua thuộc tính setModel. Phần mã  lệnh như sau

Bây giờ, khi thi hành chương trình, bạn gọi Form này sẽ nhận được kết quả như sau

À, bạn nhớ tạo ra 1 MenuItem trong hệ thống chương trình chính, sau đó chọn cho nó 1actionPerformed với nội dung của sự kiện này là tạo ra 1 đối tượng của lớp dsNguoiQuen mà chúng ta đã tạo ra, sau đó dùng thuộc tính setVisible để làm cho cửa sổ này hiển thị trên màn hình là xong

1 Nhận xét

  1. Em chào thầy ạ. Thầy cho em hỏi tại sao ở bước thứ ba sau khi đã select các column từ db xong thì e không thể thực hiện được thao tác ResultSet kq= kn.getData(strQ)
    và hình như em chưa thấy thầy định nghĩa cho trường này ạ. Mong thầy giải đáp giúp em.

    Trả lờiXóa

Đăng nhận xét

Mới hơn Cũ hơn