Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 188
  • Last Modified:

Java FocusManager redispatchEvent to a different JFrame

I have two JFrames. frame1 has focus. I want frame1 to redispatch keyboard events to the currently focused component of frame2.

I've studied the example here of adding alternate KeyEventDispathers to the KeyboardFocusManager:
http://www.developer.com/java/other/article.php/3452231/The-KeyEventDispatcher-in-Java.htm

And I've had success redirecting keyboard events from frame1 to a specific JTextField in frame2.

What I would like is to redirect keyboard events from frame1 to whatever the currently focused component of frame2 is. How can I achieve that?
0
deleyd
Asked:
deleyd
  • 4
  • 4
  • 3
3 Solutions
 
zzynxSoftware engineerCommented:
>> And I've had success redirecting keyboard events from frame1 to a specific JTextField in frame2.
And how did you accomplish that? That could be a good start for a solution to your current question.
0
 
krakatoaCommented:
As I know you are not a tutee, then perhaps you can adapt this code :

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


public class JfConvo extends JFrame implements KeyListener{

static JFrame jf2;
static JFrame jf1;
static JTextArea jta1 = new JTextArea();
static JTextArea jta2 = new JTextArea();
static JTextArea jta22 = new JTextArea();
static mA mAImpl;
static Component focusHolder;

public static void main(String[] args){

	jf2 = new JFrame();

	jf2.getContentPane().add(jta2,BorderLayout.NORTH);
	jf2.getContentPane().add(jta22,BorderLayout.SOUTH);

	jf1 = new JfConvo();

	jf1.getContentPane().add(jta1);

	jf1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	jf2.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
	
	jf1.setSize(new Dimension(150,90));
	jf2.setSize(new Dimension(150,90));
	
	jf1.setVisible(true);
	jf2.setVisible(true);
	
	jta1.addKeyListener(new JfConvo());

	MouseAdapter mAImpl = new mA();
	
	jta2.addMouseListener(mAImpl);
	jta22.addMouseListener(mAImpl);


}


public void keyReleased(KeyEvent k){


Object o = k.getSource();

	
((JTextArea)focusHolder).setText(((JTextArea)o).getText());
}


public void keyPressed(KeyEvent k){}
public void keyTyped(KeyEvent k){}

public static class mA extends MouseAdapter{

public void mouseClicked(MouseEvent e) {}
//Invoked when the mouse button has been clicked (pressed and released) on a component.
 
public void mouseEntered(MouseEvent e) {((Component)e.getSource()).requestFocus();focusHolder = ((Component)e.getSource());}
//Invoked when the mouse enters a component.
 
public void mouseExited(MouseEvent e) {}
//Invoked when the mouse exits a component.
 
public void mousePressed(MouseEvent e) {}
//Invoked when a mouse button has been pressed on a component.
 
public void mouseReleased(MouseEvent e) {}
//Invoked when a mouse button has been released on a component 


}

}

Open in new window


The two small JFrames will appear stacked on each other, top left, so make sure to drag one off).

(and perhaps zzynx might even optimize it for you, as he is great at doing things *properly*)

(Greetings zzynx!) ;)
0
 
zzynxSoftware engineerCommented:
krakatoa did already a nice job. Here's the corrected and optimized code:

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class JfConvo extends JFrame implements KeyListener {

    static JFrame frame2;
    static JfConvo frame1;
    static JTextArea sourceTextArea = new JTextArea();
    static JTextArea copyTextArea1 = new JTextArea();
    static JTextArea copyTextArea2 = new JTextArea();
    static MyMouseAdapter mouseAdapter;
    static Component focusHolder;

    public JfConvo(String title) {
        super(title);
    }

    public static void main(String[] args){

        // Just for layout reasons
        copyTextArea1.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
        copyTextArea2.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

        frame1 = new JfConvo("Frame 1 (the source)");
        frame1.getContentPane().add(sourceTextArea);
        frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame2 = new JFrame("Frame 2 (the copycat)");
        frame2.getContentPane().add(copyTextArea1,BorderLayout.NORTH);
        frame2.getContentPane().add(copyTextArea2,BorderLayout.SOUTH);
        frame2.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

        frame1.setSize(new Dimension(300,300));
        frame1.setLocation(0,0);
        frame2.setSize(new Dimension(300,300));
        frame2.setLocation(300,0);

        frame1.setVisible(true);
        frame2.setVisible(true);

        sourceTextArea.addKeyListener(frame1);

        mouseAdapter = new MyMouseAdapter();

        copyTextArea1.addMouseListener(mouseAdapter);
        copyTextArea2.addMouseListener(mouseAdapter);
    }


    public void keyReleased(KeyEvent k){
        Object o = k.getSource();
        ((JTextArea)focusHolder).setText(((JTextArea)o).getText());
    }

    public void keyPressed(KeyEvent k){

    }

    public void keyTyped(KeyEvent k){

    }

    public static class MyMouseAdapter extends MouseAdapter{

        public void mouseClicked(MouseEvent e) {
            //Invoked when the mouse button has been clicked (pressed and released) on a component.
        }

        public void mouseEntered(MouseEvent e) {
            //Invoked when the mouse enters a component.
            ((Component)e.getSource()).requestFocus();
            focusHolder = ((Component)e.getSource());
        }

        public void mouseExited(MouseEvent e) {
            //Invoked when the mouse exits a component.
        }

        public void mousePressed(MouseEvent e) {
            //Invoked when a mouse button has been pressed on a component.
        }

        public void mouseReleased(MouseEvent e) {
            //Invoked when a mouse button has been released on a component
        }
    }
}

Open in new window


Hi deleyd,

1. Compile and run this code
2. Click in Frame 2 the text area on top (to give it the focus)
3. Type in the text area of Frame 1 something (and see it appear in the focused top text area of frame 2)
4. Click in Frame 2 the text area at the bottom (to give it the focus)
5. Type further in the text area of Frame 1 (and see it appear in the focused bottom text area of frame 2)

I think you get what you wanted :)

( Hi, krakatoa! ;-)
[
btw, you wrote
    jta1.addKeyListener(new JfConvo());

Open in new window

while - I'm quite sure - you wanted to write:
    jta1.addKeyListener(jf1);

Open in new window

but you couldn't since jf1 was defined as being a JFrame instance instead of a JfConvo instance
]
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
krakatoaCommented:
>>but you couldn't since jf1 <<

yeah that could be I forgot that detail, and looking at it properly I can see you are absolutely right. ;)

>>4. Click in Frame 2 the text area at the bottom (to give it the focus)<<

- one small thing here - you don't need to click, just run the mouse over the textarea. ;)
0
 
krakatoaCommented:
-and 'just for fun' this would have been a better class :

public static class mA extends MouseAdapter implements KeyListener{

public void mouseClicked(MouseEvent e) {}
//Invoked when the mouse button has been clicked (pressed and released) on a component.
 
public void mouseEntered(MouseEvent e) {((Component)e.getSource()).requestFocus();focusHolder = ((Component)e.getSource());}
//Invoked when the mouse enters a component.
 
public void mouseExited(MouseEvent e) {}
//Invoked when the mouse exits a component.
 
public void mousePressed(MouseEvent e) {}
//Invoked when a mouse button has been pressed on a component.
 
public void mouseReleased(MouseEvent e) {}
//Invoked when a mouse button has been released on a component 

public void keyPressed(KeyEvent k){}
public void keyTyped(KeyEvent k){}

	public void keyReleased(KeyEvent k){

			Object o = k.getSource();

		((JTextArea)focusHolder).setText(((JTextArea)o).getText());
	}

}

Open in new window


amalgamating both listeners, and predicated on this foundation :

MouseAdapter mAImpl = new mA();
	
	jta2.addMouseListener(mAImpl);
	jta22.addMouseListener(mAImpl);
	jta1.addKeyListener((KeyListener)mAImpl);

Open in new window

0
 
deleydAuthor Commented:
Very interesting code thank you for the sample program. Let's see where the magic is, how this works...

Looks like we are keeping track ourselves of which element in frame2 is the focused element, holding it in focusHolder.

And we do that by, Oh I see where a potential problem here is.

One is focusHolder doesn't contain anything at the beginning. I have to first set focusHolder, or somehow tell it which JTextArea in frame2 has focus initially, so again I either need a way to query frame2, or just 'know' in some god like way which element in frame2 will be the one we start with.

In frame2  I can use Ctrl-Tab to switch to the other JTextArea and focusHolder doesn't get updated. (I could try to catch every possible keystroke that might change the focused component, or add a Focus Change Listener to every component on frame1, though that would be tedious.)

I'm now guessing it's probably the Operating System itself which keeps track of which element in each window has focus? I wonder how Java then gets that information so it can tell me who the focusOwner() is.

I'm also wondering how a keystroke from the keyboard ends up being a KeyEvent in Java. KeyEvent requires a source for it's constructor, which is the currently focused component. (To me that sounds like a destination rather than a source.)

I found I could reverse the scenario and keep frame1 the focused frame by adding to frame2:

frame2.setFocusableWindowState(false);
frame2.setAlwaysOnTop(true);

Open in new window

and I can send keystrokes to the EventQueue:
                Toolkit toolkit = Toolkit.getDefaultToolkit();  
                EventQueue queue = toolkit.getSystemEventQueue();  
                queue.postEvent(new KeyEvent(textField,  
                                             KeyEvent.KEY_TYPED,  
                                             System.currentTimeMillis(),  
                                             0,  
                                             KeyEvent.VK_UNDEFINED,  
                                             newChar)); 

Open in new window

However once again I need to know the "source" component (e.g. textField) in order to create the KeyEvent.

Does Java conceptually instead of having keystrokes sent to a window, keystrokes instead originate from the textField as KeyEvents?
0
 
zzynxSoftware engineerCommented:
Looks like we are keeping track ourselves of which element in frame2 is the focused element, holding it in focusHolder.
Correct. Whenever you hoover the mouse over one of the text areas of frame 2 that text area is saved in focusHolder.

One is focusHolder doesn't contain anything at the beginning.
That shouldn't be a problem. To avoid a NullPointerException you could adapt the code like this:

    public void keyReleased(KeyEvent k){
        if (focusHolder==null) return;
        Object o = k.getSource();
        ((JTextArea)focusHolder).setText(((JTextArea)o).getText());
    }

Open in new window


... or somehow tell it which JTextArea in frame2 has focus initially
That's possible by making your frame2 an instance of your own MyFrame class (extending from JFrame) and by adding a method getInitialFocusHolder(). Then you could initialize focusHolder like this:
focusHolder = frame2.getInitialFocusHolder();

Open in new window


In frame2  I can use Ctrl-Tab to switch to the other JTextArea and focusHolder doesn't get updated.
Right you are.

...add a Focus Change Listener to every component on frame1
to every component of frame2, you mean.

This would do the job:
	copyTextArea1.addFocusListener(new FocusAdapter() {
            public void focusGained(FocusEvent e) {
                focusHolder = (JTextArea)e.getSource();
            }
        );
	copyTextArea2.addFocusListener(new FocusAdapter() {
            public void focusGained(FocusEvent e) {
                focusHolder = (JTextArea)e.getSource();
            }
        );

Open in new window


though that would be tedious.
Right. No pain, no gain. ;-)

To me that sounds like a destination rather than a source
Eg. you click in a text field and it gets the focus. That field is the destination of the clicking process. But it generates a mouseClicked mouse event that is broadcasted to every interested listener. That field is the source of the mouse event.
The mouse was clicked in the source (textfield) and as a result a mouse event is broadcasted to listeners.

Does Java conceptually instead of having keystrokes sent to a window, keystrokes instead originate from the textField as KeyEvents?
Not sure if I understand what you ask...
Events (key events, mouse events, ...) are not sent to anything. They are "broadcasted" or fired. And any listener that is interested (that "subscribed" so to say) is receiving them.
So, in fact when you broadcast/fire an event you don't know beforehand who is listening.
0
 
deleydAuthor Commented:
Perhaps I confuse keystroke with KeyEvent.

Let's see, I type a key, the key somehow goes into the textField,..

A KeyEvent is generated, and the textField is the source of the KeyEvent, which we broadcast to anyone who wants to know if that textField had a KeyEvent happen to it.

But I still don't know how to keystroke gets into the textField in the first place. How does that happen? Does Java handle it? or does the OS handle it and somehow Java learns about it and generates a KeyEvent saying it happened?

And how can I create an onscreen keyboard which emulates a real keyboard? I've seen virtual keyboards that use the Robot class, but I really don't want to be sending the keys to the system wide queue, I just want to send the keys to the queue for my target Java frame.
0
 
krakatoaCommented:
And how can I create an onscreen keyboard which emulates a real keyboard? I've seen virtual keyboards that use the Robot class, but I really don't want to be sending the keys to the system wide queue, I just want to send the keys to the queue for my target Java frame.

 . . . these are all pretty much separate questions, and deserve separate threads. You started off wanting to know how to get one component to pick up text from another, and I think you've got a selection of answers to that already. The code is provided to prove a point - it's hardly ever intended as a full class solution on this site, and the main point is : it's all about Listeners.
0
 
deleydAuthor Commented:
Thank you zzynx and krakatoa!

(zzynx I noticed the name is very close to zzyzx, the silly name for a road out in the middle of the Mojave desert on I-15 which I occasionally drive by once in awhile on trips. zzyzx and xxyzy are my favorite foo bar substitute names. I agree with your bio comments!)
0
 
zzynxSoftware engineerCommented:
You're welcome, deleyd
Thanx 4 axxepting.

zzynx I noticed the name is very close to zzyzx, the silly name for a road out in the middle of the Mojave desert on I-15 which I occasionally drive by once in awhile on trips.
Really?
Indeed: http://en.wikipedia.org/wiki/Zzyzx,_California . And it's even a town.
And apparently also the name of a film: http://en.wikipedia.org/wiki/Zzyzx_%28film%29
:) Funny. Thanks for the info.

I agree with your bio comments!
;-)

"See" you around
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 4
  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now