I am writing a small game, with one JFrame that holds the main game, and another JFrame that displays the score. the problem is, when I am done constructing them, the score JFrame always ends up focused! I have tried calling scoreDisplay.toFront(), scoreDisplay.requestFocus(), and even:
display.setState(JFrame.ICONIZED);
display.setState(JFrame.NORMAL);
Is there any way to make this work?
Thanks in advance,
john murano
Call the requestFocus() method.
This is not guaranteed to work, because there are many reasons why an operating system would not allow a frame to have focus. There could be another frame with higher priority in a different application. There are also some linux desktops which (if I recall correctly) do not allow frames to request focus.
To give you a better chance of success, I also recommend calling the toFront() method before requesting focus.
frame.setVisible(true);
frame.toFront();
frame.requestFocus();
Please keep in mind, none of this is guaranteed because frame handling, especially with focus and layering, is very operating system-dependant. So set the frame to visible, move it to the front, and request the focus. Once you give up the EDT, the operating system will likely give the frame the focus. At the very least, the window should be on top.
Toggle alwaysOnTop
See here:
http://forums.sun.com/thread.jspa?threadID=5124278
Read about toFront in the API
http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Window.html#toFront
Some platforms may not permit this VM
to place its Windows above windows of
native applications, or Windows of
other VMs.
On Windows OS for example toFront
causes the icon on the Task Bar to
flicker, but the window stays in the
back.
The only think that will force the
window to front is setAlwaysOnTop.
frame.setAlwaysOnTop(true);
frame.setAlwaysOnTop(false);
Have you consider setting the score in the same frame as the game frame?
Other possible ( quick and dirty ) option is to create them in reverse order, or at least ( if score depends on game ) display them in reverse order.
score.setVisible( true );
game.setVisible( true );
My guess is that currently they are:
game.setVisible( true );
score.setVisible( true );
The way that I would do is:
frame.toFront();
frame.setState(Frame.NORMAL);
and If you also want have more control on it you should use requestFocuse.
BTW, here is an example :
http://coding.derkeiler.com/Archive/Java/comp.lang.java.gui/2006-06/msg00152.html
Just add the following line of code above the JOptionPaneMessageDialog code ...
this.setAlwaysOnTop(false);
toFront () worked for me in a similar situation where I wanted a JFrame to create another JFrame but have the first JFrame get or retain focus. The new JFrame was always getting the focus.
requestFocus () didn't work.
requestFocusInWindow () didn't work.
Various calls to one or the other above two methods didn't work, be it from a JFrame or a GlassPane or a getContentPane () or a JPanel().
setAlwaysOnTop (true) didn't work.
Inside a JFrame subclass:
public void configure () {
if (glassPane == null) {
return;
}
final boolean vis = ! glassPane.isVisible (); // Toggle
glassPane.setVisible (vis);
if (vis) {
configFrame = new ConfigFrame ("Configuration", props, glassPane, this);
configFrame.addWindowListener (new AdapterForClosingSubs (configureToggle));
toFront ();
} else {
configFrame.setVisible (false);
configFrame.dispose ();
configFrame = null;
}
if (getFocusOwner () != null) {
System.out.println ("configure focus owner " + getFocusOwner ().getName ());
}
}
private final Runnable configureToggle = () -> {
configure ();
};
fwiw, Java 17.
frame.setExtendedState( JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
Try the above..
Related
I have a simple Swing application which runs in full screen mode. My application instantiates a JFrame, which in turn instantiates a JPanel, where all of the drawing is done in the paintComponent method. I also have a MouseListener watching for certain events.
One of those events (clicking on a certain area of the screen) triggers a prompt. Here is my code to show the prompt (keep in mind this comes from within my class that is extending JPanel).
int choice = JOptionPane.showConfirmDialog(this, "Are you sure you want to quit?", "Quit?", JOptionPane.YES_NO_OPTION);
if ( choice == JOptionPane.OK_OPTION ) {
dialogOpen = false;
System.exit(0);
} else {
dialogOpen = false;
repaint();
}
The only trouble is... as soon as this code runs, the entire window disappears. More specifically, it looks like it minimizes itself, because I can click on the Java icon in the taskbar and it pops right back up. But how do I stop it from minimizing itself? All I want to do is display a simple prompt!
I figured it out. Thanks to everyone for their helpful comments (what is it with people and commenting here, by the way? how come people write everything that could go in an answer in the comments instead?)
Rather than calling .showConfirmDialog(this, ...) (where this is my JPanel subclass), I needed to call .showConfirmDialog(parent, ...) (where parent is my JFrame subclass). Then, I added a WindowStateListener on the JFrame to detect state changes and reset the window state.
I am coding MVC. In my controller i am listening to the action and if the user clicks a "SHOW-LIST" button i am making an instance of my view class which extends from JFrame and therein the view class i create a new JFrame. My problem is that if i click on SHOW-LIST button multiple times, i have the frame opened multiple time. Can somebody please tell me how can i do so so that once a new frame is about to open the old frame closes..
Controller
public void actionPerformed(ActionEvent event) {
String viewAction = event.getActionCommand();
...
if (viewAction.equals("SHOW-LIST")) {
showListUI = new ShowListDialogUI(displayedCustomerList);
}
}
View
class ShowListDialogUI extends JFrame{
public ShowListDialogUI (List<Customer> customerList) {
..
// I am drawing it here
..
}
}
Can somebody please tell me how can i do so so that once a new frame
is about to open the old frame closes..
use CardLayout, then there no reason to playing with Top-Level Containers, put there required number of JPanels, then just to switch betweens JPanel views
as #trashgod notified, really not good idea, way
otherwise have to clean-up (remove all contents) uselless container, because Top-Level Containers never will be GC'ed
Well, depends on the use case, but instead of closing the old one, and creating the new one, you could focus the existing one (and probably update data?).
Your controller can manage the frames and keep track of it. In the most easiest (and not recommended) way, you have a boolean "isFrameOpen". You set it to true if you open the frame, to false if you close it (your frame has to communicate with the controller then, or the controller has to know about the status of the frame at least). If boolean is true, then focus/recreate it. If false, create a new one.
In more advanced solutions, you can keep track over all frames with a map and you have to deal carefully with concurrent access.
--tb
I want to create a JDialog which can only float within its parent Frame. That is it cannot be dragged out from its parent frame. Any idea? mouse-motion listener?
thanks,
EDIT:
My applicaiton is based on frame not internal frame, so I cannot use JInternalFrame
I need a non-modal dialog so, I cannot use JOptionPane with internal feature.
Use JInternalFrame instead. See this page for an example.
Ok, you should have specified the "hidden" problem in the initial question.
I've have found a very tricky solution, I don't suggest to use it except from developing a better one, perhaps starting from this.
Given an JInternalFrame, provide it with a componentMove listener to inhibit moving it in hidden positions.
As far as I've tested it, it has refresh problems (maybe they can be solved) and the stability in extreme case to assess too.
Provided "as is" for further improvement, not as a nice piece of software :-)
public void componentMoved(ComponentEvent e) {
Rectangle r = new Rectangle();
MyInternalFrame mif = MyInternalFrame.this;
JDesktopPane dp = mif.getDesktopPane();
if (mif.getX() + mif.getWidth()> dp.getWidth()) {
mif.setLocation(mif.getDesktopPane().getWidth()-mif.getWidth(),mif.getY());
}
if (mif.getY() + mif.getHeight()> dp.getHeight()) {
mif.setLocation(mif.getX(), mif.getDesktopPane().getHeight()-mif.getHeight());
}
if (mif.getX()<0) {
mif.setLocation(0, mif.getY());
}
if (mif.getY()<0) {
mif.setLocation(mif.getX(), 0);
}
}
});
I'm writing a Java app (Swing GUI) that periodically pops up a JFrame.
Is it possible somehow to bring the window to front (foo.setAlwaysOnTop(true) would be even better) but without having it focus?
Some people move their eyes away from the screen from time to time to look at their keyboard while typing, and I'm sure that if this window would always capture the keyboard focus people would get really annoyed as it's causing them to lose quite a few keystrokes every time it pops up unnoticed.
In other cases, even when the user is actually capable of typing without looking at the keyboard all the time, having a window pop up and get focus could cause unwanted actions from the pop-up window itself (some Tab+Enter combination for example, where the user accidentally selects an option she really wouldn't had selected otherwise).
Thanks in advance!
Update
As Jonas suggests, foo.setFocusableWindowState(false); seems to work if called after the window has been rendered (tested on Gnome only).
This does not work:
foo.setFocusableWindowState(false);
foo.setVisible(true);
foo.setFocusableWindowState(true);
However, this does:
foo.setFocusableWindowState(false);
foo.setVisible(true);
Thread.sleep(1000);
foo.setFocusableWindowState(true);
I'll have to see if there's an event I can catch/listen to that allows me to do foo.setFocusableWindowStatue(true); when appropriate.
I consider my problem solved.
This may work:
foo.setFocusableWindowState(false);
As of Java 1.7 you can call
frame.setAutoRequestFocus(false);
I recently ran into the same problem, and the tentative solution has been:
JFrame frame = ...;
frame.setExtendedState(JFrame.NORMAL);
frame.setAlwaysOnTop(true);
frame.requestFocus();
frame.setAlwaysOnTop(false);
Suggestion: In the GUI Component that creates the Frame, put 2 consecutive calls:
frameJustCreated.requestFocus();
this.requestFocus();
1st one bring the window of the new JFrame to the top, 2nd one keeps the window where the user is typing at the top.
If you want to call setFocusableWindowState(true) in an event (so, not to wait e.g. 1 second), you can add a WindowListener (e.g. derived from WindowAdapter) that changes the property:
appFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
super.windowOpened(e);
e.getWindow().setFocusableWindowState(true);
}
});
appFrame.setFocusableWindowState(false);
appFrame.setVisible(true);
JInternalFrame toFront() calls to moveToFront()
Override moveToFront()
public void moveToFront() {
Window window = SwingUtilities.getWindowAncestor(this);
Component focusOwner = (window != null) ? window.getFocusOwner() :
null;
boolean descendant = false;
if (window != null && focusOwner != null &&
SwingUtilities.isDescendingFrom(focusOwner, this)) {
descendant = true;
requestFocus();
}
super.moveToFront();
if (descendant) {
focusOwner.requestFocus();
}
}
the fix is in moveToFront to check if a child has focus, if it does, then temporarily request focus on the internal frame. After the internal frame has movthe ed to front, then request focus back on the previously focused component. This will ensure the appropriate events are generated.
refer
https://bugs.openjdk.java.net/browse/JDK-4309079
Apologies for the somewhat unclear question - couldn't think of a better way of putting it.
I use a JXTaskPane (from the Swing labs extension API) to display some information.
The user can "click" the title to expand the panel. The JXTaskPane is in a container JPanel, which is then added to a JFrame, my main application window.
I want my application window to resize to the size of the expanded task pane. To achieve this, I added a component listener to my container JPanel which would set size to the now expanded panel.
panel.addComponentListener(new ComponentListener()
{
public void componentResized(ComponentEvent e)
{
Dimension newSize = ((JXTaskPane)e.getSource()).getSize();
reSizeFrame(newSize);
}
}
private void reSizeFrame(Dimension newSize)
{
if ((newSize.height < maxSize.height) && (newSize.width < maxSize.width))
{
containerPanel.setSize(newSize);
appFrame.setSize(containerPanel.getSize());
appFrame.pack();
}
}
The problem is that the componentResized method is called as the task pane expands, as a result the resizeFrame method is called lots of times, and looks really awful on the screen.
How can I detect when the JXTaskpane has finished resizing? I thought of two approaches:
Put the resizeFrame() method in a SwingUtilities.invokeLate(..) call.
Put in a timer resizeFrame call, so any subsequent calls do not do anything until the timer fires. This should give enough time for the panel to resize.
What is the best way forward?
Also - This is my first serious Java GUI app after years of server side program. StackOverflow has been very helpful. So thanks!
I know you've already selected an answer, but overriding the paint method is definitely not correct, and while you may be able to hack something in place, it won't be ideal.
Looking at the source for JXTaskPane and specifically looking in setExpanded() (line 387), you can see it calls JXCollapsiblePane.setCollapsed(...) and then fires a property change event for expanded. A listener on that property won't be correct, because it'll fire before the animation is complete. So, if you go into JXCollapsiblePane and look at setCollapsed(...) (line 470) you'll see that if it's animated, it sets the paramaters and starts a timer. We want to know when the animation ends, so in that file, look at the animator (line 620, and specifically 652-667), which shows that when the animation ends, it fires a property change for ANIMATION_STATE_KEY with a value of "collapsed" or "expanded". This is the event you actually want. However, you don't have access to JXCollapsiblePane, so go back to JXTaskPane and search for ANIMATION_STATE_KEY, and you find line 208, which shows that JXTaskPane creates a listener on JXCollapsiblePane.ANIMATION_STATE_KEY and refires it as it's own event.
Since you do have access to JXTaskPane, you can listen for that event, so doing ...
taskPane.addPropertyChangeListener(JXCollapsiblePane.ANIMATION_STATE_KEY, new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
if(e.getNewValue().equals("expanded") {
...
}
else if(e.getNewValue().equals("collapsed") {
...
}
}
}
should get your event exactly when you want it.
The correct way to listen for events in Swing is through property listeners. Unfortunately, the only way to find out what the correct properties and values are is by digging through source code.
As a suggestion, have you tried overriding the paint method, first calling super and then putting your resize code at the end of that if (and only if) the size has changed significantly.
I'm not familiar with JXTaskPane, but my first reaction is that maybe you're handling the wrong event. You want the frame to resize when the user clicks on the header - so why not handle that event (perhaps using EventQueue.invokeLater() to resize the frame after the task pane has been resized)?
But if that doesn't work and you need to use the approach you've outlined above, using a javax.swing.Timer is probably best. Set it for 200 milliseconds or so and just restart() it every time componentResized() fires.