【问题标题】:Strange behaviour in KeyListener when using Clipboard使用剪贴板时 KeyListener 中的奇怪行为
【发布时间】:2013-01-02 17:47:25
【问题描述】:

我尝试为我的 JTable 做一个简单的 ctrl+c,但是当使用控制按钮时,整个行被复制,而不是指定的单元格。如何获得想要的效果?

public class ClipboardTable {

private static final Clipboard clipboard = Toolkit.getDefaultToolkit()
        .getSystemClipboard();
public static JTable tab;

public static void copyToClipboard(JTable ctaable) {
    StringBuilder str = new StringBuilder("");
    for (int i = 0; i < ctaable.getSelectedRows().length; i++) {
        str.append(ctaable.getValueAt(ctaable.getSelectedRows()[i], 0));
    }
    StringSelection strsel = new StringSelection(str.toString());
    clipboard.setContents(strsel, strsel);
    System.out.println("expected: "+str.toString());
}

public static void main(String[] args) {
    JFrame jf = new JFrame();
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Object[][] data = {{1,2,3},{5,6,7},{8,9,0}};
    tab = new JTable(data, new String[] {"a","b","c"});
    KeyListener searchKeyListen = new KeyAdapter() {
        @Override
        public void keyPressed(KeyEvent e) {
            ClipboardTable.copyToClipboard(ClipboardTable.tab); //this works fine
            if (e.isControlDown()) {
                if ((e.getKeyCode() == KeyEvent.VK_C)) {
                    ClipboardTable.copyToClipboard(ClipboardTable.tab); // whole row is copied instead of only Cell
                }
            }
        }
    };
    tab.addKeyListener(searchKeyListen);
    jf.add(tab);
    jf.pack();
    jf.setVisible(true);
}
}

【问题讨论】:

  • 我刚刚注意到 CTRL+C 已经实现,这就是干扰
  • 我也是这样,但似乎通过使用KeyBindings 行为已通过(因此我删除了我的评论)请参阅我的答案here

标签: java swing jtable clipboard keylistener


【解决方案1】:

Keybindings 用于 Swing,因为 KeyListener/KeyAdapter 在与 Swing 组件一起使用时存在已知问题。

上面的实现似乎可以正常工作:

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.KeyStroke;

public class ClipboardTable {

    private static final Clipboard clipboard = Toolkit.getDefaultToolkit()
            .getSystemClipboard();
    public static JTable tab;

    public static void copyToClipboard(JTable ctaable) {
        StringBuilder str = new StringBuilder("");
        for (int i = 0; i < ctaable.getSelectedRows().length; i++) {
            str.append(ctaable.getValueAt(ctaable.getSelectedRows()[i], 0));
        }
        StringSelection strsel = new StringSelection(str.toString());
        clipboard.setContents(strsel, strsel);
        System.out.println("expected: " + str.toString());
    }

    public static void main(String[] args) {
        JFrame jf = new JFrame();
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Object[][] data = {{1, 2, 3}, {5, 6, 7}, {8, 9, 0}};
        tab = new JTable(data, new String[]{"a", "b", "c"});

        tab.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK, true), "CTRL C");
        tab.getActionMap().put("CTRL C", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                ClipboardTable.copyToClipboard(ClipboardTable.tab); // whole row is copied instead of only Cell
            }
        });

        jf.add(tab);
        jf.pack();
        jf.setVisible(true);
    }
}

【讨论】:

  • 我总是听说 keyListener 更糟糕,但我不明白为什么。你能详细说明一下吗?
  • @schippi KeyListener 适用于 AWT 组件,您使用的是 Swing。因此可能会出现焦点问题,即您希望组件由 KeyListener 聚焦,而实际上它没有(因此您不会收到 KeyEvents 等)这可以通过在组件上调用 requestFocusInWinow() 来解决,但仅此而已一个黑客。所以主要是因为 KeyAdapter 是为 AWT 设计的。
  • @schippi KeyListerner 是一个低级 API,通常不适合一般交互。您无法保证调用 KeyListeners 的顺序,这意味着您可能会对正在等待击键的其他组件产生不利影响(或者因为其他一些侦听器消耗了它而永远不会被调用)。 KeyListener 只有在它附加到的组件有焦点时才能被通知,KeyBindings 可以被配置来克服这些限制
  • +1 @MadProgrammer 更好的解释,这就是为什么 KeyListener 和 CTRL+C 从来没有为 op 工作的原因,因为侦听器会在操作系统之前拦截,因此操作系统会覆盖它
【解决方案2】:

您可以设置每个单元格的选择范围:

tab.setCellSelectionEnabled(true);

请注意,Swing 中的首选方法是使用 Key Bindings 而不是 KeyListeners

【讨论】:

  • 好吧,这只是一个例子 - 我想要行选择以进行概述,但只有指定列中的值应该被复制,即使选择了另一列中的单元格
【解决方案3】:

你应该

  • 删除KeyListener
  • 选择Action 和正确的key binding。作为Action,您可以使用TransferHandler.getCopyAction()
  • 在您的 JTable 上添加自定义 TransferHandler,以防您对标准行为不满意

【讨论】:

    猜你喜欢
    • 2023-04-03
    • 1970-01-01
    • 2022-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    相关资源
    最近更新 更多