繁体   English   中英

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

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

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

我也调查过:

  • TextArea - 没有富文本格式
  • JEdi​​tPane - 无法追加,只能取代哪些是性能不佳的明智之举
  • JList - 无法选择文本

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

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

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

我不知道你为什么不想使用JTextPaneJEditorPane 您按文档插入文本。 这里的示例 - > 如何使用编辑器窗格和文本窗格

但是为了你的目的,你可以做一些像这样的事情。 我重写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");
                }

            });
        }

}

我通过启用编辑然后使负责编辑的组件忽略任何更改来完成此操作。 为此,我创建了一个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;
        }
    }

}

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

这可能是有意义的......使用编辑魔术和厚脸皮渲染的组合使其看起来没有进行编辑:编辑器的click-count-to-start设置为1, componentJTextPane )由编辑器的方法确实是setEditable( false )

如果这让你感到沮丧,你可能会对我的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