如何在禁用编辑的JTable单元格中选择文本?

时间:2014-03-16 18:08:42

标签: java swing jtable

想象一下,我正在使用Java构建一个IRC客户端,我想在聊天视图中使用富文本来显示IRC颜色和彩色刻痕。我想用JTable来构建它。我可以这样做,但文字是不可选择的。使表格可编辑没有意义。

我也曾调查过:

  • TextArea - 没有富文本格式
  • JEditPane - 无法追加,只能替换性能不佳的
  • JList - 无法选择文字

所以我有一张桌子工作,我只需要在不使其可编辑的情况下选择文本。我也只想要文本内容,并且在复制文本选择时没有HTML被复制到剪贴板中。

我尝试了setRowSelectionAllowed()setColumnSelectionEnabled()setCellSelectionEnabled()以及setSelectionMode的各种迭代,表模型为isCellEditable()返回false。什么都没有使文本可选。

编辑:根据答案1我对文本编辑器窗格的看法不对,所以我正在尝试这些解决方案。

4 个答案:

答案 0 :(得分:2)

我不知道你为什么不想使用JTextPaneJEditorPane。您按文档插入文本。这里的例子 - > How to use Editor Panes and Text Panes

但为了您的目的,您可以做一些类似的事情。我重写changeSelection以点击时选择所有文字,单元格可编辑但其cellEditors不可编辑。

public class JTableTest {


        private final DefaultCellEditor cellEditor;
        private final JTextField textfield;
        private JPanel panel;
        private MyTableModel tableModel = new MyTableModel();
        private JTable table = new JTable() {

            @Override
            public TableCellEditor getCellEditor(int row, int column) {               
                    return JTableTest.this.cellEditor;                
            }

            @Override
            public void changeSelection(
                    final int row, final int column, final boolean toggle, final boolean extend) {
                super.changeSelection(row, column, toggle, extend);
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if ((getCellEditor(row, column) != null && !editCellAt(row, column))) {                        
                            JTextField textfield=(JTextField)JTableTest.this.cellEditor.getComponent();
                            textfield.selectAll();                          
                        }
                    }
                });
            }
        };

        public JTableTest() {
            JScrollPane scroll = new JScrollPane(table);
            table.setModel(tableModel);
            panel = new JPanel(new BorderLayout());
            panel.add(scroll, BorderLayout.CENTER);
            textfield = new JTextField();
            textfield.setEditable(Boolean.FALSE);
            textfield.setBorder(null);
            cellEditor = new DefaultCellEditor(textfield);
            tableModel.insertValue(new ItemRow("nonEditable", "Editable"));
        }



        private class ItemRow {

            private String column1;
            private String column2;

            public ItemRow(String column1, String column2) {
                this.column1 = column1;
                this.column2 = column2;
            }

            public String getColumn1() {
                return column1;
            }

            public void setColumn1(String column1) {
                this.column1 = column1;
            }

            public String getColumn2() {
                return column2;
            }

            public void setColumn2(String column2) {
                this.column2 = column2;
            }
        }

        private class MyTableModel extends AbstractTableModel {

            public static final int COLUMN1_INDEX = 0;
            public static final int COLUMN2_INDEX = 1;
            private final List<ItemRow> data = new ArrayList<>();

            private final String[] columnsNames = {
                "Column1",
                "Column2",};

            private final Class<?>[] columnsTypes = {
                String.class,
                String.class
            };


            public MyTableModel() {
                super();
            }

            @Override
            public Object getValueAt(int inRow, int inCol) {
                ItemRow row = data.get(inRow);
                Object outReturn = null;

                switch (inCol) {
                    case COLUMN1_INDEX:
                        outReturn = row.getColumn1();
                        break;
                    case COLUMN2_INDEX:
                        outReturn = row.getColumn2();
                        break;
                    default:
                        throw new RuntimeException("invalid column");
                }

                return outReturn;
            }

            @Override
            public void setValueAt(Object inValue, int inRow, int inCol) {
                System.out.println("Gets called ");
                if (inRow < 0 || inCol < 0 || inRow >= data.size()) {
                    return;
                }

                ItemRow row = data.get(inRow);
                switch (inCol) {
                    case COLUMN1_INDEX:
                        row.setColumn1(inValue.toString());
                        break;
                    case COLUMN2_INDEX:
                        row.setColumn2(inValue.toString());
                        break;
                }
                fireTableCellUpdated(inRow, inCol);
            }

            @Override
            public int getRowCount() {
                return data.size();
            }

            @Override
            public int getColumnCount() {
                return columnsTypes.length;
            }

            @Override
            public String getColumnName(int inCol) {
                return this.columnsNames[inCol];
            }

            @Override
            public Class<?> getColumnClass(int columnIndex) {
                return this.columnsTypes[columnIndex];
            }

            /**
             *
             * @param row
             */
            public void insertValue(ItemRow row) {
                data.add(row);
                fireTableRowsInserted(data.size() - 1, data.size() - 1);
            }

            @Override
            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return true;
            }



        }


        private static void createAndShowGUI(final Container container, final String title) {
            //Create and set up the window.
            JFrame frame = new JFrame(title);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationByPlatform(Boolean.TRUE);
            frame.add(container);
            //Display the window.
            frame.pack();
            frame.setVisible(true);
        }

        public static void main(String args[]) {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    createAndShowGUI(new JTableTest().panel, "Test");
                }

            });
        }

}

答案 1 :(得分:1)

我通过启用编辑然后使负责编辑的组件忽略任何更改来完成此操作。为此我创建了一个TableCellEditor并截获了JTextField的键类型,这是用于编辑的组件。

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;

public class TableCellSelectionTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable() {
            public void run()
            {
                new TableCellSelectionTest().initUI();
            }
        });
    }

    public void initUI()
    {
        JFrame frame = new JFrame();
        int N = 5;
        int M = 3;
        Object[][] data = new Object[N][M];
        for (int i = 0; i < N; ++i)
        {
            for (int j = 0; j < M; ++j)
            {
                data[i][j] = "This is the cell (" + i + ", " + j +")";
            }
        }
        String[] columnNames = { "Column 1", "Column 2", "Column 3" };
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        final MyTableCellEditor editor = new MyTableCellEditor();
        JTable table = new JTable(model) {
            @Override
            public TableCellEditor getCellEditor(int row, int column)
            {
                return editor;
            }
        };

        frame.add(new JScrollPane(table), BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    class MyTableCellEditor extends AbstractCellEditor implements
            TableCellEditor
    {
        Object _value;

        @Override
        public Object getCellEditorValue()
        {
            return _value;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table,
                Object value, boolean isSelected, int row, int column)
        {
            _value = value;
            JTextField textField = new JTextField(_value.toString());
            textField.addKeyListener(new KeyAdapter()
            {
                 public void keyTyped(KeyEvent e) {
                         e.consume();  //ignores the key
                   }


            @Override
            public void keyPressed(KeyEvent e)
            {
                e.consume();
            }});
            textField.setEditable(false); //this is functionally irrelevent, makes slight visual changes
            return textField;
        }
    }

}

答案 2 :(得分:1)

我在这里尝试了两个答案......但至少有一个问题是你可以告诉你何时进入“编辑”模式。

这可能是有意义的......使用编辑魔术和厚脸皮渲染的组合使其看起来没有进行编辑:编辑器的点击计数到开始设置为1,{{1}由编辑器方法提供的ybg component

如果这引起你的兴趣,你可能会对我JTextPane的实现感兴趣,setEditable( false )可以调整(完全利用JTable强大的包装能力)行高到文本,对于单个行,包括更改列时:How to wrap lines in a jtable cell?

JTextPane

答案 3 :(得分:0)

也许你可以实现自己的TableCellRenderer来扩展表中的JTextField。