United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4344900 Keyboard accelerators not working with canvas
JDK-4344900 : Keyboard accelerators not working with canvas

Details
Type:
Bug
Submit Date:
2000-06-12
Status:
Resolved
Updated Date:
2000-12-13
Project Name:
JDK
Resolved Date:
2000-12-13
Component:
client-libs
OS:
solaris_8,windows_nt
Sub-Component:
javax.swing
CPU:
x86,sparc
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.2.2,1.3.0
Fixed Versions:
1.4.0 (beta)

Related Reports
Duplicate:
Relates:

Sub Tasks

Description

Name: skT45625			Date: 06/12/2000


Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)


Recently, I switched to JDK 1.3 and my menu's keyboard accelerators
stopped working.  Since I was using Magician OpenGL, I first suspected
that it might be related to the GL component I was using.  I tried
replacing it with a JPanel and, sure enough, the keyboard accelerators
started working again.  Since the GL component extends Canvas, I decided
to try a canvas instead, but this caused the keyboard accelerators to
stop working.

The code below brings up two frames.  One with a Canvas inside and one
with a JPanel inside.  If you try the Ctrl-A command on either, it will
bring up a confirmation dialog box.  But after you click inside the
canvas area, that frame will no longer respond to the keyboard
shortcut.  It works if you have clicked on the title area or menu area,
but stops working once the canvas area has been clicked.  The frame with
the JPanel continues to respond regardless of where you click inside it.

You don't need Magician to run this code.  Hopefully, solving this
problem will help me fix the real application, which uses Magician.
It may be a problem with focus or heavyweight components.  You might
also try using it in JDK 1.3 versus 1.2.2.  My Magician-based app
works perfectly under 1.2.2, but not 1.3.


=====================================================================

//Bug test for menu accelerators.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class TestFrame extends JFrame implements WindowListener{

    // Member variables...
        JFrame parentFrame = this;


//---------------------------------------------------------------------------
// Constructor...
        public TestFrame(String title, boolean useJPanel) {

        super (title);

        AbstractAction action;
        JMenuBar menuBar = new JMenuBar();
        JMenuItem mi;

        // Set up the File menu...
        JMenu fileMenu = new JMenu("File");             // ---> File Menu
        action = new Action1(); // Action 1
        mi = fileMenu.add(action);        // Ctrl-A
                mi.setAccelerator(KeyStroke.getKeyStroke(
                KeyEvent.VK_A, ActionEvent.CTRL_MASK));

        action = new ActionExit();      // Exit
        mi = fileMenu.add(action);        // Ctrl-Q
                mi.setAccelerator(KeyStroke.getKeyStroke(
                KeyEvent.VK_Q, ActionEvent.CTRL_MASK));

        fileMenu.getPopupMenu().setLightWeightPopupEnabled(false);
        menuBar.add(fileMenu);
        setJMenuBar(menuBar);

        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        setSize(200, 100);
        show();


        // Keyboard shortcuts don't work in the canvas frame after the
        // canvas area has been clicked.
        if (useJPanel) {
                JPanel panel = new JPanel();
            panel.setSize(200, 100);
                panel.setBackground(Color.red);
                getContentPane().add(panel);
            repaint();
        }
        else {
                Canvas canvas = new Canvas();
            canvas.setSize(200, 100);
                canvas.setBackground(Color.blue);
                getContentPane().add(canvas);
            repaint();
        }
    }

//==========================================================================
    /** Action class. */
    class Action1 extends AbstractAction {
       
//----------------------------------------------------------------------
        public Action1() {
            super( "Action 1..." );
            putValue(Action.SHORT_DESCRIPTION, "Action 1...");
        }

       
//----------------------------------------------------------------------
        public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(parentFrame,
                "Action 1", "Action Performed",
                    JOptionPane.INFORMATION_MESSAGE);
        }
    }

   

//==========================================================================
    /** Action class. */
    class ActionExit extends AbstractAction {
       
//----------------------------------------------------------------------
        public ActionExit() {
            super( "Exit" );
            putValue(Action.SHORT_DESCRIPTION, "Exit");
        }

       
//----------------------------------------------------------------------
        public void actionPerformed(ActionEvent e) {
                System.exit(0);
        }
    }


//------------------------------------------------------------------------------
// Window listener methods that must be defined...
    public void windowClosed ( WindowEvent evt ) {}
    public void windowActivated( WindowEvent evt ) {}
    public void windowDeactivated( WindowEvent evt ) {}
    public void windowDeiconified( WindowEvent evt ) {}
    public void windowIconified( WindowEvent evt ) {}
    public void windowOpened( WindowEvent evt ) {}


//------------------------------------------------------------------------------
/*
 * When the user closes the window, destroy everything and close the program.
 */
    public void windowClosing( WindowEvent evt ) {

        dispose();
        System.exit( 0 );
    }


//------------------------------------------------------------------------------
/*
 * Create two instances of the frame.
 * One with a Canvas in which keyboard accelerators do not work, and one
 * with a JPanel in which they do.
 */
    static public void main (String args[]) {

        TestFrame canvasFrame = new TestFrame("Canvas", false);
        TestFrame jPanelFrame = new TestFrame("JPanel", true);
    }
}
(Review ID: 106011) 
======================================================================

jocelyn.charbonneau@Eng 2000-12-11
I tried the fix in JDK1.4, beta-43 and beta-44 and it is clearly not sufficiant
for the context of BugID #4395074, where it was deemed a duplicate of this one.  The fix makes accelerators an mnemonics work when the pointer is not on top of 
the heavyweight component, but it doesn't work otherwise.

[pf, 12/12/2000]
   As Jocelyn points out, this does not fix his original bug report
(4395074) even in JDK1.4.  Besides, having a fix in 1.4 is not a
solution for our product, since we need the fix in the versions of
Java which go in Solaris 8, and Solaris 8 updates, and Solaris 9.

                                    

Comments
EVALUATION

Swings keyboard navigation is triggered from JComponent.processKeyEvent, as such, when a non-JComponent has focus JComponent.processKeyEvent will never be called and the bindings will never be used.
We such provide a method that people can call into if they are using a mix of JComponent and non JComponent classes.
scott.violet@eng 2000-07-06

To accomodate this we will add SwingUtilities.processKeyBindings(KeyEvent). When creating a non-JComponent that can get focus, or a JComponent that does not invoke super.processKeyEvent, you will then have to do the following to process JComponent key bindings:
                canvas.addKeyListener(new KeyListener() {
                    public void keyTyped(KeyEvent e) {
                        SwingUtilities.processKeyBindings(e);
                    }
                    public void keyPressed(KeyEvent e) {
                        SwingUtilities.processKeyBindings(e);
                    }
                    public void keyReleased(KeyEvent e) {
                        SwingUtilities.processKeyBindings(e);
                    }
                });

scott.violet@eng 2000-07-14

Moving back to integrated. Customer will escalate if they need patch.
scott.violet@eng 2000-12-12
                                     
2000-07-14
WORK AROUND

stuart.findlay@ireland 2001-02-09

I have a workaround for this bug which passes the appropriate keyEvent from the lightweight to the parent. See file TestFram_Workaround.java in attachments.

Name: skT45625			Date: 06/12/2000


Use 1.2 instead of 1.3.
======================================================================

                                     
2004-06-11
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
merlin-beta

FIXED IN:
merlin-beta

INTEGRATED IN:
merlin-beta


                                     
2004-06-14



Hardware and Software, Engineered to Work Together