LocationRelativeTo (JAVA) is Failing - java

I often use:
setLocationRelativeTo(null);
In my JFrame Constructor to make the Frame appear right in the middle, but now it doesnt works. It just puts the JFrame in one corner.
If you have any idea of what this happens or if you now another way to always making the Jframe appear at the middle in any computer please tell me.
I said this because I could use
setLocation(x,y);
and just put the coordinates that will put the Jframe in the center of my screen but, for example if my PC is 1920 x 1080 the Jframe wont appear in the center in a 1280 x 720 PC.
If Im wrong in this please correct me, Im new to Java so I can miss a lot of things Bill Gates wont miss. (I now windows is not coded in Java)

For reference, here's an example that works correctly; you might compare it to your current approach. In particular,
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
Be sure to pack() the enclosing top-level container.
Invoke setVisible(true) as the last step in creating the GUI.
MCVE:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
/** #see https://stackoverflow.com/a/29643591/230513 */
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JLabel("Test", JLabel.CENTER));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new Test().display();
});
}
}

Related

How do I prevent JFrame from always being on top of all other applications?

Before anyone asks, I have tried using setAlwaysOnTop(false). Here is a repeatable example.
import javax.swing.JFrame;
public class SOQ_20200913
{
public SOQ_20200913()
{
JFrame frame = new JFrame("SOQ_20200913");
//for simplicity's sake, you could also comment these 2 lines - they don't seem to help or hurt the situation
frame.setLocation(200, 200);
frame.setSize(300, 300);
frame.setAlwaysOnTop(false);
frame.setVisible(true);
}
public static void main(String[] args)
{
SOQ_20200913 stackOverflowQuestion = new SOQ_20200913();
}
}
After I run, I click away and try to click on my code, and then my web browser, but the JFrame always remains on top.
Am I missing something? Is there some other field I should be setting here?

Maximizing JFrame in Java

There have been several questions related to this, for example here and here, that both say the way to maximize a JFrame is to use the following code:
frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //Some answers have these lines
frame.setVisible(true); //reversed
However, for me, not sure if this is a windows 10 bug/java 8 bug or not, when I use this code the result is this (no matter which way round the two lines of code above are):
As you can see in the image, the window is the correct size, however, it slightly overlays the bottom, and it is slightly offset from the left. Is there a way to fix this problem, or actually maximise the program by hitting the maximise button on the JFrame with code?
Edit
Here is a MCVE that demonstrates the problem:
import java.awt.GridLayout;
import javax.swing.JFrame;
public class CDBurner extends JFrame {
private static final long serialVersionUID = -6027473114929970648L;
private CDBurner() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1, 1));
setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH);
setVisible(true);
setLocationRelativeTo(null);
requestFocus();
}
public static void main(String[] args) {
new CDBurner();
}
}
The line
setLocationRelativeTo(null);
sets the position of the frame. If it comes after
setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH);
it changes the location of the frame after it maximizes, causing the gap you observed. You should remove that line since maximizing the frame sets its position anyway (though you can just put it before setting the extended state, in which case it does nothing).

Creating JFrame and getconentpane full-size

I am using Java, and trying to make my JFrame's size as the size of the window, not to overlap the taskbar. Off-course, I want it to be the exact same size at every screen resolution. Moreover, to make the frame.GetContentPane() size as the size of the frame. Later I will want to create JPanels within the frmae at a constant size.
I have seen many solution, but unfortunately, non of them work for me.
Please help! Thank you very very much.
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
Here is an example, how to set window size to maximum (may be incorrect when computer has more than one display).
import java.awt.GraphicsEnvironment;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class TestWindow {
/**
*
* #param args
*/
public static void main(String[] args) {
JFrame frm = new JFrame("Test max size");
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setSize(
GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().getSize());
frm.setVisible(true);
}
}
Another possibilities are: make frame maximized or use fullscreen mode. Content pane gets the maximum size automatically.

Swing getHeight() value changing from 0 to 16

I am trying to make a box in Swing that has a label of "user", a text field for the username, and a button "sign in". This is my code
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.*;
public class Engine
{
JFrame frame;
public void go()
{
setUpGui();
userNameScreen();
}
public void setUpGui()
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void userNameScreen()
{
JPanel background = new JPanel();
frame.getContentPane().add(background);
JLabel labelUserName = new JLabel("User:");
background.add(labelUserName);
System.out.println(labelUserName.getHeight()); // 0
JTextField textFieldUserName = new JTextField();
System.out.println(labelUserName.getHeight()); // 16
textFieldUserName.setPreferredSize(new Dimension(110,labelUserName.getHeight()));
background.add(textFieldUserName);
JButton buttonSignIn = new JButton("Sign In");
background.add(buttonSignIn);
/*
background.add(labelUserName);
background.add(textFieldUserName);
background.add(buttonSignIn);
frame.getContentPane().add(background);
*/
frame.pack();
}
}
My driver class just creates an instance of engine, then runs the method go().
I read that Swing components do not have attributes of height/width until they are added (because that is for the layout manager to decide how much room they have), so it makes sense that in the method userNameScreen(), adding in all components at the end* (commented out here) makes the textFieldUserName variable have no height.
However, you can see in that same method userNameScreen(), I have it do
System.out.println(labelUserName.getHeight());
twice. The first time, it is 0. The second, it is 16. I don't understand why the first time, it would register it as 0. It has already been added to the panel (in the line before), and there doesn't seem to be anything that would change its height between that first println() and the next. So why is the value 0 in the first one, and why does it change to 16 almost immediately after?
*I should note, when I say adding in all the stuff commented out at the end, it also includes removing/commenting out all the same commands done elsewhere in the code.
It is a side effect from not creating/modifying your Swing components on the EDT. Now the EDT is busy doing the layout while you are adding components in another thread.
Your main method should look like:
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Engine().go();
}
});
}
I'm not sure why this is happening but may be because the addition of the component maybe on a background thread and might not have been updated till the next statement is called and its updated a few millisecs later and appears when you call it second time.

JPanel's child components paint/layout problem

I'm having a problem that when my frame is shown (after a login dialog) the buttons are not on correct position, then in some miliseconds they go to the right position (the center of the panel with border layout).
-- update
In my machine, this SSCCE shows the layout problem in 2 of 10 times I run it:
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TEST {
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
System.out.println("Debug test...");
JPanel btnPnl = new JPanel();
btnPnl.add(new JButton("TEST"));
JFrame f = new JFrame("TEST");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(btnPnl);
f.setPreferredSize(new Dimension(800, 600));
f.pack();
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
f.setVisible(true);
System.out.println("End debug test!");
}
});
}
}
The button first appers in the up-left, and then it goes to the center. Is it a java bug?
--update
Looks like the SSCCE don't show the problem for everyone that is trying.
Maybe it's my computer performance problem. I still think Java Swing is creating new threads for make the layout behind the scenes. But I'm not sure.
--update
The problem only occur with the f.setExtendedState(JFrame.MAXIMIZED_BOTH);
Your problem intrigued me. After some investigation I think I confirmed something that I recall about setting the window state (maximized, restored, etc) which is that setting the state is a request to the operating system and is left to the whim of the OS to process the request. This means it is asynchronous, or at least done later, after you set it. I confirmed using logging and adding resize listeners where you can see that the frame is resized after your block of code exits. Because of this, the pack() will layout components to their preferred size. So imagine the frame being sized to 800x600 and components positioned as such (button centered horizontally around 400). Then later, the OS changes the size of the frame to full screen (e.g. 1024x768) - for a moment, you'll see the button still at 400. Then the frame processes the new size and re-lays out components and centers the button at around 512. So you'll see the flicker as it transitions during this process. Perhaps a solution is to NOT pack() - it will remain at a size of zero and user will see minimum flicker.
Try this change first:
// pack()
If that looks good then you might have the next problem...if the user clicks the restore button, the whole frame shrinks into a black hole. So try calling pack AFTER the frame has been predictably resized due to the maximize. Something like this:
f.addComponentListener( new ComponentAdapter( ComponentEvent e ) {
public void componentResized( Component) {
if( f.getSize().getWidth() > 0 ) {
e.getComponent().removeComponentListener( this );
((JFrame)e.getComponent()).pack();
}
}
}
So if the user later clicks restore button the frame will have a nicely packed size ready to go.
--Update
OK, one last attempt. While I think my description of the problem has some truth, my solutions offered did nothing. Here's one last attempt. Remove pack() and setPreferredSize() and replace with setting the size to the screen size. This seems to reduce the flicker greatly on my system. This is because there should be no difference between the initial layout and the maximized layout done later. You can see this if you switch between restore and maximized. Although I still see a very slight flicker when switching the two, at least it seems to look better when first displayed.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TEST {
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
System.out.println("Debug test...");
JPanel btnPnl = new JPanel();
btnPnl.add(new JButton("TEST"));
JFrame f = new JFrame("TEST");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(btnPnl);
// f.setPreferredSize(new Dimension(800, 600));
// f.pack();
f.setSize( Toolkit.getDefaultToolkit().getScreenSize() );
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
f.setVisible(true);
System.out.println("End debug test!");
}
});
-Mike
Maybe you are missing a frameThatContainsCentralPanel.pack()?
Well, if it works with a SSCCE, then you've proven the problem isn't with the basic logic. There must be something different between the SSCCE and your real code. Since we don't have access to your real code you need to do the debugging yourself to see what the difference is.
However, in this case a better solution is to use a CardLayout, which is designed to let you swap panels easily. Read the Swing tutorial for a working example.
Or anther approach is to use a "login dialog". Once the login is successfull, you display your main frame with the panel for your application.
I would guess that you need to call pack() before making your frame visible.
If you are calling the above code not on the event thread then you have a race condition and all bets are off - you can only manipulate the GUI from the EDT (event dispatch thread).
EDIT: I tried your SSCCE on my system and it is not exhibiting the behavior you are seeing. I tried it about 50 times, and also tried creating 10 windows by looping your code. I am running 1.6.0_18 on Windows XP SP3.
The "then in some milliseconds" part sounds to me like you need to call validate() on your frame. Also, if you use f.pack(), your panel needs a preferred size, because pack() gives the parent's components their preferred sizes and resizes based on them.
If I copied your code, I had the same problem, but not so heavy.
I solved it by setting a preferred size for your frame before packing. So:
import java.awt.Dimension;
System.out.println("Debug test...");
JPanel btnPnl = new JPanel();
btnPnl.add(new JButton("TEST"));
JFrame f = new JFrame("TEST");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(btnPnl);
f.setPreferredSize(new Dimension(800, 600));
f.pack();
f.setVisible(true);
System.out.println("End debug test!");
I'm running on Linux.
It is indeed strange... I'm sure it is something about the size of all the containers in the swing tree.
I would expect the frame to be maximised both before it is shown, but after checking this I'm sure that on linux frame is maximised after it has been displayed. You can make the frame size equal to a Screen size before calling setVisible, or you can make the components invisible until you know that the it's got preferred initial size. Here is modified sample which shows the elements after the frame has been activated (on linux activated event comes late enough to not show the "jumping button"):
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TEST {
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
final JPanel btnPnl = new JPanel();
btnPnl.add(new JButton("TEST"));
final JFrame f = new JFrame("TEST");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(btnPnl);
// calculate preferred size for TEST frame
// f.isDisplayable() will become true
f.pack();
// extended state, if can be applied, needs to be called after f.isDisplayable()
WindowListener maxBoth = new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
f.setExtendedState(Frame.MAXIMIZED_BOTH);
}
};
// after windows has been opened - maximize both
f.addWindowListener(maxBoth);
// initially hide the elements
// after maximized state has been applied show them
f.getContentPane().setVisible(false);
f.addWindowListener(new WindowAdapter() {
#Override
public void windowActivated(WindowEvent e) {
f.getContentPane().setVisible(true);
// remove this listener
f.removeWindowStateListener(this);
}
});
// set the frame visible
f.setVisible(true);
}
});
}
}
Looks like a java bug. I've reported it (but for some reason it still not show on the bugs reports).

Categories