简体   繁体   English

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

[英]How do I make it possible to select text in a JTable cell with editing disabled?

Imagine I'm building an IRC client with Java and I'd like rich text in the chat view to show IRC colors and colored nicks. 想象一下,我正在用Java构建一个IRC客户端,我想在聊天视图中使用富文本来显示IRC颜色和彩色刻痕。 I'd like to build this with a JTable. 我想用JTable来构建它。 I can do that, but the text is then not selectable. 我可以这样做,但文字是不可选择的。 Making the table editable doesn't make sense. 使表格可编辑没有意义。

I've also investigated: 我也调查过:

  • TextArea - no rich text formatting TextArea - 没有富文本格式
  • JEditPane - can't append, only replace which is bad performance wise JEdi​​tPane - 无法追加,只能取代哪些是性能不佳的明智之举
  • JList - can't select text JList - 无法选择文本

So I got a table working I just need the text to be selectable without making it editable. 所以我有一张桌子工作,我只需要在不使其可编辑的情况下选择文本。 I'd also would only like the text contents, and none of the HTML to be copied into the clipboard upon copying the text selection. 我也只想要文本内容,并且在复制文本选择时没有HTML被复制到剪贴板中。

I have tried various iterations of setRowSelectionAllowed() , setColumnSelectionEnabled() and setCellSelectionEnabled() and setSelectionMode the table model returns false for isCellEditable() . 我已经尝试了setRowSelectionAllowed()setColumnSelectionEnabled()setCellSelectionEnabled()以及setSelectionMode的各种迭代,表模型为isCellEditable()返回false。 Nothing has made the text selectable. 什么都没有使文本可选。

EDIT: as per answer 1 I was wrong about text editor panes so I'm trying those solutions. 编辑:根据答案1我错误的文本编辑器窗格,所以我正在尝试这些解决方案。

I don't know why you don't want to use a JTextPane or JEditorPane . 我不知道你为什么不想使用JTextPaneJEditorPane You insert text by its document. 您按文档插入文本。 Examples here --> How to use Editor Panes and Text Panes . 这里的示例 - > 如何使用编辑器窗格和文本窗格

But for your purpose you can for example do something like this. 但是为了你的目的,你可以做一些像这样的事情。 I override changeSelection to selectAll text when is clicking, the cells are editable but its cellEditors are not editable. 我重写changeSelection以在单击时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");
                }

            });
        }

}

I accomplished this by enabling the editing and then making the component responsible for the edition ignore any changes. 我通过启用编辑然后使负责编辑的组件忽略任何更改来完成此操作。 For this I created a TableCellEditor and intercepted the key types to the JTextField, the component used for editing. 为此,我创建了一个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;
        }
    }

}

I tried both the answers here... but one problem at least is that you can tell when you've entered the "editing" mode. 我在这里尝试了两个答案......但至少有一个问题是你可以告诉你何时进入“编辑”模式。

This might be of interest... uses a combination of Editor magic and cheeky rendering to make it look like no editing is going on: editor's click-count-to-start is set to 1, and the component ( JTextPane ) delivered by the editor's method does setEditable( false ) . 这可能是有意义的......使用编辑魔术和厚脸皮渲染的组合使其看起来没有进行编辑:编辑器的click-count-to-start设置为1, componentJTextPane )由编辑器的方法确实是setEditable( false )

If this tickles your fancy, you might be interested at looking at my implementation of a JTable which adjusts (perfectly, harnessing the JTextPane 's powerful wrapping power) the row height to the text, for individual rows, including when you change the columns: How to wrap lines in a jtable cell? 如果这让你感到沮丧,你可能会对我的JTable实现感兴趣,它可以调整(完美地利用JTextPane强大的包装能力)行高到文本,对于单个行,包括更改列时: 如何在jtable单元格中包装行?

public class SelectableNonEditableTableTest {
    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame main_frame = new JFrame();
                main_frame.setPreferredSize(new Dimension(1200, 300));
                main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                ArrayList<String> nonsense = new ArrayList<String>(
                        Arrays.asList(
                                "Lorem ipsum dolor sit amet, sed dolore vivendum ut",
                                "pri an soleat causae doctus.",
                                "Alienum abhorreant mea ea",
                                "cum malorum diceret ei. Pri oratio invidunt consequat ne.",
                                "Ius tritani detraxit scribentur et",
                                "has detraxit legendos intellegat at",
                                "quo oporteat constituam ex"));

                JTable example_table = new JTable(10, 4);

                example_table.setRowHeight( example_table.getRowHeight() * 2 );

                DefaultCellEditor cell_editor = new SelectableNonEditableCellEditor(
                        new JTextField());
                cell_editor.setClickCountToStart(1);
                example_table.setDefaultEditor(Object.class, cell_editor);

                TableCellRenderer renderer = new SelectableNonEditableTableRenderer();
                example_table.setDefaultRenderer(Object.class, renderer);

                for (int i = 0; i < 10; i++) {
                    example_table.setValueAt(nonsense.get(i % nonsense.size()),
                            i, i % 4);
                }

                main_frame.getContentPane().add(new JScrollPane(example_table));

                main_frame.pack();
                main_frame.setVisible(true);

            }
        });
    }

}

class SelectableNonEditableCellEditor extends DefaultCellEditor {

    public SelectableNonEditableCellEditor(JTextField textField) {
        super(textField);
    }

    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected, int row, int col) {
        Component comp = super.getTableCellEditorComponent(table, value,
                isSelected, row, col);
        if (value instanceof java.lang.String) {
            DefaultStyledDocument sty_doc = new DefaultStyledDocument();
            try {
                sty_doc.insertString(0, (String) value, null);
            } catch (BadLocationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            JTextPane jtp_comp = new JTextPane(sty_doc);
            jtp_comp.setEditable(false);
            return jtp_comp;
        }
        return comp;
    }

}

class SelectableNonEditableTableRenderer extends JTextPane implements
        TableCellRenderer {
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        if (value instanceof DefaultStyledDocument) {
            setDocument((DefaultStyledDocument) value);
        } else {
            setText((String) value);
        }
        return this;
    }
}

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM