Frage

I have an older stand alone java swing-based app that uses JFrame with JMenuBar containing multiple Jmenu elements (with respective JMenuItem items).

After upgrading to the latest 1.6.0_41 (or 1.7.x) JVM on Windows (7 and vista) I've noticed that the menu item with the shortcut Ctrl-C (or Ctrl-Insert) doesn't receive its ActionEvent anymore if JTable is added to the frame. The menu ActionListener is invoked if the menu is accessed by the mouse click however. The shortcut works if JTable is removed. If I change the shortcut combination to something other than Ctrl-C or Ctrl-Insert (i.e. Ctrl-L) the ActionListener is invoked.

The way it used to work (I've just confirmed it with jvm 1.4, on Windows Vista - I know it's been awhile since that environment got any serious attention :) is that Ctrl-C will perform the standard copy to clipboard function inside of the JTable if the focus was inside of an editable field. Otherwise my menu ActionListener was invoked via shortcut assigned through setAccelerator() method.

It looks like JTable implementation changed in 1.6.* to process Ctrl-C bound event differently on Windows.

Running this app on Mac OS (JVM 1.6.0_43) I can see ActionListener is invoked via Ctrl-C shortcut. Although it might be because the JTable uses Command-C instead of Ctrl-C to copy to the clipboard under Mac OS.

I've extracted the relevant portion of the code that demonstrates the problem. Any suggestions are greatly appreciated.

public class TestFrame extends JFrame {

public TestFrame(String title) {

    super(title);
}

private void init() {

    getContentPane().setLayout(new BorderLayout());

    addMenu();
    addTable();

    // Change default exit operation
    setDefaultCloseOperation(EXIT_ON_CLOSE);

    pack();
    setVisible(true);
}

private void addTable() {

    JTable jTable = new JTable(createTableModel());

    // Place table in JScrollPane
    JScrollPane scrollPane = new JScrollPane(jTable);

    // Add Table
    add(scrollPane, BorderLayout.CENTER);
}

private TableModel createTableModel() {

    Object[][] data = new Object[][]{ 
            {new Date(), "First Row, 2nd column", "First Row, 3rd column"},
            {new Date(), "Second Row, 2nd column", "Second Row, 3rd column"},
        };

    Object[] columnNames = new Object[]{"Date", "Type", "Description"};

    DefaultTableModel model = new DefaultTableModel(data, columnNames) {

        public boolean isCellEditable(int row, int column) {
            return column != 0;
        }

    };

    return model;
}

private void addMenu() {

    // Create the menu bar.
    JMenuBar menuBar = new JMenuBar();
    setJMenuBar(menuBar);

    JMenu editMenu = new JMenu("Edit");
    menuBar.add(editMenu);

    TestActionListener listener = new TestActionListener();
    JMenuItem menuItem = null;

    menuItem = new JMenuItem("Copy 1");
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, ActionEvent.CTRL_MASK));
    menuItem.addActionListener(listener);
    editMenu.add(menuItem);

    menuItem = new JMenuItem("Copy 2");
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
    menuItem.addActionListener(listener);
    editMenu.add(menuItem);

    menuItem = new JMenuItem("Copy 3");
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.CTRL_MASK));
    menuItem.addActionListener(listener);
    editMenu.add(menuItem);
}


public static void main(String[] args) {

    TestFrame frame = new TestFrame("Test");
    frame.init();
}


private static class TestActionListener implements ActionListener {

    public void actionPerformed(ActionEvent e) {
        System.out.println("TestFrame.TestActionListener.actionPerformed(): e="+ e);
    }
}

}

War es hilfreich?

Lösung 2

If you question is how to remove the Control+C binding from the table then you can do:

KeyStroke copy = KeyStroke.getKeyStroke("control C");
InputMap im = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.getParent().remove(copy);

However, this will remove the binding from all tables.

Andere Tipps

The problem is that your frame is not focused and there are no elements in your whole component hierarchy which has the focus, meaning that no one will "grab" the event and try to do something with it. Since JMenuItem's bind their shortcut to the input map JComponent.WHEN_IN_FOCUSED_WINDOW, your shortcut never "answers" the event.

To fix this, either put the focus on one of the component or directly on the JFrame (for example with frame.requestFocusInWindow();). Small example here:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class TestFrame extends JFrame {

    public TestFrame(String title) {

        super(title);
    }

    private void init() {

        getContentPane().setLayout(new BorderLayout());

        addMenu();
        addTable();

        // Change default exit operation
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        pack();
        setVisible(true);
    }

    private void addTable() {

        JTable jTable = new JTable();

        // Place table in JScrollPane
        JScrollPane scrollPane = new JScrollPane(jTable);

        // Add Table
        add(scrollPane, BorderLayout.CENTER);
    }

    private void addMenu() {

        // Create the menu bar.
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);

        JMenu editMenu = new JMenu("Edit");
        menuBar.add(editMenu);

        TestActionListener listener = new TestActionListener();
        JMenuItem menuItem = null;

        menuItem = new JMenuItem("Copy 1");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.CTRL_MASK));
        menuItem.addActionListener(listener);
        editMenu.add(menuItem);

        menuItem = new JMenuItem("Copy 2");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK));
        menuItem.addActionListener(listener);
        editMenu.add(menuItem);

        menuItem = new JMenuItem("Copy 3");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.CTRL_MASK));
        menuItem.addActionListener(listener);
        editMenu.add(menuItem);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                TestFrame frame = new TestFrame("Test");
                frame.init();
                frame.requestFocusInWindow();
            }
        });
    }

    private static class TestActionListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("TestFrame.TestActionListener.actionPerformed(): e=" + e);
        }
    }
}

Additional remarks:

  • Don't extend JFrame if not needed
  • Start your UI from the Event Dispatching Thread (EDT) by using SwingUtilities.invokeLater()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top