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());
}
}
}
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.
"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:
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) {
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With