Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make JTable cell editor value be selectable, but not editable?

I have tried to keep my JTable's tight and secure, making only editable columns editable via isCellEditable(). However, my clients are insisting that they want to double click on a cell so they can copy its contents, even if it is read only. I could let the cell be editable and not do anything with any edits they could make in the setValueAt() (so it reverts back to original value when editor exits). But I don't want this application to feel so freeform. Is there an easy effective way to make the JTextField used as the cell editor to allow selecting of text in the editor, but not editable?

I tried this override on my JTable below, but I don't think I'm looking for the right "instanceof" object.

@Override
public TableCellEditor getDefaultEditor(Class<?> columnClass) {
    if (super.getDefaultEditor(columnClass) instanceof JTextField) {
        JTextField jTextField = new JTextField();
        jTextField.setEditable(false);
        return (TableCellEditor) jTextField;
    }
    if (columnClass == null) {
        return null;
    }
    else {
        Object editor = defaultEditorsByColumnClass.get(columnClass);
        if (editor != null) {
            return (TableCellEditor)editor;
        }
        else {
            return getDefaultEditor(columnClass.getSuperclass());
        }
    }
}
like image 537
tmn Avatar asked Sep 18 '14 16:09

tmn


2 Answers

However, my clients are insisting that they want to double click on a cell so they can copy its contents, even if it is read only.

Create a custom editor that uses a readonly text field:

JTextField tf = new JTextField();
tf.setEditable(false);
DefaultCellEditor editor = new DefaultCellEditor( tf );
table.setDefaultEditor(Object.class, editor);

Use the keyboard or mouse to select the text you want to copy. Then you would then use Ctrl+C to copy the selected text. Or you could even add a popup menu to the text field and add a Copy menu item.

like image 90
camickr Avatar answered Oct 29 '22 11:10

camickr


"However, my clients are insisting that they want to double click on a cell so they can copy its contents, even if it is read only"

You could just use a MouseListener, and on a double click, programmatically copy the contents of the cell to the clipboard. Something like:

table.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 2) {
            System.out.println("double click");
            Point p = e.getPoint();
            int row = table.rowAtPoint(p);
            int col = table.columnAtPoint(p);
            Object value = table.getValueAt(row, col);
            StringSelection stringSelection = new StringSelection(value.toString());
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            clipboard.setContents(stringSelection, ProgrammaticCopyDemo.this);
        }
    }
});

Here's a full example:

enter image description here

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.IOException;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.JTextComponent;

public class ProgrammaticCopyDemo implements ClipboardOwner {

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

    public ProgrammaticCopyDemo() {
        JTable table = getTable();
        addCopylistenerToTable(table);

        JTextArea area = new JTextArea(3, 20);
        addPasteListenerToArea(area);

        JFrame frame = new JFrame();
        frame.add(new JScrollPane(table));
        frame.add(area, BorderLayout.PAGE_END);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private void addPasteListenerToArea(final JTextComponent component) {
        JPopupMenu menu = new JPopupMenu();
        menu.add(new AbstractAction("Paste") {
            public void actionPerformed(ActionEvent e) {
                String copiedContent = getClipboardContents();
                int caretPosition = component.getCaretPosition();
                try {
                    component.getDocument().insertString(caretPosition, copiedContent, null);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }

            }

            private String getClipboardContents() {
                String result = "";
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                Transferable contents = clipboard.getContents(null);
                boolean hasTransferableText
                        = (contents != null)
                        && contents.isDataFlavorSupported(DataFlavor.stringFlavor);
                if (hasTransferableText) {
                    try {
                        result = (String) contents.getTransferData(DataFlavor.stringFlavor);
                    } catch (UnsupportedFlavorException | IOException ex) {
                        System.out.println(ex);
                        ex.printStackTrace();
                    }
                }
                return result;
            }
        });
        component.setComponentPopupMenu(menu);
    }

    private void addCopylistenerToTable(final JTable table) {
        table.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    System.out.println("double click");
                    Point p = e.getPoint();
                    int row = table.rowAtPoint(p);
                    int col = table.columnAtPoint(p);
                    Object value = table.getValueAt(row, col);
                    StringSelection stringSelection = new StringSelection(value.toString());
                    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                    clipboard.setContents(stringSelection, ProgrammaticCopyDemo.this);
                }
            }
        });
    }

    private JTable getTable() {
        String[][] data = {
            {"Hello", "World"},
            {"Stack", "Overflow"},
            {"Foo", "Bar"}
        };
        String[] cols = {"Col", "Col"};
        DefaultTableModel model = new DefaultTableModel(data, cols) {
            @Override
            public boolean isCellEditable(int row, int col) {
                return false;
            }
        };
        return new JTable(model) {
            @Override
            public Dimension getPreferredScrollableViewportSize() {
                return getPreferredSize();
            }
        };
    }

    @Override
    public void lostOwnership(Clipboard clipboard, Transferable contents) {
    }
}
like image 40
Paul Samsotha Avatar answered Oct 29 '22 11:10

Paul Samsotha