Tôi đang cố tạo bảng có tiêu đề cột tùy chỉnh. Tôi muốn các tiêu đề cột bao gồm một nút mà người dùng có thể nhấp vào. Chức năng của nút sẽ là xóa cột khỏi bảng. Về cơ bản, tôi đang cố gắng để xây dựng một cái gì đó như this.JTable có nút “đóng” trong tiêu đề cột
Dưới đây là mã của tôi:
public class CustomColumnHeadersTable {
private static String[] columnNames = {
"Column 1", "Column 2", "Column 3"
};
private static String[][] data = {
{"A", "B", "C"},
{"D", "E", "F"},
{"G", "H", "I"}
};
public CustomColumnHeadersTable() {
DefaultTableModel model = new DefaultTableModel((Object[][]) data, columnNames);
JTable table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
//set Header Renderer of each column to use the Custom renderer
Enumeration enumeration = table.getColumnModel().getColumns();
while (enumeration.hasMoreElements()) {
TableColumn aColumn = (TableColumn) enumeration.nextElement();
aColumn.setHeaderRenderer(new CustomColumnCellRenderer());
}
JFrame frame = new JFrame();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setPreferredSize(new Dimension(300, 150));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) {
CustomColumnHeadersTable ccht = new CustomColumnHeadersTable();
}
}
class CustomColumnCellRenderer implements TableCellRenderer {
private static String iconURL = "http://www.accessdubuque.com/images/close_icon.gif";
//using a URL for the icon, so I don't have to upload the icon with the question
private static Dimension buttonSize = new Dimension(16, 16);
private static Dimension buttonBoxSize = new Dimension(16, 16);
private static Border panelBorder = BorderFactory.createRaisedBevelBorder();
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JPanel panel = new JPanel();
JLabel label = new JLabel();
JButton button = new JButton();
Box buttonBox = Box.createHorizontalBox();
BorderLayout layout = new BorderLayout();
label.setText(table.getColumnName(column));
try { button.setIcon(new ImageIcon(new URL(iconURL))); }
catch (MalformedURLException ex) {
Logger.getLogger(CustomColumnCellRenderer.class.getName()).log(Level.SEVERE, null, ex);
}
//set size of the button and it's box
button.setMaximumSize(buttonSize);
button.setSize(buttonSize);
button.setPreferredSize(buttonSize);
buttonBox.setMaximumSize(buttonBoxSize);
buttonBox.setSize(buttonBoxSize);
buttonBox.setPreferredSize(buttonBoxSize);
button.addMouseListener(new CustomMouseListener()); //doesn't work...
buttonBox.add(button);
panel.add(label, BorderLayout.CENTER);
panel.add(buttonBox, BorderLayout.EAST);
panel.setBorder(panelBorder);
return panel;
}
}
class CustomMouseListener implements MouseListener
{
public void mouseClicked(MouseEvent e) { System.out.println("Mouse Clicked."); }
public void mousePressed(MouseEvent e) { System.out.println("Mouse Pressed."); }
public void mouseReleased(MouseEvent e) { System.out.println("Mouse Released."); }
public void mouseEntered(MouseEvent e) { System.out.println("Mouse Entered."); }
public void mouseExited(MouseEvent e) { System.out.println("Mouse Exited."); }
}
Theo mặc định, nếu tôi hiểu đúng, JTable sử dụng một JLabel để render các tiêu đề cột. Ý tưởng của tôi là sử dụng triển khai TableCellRenderer tùy chỉnh và xây dựng tiêu đề cột của riêng tôi từ một số thành phần, cụ thể là, một JPanel có chứa một JLabel và một JButton. Tôi xây dựng và trả về điều đó trong hàm getTableCellRendererComponent (...).
Trực quan, tính năng này hoạt động. Vấn đề là tôi không thể phát hiện nhấp chuột vào nút (hoặc, cho rằng vấn đề, trên bảng điều khiển nắm giữ nó). Đơn giản chỉ cần thêm một MouseListener vào nút không hoạt động. Sự kiện không bao giờ đạt đến nó.
Tôi đã tìm thấy một số thứ tương tự trên web nhưng chúng không đạt được chức năng tôi cần.
Đầu tiên, có một ví dụ về cách đặt một JCheckBox vào tiêu đề, ở đây:
http://java-swing-tips.blogspot.com/2009/02/jtableheader-checkbox.html
Vấn đề ở đây là toàn bộ tiêu đề là hộp kiểm. Nhấp vào hộp kiểm hoặc trên nhãn được liên kết sẽ tạo ra cùng một hiệu ứng. Do đó, không thể sắp xếp cột. Tôi muốn làm cho nó để nhấp vào nhãn sắp xếp cột và nhấp vào nút đóng sẽ xóa cột khỏi bảng. Nói cách khác, tiêu đề cần phải có hai khu vực riêng biệt với trình xử lý sự kiện chuột riêng biệt.
tôi tìm thấy một ví dụ ở đây:
http://www.devx.com/getHelpOn/10MinuteSolution/20425/1954?pf=true
này bao gồm việc đặt JButtons vào các tế bào của bảng, sau đó phát hiện cú click chuột trên bảng chính nó, tính toán cột và hàng nơi nhấp chuột xảy ra, và cử các sự kiện vào nút thích hợp.
Có một số vấn đề với điều này. Đầu tiên, các nút nằm trong các ô, không nằm trong các tiêu đề. Và thứ hai, đây chỉ là một thành phần, không phải một số thành phần bên trong một JPanel. Mặc dù tôi có ý tưởng gửi đi các sự kiện từ ví dụ này, tôi không thể làm cho nó hoạt động cho một thành phần phức hợp.
Tôi đã thử một cách tiếp cận khác. Tôi lý luận rằng nếu tôi có thể nhận được tọa độ của các nút đóng, sau đó biết tọa độ của nhấp chuột tôi có thể tính toán nút nào được nhấp và gửi sự kiện một cách thích hợp. Tôi chạy một vài thử nghiệm và phát hiện ra rằng các thành phần bên trong tiêu đề bảng không thực sự nằm trên màn hình.
Tôi đã thêm biến JButton tĩnh vào lớp chính (công khai) của tôi và tạo lớp thực hiện TableCellRenderer là lớp bên trong của lớp chính. Trong getTableCellRendererComponent (...), trước khi trở về, tôi gán JButton mà tôi vừa tạo cho biến tĩnh đó. Bằng cách này, tôi có thể có được một xử lý trên nó, vì vậy để nói chuyện. Sau đó, trong chính, tôi đã cố gắng getX(), getY(), getWidth(), getHeight() và getLocationOnScreen() sử dụng biến tĩnh đó. X, Y, Chiều rộng và Chiều cao đều trả về 0. GetLocationOnScreen() treo chương trình, nói rằng thành phần phải có mặt trên màn hình để chức năng này hoạt động.
Mã này trông giống như sau:
public class CustomColumnHeadersTable {
private static JButton static_button;
///the rest as before....
"class CustomColumnCellRenderer thực hiện TableCellRenderer" trở thành một lớp bên trong của CustomColumnHeadersTable. Cho rằng, tôi phải từ bỏ các biến tĩnh trong CustomColumnCellRenderer, vì vậy tôi không bận tâm với các biểu tượng hoặc url hoặc bất cứ điều gì như thế. Thay vì một nút với một biểu tượng, tôi chỉ sử dụng một nút đơn giản mà nói "NÚT" ...
Tiếp theo, bên trong getTableCellRendererComponent (...), ngay trước khi tuyên bố trở lại, tôi đã làm
static_button = button;
Và cuối cùng, bên trong main(), tôi đã cố gắng làm điều này:
System.out.println("X: " + static_button.getX());
System.out.println("Y: " + static_button.getY());
System.out.println("W: " + static_button.getWidth());
System.out.println("H: " + static_button.getHeight());
System.out.println("LOC: " + static_button.getLocation());
System.out.println("LOC on screen: " + static_button.getLocationOnScreen());
Kết quả trông như thế này:
X: 0
Y: 0
W: 0
H: 0
LOC: java.awt.Point[x=0,y=0]
Exception in thread "main" java.awt.IllegalComponentStateException: component must be showing on the screen to determine its location
at java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:1943)
at java.awt.Component.getLocationOnScreen(Component.java:1917)
...
Nói cách khác, nút có tất cả các kích thước của 0, và theo Java nó không thực sự nằm trên màn hình (mặc dù tôi có thể nhìn thấy nó ...). Gọi getLocationOnScreen() làm hỏng chương trình.
Vì vậy, vui lòng trợ giúp nếu có thể. Có lẽ ai đó biết cách làm điều này. Có lẽ bạn chỉ có thể đề xuất một số cách tiếp cận khác để thử. Hoặc, có thể bạn biết điều đó là không thể ...
Cảm ơn sự giúp đỡ của bạn.
Cảm ơn bạn! Tôi đã thử một cái gì đó tương tự - quyết định chỉ tính toán nếu các nhấp chuột rơi vào nút. Vì vậy, tôi cần giữ nút ở một nơi duy nhất. Nói, đó là 16x16, và tôi cần phải luôn luôn giữ nó 8 pixel bên trái của cạnh cột. Mặc dù tôi đã có thể làm điều đó bằng cách sử dụng Hộp và keo, tôi đã không thể làm cho nó để chơi tốt với JLabel. Nói, cột của tôi trông như thế này: | Tên cột [x] |. Nếu cột được kích thước lại, tôi muốn nó trông giống như | Colum ... [x] |. IOW, hình elip sẽ xuất hiện tự động. Thay vào đó, nút chỉ vẽ trên nhãn. Bất kỳ ý tưởng? – Aleksey