Setting the Focus on Java windows (JInternalFrames)

N

Neo

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?
 
R

RedGrittyBrick

Neo said:
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?

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.
 
R

RedGrittyBrick

RedGrittyBrick said:
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.

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< ------------------------------
 
J

John B. Matthews

RedGrittyBrick said:
[...]
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>
 
J

John B. Matthews

Lew said:
John said:
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).]

Java 5 has the @Override notation, but AIUI only for class inheritance, not
interface implementation.

Do I have that right?

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?
 
R

RedGrittyBrick

John said:
RedGrittyBrick said:
RedGrittyBrick said:
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.
 
J

John B. Matthews

RedGrittyBrick said:
John said:
RedGrittyBrick said:
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.
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.


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.
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()));
}
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."
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."
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.
Interesting - thanks for posting this.

Likewise.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top