簡體   English   中英

獲取內表的點擊單元格

[英]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 具有不同的含義,因為它們沒有對齊並且大小不同。 通過從外部表中捕獲的坐標無法獲取選定的內部單元格。

我根據您的來源修改項目。 主要變化是:

  1. 對於數據 model,我將單個數據元素保留為字符串,而不是帶有單個字符串的 ArrayList(請參閱ComplexTableModel.prepareData()
  2. 我沒有將MouseAdapter添加到表中,而是將動作偵聽器添加到 JPopupMenu (請參閱TablePopupMenu
  3. 我在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM