Java: Cách sử dụng JList

JList giới thiệu cho người dùng một nhóm các mục, được hiển thị trong một hoặc nhiều cột, để lựa chọn. Danh sách có thể có nhiều mục, vì vậy chúng thường được đặt trong các ngăn cuộn.

Ngoài JList, các thành phần Swing sau đây trình bày nhiều mục có thể chọn cho người dùng: combo box, menu, table, và checkbox group hoặc radio group. Để hiển thị dữ liệu phân cấp, hãy sử dụng tree.

Các hình sau đây cho thấy hai ứng dụng sử dụng danh sách. Phần này sử dụng những ví dụ này làm cơ sở cho các cuộc thảo luận tiếp theo.

Các hình sau đây cho thấy hai ứng dụng sử dụng List. Bài viết này sử dụng những ví dụ này làm cơ sở cho các thảo luận tiếp theo.

Ảnh chụp nhanh ListDialog, hiển thị một danh sách đơn giảnẢnh chụp nhanh ListDemo, cho phép bạn thêm và xóa các mục danh sáchListDialog
(được sử dụng bởi ListDialogRunner)ListDemo

Phần còn lại của phần này thảo luận về các chủ đề sau:

Tạo Model

Có ba cách để tạo mô hình danh sách:

  • DefaultListModel – cung cấp khá nhiều kiến thức cho bạn. Các ví dụ trong bài viết này sử dụng DefaultListModel.
  • AbstractListModel – bạn quản lý dữ liệu và gọi các phương thức “kích hoạt”. Đối với cách tiếp cận này, bạn phải phân lớp AbstractListModel và triển khai các phương thức getSize và getElementAt kế thừa từ interface ListModel.
  • ListModel – bạn quản lý mọi thứ.

Khởi tạo List

Đoạn mã sau đây là là từ ví dụ ListDialog có tác dụng tạo và thiết lập List:

list = new JList(data); //data có kiểu Object[]
list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
list.setVisibleRowCount(-1);
...
JScrollPane listScroller = new JScrollPane(list);
listScroller.setPreferredSize(new Dimension(250, 80));

Đoạn mã trên sẽ chuyển một mảng đến hàm tạo của List. Mảng chứa các chuỗi được chuyển vào từ một đối tượng khác.

Các hàm tạo khác của JList cho phép bạn khởi tạo List từ một Vector hoặc từ một đối tượng tuân theo interface ListModel. Nếu bạn khởi tạo một danh sách bằng một mảng hoặc vectơ, hàm tạo sẽ ngầm định tạo một ListModel mặc định. ListModel mặc định là bất biến – bạn không thể thêm, bớt hoặc thay thế các mục trong danh sách. Để tạo một danh sách có các mục có thể được thay đổi riêng lẻ, hãy đặt mô hình của danh sách thành một thể hiện của lớp ListModel có thể thay đổi, chẳng hạn như một thể hiện của DefaultListModel. Bạn có thể đặt mô hình của danh sách khi tạo danh sách hoặc bằng cách gọi  phương thức setModel. Xem phần Thêm và xóa mục khỏi List để biết nắm được chi tiết.

Lời gọi setSelectionMode() sẽ chỉ định số lượng mục người dùng có thể chọn và liệu chúng có phải liền nhau hay không; phần tiếp theo cho bạn biết thêm về các cách thức lựa chọn.

Lời gọi setLayoutOrientation() sẽ cho phép danh sách hiển thị dữ liệu của nó trong nhiều cột. Giá trị JList.HORIZONTAL_WRAP chỉ định rằng danh sách sẽ hiển thị các mục của nó từ trái sang phải trước khi chuyển sang một hàng mới. Một giá trị có thể khác là JList.VERTICAL_WRAP, giá trị này chỉ định rằng dữ liệu được hiển thị từ trên xuống dưới (như bình thường) trước khi chuyển sang một cột mới. Các hình sau cho thấy hai khả năng của các giá trị này cùng với giá trị mặc định JList.VERTICAL.

HORIZONTAL_WRAP

VERTICAL_WRAP

THEO CHIỀU DỌC

HORIZONTAL_WRAP

VERTICAL_WRAP

VERTICAL

Kết hợp với lệnh gọi tới setLayoutOrientation, lệnh gọi setVisibleRowCount(-1) làm cho danh sách hiển thị số lượng mục tối đa có thể trong vùng trống có sẵn trên màn hình. Một cách sử dụng phổ biến khác của setVisibleRowCount là chỉ định cho ngăn cuộn của danh sách số hàng mà danh sách muốn hiển thị.

Chọn các mục trong một List

Một danh sách sử dụng một phiên bản của ListSelectionModel để quản lý lựa chọn của nó. Theo mặc định, mô hình lựa chọn danh sách cho phép chọn bất kỳ tổ hợp mục nào tại một thời điểm. Bạn có thể chỉ định một chế độ lựa chọn khác bằng cách gọi phương thức setSelectionMode trong danh sách. Ví dụ, cả ListDialog và ListDemo đều đặt chế độ lựa chọn thành SINGLE_SELECTION (một hằng số được xác định bởi ListSelectionModel) để chỉ một mục trong danh sách có thể được chọn. Bảng sau đây mô tả ba chế độ lựa chọn danh sách:

Chế độ

Mô tả

SINGLE_SELECTION
Một lựa chọn nghĩa là chỉ có thể chọn một mục cùng một lúc

Mỗi lần chỉ có thể chọn một mục. Khi người dùng chọn một mục, bất kỳ mục nào đã chọn trước đó sẽ được bỏ chọn trước.

SINGLE_INTERVAL_SELECTION
Lựa chọn một khoảng thời gian có nghĩa là nhiều mục liền nhau có thể được chọn cùng một lúc

Có thể chọn nhiều mục liền kề. Khi người dùng bắt đầu một phạm vi lựa chọn mới, mọi mục đã chọn trước đó sẽ được bỏ chọn trước.

MULTIPLE_INTERVAL_SELECTION 
Lựa chọn nhiều khoảng thời gian có nghĩa là bất kỳ tổ hợp mục nào có thể được chọn cùng một lúc

Mặc định. Bất kỳ sự kết hợp của các mục có thể được chọn. Người dùng phải bỏ chọn các mục một cách rõ ràng.

Bất kể danh sách của bạn sử dụng lựa chọn nào, List sẽ kích hoạt danh sách các sự kiện lựa chọn bất cứ khi nào lựa chọn thay đổi. Bạn có thể xử lý các sự kiện này bằng cách thêm một trình lắng nghe lựa chọn List vào danh sách bằng phương thức addListSelectionListener. Mỗi lựa chọn danh sách người nghe phải thực hiện một phương thức valueChanged. Đây là phương thức valueChanged dành cho người nghe trong ListDemo:

public void valueChanged(ListSelectionEvent e) {
    if (e.getValueIsAdjusting() == false) {

        if (list.getSelectedIndex() == -1) {
        //Không lựa chọn, không kích hoạt nút.
            fireButton.setEnabled(false);

        } else {
        //Lựa chọn, kích hoạt nút
            fireButton.setEnabled(true);
        }
    }
}

Nhiều sự kiện lựa chọn List có thể được tạo từ một hành động của người dùng, chẳng hạn như một cú nhấp chuột. Phương thức getValueIsAdjusting trả về true nếu người dùng vẫn thao tác lựa chọn. Chương trình cụ thể này chỉ quan tâm đến kết quả cuối cùng của hành động của người dùng, vì vậy phương thức valueChanged chỉ thực hiện điều gì đó nếu getValueIsAdjusting trả về false.

Bởi vì danh sách đang ở chế độ chọn một lần, đoạn mã trên có thể sử dụng getSelectedIndex để lấy chỉ mục của mục vừa chọn. JList cung cấp các phương thức khác để thiết lập hoặc nhận lựa chọn khi chế độ lựa chọn cho phép chọn nhiều mục. Nếu muốn, bạn có thể lắng nghe các sự kiện trên mô hình lựa chọn danh sách của danh sách hơn là trên chính danh sách. ListSelectionDemo là một ví dụ cho thấy cách lắng nghe các sự kiện lựa chọn danh sách trên mô hình lựa chọn danh sách và cho phép bạn thay đổi chế độ lựa chọn của danh sách một cách chủ động.

Thêm và xóa các mục khỏi danh sách

Ví dụ ListDemo mà chúng tôi đã hiển thị trước đây có một danh sách có nội dung có thể thay đổi. Bạn có thể tìm thấy mã nguồn cho ListDemo trong ListDemo.java. Đây là mã ListDemo tạo đối tượng mô hình danh sách có thể thay đổi, đặt các mục ban đầu trong đó và sử dụng ListModel để tạo danh sách:

listModel = new DefaultListModel();
listModel.addElement("Jane Doe");
listModel.addElement("John Smith");
listModel.addElement("Kathy Green");

list = new JList(listModel);

Chương trình cụ thể này sử dụng một thể hiện của lớp DefaultListModel, một lớp do Swing cung cấp. Bất chấp tên lớp, danh sách không có DefaultListModel trừ khi chương trình của bạn làm như vậy một cách rõ ràng. Nếu DefaultListModel không phù hợp với nhu cầu của bạn, bạn có thể viết một mô hình danh sách tùy chỉnh, mô hình này phải tuân theo interface ListModel.

Đoạn mã sau thể hiện phương thức actionPerformed cho trình xử lý hành động được đăng ký trên nút Fire. Dòng lệnh in đậm sẽ xóa mục đã chọn trong danh sách. Các dòng còn lại trong phương thức sẽ vô hiệu hóa nút kích hoạt nếu danh sách bây giờ trống và thực hiện lựa chọn khác nếu không trống.

public void actionPerformed(ActionEvent e) {
    int index = list.getSelectedIndex();
    listModel.remove(index);

    int size = listModel.getSize();

    if (size == 0) { //nếu trống thì disable nút.
        fireButton.setEnabled(false);

    } else { //nếu không thì lấy chỉ mục muốn xóa
        if (index == listModel.getSize()) {
            //chỉ mục đã xóa nằm ở cuối
            index--;
        }

        list.setSelectedIndex(index);
        list.ensureIndexIsVisible(index);
    }
}

Phương thức actionPerformed dùng cho trình xử lý hành động được chia sẻ bởi nút Hire và trường văn bản (textfield):

public void actionPerformed(ActionEvent e) {
    String name = employeeName.getText();

    //Người dùng không soạn tên duy nhất...
    if (name.equals("") || alreadyInList(name)) {
        Toolkit.getDefaultToolkit().beep();
        employeeName.requestFocusInWindow();
        employeeName.selectAll();
        return;
    }

    int index = list.getSelectedIndex(); //lấy chỉ mục đã chọn
    if (index == -1) { //nếu không chọn thì chèn vào vị trí đầu
        index = 0;
    } else {           //nếu không thì chèn vào vị trí đã chọn
        index++;
    }

    listModel.insertElementAt(employeeName.getText(), index);

    //thiết lập lại text field.
    employeeName.requestFocusInWindow();
    employeeName.setText("");

    //chọn mục mới và cho hiện.
    list.setSelectedIndex(index);
    list.ensureIndexIsVisible(index);
}

Đoạn mã trên sử dụng phương thức insertElementAt của ListModel để chèn tên mới vào sau lựa chọn hiện tại hoặc nếu không có lựa chọn nào thì chèn vào đầu danh sách. Nếu bạn chỉ muốn thêm vào cuối danh sách, bạn có thể sử dụng phương thức addElement của lớp DefaultListModel thay thế.

Bất cứ khi nào các mục được thêm vào, xóa khỏi hoặc sửa đổi trong danh sách, thì ListModel sẽ kích hoạt các sự kiện dữ liệu danh sách. Tham khảo ví dụ ListDataEventDemo để biết thông tin về cách lắng nghe các sự kiện này. Ví dụ này tương tự ví dụ ListDemo, nhưng thêm các nút di chuyển các mục lên hoặc xuống trong danh sách.

Viết Trình kết xuất ô tùy chỉnh

Một danh sách sử dụng một đối tượng được gọi là trình kết xuất ô để hiển thị từng mục của nó. Trình kết xuất ô mặc định biết cách hiển thị chuỗi và biểu tượng và nó hiển thị Objects bằng cách gọi toString. Nếu bạn muốn thay đổi cách trình kết xuất mặc định hiển thị các biểu tượng hoặc chuỗi hoặc nếu bạn muốn hành vi khác với những gì được cung cấp bởi toString, bạn có thể triển khai trình kết xuất ô tùy chỉnh. Hãy thực hiện các bước sau để cung cấp trình kết xuất ô tùy chỉnh cho List:

  • Viết một lớp thực thi interface ListCellRenderer.
  • Tạo một thể hiện của lớp của bạn và gọi phương thức setCellRenderer của List và thể hiện của lớp làm đối số.

Ở đây ta có ví dụ về combo box với trình kết xuất tùy chỉnh – và các hộp tổ hợp sử dụng cùng loại trình kết xuất như List. Bạn có thể tham khảo chi tiết về ví dụ có tên CustomComboBoxDemo.

API danh sách

Các bảng dưới đây liệt kê các phương thức cũng như hàm tạo thương được sử dụng của lớp JList. Các phương thức khác mà bạn có nhiều khả năng sẽ gọi trên một đối tượng JList là những phương thức chẳng hạn như setPreferredSize mà các lớp cha của nó cung cấp. Xem API JComponent để biết bảng các phương thức kế thừa thường được sử dụng.

Phần lớn hoạt động của một danh sách được quản lý bởi các đối tượng khác. Các mục trong danh sách được quản lý bởi đối tượng mô hình danh sách, lựa chọn được quản lý bởi đối tượng mô hình lựa chọn danh sách và hầu hết các chương trình đều đặt danh sách trong ngăn cuộn để xử lý việc cuộn. Phần lớn, bạn không cần phải lo lắng về các mô hình vì việc JList tạo ra chúng khi cần thiết và bạn tương tác ngầm với chúng bằng các phương pháp tiện lợi của JList.

Điều đó nói rằng, API để sử dụng List thuộc các danh mục sau:

 

Khởi tạo dữ liệu danh sách

Phương thức hoặc hàm tạo

Mục đích

JList (ListModel)
JList (Đối tượng [])
JList (Vector)
JList ()

Tạo một danh sách với các mục danh sách ban đầu được chỉ định. Các hàm tạo thứ hai và thứ ba mặc nhiên tạo ra một bất biến ListModel; sau đó bạn không nên sửa đổi mảng đã chuyển vào hoặc Vector.

void setModel (ListModel)
ListModel getModel ()

Đặt hoặc lấy mô hình có chứa nội dung của danh sách.

void setListData (Object [])
void setListData (Vector)

Đặt các mục trong danh sách. Các phương thức này mặc nhiên tạo ra một bất biến ListModel.

Hiển thị danh sách

Phương thức

Mục đích

void setVibleRowCount (int)
int getVbrokenRowCount ()

Đặt hoặc lấy thuộc visibleRowCounttính. Đối với VERTICALhướng bố cục, điều này sẽ đặt hoặc lấy số lượng hàng ưa thích để hiển thị mà không yêu cầu cuộn. Đối với các hướng HORIZONTAL_WRAP hoặc bố cục VERTICAL_WRAP, nó xác định cách các ô bao bọc. Xem setLayoutOrientation(int) để biết thêm thông tin. Giá trị mặc định của thuộc tính này là VERTICAL.

void setLayoutOrientation (int)
int getLayoutOrientation ()

Đặt hoặc lấy cách sắp xếp các ô trong danh sách. Các định dạng bố cục có thể có được chỉ định bởi các JListgiá trị được xác định VERTICAL (một cột ô duy nhất; mặc định), HORIZONTAL_WRAP (kiểu “báo” với nội dung theo chiều ngang rồi theo chiều dọc) và VERTICAL_WRAP (kiểu “báo” với nội dung theo chiều dọc rồi theo chiều ngang) .

int getFirstVosystemIndex ()
int getLastVosystemIndex ()

Nhận chỉ mục của mục hiển thị đầu tiên hoặc cuối cùng.

void ensureIndexIsVosystem (int)

Cuộn để chỉ mục được chỉ định hiển thị trong khung nhìn có danh sách này.

Quản lý lựa chọn danh sách

Phương thức

Mục đích

void addListSelectionListener (ListSelectionListener)

Đăng ký để nhận thông báo thay đổi lựa chọn.

void setSelectedIndex (int)
void setSelectedIndices (int [])
void setSelectedValue (Object, boolean)
void setSelectionInterval (int, int)

Đặt lựa chọn hiện tại như được chỉ ra. Sử dụng setSelectionMode để đặt phạm vi lựa chọn có thể chấp nhận được. Đối số boolean chỉ định liệu danh sách có nên cố gắng tự cuộn để mục đã chọn được hiển thị hay không.

int getAnchorSelectionIndex ()
int getLeadSelectionIndex ()
int getSelectedIndex ()
int getMinSelectionIndex ()
int getMaxSelectionIndex ()
int [] getSelectedIndices ()
Đối tượng getSelectedValue ()
Đối tượng [] getSelectedValues ​​()

Nhận thông tin về lựa chọn hiện tại như được chỉ ra.

void setSelectionMode (int)
int getSelectionMode ()

Đặt hoặc lấy chế độ lựa chọn. Giá trị có thể chấp nhận là: SINGLE_SELECTIONSINGLE_INTERVAL_SELECTION, hoặc MULTIPLE_INTERVAL_SELECTION (mặc định), được định nghĩa trong ListSelectionModel.

void clearSelection ()
boolean isSelectionEmpty ()

Đặt hoặc lấy xem bất kỳ mục nào được chọn.

boolean isSelectedIndex (int)

Xác định xem chỉ mục được chỉ định có được chọn hay không.

Quản lý dữ liệu danh sách

Lớp hoặc Phương thức

Mục đích

int getNextMatch (String, int, javax.swing.text.Position.Bias)

Cho chỉ mục bắt đầu, hãy tìm kiếm mục bắt đầu bằng chuỗi đã chỉ định trong danh sách và trả về chỉ mục đó (hoặc -1 nếu không tìm thấy chuỗi). Đối số thứ ba, chỉ định hướng tìm kiếm, có thể là Position.Bias.Forwardhoặc Position.Bias.Backward. Ví dụ: nếu bạn có danh sách 6 mục thì getNextMatch("Matisse", 5, javax.swing.text.Position.Bias.Forward) tìm kiếm chuỗi “Matisse” trong mục ở chỉ mục 5, sau đó (nếu cần) ở chỉ mục 0, chỉ mục 1, v.v.

void setDragEnabled (boolean)
boolean getDragEnabled ()

Đặt hoặc lấy thuộc tính xác định xem có bật xử lý kéo tự động hay không. Xem Kéo và Thả và Truyền dữ liệu để biết thêm chi tiết.

Ví dụ sử dụng List

Bảng này hiển thị các ví dụ sử dụng JList và nơi các ví dụ đó được mô tả.

Ví dụ

Ghi chú

SplitPaneDemo

Chứa một danh sách lựa chọn duy nhất, bất biến.

ListDemo

Trình bày cách thêm và xóa các mục khỏi danh sách trong thời gian chạy.

ListDialog

Triển khai hộp thoại phương thức với danh sách lựa chọn duy nhất.

ListDataEventDemo

Thể hiện việc lắng nghe các sự kiện dữ liệu danh sách trên mô hình danh sách.

ListSelectionDemo

Chứa một danh sách và một bảng chia sẻ cùng một mô hình lựa chọn. Bạn có thể tự động chọn chế độ lựa chọn.

SharedModelDemo

Sửa đổi ListSelectionDemo để danh sách và bảng chia sẻ cùng một mô hình dữ liệu.

CustomComboBoxDemo

Cho biết cách cung cấp trình kết xuất tùy chỉnh cho hộp kết hợp. Vì danh sách và hộp tổ hợp sử dụng cùng một loại trình kết xuất, bạn có thể sử dụng những gì bạn học được ở đó để áp dụng nó cho danh sách. Trên thực tế, một danh sách và một hộp tổ hợp có thể dùng chung một trình kết xuất.