[英]Get the inner-table's clicked cell
我有一個 JTable 帶有自定義單元格編輯器和自定義單元格渲染。 這是為了允許在單元格內顯示表格。
我需要能夠右鍵單擊內部表格單元格,然后刪除 select。 我現在的問題是識別內表的單擊單元格。 它有時有效,有時無效(它要么給出 -1 作為單元格索引,要么給出不正確的單元格索引)。
這是我的代碼:
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
public class ComplexTable extends JTable {
private int[] colorsArray = {0xbbbbbb, 0xff0000, 0xb28959, 0x318c23, 0xc200f2, 0xbf0000, 0x735839};
private Point clickedLocation;
private JPopupMenu popupMenu;
MouseAdapter mouseAdapter = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
clickedLocation = e.getPoint();
}
@Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
clickedLocation = e.getPoint();
}
};
public ComplexTable( TableModel tableModel) {
this.setModel(tableModel);
this.addMouseListener(mouseAdapter);
popupMenu = new JPopupMenu();
JMenuItem deleteItem = new JMenuItem("Delete");
deleteItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = ComplexTable.this.getSelectedRow();
int selectedColumn = ComplexTable.this.getSelectedColumn();
JTable table = ComplexTable.this;
if(selectedRow < 0){
return;
}
Component c = table.getCellEditor(selectedRow, selectedColumn).
getTableCellEditorComponent(table,
table.getValueAt(selectedRow, selectedColumn), true, selectedRow, selectedColumn);
if (c instanceof JScrollPane) {
JViewport viewport = ((JScrollPane) c).getViewport();
JTable innerTable = (JTable) viewport.getView();
int innerTableSelRow = innerTable.rowAtPoint(clickedLocation);
int innerTableSelCol = innerTable.columnAtPoint(clickedLocation);
System.out.println("inner " + innerTableSelRow + "," + innerTableSelCol);
}
System.out.println("outer " + selectedRow + "," + selectedColumn);
}
});
popupMenu.add(deleteItem);
this.setComponentPopupMenu(popupMenu);
for (int i = 0; i < tableModel.getRowCount(); i++) {
this.setRowHeight(i, 55);
}
TableCellRenderer outerTableCellRenderer = new TableCellRenderer() {
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
// If what we're displaying isn't an ArrayList of values we return the normal renderer
if (((ArrayList<String>) value).size() == 1) {
return table.getDefaultRenderer(((ArrayList<String>) value).get(0).getClass())
.getTableCellRendererComponent(table, ((ArrayList<String>) value).get(0), isSelected, hasFocus, row, column);
} else {
final ArrayList<Object> passed = (ArrayList<Object>) value;
JTable innerTable = new JTable(new AbstractTableModel() {
public int getColumnCount() {
return 1;
}
public int getRowCount() {
return passed.size();
}
public Object getValueAt(int rowIndex, int columnIndex) {
return passed.get(rowIndex);
}
public boolean isCellEditable(int row, int col) {
return true;
}
});
innerTable.setTableHeader(null);
InnerTableCellRenderer innerTableCellRenderer = new InnerTableCellRenderer();
TableColumnModel columnModel = innerTable.getColumnModel();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
columnModel.getColumn(i).setCellRenderer(innerTableCellRenderer);
}
innerTable.addMouseListener(mouseAdapter);
return new JScrollPane(innerTable);
}
}
};
OuterTableCellEditor outerTableCellEditor = new OuterTableCellEditor();
TableColumnModel tableColumnModel = this.getColumnModel();
for (int i = 0; i < tableColumnModel.getColumnCount(); i++) {
tableColumnModel.getColumn(i).setCellRenderer(outerTableCellRenderer);
tableColumnModel.getColumn(i).setCellEditor(outerTableCellEditor);
}
}
class OuterTableCellEditor extends AbstractCellEditor implements TableCellEditor {
Object value = null;
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
this.value = value;
if (((ArrayList<String>) value).size() == 1) {
JTextField textField = new JTextField(((ArrayList<String>) value).get(0));
textField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ArrayList<String> newValue = new ArrayList<>();
newValue.add(((JTextField) e.getSource()).getText());
OuterTableCellEditor.this.value = newValue;
fireEditingStopped();
}
});
textField.setComponentPopupMenu(popupMenu);
return textField;
} else {
final ArrayList<Object> passed = (ArrayList<Object>) value;
final JTable innerTable = new JTable();
innerTable.setTableHeader(null);
AbstractTableModel innerTableModel = new AbstractTableModel() {
public int getColumnCount() {
return 1;
}
public int getRowCount() {
return passed.size();
}
public Object getValueAt(int rowIndex, int columnIndex) {
return passed.get(rowIndex);
}
public boolean isCellEditable(int row, int col) {
return true;
}
public void setValueAt(Object value, int row, int col) {
passed.set(row, value);
fireTableCellUpdated(row, col);
}
};
innerTable.setModel(innerTableModel);
InnerTableCellRenderer innerTableCellRenderer = new InnerTableCellRenderer();
TableColumnModel columnModel = innerTable.getColumnModel();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
columnModel.getColumn(i).setCellRenderer(innerTableCellRenderer);
}
innerTable.setComponentPopupMenu(popupMenu);
innerTable.addMouseListener(mouseAdapter);
return new JScrollPane(innerTable);
}
}
@Override
public Object getCellEditorValue() {
return this.value;
}
}
class InnerTableCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value, boolean
isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(new Color(colorsArray[row]));
return c;
}
}
public static void main(String[] args) {
String[] columns = {"Name", "E-Mail", "Phone"};
Object[][] data = new Object[2][columns.length];
ArrayList<Object> namesList = new ArrayList<>();
namesList.add("Peter");
data[0][0] = namesList;
String[] emails = {"peter@yahoo.com", "strange@name.com"};
data[0][1] = new ArrayList<>(Arrays.asList(emails));
String[] phones = {"555 35 25 65", "555 35 24 63", "555 05 55 55", "555 05 55 66"};
data[0][2] = new ArrayList<Object>(Arrays.asList(phones));
String[] number = {"12.2"};
data[1][0] = new ArrayList<Object>(Arrays.asList(number));
String[] email = {"Jack@hotmail.com"};
data[1][1] = new ArrayList<Object>(Arrays.asList(email));
String[] phones2 = {"555 35 24 33", "555 11 88 88", "332 55 25 34"};
data[1][2] = new ArrayList<Object>(Arrays.asList(phones2));
AbstractTableModel outerTableModel = new AbstractTableModel() {
public String getColumnName(int col) {
return columns[col];
}
public Class getColumnClass(int col) {
if (getRowCount() < 1) {
return null;
}
return data[0][col].getClass();
}
public int getRowCount() {
return data.length;
}
public int getColumnCount() {
return columns.length;
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public boolean isCellEditable(int row, int col) {
return true;
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
};
ComplexTable complexTable = new ComplexTable(outerTableModel);
JFrame frame = new JFrame();
frame.setBounds(100, 100, 700, 400);
frame.setPreferredSize(new Dimension(600, 400));
frame.add(new JScrollPane(complexTable));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
從觀察來看,外部表依賴JTable.getSelectedRow()
和JTable.getSelectedColumn()
來獲取選定的單元格,而內部表依賴於最后點擊的位置,由MouseAdapter
提供。
第一個問題是,右鍵單擊不會更改表格單元格的選擇。 這意味着如果您選擇(左鍵單擊)[0,0] 單元格(左上角)並右鍵單擊右下角,則外部選擇仍然是 [0,0]。
第二個問題是, MouseAdapter
附加到外部表和內部表。 您需要確保事件序列以您想要的方式發生。 由於單擊內表也是外表的另一個單擊事件。 如果內表點擊事件在外表之前觸發,則clickedLocation
將被外表坐標覆蓋,因此其值為 w.r.t 外表。 外桌大小約700*400,內桌可能200*80。 外部表和內部表的 x 和 y 具有不同的含義,因為它們沒有對齊並且大小不同。 通過從外部表中捕獲的坐標無法獲取選定的內部單元格。
我根據您的來源修改項目。 主要變化是:
ComplexTableModel.prepareData()
)MouseAdapter
添加到表中,而是將動作偵聽器添加到 JPopupMenu (請參閱TablePopupMenu
)popupMenuWillBecomeVisible()
事件中獲取表格單元格選擇。復雜表.java
public class ComplexTable extends JTable {
private NestedTableCellRenderer nestedTableRenderer;
private NestedTableCellEditor nestedTableEditor;
private Point outerSelection;
private Point innerSelection;
public ComplexTable(TableModel tm) {
super(tm);
setRowHeight(55);
setComponentPopupMenu(new TablePopupMenu());
nestedTableRenderer = new NestedTableCellRenderer(this);
nestedTableEditor = new NestedTableCellEditor(this);
}
@Override
public TableCellRenderer getCellRenderer(int row, int column) {
Object data = this.getModel().getValueAt(row, column);
if (data instanceof List) {
return nestedTableRenderer;
} else {
return super.getCellRenderer(row, column);
}
}
@Override
public TableCellEditor getCellEditor(int row, int column) {
Object data = this.getModel().getValueAt(row, column);
if (data instanceof List) {
return nestedTableEditor;
} else {
return super.getCellEditor(row, column);
}
}
private void printSelection() {
System.out.println(String.format("outer[%s, %s], inner[%s, %s]", outerSelection.x, outerSelection.y,
innerSelection.x, innerSelection.y));
}
public static void main(String[] args) {
ComplexTable complexTable = new ComplexTable(new ComplexTableModel());
JFrame frame = new JFrame();
frame.setBounds(100, 100, 700, 400);
frame.setPreferredSize(new Dimension(600, 400));
frame.add(new JScrollPane(complexTable));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
class TablePopupMenu extends JPopupMenu implements ActionListener, PopupMenuListener {
private JMenuItem deleteMenuItem;
public TablePopupMenu() {
deleteMenuItem = new JMenuItem("Delete");
deleteMenuItem.addActionListener(this);
add(deleteMenuItem);
addPopupMenuListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
ComplexTable.this.printSelection();
}
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
// update outer selection on context menu shown
Point mousePoint = ComplexTable.this.getMousePosition();
int row = ComplexTable.this.rowAtPoint(mousePoint);
int col = ComplexTable.this.columnAtPoint(mousePoint);
ComplexTable.this.changeSelection(row, col, false, false);
outerSelection = new Point(row, col);
JTable table = (JTable) this.getInvoker();
if (!(table instanceof ComplexTable)) {
// inner table is a generic swing table, thus the event fires from inner table
innerSelection = new Point(table.getSelectedRow(), table.getSelectedColumn());
} else {
// clear the selection as -1, -1
innerSelection = new Point(-1, -1);
}
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
}
}
復雜表Model.java
public class ComplexTableModel extends AbstractTableModel {
private String[] columnNames = { "Name", "E-Mail", "Phone" };
Object[][] rawData = new Object[2][columnNames.length];
public ComplexTableModel() {
prepareData();
}
private void prepareData() {
rawData[0][0] = "Peter";
rawData[0][1] = Arrays.asList("peter@yahoo.com", "strange@name.com");
rawData[0][2] = Arrays.asList("555 35 25 65", "555 35 24 63", "555 05 55 55", "555 05 55 66");
rawData[1][0] = "12.2";
rawData[1][1] = "Jack@hotmail.com";
rawData[1][2] = Arrays.asList("555 35 24 33", "555 11 88 88", "332 55 25 34");
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
@Override
public String getColumnName(int column) {
return columnNames[column];
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public int getRowCount() {
return rawData.length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return rawData[rowIndex][columnIndex];
}
}
NestedTableCellRenderer.java
public class NestedTableCellRenderer implements TableCellRenderer {
private JTable masterTable;
public NestedTableCellRenderer(JTable masterTable) {
this.masterTable = masterTable;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
List<?> valueList = (List<?>) value;
JTable innerTable = new JTable() {
@Override
public boolean isCellEditable(int row, int column) {
return true;
}
};
((DefaultTableModel) innerTable.getModel()).addColumn("", new Vector<Object>(valueList));
innerTable.setDefaultRenderer(Object.class, new ColoredInnerTableCellRenderer());
innerTable.setComponentPopupMenu(masterTable.getComponentPopupMenu());
innerTable.setTableHeader(null);
return new JScrollPane(innerTable);
}
}
class ColoredInnerTableCellRenderer extends DefaultTableCellRenderer {
private int[] colorsArray = { 0xbbbbbb, 0xff0000, 0xb28959, 0x318c23, 0xc200f2, 0xbf0000, 0x735839 };
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(new Color(colorsArray[row % colorsArray.length]));
return c;
}
}
NestedTableCellEditor.java
public class NestedTableCellEditor extends AbstractCellEditor implements TableCellEditor {
private JTable masterTable;
Object value = null;
public NestedTableCellEditor(JTable masterTable) {
this.masterTable = masterTable;
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
this.value = value;
final List<Object> dataList = (List<Object>) value;
final JTable innerTable = new JTable();
innerTable.setTableHeader(null);
AbstractTableModel innerTableModel = new AbstractTableModel() {
public int getColumnCount() {
return 1;
}
public int getRowCount() {
return dataList.size();
}
public Object getValueAt(int rowIndex, int columnIndex) {
return dataList.get(rowIndex);
}
public boolean isCellEditable(int row, int col) {
return true;
}
public void setValueAt(Object value, int row, int col) {
dataList.set(row, value);
fireTableCellUpdated(row, col);
}
};
innerTable.setModel(innerTableModel);
innerTable.setDefaultRenderer(Object.class, new ColoredInnerTableCellRenderer());
innerTable.setComponentPopupMenu(masterTable.getComponentPopupMenu());
return new JScrollPane(innerTable);
}
@Override
public Object getCellEditorValue() {
return this.value;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.