Я пытаюсь создать таблицу с пользовательскими заголовками столбцов.Я хочу, чтобы заголовки столбцов включали кнопку, на которую пользователи могут нажимать.Функцией кнопки будет удаление столбца из таблицы.По сути, я пытаюсь построить что-то вроде this .
Вот мой код:
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."); }
}
По умолчанию, если я правильно понимаю, JTable использует JLabel для рендерингазаголовки столбцов.Моя идея состоит в том, чтобы использовать пользовательскую реализацию TableCellRenderer и создать свой собственный заголовок столбца из нескольких компонентов, а именно JPanel, который содержит JLabel и JButton.Я строю и возвращаю это в функции getTableCellRendererComponent (...).
Визуально это работает.Проблема в том, что я не могу обнаружить щелчки мышью на кнопке (или, если на то пошло, на панели, которая ее удерживает).Простое добавление MouseListener к кнопке не работает.Событие никогда не достигает этого.
Я нашел несколько похожих вещей в Интернете, но они не достигают нужной мне функциональности.
Во-первых, есть пример того, как поместить JCheckBox взаголовок, здесь:
http://java-swing-tips.blogspot.com/2009/02/jtableheader-checkbox.html
Проблема в том, что весь заголовок является флажком.Нажатие на флажок или на соответствующую метку производит тот же эффект.Таким образом, невозможно отсортировать столбец.Я хотел бы сделать так, чтобы при нажатии на метку сортировался столбец, а при нажатии на кнопку закрытия столбец удалялся из таблицы.Другими словами, заголовок должен иметь две отдельные области с отдельными обработчиками событий мыши.
Я нашел другой пример здесь:
http://www.devx.com/getHelpOn/10MinuteSolution/20425/1954?pf=true
Это включает в себя размещение JButtons в ячейках таблицы,затем обнаружение щелчков мышью на самой таблице, вычисление столбца и строки, где произошел щелчок, и отправка события соответствующей кнопке.
У этого тоже есть несколько проблем.Во-первых, кнопки находятся в ячейках, а не в заголовках.И во-вторых, это опять-таки только один компонент, а не несколько компонентов внутри JPanel.Хотя в этом примере я получил представление о распределении событий, я не могу заставить его работать для составного компонента.
Я попробовал другой подход.Я рассуждал, что если я смогу получить координаты кнопок закрытия, то, зная координаты щелчка мышью, я могу рассчитать, какая кнопка была нажата, и соответствующим образом распределить событие.Я провел несколько тестов и обнаружил, что компоненты внутри заголовка таблицы на самом деле не расположены на экране.
Я добавил статическую переменную JButton в свой основной (публичный) класс и сделал класс, реализующий TableCellRenderer, внутренним.класс основного класса.В getTableCellRendererComponent (...) перед возвратом я назначаю только что созданный JButton этой статической переменной.Таким образом, я могу справиться с этим, так сказать.Затем в основном я попытался использовать getX (), getY (), getWidth (), getHeight () и getLocationOnScreen (), используя эту статическую переменную.X, Y, Ширина и Высота все возвращают 0.GetLocationOnScreen () завершает работу программы, говоря, что компонент должен присутствовать на экране, чтобы эта функция работала.
Код для этого выглядит примерно так:
public class CustomColumnHeadersTable {
private static JButton static_button;
///the rest as before....
"Класс CustomColumnCellRendererреализует TableCellRenderer "становится внутренним классом CustomColumnHeadersTable.Для этого я должен отказаться от статических переменных в CustomColumnCellRenderer, поэтому я не стал беспокоиться о значках, URL-адресах или о чем-либо подобном.Вместо кнопки со значком, я просто использовал простую кнопку с надписью «КНОПКА» ...
Далее, внутри getTableCellRendererComponent (...), перед оператором возврата я сделал
static_button = button;
И, наконец, внутри main () я попытался сделать это:
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());
Вывод выглядит так:
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)
...
Другими словами, кнопка имеетвсе размеры 0, и в соответствии с Java это на самом деле не находится на экране (хотя я вижу это ...).Вызов getLocationOnScreen () приводит к сбою программы.
Так что, пожалуйста, помогите, если можете.Может кто знает как это сделать.Может быть, вы могли бы просто предложить другой подход, чтобы попробовать.Или, может быть, вы знаете, что это вообще невозможно ...
Спасибо за вашу помощь.