Usually you have to arrange that focus requests are scheduled later than
the completion of the processing of the current GUI event (e.g.
mouse-click on a button or menu item).
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
widget.requestFocus();
}
});
Note, IME this applies even if the current thread is the EDT.
--
RGB
I must remember not to post untested guesswork!
The OP needs setSelected(true).
----------------------------- 8< ------------------------------
/**
* How to switch "Focus" between JInternalFrames
* @author RedGrittyBrick
*/
package org.redgrittybrick.test;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
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;
public class InternalFrameFocus {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new InternalFrameFocus().createAndShowGUI();
}
});
}
void createAndShowGUI() {
final JInternalFrame frameA = new JInternalFrame("A");
frameA.setSize(100, 70);
frameA.setLocation(60, 20);
frameA.setVisible(true);
final JInternalFrame frameB = new JInternalFrame("B");
frameB.setSize(100, 70);
frameB.setLocation(20, 40);
frameB.setVisible(true);
JDesktopPane desktop = new JDesktopPane();
desktop.setPreferredSize(new Dimension(300, 200));
desktop.add(frameA);
desktop.add(frameB);
Action a = new AbstractAction("A") {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
frameA.setSelected(true);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}
};
Action b = new AbstractAction("B") {
@Override
public void actionPerformed(ActionEvent arg0) {
try {
frameB.setSelected(true);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}
};
JMenuItem itemA = new JMenuItem(a);
JMenuItem itemB = new JMenuItem(b);
JMenu menu = new JMenu("Focus");
menu.add(itemA);
menu.add(itemB);
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);
}
}
----------------------------- 8< ------------------------------
--
RGB
> 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).]
<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();
}
});
}
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);
frames.add(frame);
}
JMenu menu = new JMenu("Focus");
for (int i = 0; i < MAX; i++) {
menu.add(new JMenuItem(frames.get(i).getAction()));
}
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 {
private Action action;
MyFrame(JDesktopPane desktop, String name, int offset) {
this.setSize(120, 80);
this.setLocation(offset, offset);
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>
--
John B. Matthews
trashgod at gmail dot com
home dot woh dot rr dot com slash jbmatthews
Java 5 has the @Override notation, but AIUI only for class inheritance, not
interface implementation.
Do I have that right?
--
Lew
Yes. I stumbled upon this difference as I prepared to ask how to get
around the compiler error. I might have hoped for something more
dispositive in the API:
<http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Override.html>
<http://java.sun.com/javase/6/docs/api/java/lang/Override.html>
Annotating interface implementation makes sense, but it seems odd to say
something overrides an interface declaration. Why not @Implement?
<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5008260>
which addresses:
<http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.6.1.4>
> Note that if a method overrides a method from a superinterface but
> not from a superclass, using @Override will cause a compile-time error.
--
Lew
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.
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
> John B. Matthews wrote:
> > In article <gbnsmq$pmb$1...@registered.motzarella.org>,
> > RedGrittyBrick <RedGrit...@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.
Excellent! I appreciate your taking time to comment. Permit me to
respond similarly.
> > <code>
> > import [...]
> >
> > /**
> > * 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.
Yes. GUI constructors, especially, tend to go on and on. One reason I
prefer nested components is that they re-factor nicely into short,
auxiliary methods returning JPanel. I just have to remember,
"Constructors must not invoke overridable methods," and keep them
private.
> > }
> > });
> > }
> >
> > 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?
Good point. This is my old Mac application bias, where the OS owns the
Desktop and documents are owned by the application rather than
by a GUI container. In a cross-platform, multi-document application, I'd
perhaps extend JDesktopPane and let it contain a list of MyDocument,
each extending JInternalFrame.
> > }
> >
> > 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 was thinking a MyFrame should be able to select itself in response to
a menu command, but I haven't worked through the implications. For
example, the menu item will have to change when the document is named
and/or saved; it will disappear when deleted/closed.
> 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.
I prefer the for-each loop, too. I just had to convince myself that the
(implied) iterator had the right order:
for (MyFrame frame : frames) {
menu.add(new JMenuItem(frame.getAction()));
}
> > }
> > 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.
I'm still accumulating heuristics to distinguish is-a versus has-a. In
this case, I was thinking "MyFrame is-a menu-selectable JInternalFrame"
rather than "JDesktopPane has-a list of Actions that parallel a list of
JInternalFrame."
> > 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!
It's my database bias: "There can be only one datum (method), but you
can have an copy (invocation) on request."
> > 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.
Yes! My favorite document-centric applications let you set a preferred
stacking order, and this is the default. Sounds like a job for the
Strategy pattern.
> > 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.
Likewise.