Is there a way to send the java frame in front of every other opened program. I know you can use
JFrame.setAlwaysOnTop(true);
but that just keeps it in front allways. I want it to only happen when a certain function is called. For instance, When I press a button on a frame, it will wait using Thread.sleep(10000) for ten seconds, but the I want it to just the frame to the front in case you clicked out of the window for a second. Any suggestions?
Take a look at Window#toFront
You may also want to take a look at
WindowListener
Swing Timer
Be careful of using Thread.sleep in a GUI environment, if used incorrectly, this will cause you window to stop updating (painting)
This is surprisingly fiddly.
The exact behavior might also depend on the operating system. But at least on Windows, a call to frame.toFront() will not necessarily bring the window to the front. Instead, it will cause the corresponding entry in the task bar to blink for a few seconds. I tried something like
f.setAlwaysOnTop(true);
f.setAlwaysOnTop(false);
which basically works, but after the window was brought to the front, it is not "active", and none of my attempts to make it active worked (e.g. requesting the focus or so).
The only solution that I found now to (reliably) work (on Windows, at least) was
if (!f.isActive())
{
f.setState(JFrame.ICONIFIED);
f.setState(JFrame.NORMAL);
}
But wonder wheter there is a more elegant solution.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class FrameToTopTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Bring me to top after 3 seconds");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
triggerBringToFront(f, 3000);
}
});
f.getContentPane().add(button);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static void triggerBringToFront(final JFrame f, final int delayMS)
{
Timer timer = new Timer(delayMS, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// This will only cause the task bar entry
// for this frame to blink
//f.toFront();
// This will bring the window to the front,
// but not make it the "active" one
//f.setAlwaysOnTop(true);
//f.setAlwaysOnTop(false);
if (!f.isActive())
{
f.setState(JFrame.ICONIFIED);
f.setState(JFrame.NORMAL);
}
}
});
timer.setRepeats(false);
timer.start();
}
}
Related
As for testing-reasons I tried to open a JDialog window with the panel and its contents of the main application frame. As I already had anything in there I wanted to see if I could simply set the JDialogs contentPane to the one I passed over. So in simplyfied form this came together:
testsforSO.java :
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class testsforSO extends JFrame {
private static final long serialVersionUID = -3890178393751567629L;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
testsforSO frame = new testsforSO();
frame.setSize(300, 300);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public testsforSO() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("I am the Frame");
getContentPane().setLayout(new BorderLayout(0, 0));
JPanel panel = new JPanel();
panel.setLayout(null);
JButton btnRestart = new JButton("Restart");
btnRestart.setBounds(10, 10, 50, 50);
btnRestart.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
testsforSO.main(null);
dispose();
}
});
panel.add(btnRestart);
getContentPane().add(panel);
repaint();
// -----------DELETE These comments-------------
// JDialog myDialg = new JDialog(this);
// myDialg.setContentPane(panel);
// myDialg.setVisible(true);
// myDialg.setSize(300,300);
// myDialg.setLocation(new Point(250, 250));
// myDialg.setTitle("I am Dialog from within the script");
myDialog.main(panel);
}
}
and myDialog.java :
import java.awt.Container;
import java.awt.EventQueue;
import javax.swing.JDialog;
public class myDialog extends JDialog {
private static final long serialVersionUID = 7079322237622743228L;
public static void main(Container myContainer) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
myDialog frame = new myDialog(myContainer);
frame.setVisible(true);
frame.setContentPane(myContainer);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public myDialog(Container myContainer) {
setContentPane(myContainer);
getContentPane().setLayout(null);
setBounds(200,200,200,200);
}
}
When starting the main frame I assumed it would contain the restarting button as well as the dialog does. But interestingly it was only the dialog with the button.
However when hitting it, the main frame properly restarted, a second dialog was set up and it contained the button again. This time however the main frame had the button as well, just without any function. Clicking on it does absolutely nothing.
Then I tried further and checked if that behaviour would change if I added the dialog directly into the main applications code (see the commented lines) and, starting the application once again only the dialog in its own class showed the button. Even hitting this one now restarted properly but the button won't show up on any other window except the lonely declared dialog.
What am I missing here and how could I refactor my code to work properly if even at all in this manner?
Understand that Swing components can only be present in one container, and while you may see the visual residue of a component in a container, the actual component is only present in the last container added to.
Myself, if I wanted dialog and jframe to have the same content pane components, I'd create a factory method to create the contentPane, and then use it to create two unique but identical contentPanes.
Also, I'd be remiss if I didn't mention something about your use of null layouts. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
For instance, when I ran your code, this is the dialog that I saw:
You hard coded the button's size to be too small to show its text on my platform. If you had used layout managers, and called pack() on the top-level window, the button would show appropriately.
I've got a short question and I hope somebody can help me.
Please look at the following code snippet:
public void mouseEntered(MouseEvent e){
//wait 2 seconds.
//if no other mouseEntered-event occurs, execute the following line
//otherwise restart, counting the 2 seconds.
foo();
}
Can somebody help me with that problem? I want to realize a behavior like an ToolTip: you enter a region with your mouse. If your mouse stays in that position, do something.
Start a Timer with a delay of 2 seconds in your mouseEntered() method that calls whatever it is you want to do.
Set up a new handler (mouseExited()) that stops the timer if it hasn't gone off.
Basically, you know the mouse is still there if mouseExited() hasn't been called. The timer will either go off in two seconds doing what you want or be cancelled if the mouse exits.
Although the answer provided by #Brian Roach is correct, there is yet another (and more succinct) way of achieving this. That is, using the ToolTipManager.
Example:
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
public final class ToolTipDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
ToolTipManager.sharedInstance().setInitialDelay(2000);
createAndShowGUI();
}
});
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(new JToolTipButton());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static final class JToolTipButton extends JButton{
private static final long serialVersionUID = -5193366265809801639L;
protected JToolTipButton(){
super("I can haz tooltip?");
setToolTipText("Hey man, get off me!");
}
}
}
By invoking setInitialDelay, I've changed the time the manager waits to display the tool tip from 750ms to 2000ms.
Note - Although I'm not sure, I think this may change the delay for ALL components (guess I was right), which may not be what you want..but it's still worth mentioning.
I am trying to develop a JFrame which has two buttons that would let me to call the main method of other classes. The first try was to put it directly into the actionPerformed of each button, this will cause the JFrame of the other class to open but showing only the title of it and not showing any contents of the JPanel additionally freezing the program (can't even press close button, have to go into task manager or eclipse to kill it). The second try was adding a method call in actionPerformed, and adding the method will this time call the main method of other class however the same result (freeze of program).
For testing purposes I have placed the call to main method of other class, straight in this class main method which has proven to me that the frame of other class has successfully appeared, including all its JPanel contents, functionality etc.
I know I could make some kind of infinite loop in my main method to wait until a boolean is set to true, but then I though there must be some less-expensive way to get it working. So here I am asking this question to you guys.
Here is the code of the 2nd try;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Chat {
public static void main (String[] args) {
JFrame window = new JFrame("Chat Selection");
//Set the default operation when user closes the window (frame)
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set the size of the window
window.setSize(600, 400);
//Do not allow resizing of the window
window.setResizable(false);
//Set the position of the window to be in middle of the screen when program is started
window.setLocationRelativeTo(null);
//Call the setUpWindow method for setting up all the components needed in the window
window = setUpWindow(window);
//Set the window to be visible
window.setVisible(true);
}
private static JFrame setUpWindow(JFrame window) {
//Create an instance of the JPanel object
JPanel panel = new JPanel();
//Set the panel's layout manager to null
panel.setLayout(null);
//Set the bounds of the window
panel.setBounds(0, 0, 600, 400);
JButton client = new JButton("Run Client");
JButton server = new JButton("Run Server");
JLabel author = new JLabel("By xxx");
client.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//run client main
runClient();
}
});
server.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//run server main
}
});
panel.add(client);
client.setBounds(10,20,250,200);
panel.add(server);
server.setBounds(270,20,250,200);
panel.add(author);
author.setBounds(230, 350, 200, 25);
window.add(panel);
return window;
}
private static void runClient() {
String[] args1={"10"};
ClientMain.main(args1);
}
}
Only one main method is allowed per application. Honestly I am not sure what you are trying to do or think is supposed to happen when you call main on other classes. When you call main on other classes all you are doing is calling a method that happens to be called main and passing args to it. Your freezing is probably because you are not using Swing correctly:
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
The problem you're having is that Java Swing is single threaded. When you're running the main function of the other class, however you do it, the GUI won't be able to keep running until it returns. Try spawning off a new thread that calls the second main method.
private static void runClient() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
String[] args1={"10"};
ClientMain.main(args1);
}
});
}
EDIT: Updated, as per #Radiodef's suggestion. Missed at the top when you said this second class had to display things on the GUI. Definitely want to go with the invokeLater then.
In an action (i.e. a method) executed by pressing a button deployed into a JFrame, I want to hide the java app and then to get a screenshot. Finally, once the screenshot is taken, I need to make the JFrame visible.
The method is the following:
public void myButtonPressedAction(){
//Hiding the JFrame
this.setVisible(false);
//Now I use Robot to get a screenshot using another method
//not reported for simplicity
myMethodToGetScreenshot();
//Making the JFrame visible
this.setVisible(true);
}
What happens is that, once visibility is set to false, the app starts to become invisible and immediately I get the screenshot: unfortunately, the screenshot also capture the JFrame while fading out (i.e., it is going to become invisible, the isVisible method returns true, but the JFrame is not completely invisible).
One possible solution is to insert a timer to put a delay between the call to setVisible(false) and the one to myMethodToGetScreenshot(). However, suppose that the system is busy, the delay could be undervalued; on the contrary, a larger delay will make my application slow!
How can I get the exact time instant such that the JFrame has been completely fade out, i.e. it is really invisible?
EDIT
This are initialized in the constructor:
String myPath= ...;//here I have a String that represent a path to a folder.
JPEGImageWriteParam JPEG_PARAMS_BEST_QUALITY = new JPEGImageWriteParam(null);
JPEG_PARAMS_BEST_QUALITY.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
JPEG_PARAMS_BEST_QUALITY.setCompressionQuality(1f);
This is the code for myMethodToGetScreenshot():
public void myMethodToGetScreenshot(){
BufferedImage capture = new Robot().createScreenCapture(screenArea);
ImageWriter writer = writerService.getWriter();
writer.setOutput(new FileImageOutputStream(new File(myPath+"screenshot.jpg")));
writer.write(null, new IIOImage(capture, null, null), JPEG_PARAMS_BEST_QUALITY);
}
This is the screenshot I get. You can see the JFrame fading out...
Then put some delay time. You can use Swing timer.
Here is a small demo:
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class ScreenshotDemo {
JFrame frame = new JFrame();
JButton button = new JButton("Catch the screenshot");
Timer timer;
Robot robot;
JLabel label = new JLabel();
public ScreenshotDemo() {
try {
robot = new Robot();
} catch (AWTException e1) {
e1.printStackTrace();
}
// Keeps frame disposed for 3 seconds
timer = new Timer(3000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Rectangle size = new Rectangle(Toolkit.getDefaultToolkit()
.getScreenSize());
Image image = robot.createScreenCapture(size);
label.setIcon(new ImageIcon(image));
frame.setVisible(true);
}
});
timer.setRepeats(false);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
frame.setVisible(false);
timer.start();
}
});
frame.add(button, BorderLayout.NORTH);
frame.add(label, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// frame.pack();
frame.setSize(1024, 768);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ScreenshotDemo();
}
});
}
}
Basically, you will hide your frame for some time (3 seconds in this demo). While frame is hidden you will take a snapshot.
Instead of setvisible you can use setExtendedState
//Minimize the JFrame
this.setExtendedState(JFrame.ICONIFIED);
//Now I use Robot to get a screenshot using another method
//not reported for simplicity
myMethodToGetScreenshot();
//Restore the JFrame
this.setExtendedState(JFrame.NORMAL);
You have to add a reasonable delay after hiding the frame and before taking the screenshot. Easiest way is to insert a call to robot.delay() before robot.createScreenCapture().
I'd give the ComponentListener a try (assuming this code goes to a member of a JFrame-extending class):
final Container contentPane = getContentPane();
ComponentAdapter componentAdapter = new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent arg0) {
myMethodToGetScreenshot();
contentPane.removeComponentListener(this);
}
};
contentPane.addComponentListener(componentAdapter);
I am trying to capture the very first moment when a component is shown on the screen without using 'dirty' solutions as with use of a timer.
Basically, I want to know the moment when I can safely start using getLocationOnScreen() method on the component.
I thought that component listener could help but no luck here. I am stuck for now and do not know which listener to use for this. Any suggestions?
Here is some sample code which shows that a component listener fails.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CompListenerTest
{
static ComponentListener cL = new ComponentAdapter()
{
#Override
public void componentShown(ComponentEvent e)
{
super.componentShown(e);
System.out.println("componentShown");
}
};
static MouseListener mL = new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e)
{
super.mousePressed(e);
JComponent c = (JComponent) e.getSource();
System.out.println("mousePressed c="+c.isShowing());
}
};
public static void main(String[] args)
{
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(300, 400));
p.setBackground(Color.GREEN);
p.addComponentListener(cL);
p.addMouseListener(mL);
System.out.println("initial test p="+p.isShowing());
JPanel contentPane = new JPanel();
contentPane.setBackground(Color.RED);
contentPane.add(p);
JFrame f = new JFrame();
f.setContentPane(contentPane);
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
Thanks in advance.
The reason a ComponentListener doesn't work is that it reports changes to the visible property - and that is true by default, even without being part of the component hierarchy.
To be reliably notified, use a HierarchyListener
Edit (musings about my knowledge evolution in regard to this question/answers, not sure what the netiquette has to say about doing it ... simply guide me if that's the wrong way to go :-)
First: the question as asked in the subject is not necessarily related to the actual problem (as commented by Boro below - any way to link to a comment?): there's no need to keep some kind of local flag to decide whether or not it is safe to send a getLocationOnScreen to a component, simply ask the component itself. Learn-item 1 for myself :-)
Second: The question as asked is quite interesting. Five experts (including myself, self-proclaimed), five different answers. Which triggered a bit of digging on my part.
My hypothesis: ComponentEvents are not useful for notification of (first-)showing. I knew that componentShown is useless because it's a kind-of propertyChange notification of the visible property of a component (which rarely changes). Puzzled about the suggested usefulness of moved/resized, though.
Constructing a use-case: fully prepare the frame in the example and keep it ready for later showing, a typical approach to improve perceived performance. My prediction - based on my hypothesis: resized/moved fired at prepare-time, nothing at show-time (note: the isShowing is what we are after, that is the latter). A snippet to add in the OP's example:
final JFrame f = new JFrame();
f.setContentPane(contentPane);
f.setSize(800, 600);
// f.pack();
JFrame controller = new JFrame("opener");
controller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Action open = new AbstractAction("open/hide second") {
#Override
public void actionPerformed(ActionEvent e) {
f.setVisible(!f.isVisible());
}
};
controller.add(new JButton(open));
controller.pack();
controller.setVisible(true);
Disappointment: no notification at prepare-time, notification at show-time, just as needed, my hypothesis seemed wrong ;-) Last chance: swap the setSize for a pack ... and voila, notification at prepare-time, no notification at show-time, happy me again. Playing a bit more: looks like ComponentEvents are fired if the a component is displayable, which may or may not be useful in some contexts but not if showing is the state we are after. The
New imperial rules (draft):
Do not use ComponentListener for notification of "showing". That's left-over from AWT-age.
Do use AncestorListener. That seems to be the Swing replacement, slightly misnomed notification of "added" which actually means "showing"
Do use HierarchyListener only if really interested in fine-grained state changes
I"ve use an AncestorListener and handled the ancestorAdded event.
Oddly, the ComponentListener works just fine when applied to the JFrame. Here is the altered source where I saw it work.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CompListenerTest
{
static ComponentListener cL = new ComponentAdapter()
{
#Override
public void componentShown(ComponentEvent e)
{
super.componentShown(e);
System.out.println("componentShown");
}
};
public static void main(String[] args)
{
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(300, 400));
p.setBackground(Color.GREEN);
System.out.println("initial test p="+p.isShowing());
JPanel contentPane = new JPanel();
contentPane.setBackground(Color.RED);
contentPane.add(p);
JFrame f = new JFrame();
f.addComponentListener(cL);
f.setContentPane(contentPane);
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
Using AncestorListener and ancestorAdded worked for me. Here's sample code:
addAncestorListener(new AncestorListener() {
#Override
public void ancestorRemoved(AncestorEvent event) {}
#Override
public void ancestorMoved(AncestorEvent event) {}
#Override
public void ancestorAdded(AncestorEvent event) {
// component is shown here
}
});
static ComponentListener cL = new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
super.componentResized(e);
System.out.println("componentShown = "+e.getComponent().isDisplayable());
}
};
For most purposes you can go with the first call to ComponentListener.componentMoved (or if you are also interested in the size ComponentListener.componentResized). Those are called whenever the position/size of the component changes.