Re: Setting the Focus on Java windows (JInternalFrames)
John B. Matthews wrote:
In article <gbnsmq$pmb$1@registered.motzarella.org>,
RedGrittyBrick <RedGrittyBrick@spamweary.invalid> wrote:
RedGrittyBrick wrote:
Neo wrote:
I'm trying to set the focus on a Java JInternalFrame but it doesn't
work. Is this a bug? I have tried every method that contains the words
"focus": requestFoucs, setFocusable, etc. I want the window to have
the focus. Can someone show me how to do this?
[...]
I must remember not to post untested guesswork!
The OP needs setSelected(true).
RGB: I can't tell you how much fun I had with your fine example; sorry
if I mangled it while tinkering, below. [I commented out the @Override
annotations to suit my older compiler (1.5.0_16).]
I'm glad someone else enjoys tinkering with this sort of small example.
I appreciate seeing how you approached refactoring the repetetive
elements. You didn't do it the way I would have done - which gives me an
opportunity to reflect on the different approaches and to learn
something new.
Some comments below - these are not criticism, just musing about my own
biases.
<code>
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.beans.PropertyVetoException;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
/**
* How to switch "Focus" between JInternalFrames
* @author RedGrittyBrick, John B. Matthews
*/
public class InternalFrameFocus {
private static final int MAX = 5;
private ArrayList<MyFrame> frames = new ArrayList<MyFrame>();
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
//@Override
public void run() {
new InternalFrameFocus().createAndShowGUI();
I've started using this idiom since Lew (IIRC) stated something to the
effect that "constructors should only construct". I suspect it doesn't
matter in this example, but I try to create habits that are most often
positive.
}
});
}
void createAndShowGUI() {
JDesktopPane desktop = new JDesktopPane();
desktop.setPreferredSize(new Dimension(300, 200));
for (int i = 1; i <= MAX; i++) {
MyFrame frame = new MyFrame(desktop, "F" + i, i * 20);
My first thought was that I would have had MyFrame(desktop, i) but I can
see there are arguments for making the constructor more general.
frames.add(frame);
It is interesting that you pass desktop to the constructor so that the
constructor adds the new frame to the desktop, yet you have the calling
method do the work of adding the frame to a list. I guess this is part
of trying to make MyFrame general and not specific to one application.
All JInternalFrames will get added to a JDesktopPane but not all (in
general) will get added to a list - hence the separation?
}
JMenu menu = new JMenu("Focus");
for (int i = 0; i < MAX; i++) {
menu.add(new JMenuItem(frames.get(i).getAction()));
My first instinct would have been to somehow define the Actions at a
high level in the object hierarchy (e.g. in some collection that is a
field of InternalFrameFocus). You have done it from the other "end".
I do prefer
List<Foo> foos = ...
for (Foo foo: foos)
foo.do();
to
static final int MAX = ...
for (int i=0; i<MAX; i++) ...
foos.get(i).do();
So I tend to rearrange things to fit this idiom. Maybe I should loosen
this habit a little.
}
JMenuBar bar = new JMenuBar();
bar.add(menu);
JFrame f = new JFrame("InternalFrameFocus");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(desktop);
f.setJMenuBar(bar);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class MyFrame extends JInternalFrame {
I'm trying to condition myself to "favor composition over inheritance"
as Joshua Bloch puts it. Actually I'd probably have written a factory
method.
private Action action;
I found it striking that you associated the action with the object being
acted on (rather than with the object that contains the objects that
trigger the actions). I'll have to reconsider my habits!
MyFrame(JDesktopPane desktop, String name, int offset) {
this.setSize(120, 80);
this.setLocation(offset, offset);
I'd try to lay them out on the other diagonal, so that whichever has
focus, the titles of all internal frames are always visible.
this.setTitle(name);
this.setVisible(true);
desktop.add(this);
action = new AbstractAction(name) {
//@Override
public void actionPerformed(ActionEvent ae) {
try {
MyFrame.this.setSelected(true);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}
};
}
public Action getAction() { return action; }
}
</code>
Interesting - thanks for posting this.
--
RGB