Menu shortcut keys in another JFrame

Greetings,

This is the scenario: my application uses one JFrame as the 'main'

application frame. It carries all the frillies: a toolbar, a main desktop

area and a menu bar with quite a lot of menu items, most having a

shortcut key.

This all works fine. One of those menu items toggles the visibility of

a second JFrame which doesn't have much functionality, i.e. it just

display two JTextAreas (which aren't editable) that display the redirected

System.out and System.err respectively.

When this second JFrame is the focus owner, those shortcut keys in

the first main application window aren't processed. I attempted to solve

it like this (this is code in the second JFrame initialization method):JRootPane trp= this.getRootPane();

JRootPane prp= ApplicationFrame.getFrame().getRootPane();

trp.getInputMap().setParent(prp.getInputMap());

trp.getActionMap().setParent(prp.getActionMap());

The idea was that by setting the maps of the application JFrame as the

parents of the maps in the second JFrame would solve this little problem.

Not so, it doesn't work. Adding a KeyListener to the second JFrame

doesn't give me much either because I can't figure out how to

'redispatch' the KeyEvent to the first main application JFrame.

Then I got lost in the KeyboardFocusManager documentation for which

I suspect that focus traversal would not be the way to go. I realize that

my little problem isn't unique and that it must've been solved before.

Does anyone want to show me how to solve this? Also, can some kind

soul explain to me why my idea (see above) doesn't work? Obviously

I don't understand keyboard event processing much ...

kind regards,

Jos

[1828 byte] By [JosAH] at [2007-11-26 12:04:21]
# 1
Have you triedsecondFrame.setFocusableWindowState(false);to prevent the second frame from gaining keyboard focus?Cheers, Jukka
duckbill at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 2

Or you could transfer the key presses to the main frame

// Define this is KeyListener for second frame

public void keyTyped(KeyEvent ke)

{

keyListenerForMainFrame.keyTyped(ke);

}

//...

Cheers

duckbill at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 3

> Have you tried> secondFrame.setFocusableWindowState(false);

> to prevent the second frame from gaining keyboard focus?

I thought about that and it will work for this particular output stream

frame. But what should be done when other future frames *do* want to

gain the focus?

I'm trying to find a way to redirect all non-understood keys from a current

frame to the main application frame.

thank you very much for your reply, much appreciated.

kind regards,

Jos

JosAH at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 4

> Or you could transfer the key presses to the main frame

> // Define this is KeyListener for second frame

> public void keyTyped(KeyEvent ke)

> {

>keyListenerForMainFrame.keyTyped(ke);

>

> //...

> Cheers

But what should that other KeyListener (the one in the main app frame)

do with the event then? It doesn't know where to re-dispatch it to. The

trouble is I got stuck in the documentation again, i.e. suppose I find the

JMenuBar in the main frame. This menu bar is a MenuContainer which

can re-dispatch this event for me but that bloody method is deprecated

and I can't find what the docs are mentioning: dispatchEvent(AWTEvent).

Thank you very much for your reply, I do appreciate it.

kind regards,

Jos

JosAH at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 5

Try this for ideas

package testing;

import javax.swing.*;

import java.awt.event.*;

public class Test

{

public static void main(String[] args)

{

JFrame frame1 = new JFrame("Main");

JFrame frame2 = new JFrame("Second");

frame1.setLocation(400, 400);

frame2.setLocation(450, 450);

frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

final JButton button = new JButton("alt + 0");

button.setMnemonic(KeyEvent.VK_0);

final JLabel label = new JLabel("0");

button.addActionListener(new ActionListener()

{

public void actionPerformed(ActionEvent ae)

{

label.setText(String.valueOf(Integer.parseInt(label.getText()) + 1));

}

});

frame2.addKeyListener(new KeyAdapter()

{

public void keyTyped(KeyEvent ke)

{

if (ke.getKeyChar() == KeyEvent.VK_0)

button.doClick();

}

});

frame1.add(button);

frame2.add(label);

frame1.pack();

frame2.pack();

frame1.setVisible(true);

frame2.setVisible(true);

}

}

I used a button to make it simple but I guess the setMnemonic(...) method works similarly for menuitems?

Jukka

duckbill at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 6

I'm sorry, that's not what I intend to do: in your scenario the second frame

knows somehow what's supposed to happen when a key is pressed.

I'm trying to figure out how the second frame can redispatch a KeyEvent

to the main frame for any key unknown to any component in the second

frame, i.e. an unconsumed KeyEvent.

I do appreciate your thinking about my nasty little problem though ;-)

kind regards,

Jos

ps. I suspect the answer can be found somewhere in the KeyboardFocusManager,

not sure though ...

JosAH at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 7

******. =) Well heres another revised version for you to consider. Now frame2 does not have clue as to what the keypresses in frame1 do...

package testing;

import javax.swing.*;

import java.awt.event.*;

public class Test

{

public static void main(String[] args)

{

final JFrame frame1 = new JFrame("Main");

final JFrame frame2 = new JFrame("Second");

frame1.setLocation(400, 400);

frame2.setLocation(450, 450);

frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

final JButton button = new JButton("alt + 0");

final JLabel label = new JLabel("0");

button.setMnemonic(KeyEvent.VK_0);

button.addActionListener(new ActionListener()

{

public void actionPerformed(ActionEvent ae)

{

label.setText(String.valueOf(Integer.parseInt(label.getText()) + 1));

}

});

frame1.addKeyListener(new KeyAdapter()

{

public void keyTyped(KeyEvent ke)

{

if (ke.getKeyChar() == KeyEvent.VK_0)

button.doClick();

}

});

frame2.addKeyListener(new KeyAdapter()

{

public void keyTyped(KeyEvent ke)

{

frame1.getKeyListeners()[0].keyTyped(ke);

}

});

frame1.add(button);

frame2.add(label);

frame1.pack();

frame2.pack();

frame1.setVisible(true);

frame2.setVisible(true);

}

}

Jukka

duckbill at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 8

> ******. =)

My email notification didn't show those stars ... ;-)

> Well heres another revised version for you to consider. Now frame2

> does not have clue as to what the keypresses in frame1 do...

That is not what I want either, sorry; your scenario needs the main

JFrame/window to know what every key press is all about. Consider

this from a user perspective: there's a secondary window somewhere,

either visible or not. A simple key press should toggle its visibility.

Clicking the title bar should bring that secondary window up front.

I just can't do that and I hate it because this little nuisance ruined my

entire Sunday afternoon.

Thank you for you reply though; it makes me realize that such a simple

thing (from a user's perspective) isn't that trivial at all ..

kind regards,

Jos

JosAH at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 9

maybe(?) something like this might do

click the menu items (or F2/F3) to show the 2nd/3rd frame, then F1/F2/F3

again, to trigger the main frame action.

I have been using KeyboardFocusManager... for something like this, but

courtesy of camickr, this seems to be simpler (although I haven't used it

enough to be sure of no hidden gotchas)

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

class Testing

{

JFrame f1;

JFrame f2;

JFrame f3;

public void buildGUI()

{

JMenu menu = new JMenu("File");

JMenuItem frame1 = new JMenuItem("Frame1 (F1)");

JMenuItem frame2 = new JMenuItem("Frame2 (F2)");

JMenuItem frame3 = new JMenuItem("Frame3 (F3)");

frame1.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent ae){

frame_1_Action();

}

});

frame2.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent ae){

frame_2_Action();

}

});

frame3.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent ae){

frame_3_Action();

}

});

menu.add(frame1);

menu.add(frame2);

menu.add(frame3);

JMenuBar menuBar = new JMenuBar();

menuBar.add(menu);

f1 = new JFrame();

f1.setJMenuBar(menuBar);

f1.setSize(100,100);

f1.setLocationRelativeTo(null);

f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f1.setVisible(true);

Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener()

{

public void eventDispatched(AWTEvent e)

{

if(e.getID() == KeyEvent.KEY_PRESSED)

{

if(((KeyEvent)e).getKeyCode() == KeyEvent.VK_F1)

{

frame_1_Action();

}

else if(((KeyEvent)e).getKeyCode() == KeyEvent.VK_F2)

{

frame_2_Action();

}

else if(((KeyEvent)e).getKeyCode() == KeyEvent.VK_F3)

{

frame_3_Action();

}

}

}

}, AWTEvent.KEY_EVENT_MASK);

}

public void frame_1_Action()

{

if(f2 != null) f2.dispose();

if(f3 != null) f3.dispose();

}

public void frame_2_Action()

{

if(f2 == null)

{

f2 = new JFrame("F2");

f2.getContentPane().add(new JLabel("F2"));

f2.setSize(100,100);

f2.setLocation(600,200);

f2.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

}

f2.setVisible(true);

}

public void frame_3_Action()

{

if(f3 == null)

{

f3 = new JFrame("F3");

f3.getContentPane().add(new JTextField("F3"));

f3.setSize(100,100);

f3.setLocation(400,500);

f3.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

}

f3.setVisible(true);

}

public static void main(String[] args)

{

SwingUtilities.invokeLater(new Runnable(){

public void run(){

new Testing().buildGUI();

}

});

}

}

Michael_Dunn at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 10

> Consider this from a user perspective:

From the user perspective there should only ever be one active window at a time. Any commands you invoke should be handled by that window.

> there's a secondary window somewhere, either visible or not.

Maybe thats the problem, the secondary window, once created should always be visible when the primary frame is activated. That is, your secondary window should be a dialog with the frame as the owner. Then the secondary window is automatically made visible when the primary window is activated

> A simple key press should toggle its visibility.

If the secondary window has focus then the KeyStroke should deactivate the secondary window and activate the primary window.

If the primary window has focus then the KeyStroke should show and activate the secondary window.

So the same KeStroke would be defined in both windows, but it would have a different meaning depending on which window was active at the time.

Here is a simply example of the primary frame and secondary dialog working together.

import javax.swing.*;

public class FrameDialogTest extends JFrame

{

public static void main(String[] args)

{

JFrame frame = new FrameDialogTest();

frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

frame.setSize(200, 200);

frame.setVisible(true);

JDialog dialog = new JDialog(frame, false);

dialog.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE );

dialog.setSize(200, 200);

dialog.setLocationRelativeTo( null );

dialog.setVisible(true);

}

}

camickr at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...
# 11

> > Consider this from a user perspective:

>

> From the user perspective there should only ever be one active

> window at a time. Any commands you invoke should be handled by

> that window.

> > there's a secondary window somewhere, either visible or not.

>

> Maybe thats the problem, the secondary window, once created

> should always be visible when the primary frame is activated. That is,

> your secondary window should be a dialog with the frame as the

> owner. Then the secondary window is automatically made visible

> when the primary window is activated

The only reason I made that second window a JFrame instead of a non-

modal dialog is that I wanted it to have its own icon in the top left corner.

I simply want that (output displaying) window to be there or not, depending

on a toggle key, but acually that second window never needs to be the

focus owner. If I make that second window non focusable I can never

put it on top of the first window when its visibility is toggled to 'on'. If I

could do that, my problems are over.

> > A simple key press should toggle its visibility.

>

> If the secondary window has focus then the KeyStroke should

> deactivate the secondary window and activate the primary window.

>

> If the primary window has focus then the KeyStroke should show and

> activate the secondary window.

>

> So the same KeStroke would be defined in both windows, but it

> would have a different meaning depending on which window was

> active at the time.

Yes, that was my previous solution: add a little key listener to that second

window that would also toggle the visibility of the second window. It didn't

'feel right', i.e. the second window would listen to that single key and it

made the user (me) wanting to be able to use the other keys defined

in the first window too.

[ example snipped: functionally equivalent to my previous solution ]

I'm afraid I have to live with that gesture 'paradigm' ... Thank you very

much for your reply; I guess I'm going to revert to that previous solution

(see above) which you also described.

kind regards,

Jos

JosAH at 2007-7-7 12:30:37 > top of Java-index,Desktop,Core GUI APIs...