catching focus leaving a jpanel

Hi,

I have a JPanel with a number of children (a form). This panel can in turn be nested in a larger form. I need to be able to detect when focus is being transfered from outside of the panel to any of its children, and when focus is being transfered from inside the panel out. When the focus is transfered out, I also want to be able to display a confirmation box with an option to cancel the focus transfer.

Any ideas on how to implement this?

Thanks

Dmitry

[490 byte] By [dberanskya] at [2007-11-27 0:15:19]
# 1

You can have the KeyboardFocusManager notify you when a focus change occurs. Then you just check if the component that now has focus is a child of your panel or not. This posting has some code to get you started:

http://forum.java.sun.com/thread.jspa?forumID=57&threadID=764444

I don't know how to prevent a focus change

camickra at 2007-7-11 22:02:00 > top of Java-index,Desktop,Core GUI APIs...
# 2
well, preventing the focus change is the rub of the problem :) everything else is relatively easy. Anyway, I crossposted the question on another forum: http://forums.java.net/jive/thread.jspa?threadID=24952&tstart=0
dberanskya at 2007-7-11 22:02:00 > top of Java-index,Desktop,Core GUI APIs...
# 3

You could look at this example from the swing tutorial:

http://java.sun.com/docs/books/tutorial/uiswing/misc/examples/InputVerificationDialogDemo.java

It seems pretty straightforward: you attach a listener to the fields you'd like to surveil, and refuse to transfer focus if you aren't pleased with their values.

rebola at 2007-7-11 22:02:00 > top of Java-index,Desktop,Core GUI APIs...
# 4
thanks, but that's not what I'm trying to do
dberanskya at 2007-7-11 22:02:01 > top of Java-index,Desktop,Core GUI APIs...
# 5

When the focus is lost, the focusLost(FocusEvent) method will fire. Couldn't you popup your dialog there, then set the focus back to the component if the user chooses to cancel the operation?

public void focusLost(FocusEvent fe) {

// pop up dialog

// if user selected cancel

// this component.setFocus()

// else

// do whatever

}

hunter9000a at 2007-7-11 22:02:01 > top of Java-index,Desktop,Core GUI APIs...
# 6
[url http://java.sun.com/developer/JDCTechTips/2002/tt1022.html#2] CONTROLLING FOCUS TRAVERSAL SEQUENCING [/url] Might help you out.You could also use requestFocus() on focusGained or keyPressed Events to control Focus.
abillconsla at 2007-7-11 22:02:01 > top of Java-index,Desktop,Core GUI APIs...
# 7

hunter, what you're suggesting won't work. Trying to change focus (e.g. by showling a dialog box) while in the middle of processing another focus event will cause a deadlock of the AWT event thread. That's why InputVerifier was added to Swing a few JDKs back. An input verifier gets activated before focus transfer takes place, thus making it possible to pop a dialog box.

abillconsl, thanks, I'll look into that. that thought has crossed my mind, but for whatever reason I immediately dismissed it. I guess this is worth an investigation.

dberanskya at 2007-7-11 22:02:01 > top of Java-index,Desktop,Core GUI APIs...
# 8

Looking back in some old code, I found this (and this worked just fine for me):

KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();

focusManager.addPropertyChangeListener(new PropertyChangeListener() {

public void propertyChange(PropertyChangeEvent e) {

// had som IFs and ELSEs here, you could put in whatever you'd like.

System.out.println("Focus change. From " + e.getOldValue() + " to " + e.getNewValue());

}

}

);

Just put this anywhere inside code being executed by the EDT.

rebola at 2007-7-11 22:02:01 > top of Java-index,Desktop,Core GUI APIs...
# 9
this won't work for the case I'm trying to implement. If you would like to know why, see the link in the second post.
dberanskya at 2007-7-11 22:02:01 > top of Java-index,Desktop,Core GUI APIs...
# 10

well, it doesn't get any more brittle than this.

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

class Testing

{

JPanel northPanel, southPanel;

public void buildGUI()

{

northPanel = getFormPanel();

southPanel = getFormPanel();

FormPanelListener fpl = new FormPanelListener();

Component[] comp = southPanel.getComponents();

for(int x = 0, y = comp.length; x < y; x++) comp[x].addFocusListener(fpl);

JFrame f = new JFrame();

f.getContentPane().add(northPanel,BorderLayout.NORTH);

f.getContentPane().add(southPanel,BorderLayout.SOUTH);

f.pack();

f.setLocationRelativeTo(null);

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.setVisible(true);

}

public JPanel getFormPanel()

{

JPanel p = new JPanel(new GridLayout(4,1));

p.add(new JTextField(10));

p.add(new JTextField(10));

p.add(new JTextField(10));

p.add(new JButton("OK"));

return p;

}

class FormPanelListener implements FocusListener

{

int counter;

public void focusGained(FocusEvent fe)

{

counter++;

}

public void focusLost(final FocusEvent fe)

{

counter--;

ActionListener al = new ActionListener(){

public void actionPerformed(ActionEvent ae){

if(counter < 1)

{

int continueAction = JOptionPane.showConfirmDialog(null,

"Leaving south panel, continue?","",JOptionPane.OK_CANCEL_OPTION);

if(continueAction != JOptionPane.OK_OPTION)

{

((JComponent)fe.getSource()).requestFocusInWindow();

}

}

}

};

javax.swing.Timer timer = new javax.swing.Timer(100,al);

timer.setRepeats(false);

timer.start();

}

}

public static void main(String[] args)

{

SwingUtilities.invokeLater(new Runnable(){

public void run(){

new Testing().buildGUI();

}

});

}

}

Michael_Dunna at 2007-7-11 22:02:01 > top of Java-index,Desktop,Core GUI APIs...