3

I have a JTable with a cellrenderer and my table is non-editable. When i select a cell and copy (ctrl-c) the value, its copying not the shown in the cell, it is copying the value which store in model. How could I copy cell value which shown in table.

public class TableDemo {

    public static void main(String[] args) {
        Vector<String> values = new Vector<String>();
        values.add("Val1");
        values.add("Val2");
        JTable table = new JTable(new Object[][] { { "key", values },
                { "key2", values } }, new String[] { "Col1", "Col2" });

        table.getColumnModel().getColumn(1).setCellRenderer(new MyTableCellRenderer());
        table.setCellSelectionEnabled(true);
        JFrame jf = new JFrame();
        jf.getContentPane().add(table);

        jf.setSize(500, 500);

        jf.setVisible(true);
    }
}

class MyTableCellRenderer extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
                row, column);

        @SuppressWarnings("unchecked")
        Vector<String> values = (Vector<String>) value;
        setText(values.get(row));

        return this;
    }
}
rdonuk
  • 3,921
  • 21
  • 39
  • Renderer is just and about painting JTables view, not, don't never to create any Object inside, e.g. Vector values = (Vector) value; – mKorbel Aug 19 '14 at 12:59
  • please whats is How could i copy cell value which shown in table., DYM??? copy - paste, by default ctrl+c - ctrl+v/x (or ctrl+insert - shift+insert), then this is done by using TableCellEditor – mKorbel Aug 19 '14 at 13:01
  • yes i need copy with ctrl-c. and you are saying not possible to get cellrenderer value? My table should be non editable by the way so cant use celleditor. – rdonuk Aug 19 '14 at 13:03
  • http://www.javaworld.com/article/2077579/learn-java/java-tip-77--enable-copy-and-paste-functionality-between-swing-s-jtables-and-excel.html – Joop Eggen Aug 19 '14 at 13:43

1 Answers1

6

You need to implement your own copy command. Here is the solution.

import java.awt.Component;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;


public class TableDemo {

    public static void main(String[] args) {
        final Vector<String> values = new Vector<String>();
        values.add("Val1");
        values.add("Val2");
        final JTable table = new JTable(new Object[][] { { "key", values },
                { "key2", values } }, new String[] { "Col1", "Col2" });

        table.getColumnModel().getColumn(1).setCellRenderer(new MyTableCellRenderer());
        table.registerKeyboardAction(new CopyAction(), KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK), JComponent.WHEN_FOCUSED);
        table.setCellSelectionEnabled(true);
        final JFrame jf = new JFrame();
        jf.getContentPane().add(table);

        jf.setSize(500, 500);

        jf.setVisible(true);
    }

    private static class CopyAction extends AbstractAction {

        /**
         * {@inheritDoc}
         */
        @Override
        public void actionPerformed(ActionEvent e) {
            final JTable tbl = (JTable) e.getSource();
            final int row = tbl.getSelectedRow();
            final int col = tbl.getSelectedColumn();
            if (row >= 0 && col >= 0) {
                final TableCellRenderer renderer = tbl.getCellRenderer(row, col);
                final Component comp = tbl.prepareRenderer(renderer, row, col);
                if (comp instanceof JLabel) {
                    final String toCopy = ((JLabel) comp).getText();
                    final StringSelection selection = new StringSelection(toCopy);
                    final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                    clipboard.setContents(selection, selection);
                }
            }
        }

    }
}

@SuppressWarnings("serial")
class MyTableCellRenderer extends DefaultTableCellRenderer {
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
                row, column);

        @SuppressWarnings("unchecked")
        final
        Vector<String> values = (Vector<String>) value;
        setText(values.get(row));

        return this;
    }
}
Sergiy Medvynskyy
  • 11,160
  • 1
  • 32
  • 48
  • everything wrapped inside `SuppressWarnings` and `return this` is wrong – mKorbel Aug 19 '14 at 13:32
  • JTables view can returs its value without Renderer is touched, incl. value modifyied in Renderer too (e.g. Icon) – mKorbel Aug 19 '14 at 13:34
  • @mKorbel I've simple extended the example from the question. But you are right the code in renderer is bad. – Sergiy Medvynskyy Aug 19 '14 at 13:41
  • @mKorbel Have you suggestion how to shorten the code in actionPerformed? – Sergiy Medvynskyy Aug 19 '14 at 13:42
  • You should actually delegate to the real table cell renderer, otherwise if you're using a look and feel which uses a different one (e.g. Aqua), the look of your table won't match other tables. (Or, like, use something like SwingX where copying might even copy the presented value without having to do anything.) – Hakanai Feb 25 '16 at 02:42