2012-03-02 23 views
5

Mô tả ngắn gọn về sự cố.Tương tác với JTable được cập nhật nhanh chóng với các hàng mới

Giả sử chúng tôi có JTable và người dùng tương tác với nó theo một cách nào đó. TableModel của bảng này liên tục thay đổi. Làm thế nào để đảm bảo rằng khi người dùng cố gắng lấy một số thông tin từ bảng bằng cách tham chiếu một số cột liên tục và hàng hiện đang được chọn (bởi rowIndex của nó mà anh ta nhận được từ JTable), anh ta sẽ không vào tình huống khi TableModel được thay đổi và rowIndex của anh ta thu được từ JTable không còn tương ứng với cùng một giá trị trong TableModel nữa.

Tiếp theo là câu hỏi đầu tiên mà giải thích vấn đề một cách chi tiết hơn:

xem xét sau tình huống:

  1. Có JTable trong đó cho thấy thông tin người dùng về các yêu cầu hiện đang chạy trong một số hệ thống

  2. Khi yêu cầu mới vào hệ thống, hàng mới đang được thêm vào bảng

  3. người dùng có thể tương tác với các bảng bằng cách kích chuột phải vào một hàng (mô hình đơn hàng lựa chọn được sử dụng trong bảng) và tùy chọn chọn từ menu (như: hủy bỏ, hoãn, thử lại, vv)

  4. có riêng lớp thực hiện giao diện ActionListener (lắng nghe bảng) và xử lý tất cả các tương tác của người dùng

  5. Khi người dùng thực hiện một số hành động trên bảng, lớp này kiểm tra hàng được chọn và gán một số giá trị cho hành động của người dùng và sau đó gọi tableModel.getValueAt (indexOfSelectedRow, someValuableDataColumnIndex))

Bây giờ hãy xem xét kịch bản khi hệ thống đang được kiểm tra căng thẳng và yêu cầu được gửi liên tục với tần suất lớn. Điều này, trong trường hợp của tôi, dẫn đến lỗi, khi đôi khi lớp xử lý hành động của người dùng nhận được thông tin sai từ mô hình bảng (hành động được gọi trên một hàng, nhưng hành động được thực hiện cho một hàng khác, thường là tiếp theo). Tôi tin rằng điều này xảy ra bởi vì trong một số lần đầu vào trong hành động xử lý mô hình bảng lớp được thay đổi vì yêu cầu mới được chấp nhận.

Câu hỏi là, cách khắc phục điều này. Tôi đang nghĩ về hai phương pháp:

  • sử dụng một cái gì đó giống như invokeAndWait() để khởi tạo trong lớp xử lý hành vi sử dụng của tôi (không thích ý tưởng này, vì imo nó sẽ dẫn đến lỗi không thể đoán trước kia)

  • tạo lớp người nghe riêng biệt sẽ lắng nghe lựa chọn người dùng trong bảng và lưu trữ dữ liệu từ hàng đã chọn ngay sau khi được chọn riêng biệt với TableModel. Bằng cách này, các hành động xử lý lớp sẽ lấy dữ liệu không phải từ mô hình bảng đang được thay đổi, nhưng từ hàng đã chọn, là hằng số trong kịch bản được mô tả. (không chắc chắn ý tưởng này sẽ hoạt động)

Vui lòng nhận xét ý kiến ​​của tôi và đề xuất ý tưởng của bạn.

Tôi rất tiếc vì không có bất kỳ mã nào ở đây, nhưng mã ban đầu sẽ chiếm quá nhiều không gian và ví dụ về mô hình không phải là điều dễ làm ở đây.

+0

Sau khi suy nghĩ một chút về ý tưởng thứ hai của tôi, tôi nhận ra nó sẽ không hoạt động. Nó có hai bước giống nhau: 1) nhận chỉ mục hàng đã chọn 2) nhận thông tin từ mô hình bảng cho một hàng với chỉ mục đó. Bất kỳ hàng mới nào xuất hiện trong bảng ở giữa hai bước đó sẽ làm mọi thứ trở nên rối loạn. – GrayR

+3

Có bao nhiêu luồng truy cập 'TableModel'? Nếu có nhiều hơn, làm cách nào để đồng bộ hóa quyền truy cập? Xem thêm [sscce] (http://stackoverflow.com/a/7519403/230513) và [Hỏi & Đáp] này (http://stackoverflow.com/q/7787998/230513). – trashgod

+0

@trashgod TableModel chỉ được truy cập bởi một chuỗi. Cũng cảm ơn cho các liên kết, thông tin intresting. Không thể tìm ra bất cứ điều gì hữu ích từ nó như bây giờ, nhưng chắc chắn sẽ xem xét nó sâu sắc hơn. – GrayR

Trả lời

4

Tôi không nghĩ rằng việc chèn hàng trong bảng sẽ thay đổi lựa chọn, miễn là bạn đang cập nhật TableModel trên EDT, hàng đã chọn vẫn giống nhau khi người dùng hiển thị cửa sổ bật lên và chọn và thao tác từ cửa sổ bật lên .

import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.Random; 

import javax.swing.*; 
import javax.swing.table.DefaultTableModel; 

public class TestJTableInsert { 
    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       final DefaultTableModel model = new DefaultTableModel(0, 1); 
       new Timer(500, new ActionListener() { 
        private final Random random = new Random(); 
        private int data = 1; 

        @Override 
        public void actionPerformed(ActionEvent e) { 
         model.insertRow(random.nextInt(model.getRowCount() + 1), 
           new Object[] { data++ }); 
        } 
       }).start(); 

       final JTable table = new JTable(model); 
       JPopupMenu popup = new JPopupMenu(); 
       popup.add(new AbstractAction("Which row is this?") { 

        @Override 
        public void actionPerformed(ActionEvent e) { 
         JOptionPane.showMessageDialog(table, 
           "This is row " + table.getValueAt(table.getSelectedRow(), 0)); 
        } 
       }); 
       table.setComponentPopupMenu(popup); 
       JFrame frame = new JFrame("Test"); 
       frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
       frame.getContentPane().add(new JScrollPane(table)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 
+0

darn, bạn đánh bại tôi - bởi vì tôi đã có bằng chứng là con người (bằng cách đọc một captcha gần như không thể phân biệt :) – kleopatra

3

ví dụ về mô hình không phải là điều dễ làm ở đây.

Dưới đây là một khởi động để chứng minh rằng việc lựa chọn được giữ không đổi (theo nghĩa là nó luôn luôn trỏ tới cùng "thực" hàng:

final DefaultTableModel model = new DefaultTableModel(0, 1); 
for (int i = 0; i < 50; i++) { 
    model.addRow(new Object[] {i}); 
}; 

final JXTable table = new JXTable(model); 
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 
table.setRowSelectionInterval(25, 25); 
Action l = new AbstractAction("random insert") { 
    Random random = new Random(); 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     int row = random.nextInt(model.getRowCount()); 
     model.insertRow(row, new Object[] {"inserted at: " + row}); 
     table.scrollRowToVisible(table.getSelectedRow()); 
    } 

}; 
new Timer(100, l).start(); 
Các vấn đề liên quan