【问题标题】:JTable right-click copy/paste menu to copy cell data on one clickJTable右键复制/粘贴菜单一键复制单元格数据
【发布时间】:2014-03-23 12:01:13
【问题描述】:

我创建了我的JPopupMenu。当我右键单击一个单元格时,它会出现在我的JTable 上。但是,我无法复制单元格中的数据,除非我首先双击然后突出显示数据,然后右键单击当前单元格以外的任何位置以显示我的弹出菜单和复制选项。

我想复制单元格中的数据,而不必双击单元格并进入单元格编辑模式,然后我需要选择数据。

我该怎么做?

popup = new JPopupMenu();
popup.setName("popupMenu");
menuItemCopy = new JMenuItem(new DefaultEditorKit.CopyAction());
menuItemCopy.setText("Copy");
menuItemCopy.setName("copy");       
popup.add(menuItemCopy);
popup.addSeparator();
menuItemPaste = new JMenuItem(new DefaultEditorKit.PasteAction());
menuItemPaste.setText("Paste");
menuItemPaste.setName("paste");
popup.add(menuItemPaste);

这是我在MouseListener 中为我的JTable 提供的代码,在mouseReleased()mousePressed() 中。

if(e.isPopupTrigger())
{
    JTable source = (JTable)e.getSource();
    int row = source.rowAtPoint( e.getPoint() );
    int column = source.columnAtPoint( e.getPoint() );

    gridView.popup.show(e.getComponent(), e.getX(), e.getY());              
}

【问题讨论】:

  • 能否获取点击单元格数据的值?
  • 请看我的帖子。如果有任何混淆,请告诉我。

标签: java swing popup jtable contextmenu


【解决方案1】:

两件事...

  1. 我不确定您希望 DefaultEditorKit.CopyActionDefaultEditorKit.PasteAction 如何与 JTable 一起使用,这些应该与 JTextComponents 一起使用...
  2. JTable 只会在按下左键(或更改键盘导航)时突出显示该行,默认情况下单击鼠标右键不会执行此操作。

现在,我想使用JTable 的组件弹出支持,但这似乎会在检测到弹出触发器后消耗所有鼠标事件,这使得(几乎)不可能突出显示上的行/列鼠标右键。

相反,我最终在我的MouseListener 中添加了一个highlight 方法,它突出显示有问题的行/列,然后触发弹出窗口。

我这样做的原因是,与复制和粘贴相关的Action 除了表格之外没有任何概念,所以他们不知道点击了哪一行/列。

这允许这些操作专注于单独担心选择。

内容通过自定义的可转移对象直接复制到系统剪贴板,该对象保持单元格的原始类型,这意味着您在粘贴对象时无需重新构建对象。

import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorEvent;
import java.awt.datatransfer.FlavorListener;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import static javax.swing.Action.NAME;
import javax.swing.JFrame;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

public class TestTable100 {

    public static void main(String[] args) {
        new TestTable100();
    }

    public TestTable100() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                DefaultTableModel model = new DefaultTableModel();
                model.addColumn("Type");
                model.addColumn("Column");
                for (File file : new File(System.getProperty("user.home")).listFiles()) {
                    model.addRow(new Object[]{file, file});
                }

                JTable table = new JTable(model);
                table.getColumnModel().getColumn(0).setCellRenderer(new FirstCellRenderer());

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                final JPopupMenu pm = new JPopupMenu();
                pm.add(new CopyAction(table));
                pm.add(new PasteAction(table));

                table.addMouseListener(new MouseAdapter() {

                    @Override
                    public void mouseClicked(MouseEvent e) {
                        if (e.isPopupTrigger()) {
                            highlightRow(e);
                            doPopup(e);
                        }
                    }

                    @Override
                    public void mouseReleased(MouseEvent e) {
                        if (e.isPopupTrigger()) {
                            highlightRow(e);
                            doPopup(e);
                        }
                    }

                    protected void doPopup(MouseEvent e) {
                        pm.show(e.getComponent(), e.getX(), e.getY());
                    }

                    protected void highlightRow(MouseEvent e) {
                        JTable table = (JTable) e.getSource();
                        Point point = e.getPoint();
                        int row = table.rowAtPoint(point);
                        int col = table.columnAtPoint(point);

                        table.setRowSelectionInterval(row, row);
                        table.setColumnSelectionInterval(col, col);
                    }

                });
            }
        });
    }

    public class FirstCellRenderer extends DefaultTableCellRenderer {

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

            File f = (File) value;

            super.getTableCellRendererComponent(table,
                            value, isSelected, hasFocus, row, column);
            String prefix = f.isDirectory() ? "DIR" : "FILE";
            setText(prefix);

            return this;
        }
    }

    public class CopyAction extends AbstractAction {

        private JTable table;

        public CopyAction(JTable table) {
            this.table = table;
            putValue(NAME, "Copy");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            int row = table.getSelectedRow();
            int col = table.getSelectedColumn();

            Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
            cb.setContents(new CellTransferable(table.getValueAt(row, col)), null);
        }

    }

    public class PasteAction extends AbstractAction {

        private JTable table;

        public PasteAction(JTable table) {
            this.table = table;
            putValue(NAME, "Paste");
            final Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
            cb.addFlavorListener(new FlavorListener() {
                @Override
                public void flavorsChanged(FlavorEvent e) {
                    setEnabled(cb.isDataFlavorAvailable(CellTransferable.CELL_DATA_FLAVOR));
                }
            });
            setEnabled(cb.isDataFlavorAvailable(CellTransferable.CELL_DATA_FLAVOR));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            int row = table.getSelectedRow();
            int col = table.getSelectedColumn();

            Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
            if (cb.isDataFlavorAvailable(CellTransferable.CELL_DATA_FLAVOR)) {
                try {
                    Object value = cb.getData(CellTransferable.CELL_DATA_FLAVOR);
                    table.setValueAt(value, row, col);
                } catch (UnsupportedFlavorException | IOException ex) {
                    ex.printStackTrace();
                }
            }
        }

    }

    public static class CellTransferable implements Transferable {

        public static final DataFlavor CELL_DATA_FLAVOR = new DataFlavor(Object.class, "application/x-cell-value");

        private Object cellValue;

        public CellTransferable(Object cellValue) {
            this.cellValue = cellValue;
        }

        @Override
        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[]{CELL_DATA_FLAVOR};
        }

        @Override
        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return CELL_DATA_FLAVOR.equals(flavor);
        }

        @Override
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            if (!isDataFlavorSupported(flavor)) {
                throw new UnsupportedFlavorException(flavor);
            }
            return cellValue;
        }

    }
}

【讨论】:

  • 谢谢。当我尝试粘贴时, table.setValueAt(value, row, col) 似乎正在工作,但在我粘贴的 JTable 单元格中没有显示任何数据。知道可能出了什么问题吗?
  • 另外,在我剪切或复制之后,粘贴选项似乎没有启用。不知道为什么。
  • 没有可运行的代码示例,我不知道,因为我的示例似乎有效......
【解决方案2】:

这是使用 Clipboard

的代码

要遵循的步骤:

  • 声明一些变量来存储当前选中的行列索引

    private static int rowIndex;
    private static int columnIndex;
    
  • MenuItem上添加ActionListener

    menuItemCopy.addActionListener(new ActionListener() {
    
        @Override
        public void actionPerformed(ActionEvent e) {
            StringSelection stringSelection = new StringSelection(String.valueOf(table1
                    .getModel().getValueAt(rowIndex, columnIndex)));
            Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard();
            clpbrd.setContents(stringSelection, null);
        }
    });
    
    menuItemPaste.addActionListener(new ActionListener() {
    
        @Override
        public void actionPerformed(ActionEvent e) {
            Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard();
            try {
                table1.getModel().setValueAt(clpbrd.getData(DataFlavor.stringFlavor), rowIndex,
                        columnIndex);
            } catch (UnsupportedFlavorException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    });
    
  • JTable 上添加MouseListener 以更新rowIndexcolumnIndex 的值,最后显示JPopupMenu

    table1.addMouseListener(new MouseAdapter() {
    
        @Override
        public void mousePressed(MouseEvent e) {
            if (e.getButton() == 3) {
                rowIndex = table1.rowAtPoint(e.getPoint());
                columnIndex = table1.columnAtPoint(e.getPoint());
    
                popup.show(e.getComponent(), e.getX(), e.getY());
            }
        }
    
    });
    

【讨论】:

  • 这行不通。表格的行和列可以从它们在模型中的原始顺序重新排列。这就是为什么我建议在我的回答中使用JXTable,因为它解决了这个问题。
  • @uyuyuy99 与您已经指出的仅使用 JTable#getValueAt 不同,它将行/列转换为模型上下文 - 我看不到 JXTable 如何增加好处。是的,你是对的,但这不会按预期工作;)
  • @MadProgrammer 哦,我明白你现在在说什么了。出于某种原因,我认为table.getValueAt() 只是JXTable 的一种方法。我会更新我的答案。
【解决方案3】:
int row = source.rowAtPoint(e.getPoint());
int column = source.columnAtPoint(e.getPoint());
Object valueInCell = table.getValueAt(row, column);

简单!

【讨论】:

  • 我认为,OP 不想获取当前鼠标位置的值。 OP想要copy cell data on one click。在剪贴板中设置复制单元格数据的代码在哪里。
  • @Braj 我假设他知道如何将文本复制到剪贴板......他甚至展示了他自己的代码已经完成了这一点。你说他“不想获取当前鼠标位置的值”,而是想复制单元格数据——这些本质上不是一回事吗?...
  • @MadProgrammer 呃,是的,我没有忘记这一点。这就是为什么我建议使用JXTable。你确定你不是要评论 Braj 的回答吗?
  • @MadProgrammer table.getValueAt() 不同于 table.getModel().getValueAt()
  • @uyuyuy99 是的,我知道
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-30
  • 2018-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-02
  • 2021-03-18
相关资源
最近更新 更多