【问题标题】:JTable disable Column SelectionJTable 禁用列选择
【发布时间】:2016-06-07 21:51:34
【问题描述】:

我正在尝试禁用 JTable 中除 1 列之外的所有行的选择。 (示例屏幕截图中的图层列)。在其他列中,我希望用户能够与之交互的微调器和复选框,而不影响图层列中的选择。

我最初的尝试是在出现任何选定行时存储它们,然后在选择 A 列之外的单元格时恢复到该组选定行。它有点作品,但问题是它在选择其他小区时它“闪烁”,然后再恢复它。如何防止“闪”?

这是我为说明问题而设置的示例:

public class TableTest {

    static int[] selectedRows = new int[0];

    final static String[] columns = new String[] { "Layer", "Enabled", "Read Only", "Storage" };

    final static DefaultTableModel model = new DefaultTableModel(new Vector(), new Vector(Arrays.asList(columns))) {

        @Override
        public void setValueAt(Object obj, int row, int col) {

            if (obj instanceof Boolean || obj instanceof Integer) {
                Object localObject = super.getValueAt(row, col);
                if (localObject instanceof Integer) {

                    Integer val = (Integer) localObject;

                    ((SpinnerCell) obj).getSpinner().setValue(val);
                } else if (localObject instanceof Boolean) {

                    Boolean val = (Boolean) localObject;

                    ((CheckboxCell) obj).getCheckBox().setEnabled(val);
                }

            } else {
                super.setValueAt(obj, row, col);
            }

        }

        @Override
        public boolean isCellEditable(int rowIndex, int colIndex) {

            return colIndex != 0;
        }

    };

    public static void main(String[] a) {

        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                final JTable table = new JTable(model) {

                    @Override
                    public TableCellRenderer getCellRenderer(final int rowIndex, int colIndex) {

                        int reaRowlIndex = convertRowIndexToModel(rowIndex);
                        int realColumnIndex = convertColumnIndexToModel(colIndex);

                        Object o = model.getValueAt(reaRowlIndex, realColumnIndex);

                        if (o instanceof TableCellRenderer) {
                            return (TableCellRenderer) o;
                        } else {
                            return super.getCellRenderer(reaRowlIndex, realColumnIndex);
                        }
                    }

                    //
                    @Override
                    public TableCellEditor getCellEditor(final int rowIndex, int colIndex) {

                        int reaRowlIndex = convertRowIndexToModel(rowIndex);
                        int realColumnIndex = convertColumnIndexToModel(colIndex);

                        Object o = model.getValueAt(reaRowlIndex, realColumnIndex);

                        if (o instanceof TableCellEditor) {
                            return (TableCellEditor) o;
                        } else {
                            return super.getCellEditor(reaRowlIndex, realColumnIndex);
                        }
                    }

                };

                table.getTableHeader().setReorderingAllowed(false);

                table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

                    @Override
                    public void valueChanged(ListSelectionEvent arg0) {
                        if (table.getSelectedColumn() == 0) {
                            selectedRows = table.getSelectedRows();

                            System.out.println("Selected Rows before " + Arrays.toString(selectedRows));
                        }

                    }
                });

                final ListSelectionModel columnListSelectionModel = table.getColumnModel().getSelectionModel();
                columnListSelectionModel.addListSelectionListener(new ListSelectionListener() {
                    @Override
                    public void valueChanged(ListSelectionEvent e) {

                        if (table.getSelectedColumn() != 0) {

                            table.clearSelection();

                            System.out.println("Selected Rows during " + Arrays.toString(table.getSelectedRows()));

                            for (int i = 0; i < selectedRows.length; i++) {
                                table.getSelectionModel().addSelectionInterval(selectedRows[i], selectedRows[i]);
                            }

                            System.out.println("Selected Rows after " + Arrays.toString(table.getSelectedRows()));
                        }

                    }
                });

                model.addRow(new Object[] { "Bird", new CheckboxCell(new JCheckBox()),
                        new CheckboxCell(new JCheckBox()), new SpinnerCell(new JSpinner()) });

                model.addRow(new Object[] { "Cat", new CheckboxCell(new JCheckBox()), new CheckboxCell(new JCheckBox()),
                        new SpinnerCell(new JSpinner()) });

                model.addRow(new Object[] { "Dog", new CheckboxCell(new JCheckBox()), new CheckboxCell(new JCheckBox()),
                        new SpinnerCell(new JSpinner()) });

                model.addRow(new Object[] { "Fish", new CheckboxCell(new JCheckBox()),
                        new CheckboxCell(new JCheckBox()), new SpinnerCell(new JSpinner()) });

                model.addRow(new Object[] { "Pig", new CheckboxCell(new JCheckBox()), new CheckboxCell(new JCheckBox()),
                        new SpinnerCell(new JSpinner()) });

                frame.add(new JScrollPane(table));

                frame.setSize(300, 200);
                frame.setVisible(true);

            }

        });

    }

    static class CheckboxCell extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

        private static final long serialVersionUID = 1L;
        private JCheckBox checkBox;

        public CheckboxCell(JCheckBox inputCheckBox) {
            checkBox = inputCheckBox;
        }

        @Override
        public Object getCellEditorValue() {
            return checkBox.isSelected();
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row,
                int column) {

            return checkBox;
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {

            return checkBox;
        }

        public JCheckBox getCheckBox() {
            return checkBox;
        }

        @Override
        public boolean isCellEditable(EventObject evt) {
            return true;
        }

        public String toString() {
            return checkBox.isSelected() + "";
        }

    }

    static class SpinnerCell extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

        private static final long serialVersionUID = 1L;
        private JSpinner editSpinner, renderSpinner;

        public SpinnerCell() {
            editSpinner = new JSpinner();
            JTextField tf = ((JSpinner.DefaultEditor) editSpinner.getEditor()).getTextField();
            tf.setForeground(Color.black);
            renderSpinner = new JSpinner();
            JTextField tf2 = ((JSpinner.DefaultEditor) renderSpinner.getEditor()).getTextField();
            tf2.setForeground(Color.black);
        }

        public SpinnerCell(JSpinner showSpinner) {
            editSpinner = showSpinner;
            JTextField tf = ((JSpinner.DefaultEditor) editSpinner.getEditor()).getTextField();
            tf.setForeground(Color.black);
            renderSpinner = showSpinner;
            JTextField tf2 = ((JSpinner.DefaultEditor) renderSpinner.getEditor()).getTextField();
            tf2.setForeground(Color.black);

        }

        @Override
        public Object getCellEditorValue() {
            return editSpinner.getValue();
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row,
                int column) {

            return editSpinner;
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {
            return renderSpinner;
        }

        public String toString() {
            return editSpinner.getValue().toString();
        }

        public JSpinner getSpinner() {
            return editSpinner;
        }

        @Override
        public boolean isCellEditable(EventObject evt) {
            return true;
        }
    }

}

【问题讨论】:

  • 为什么?我看不出这有什么意义。您仍然想突出显示所有选定的行,但只让用户通过单击第一列来选择一行?那个 UI 根本不直观,我当然不会使用。
  • 我真正的实现在除第一列之外的所有内容中都有 jcheckboxes 和 jspinners。我试图阻止点击 jcheckboxes 和 jspinners 选择行。我只希望第一列是可选的,同时仍然让 jcheckboxes 和 jspinners 工作。
  • 我已经用我想要完成的更直接的版本更新了示例。

标签: java swing jtable


【解决方案1】:

这是我的简短示例:

  • 覆盖JTable#changeSelection(...)
  • table.setCellSelectionEnabled(true);
  • 覆盖ListSelectionModel#isSelectedIndex(...)
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

public class TableTest2 {
  public JComponent makeUI() {
    String[] columnNames = {"Layer", "Enabled", "Read Only"};
    Object[][] data = {
      {"Bird", true, false}, {"Cat",  true, false},
      {"Dog",  true, false}, {"Fish", true, false}, {"Pig",  true, false}
    };
    TableModel model = new DefaultTableModel(data, columnNames) {
      @Override public Class<?> getColumnClass(int column) {
        return getValueAt(0, column).getClass();
      }
      @Override public boolean isCellEditable(int row, int col) {
        return col != 0;
      }
    };
    JTable table = new JTable(model) {
      @Override public void changeSelection(
          int rowIndex, int columnIndex, boolean toggle, boolean extend) {
        if (convertColumnIndexToModel(columnIndex) != 0) {
          return;
        }
        super.changeSelection(rowIndex, columnIndex, toggle, extend);
      }
    };
    table.setAutoCreateRowSorter(true);
    table.setCellSelectionEnabled(true);
    table.getColumnModel().setSelectionModel(new DefaultListSelectionModel() {
      @Override public boolean isSelectedIndex(int index) {
        return table.convertColumnIndexToModel(index) == 0;
      }
    });
    return new JScrollPane(table);
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new TableTest2().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

【讨论】:

  • 谢谢。这很完美。一旦启用,我将奖励赏金。
【解决方案2】:

如果你想防止闪现,你需要在选择之前拦截一个事件,因为table.getSelectedColumn() 只在选择之后起作用,你会一直看到选择闪现。

您可以使用按键侦听器来检查“右箭头”、“数字键盘右”和“结束”按键,并使用鼠标单击侦听器来检查用户单击的位置,然后将事件更改为选择 A 列仅限。

例如,请参阅此答案,该答案展示了如何在做出选择之前检查用户单击鼠标的位置:https://stackoverflow.com/a/7351053/1270000

然后你只需要添加一些代码来选择 A 列中正确的单元格,并且不要忘记使用事件“e.consume()”以防止原始事件因用户选择错误而完成。

【讨论】:

    【解决方案3】:

    尚未尝试过,但您或许可以使用自定义 ListSelectionModel。

    这是一个示例,可让您打开/关闭对行的选择:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class ToggleListSelectionModel extends DefaultListSelectionModel
    {
        @Override
        public void setSelectionInterval(int index0, int index1)
        {
            //  Select multiple lines
    
            if (index0 != index1)
            {
                super.addSelectionInterval(index0, index1);
                return;
            }
    
            //  Toggle selection of a single line
    
            if  (super.isSelectedIndex(index0))
            {
                super.removeSelectionInterval(index0, index0);
            }
            else
            {
                super.addSelectionInterval(index0, index0);
            }
        }
    
        private static void createAndShowGUI()
        {
            String[] numbers = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
            final JList<String> list = new JList<String>( numbers );
            list.setVisibleRowCount( numbers.length );
            list.setSelectionModel(new ToggleListSelectionModel());
    //      list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    
            JButton clear = new JButton("Clear");
            clear.addActionListener( new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    list.clearSelection();
                }
            });
    
            JFrame frame = new JFrame("SSCCE");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new JScrollPane(list), BorderLayout.CENTER);
            frame.add(clear, BorderLayout.PAGE_END);
            frame.setLocationByPlatform( true );
            frame.pack();
            frame.setVisible( true );
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowGUI();
                }
            });
        }
    }
    

    在您的情况下,我猜您需要访问该表,以便您可以使用 getSelectedColumn() 方法。

    您可以从上面的示例中删除逻辑并将其替换为:

    if (table.getSelectedColumn() == 0)
        super.setSelectionInterval(index0, index1);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-08
      • 2018-10-30
      • 2023-03-24
      • 1970-01-01
      • 2013-07-12
      相关资源
      最近更新 更多