Layering two active JPanels on top of each other - java

I'm trying to create a simple animation whereby a swimmer follows a path underwater. I have two JPanels - one for the swimmer and one for the background. Both are active, the swimmer is moving its limbs and the background has fish/obstacles that need to be updated.
I am trying to put the swimmer on top of the background. I'm trying to use a JLayeredPane, so I create the two layers and add them:
JLayeredPane lp = frame.getLayeredPane();
lp.setPreferredSize(new Dimension(650, 550));
underwaterScene.setSize(lp.getPreferredSize());
underwaterScene.setLocation(0,0);
swimmer.setSize(lp.getPreferredSize());
swimmer.setLocation(0,0);
swimmer.setOpaque(false);
lp.add(underwaterScene, Integer.valueOf(1));
lp.add(swimmer, Integer.valueOf(2));
The swimmer's paintComponent method simply draws the swimmer in the correct place:
g.drawImage(swimmer.sprite, swimmer.x, swimmer.y, 150, 100, null);
Currently, I only see the swimmer layer. If I remove the lp.add(swimmer ... call then I can see the background layer, so I know that it's being added.
My question is: why isn't the swimmer appearing on top of the background without completely blocking it?
Thanks in advance for any help!

Here is a working example.
Also, you can find out its context here:
https://github.com/fzoli/RemoteControlCar/blob/master/desktop/BrowserTest/src/ConstrainVisibility.java#L58
public class ConstrainVisibility extends JPanel {
protected static final String LS = System.getProperty("line.separator");
protected static final int OFFSET_X = 150;
protected static final int OFFSET_Y = 120;
protected static final int WIDTH = 200;
protected static final int HEIGHT = 200;
public ConstrainVisibility() {
super(new BorderLayout());
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setOpaque(true);
layeredPane.setBackground(new Color(200, 200, 255));
int layerIndex = 0;
// A flash player
// A swing panel
JPanel swingPanel = new JPanel();
swingPanel.setBorder(BorderFactory.createTitledBorder("Swing JPanel"));
swingPanel.setBackground(Color.GREEN);
swingPanel.setBounds(OFFSET_X * layerIndex, OFFSET_Y * layerIndex, WIDTH, HEIGHT);
layeredPane.setLayer(swingPanel, layerIndex++);
layeredPane.add(swingPanel);
// A web browser
JWebBrowser webBrowser = new JWebBrowser(JWebBrowser.constrainVisibility());
webBrowser.setBarsVisible(false);
webBrowser.setStatusBarVisible(true);
webBrowser.setHTMLContent(
"<html>" + LS +
" <body>" + LS +
" <h1>A web page</h1>" + LS +
" <p>A paragraph with a link.</p>" + LS +
" </body>" + LS +
"</html>");
webBrowser.setBounds(OFFSET_X * layerIndex, OFFSET_Y * layerIndex, WIDTH, HEIGHT);
layeredPane.setLayer(webBrowser, layerIndex++);
// A swing button
JButton swingButton = new JButton("Swing JButton");
swingButton.setBounds(OFFSET_X * layerIndex, OFFSET_Y * layerIndex, WIDTH, HEIGHT);
layeredPane.setLayer(swingButton, layerIndex++);
layeredPane.add(swingButton);
layeredPane.add(webBrowser);
layeredPane.setPreferredSize(new Dimension(WIDTH + OFFSET_X * (layerIndex - 1), HEIGHT + OFFSET_Y * (layerIndex - 1)));
add(new JScrollPane(layeredPane), BorderLayout.CENTER);
}
/* Standard main method to try that test as a standalone application. */
public static void main(String[] args) {
UIUtils.setPreferredLookAndFeel();
NativeInterface.open();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("DJ Native Swing Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ConstrainVisibility(), BorderLayout.CENTER);
frame.setSize(800, 600);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
NativeInterface.runEventPump();
}
}

Related

Why is my Component repainted over and over without any changes happening?

I have a beginner Swing/AWT question for you.
I am doing custom painting of a BoxPanel Object that extends JPanel.
I have n of these BoxPanels that are then drawn in a JFrame called FormSolutionViewer using a FlowLayout.
Now the issue I am having is that after the JFrame is created and made visible, it is repainted in an infinite loop, without any changes happening to the components. Can someone explain to me why this is and how to fix it so that it only gets repainted when the window is resized or some of the data actually changes?
public class BoxPanel extends JPanel {
private Box box;
private int scaleFactor;
public BoxPanel(Box box, int scaleFactor) {
super();
this.box = box;
this.scaleFactor = scaleFactor;
this.setLayout(null); // Use null layout for absolute positioning
}
/**
* Need to override getPreferredSize() when using a FlowLayout
*/
#Override
public Dimension getPreferredSize() {
return new Dimension(this.box.getLength() * this.scaleFactor, this.box.getLength() * this.scaleFactor);
}
/**
* Paint the box border, background and its rectangles
* #param g
*/
public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.white);
// Display no. of rectangles contained in tooltip
this.setToolTipText("Box contains " + this.box.getRectangles().size() + " rectangles");
// Draw border of box
this.setBorder(BorderFactory.createLineBorder(Color.black));
/* Draw rectangles contained in box */
int i = 1;
for (Rectangle rect : box.getRectangles()) {
System.out.println("Rectangle " + i + ": " + rect.toString());
g.setColor(Color.BLACK); // Set color for border
g.drawRect(rect.getPos().getX() * this.scaleFactor, rect.getPos().getY() * this.scaleFactor,
rect.getWidth() * this.scaleFactor, rect.getHeight() * this.scaleFactor);
i++;
}
}
}
public class FormSolutionViewer extends JFrame {
private JPanel contentPane;
private FeasibleSolution solution;
int scaleFactor = 40;
int spacing = 5;
/**
* Create the frame.
*/
public FormSolutionViewer(FeasibleSolution solution, int x, int y, int dpi) {
this.solution = solution;
this.scaleFactor = (int) Math.round(dpi / 2.4);
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
setBounds(x, y, 800, 600);
setTitle("Initialized Solution of " + solution.getInstance().toString());
this.setBackground(new Color(250, 250, 250));
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(spacing, spacing, spacing, spacing));
FlowLayout layout = new FlowLayout(FlowLayout.LEADING, 5, 5);
contentPane.setLayout(layout);
this.setContentPane(contentPane);
/* Place the boxes */
int boxNo = 0;
int rowCount = 0;
for (Box box : solution.getBoxes()) {
boxNo++;
BoxPanel boxPanel = new BoxPanel(box, scaleFactor);
contentPane.add(boxPanel);
contentPane.setSize(this.getWidth(), 500);
boxPanel.setVisible(true);
}
}
}
this.setBackground(Color.white);
...
this.setToolTipText("Box contains " + this.box.getRectangles().size() + " rectangles");
...
this.setBorder(BorderFactory.createLineBorder(Color.black));
Don't set a property of the component in the painting method. When a property of a component is changed, Swing invokes revalidate()/repaint() on the component to reflect the new state of the component.
The point of a painting method is to paint the component in its current state, not change its state.

Java GUI - How to center a single button

I'm very new to java (I'm used to python).
NOTE: I do want the position to stay in the center even when the gui is resized.
I was wondering how I can center a single button? At the moment, the button is at the top of the gui.
public class main_gui extends JFrame{
public static void main(String[] args) {
// Initial window
JFrame start_frame = new JFrame("P.D");
start_frame.setSize(1200, 800);
start_frame.setVisible(true);
start_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Panel to hold our buttons
JPanel start_panel = new JPanel();
start_frame.add(start_panel);
// Button to initialize everything
JButton start_button = new JButton("Start");
// Take out the border around the text
start_button.setFocusable(false);
start_panel.add(start_button);
}
}
Here is what is currently looks like, I just want this button down a bit, to the center.
There is no need for the panel. Just add the button directly to the frame.
The easiest way is to use a GridBagLayout:
frame.setLayout( new GridBagLayout() );
frame.add(startButton, new GridBagConstraints());
By default the component will be centered horizontally and vertically within the GridBagLayout.
A quick solution would be to set the vertical gap between components of your FlowLayout to half the size of your JFrame:
public class MainGUI {
static java.awt.Dimension bd;
public static void main(String[] args) {
// Initial window
JFrame start_frame = new JFrame("P.D");
start_frame.setSize(1200, 800);
start_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Button to initialize everything
JButton start_button = new JButton("Start");
bd = start_button.getPreferredSize();
// Take out the border around the text
start_button.setFocusable(false);
// Panel to hold our buttons
java.awt.Dimension d = start_frame.getSize();
JPanel start_panel = new JPanel(new java.awt.FlowLayout(FlowLayout.CENTER, 0, d.height / 2 - bd.height / 2));
start_panel.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent evt) {
JPanel c = (JPanel) evt.getSource();
c.setLayout(new java.awt.FlowLayout(FlowLayout.CENTER, 0, c.getSize().height / 2 - bd.height / 2));
}
});
start_panel.add(start_button);
start_frame.add(start_panel);
start_frame.setVisible(true);
}
}
When the size of your JFrame is changed, the ComponentAdapter recalculates the new height and places the button to the new center.
In order to place the button to the vertical center, we calculate the height of your button and subtract its half from the vertical gap.
The horizontal center is automatically applied by the layout.
Your class should not extend JFrame if you instantiate another JFrame inside it and use it.
Class names should be nouns, in mixed case with the first letter of each internal word capitalized.
It is recommended to make your JFrame visible after you have added all widgets to it.
In order to use the SwingUtilities invoker and make your application code cleaner, let your class extend JFrame, write a constructor and call it this way:
public class MainGUIJFrame extends JFrame {
public MainGUIJFrame() {
initComponents();
}
private void initComponents() {
setTitle("P.D");
setSize(1200, 800);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
start_button = new JButton("Start");
bd = start_button.getPreferredSize();
// Take out the border around the text
start_button.setFocusable(false);
java.awt.Dimension d = getSize();
start_panel = new JPanel(new java.awt.FlowLayout(FlowLayout.CENTER, 0, d.height / 2 - bd.height / 2));
start_panel.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent evt) {
JPanel c = (JPanel) evt.getSource();
c.setLayout(new java.awt.FlowLayout(FlowLayout.CENTER, 0, c.getSize().height / 2 - bd.height / 2));
}
});
start_panel.add(start_button);
add(start_panel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new MainGUIJFrame().setVisible(true);
}
});
}
private JButton start_button;
private JPanel start_panel;
private java.awt.Dimension bd;
}
You keep main simple and small this way, and bd does not have to be static anymore.
You can use a layout manager like BorderLayout if you want to put the button in the center so that it occupies the whole space in the frame. So, your code will look something like this:
public class main_gui extends JFrame{
public static void main(String[] args) {
// Initial window
JFrame start_frame = new JFrame("P.D");
start_frame.setSize(1200, 800);
start_frame.setVisible(true);
start_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Panel to hold our buttons
JPanel start_panel = new JPanel();
start_panel.setLayout(new BorderLayout());
start_frame.add(start_panel);
// Button to initialize everything
JButton start_button = new JButton("Start");
// Take out the border around the text
start_button.setFocusable(false);
start_panel.add(start_button, BorderLayout.CENTER);
}
}
You may go without using a layout manager. It's a bad practice but it should work. This code will put a small button in the center of the frame:
public class MainGUI {
public static void main(String[] args) {
JFrame start_frame = new JFrame("P.D");
int width = 1200;
int height = 800;
start_frame.setSize(width, height);
start_frame.setVisible(true);
start_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Panel to hold our buttons
JPanel start_panel = new JPanel();
start_panel.setLayout(null);
start_frame.add(start_panel);
// Button to initialize everything
JButton start_button = new JButton("Start");
buttonWidth = 80;
buttonHeight = 20;
start_button.setBounds(new Rectangle((width - buttonWidth)/2, (height - buttonHeight)/2, buttonWidth, buttonHeight));
start_button.setSize(new Dimension(buttonWidth, buttonHeight));
start_button.setFocusable(false);
start_panel.add(start_button);
}
}
The best way to do it is to use a Layout of your choice and try to make it work using that.
However, if you are sure your window won't be getting resized, or you're happy to deal with such events yourself, you could attempt working without a layout and position the button manually, e.g.:
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.Dimension;
public class main_gui {
public static void main(String[] args) {
// Initial window
JFrame start_frame = new JFrame("P.D");
int FrameWidth = 1200, FrameHeight = 800;
start_frame.setSize(FrameWidth, FrameHeight);
start_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Panel to hold our buttons
JPanel start_panel = new JPanel();
start_panel.setLayout(null); // Now working without a layout manager
// i.e, can position things manually.
start_frame.add(start_panel);
// Button to initialize everything
JButton start_button = new JButton("Start");
start_button.setFocusable(false); // Take out the border around the text
Dimension size = start_button.getPreferredSize();
start_button.setBounds( FrameWidth/2 - size.width/2,
FrameHeight/2 - size.height/2,
size.width, size.height);
start_panel.add(start_button);
// Display the Layout after all components have been added.
// (adding components after the frame has been set to visible
// may result in components not showing up reliably!)
start_frame.setVisible(true);
}
}

Resizing JPanel when JFrame is maximized

Alright, so the following code shows a JPanel within a JFrame when the program is first run. If the window is re-sized by dragging one of the sides or corners of the frame, the JPanel re-sizes itself and maintains the aspect ratio of the monitor.
NOTE: The JPanel is set to remain within the bounds of the window on a 1920x1080 resolution monitor only. On any other monitor size, the JPanel may get cut off. See my comment above setPreferredSize() in the updatePanelSize() method.
public class Frame extends JFrame {
Panel panel = new Panel();
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Frame();
}
});
}
// Setup the window, add the panel, and initialize a "window" listener.
public Frame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(1280, 720);
setLocationRelativeTo(null);
setVisible(true);
setTitle("Frame");
setLayout(new GridBagLayout());
add(panel);
initListeners();
}
public void initListeners() {
/** When the window is resized, the panel size is updated. */
addComponentListener(new ComponentListener() {
#Override
public void componentResized(ComponentEvent e) {
panel.updatePanelSize();
}
#Override
public void componentHidden(ComponentEvent evt) {}
#Override
public void componentShown(ComponentEvent evt) {}
#Override
public void componentMoved(ComponentEvent evt) {}
});
}
}
public class Panel extends JPanel {
public Panel() {
setBackground(new Color(100, 0, 0));
setPreferredSize(new Dimension(1052, 592));
}
// Resizes the JPanel while maintaining the same aspect ratio
// of the monitor.
public void updatePanelSize() {
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
float monitorWidth = gd.getDisplayMode().getWidth();
float monitorHeight = gd.getDisplayMode().getHeight();
// Aspect ratio of the monitor in decimal form.
float monitorRatio = monitorWidth / monitorHeight;
JComponent parent = (JComponent) getParent();
float width = parent.getWidth();
float height = parent.getHeight();
width = Math.min(width, height * monitorRatio);
height = width / monitorRatio;
// I am subtracting the width and height by their respected aspect ratio
// coefficients (1920x1080 -> 16:9 (width:height)) and multiplying them
// by some scale (in this case 10) to add a "padding" to the JPanel.
// The ratio coefficients and scale will need to be edited based upon the
// resolution of your monitor.
setPreferredSize(new Dimension((int)width - (16 * 10), (int)height - (9 * 10)));
System.out.println("PanelRes: " + ((int)width - (16 * 10)) + "x" + ((int)height - (9 * 10)));
System.out.println("PanelRatio: " + getWidth() / getHeight());
}
}
The problem I am having is that if I maximize the window by double clicking the window toolbar (or whatever the correct term for the top of the window would be) or by clicking the maximize button, the JPanel does not re-size like it ought to. The Overridden componentResized() method is called when the window is maximized, but the JPanel doesn't resize. Any help on solving this issue would be great.
On resize the panel is immediately accepting the new preferred dimensions in updatePanelSize(), but on maximize/restore the panel is apparently ignoring the new preferred dimensions.
I've added a call to revalidate(), to force the panel to update in those cases where it hasn't applied the new preferred dimensions.
public void updatePanelSize() {
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice();
float monitorWidth = gd.getDisplayMode().getWidth();
float monitorHeight = gd.getDisplayMode().getHeight();
// Aspect ratio of the monitor in decimal form.
float monitorRatio = monitorWidth / monitorHeight;
JComponent parent = (JComponent) getParent();
float width = parent.getWidth();
float height = parent.getHeight();
width = Math.min(width, height * monitorRatio);
height = width / monitorRatio;
// I am subtracting the width and height by their respective aspect ratio...
int paddedWidth = (int) width - (16 * 10);
int paddedHeight = (int) height - (9 * 10);
setPreferredSize(new Dimension(paddedWidth, paddedHeight));
int resultWidth = getWidth();
int resultHeight = getHeight();
if (paddedWidth != resultWidth && paddedHeight != resultHeight) {
revalidate(); // preferred dimensions not applied, so force them
}
System.out.println("PreferredSize: " + paddedWidth + "x" + paddedHeight);
System.out.println("PanelRes: " + resultWidth + "x" + resultHeight);
System.out.println("PanelRatio: " + (float)resultWidth / resultHeight);
}

How to tell where a JPanel is when dragging a JLabel

I am dragging a JLabel around the screen, and when I release above the JPanel it is supposed to snap to where it completely covers the JPanel. Also, if I release anywhere else it is supposed to snap to its original position. I have the snap part, but I don't know how to tell if it is over the JPanel. I have my code below.
import java.awt.Color;
java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.event.MouseEvent;
public class Main {
public static final int CARD_HEIGHT = 97;
public static final int CARD_WIDTH = 73;
/**
* Mouse Handler components
* Changes the location of the JLabel with the mouse
*/
public static MouseInputAdapter mouseHandler = new MouseInputAdapter(){
public int labelDisX;
public int labelDisY;
public void mousePressed(MouseEvent e) {
labelDisX = e.getX();
labelDisY = e.getY();
//move the card above all others
e.getComponent().getParent().setComponentZOrder(e.getComponent(), 0);
e.getComponent().getParent().repaint();
}
public void mouseReleased(MouseEvent e) {
//if not above panel, then move to original spot
if(!abovePanel()) {
e.getComponent().setLocation(labelDisX, labelDisY);
}
}
public void mouseDragged (MouseEvent e) {
JPanel panel = (JPanel) e.getComponent().getParent();
//get preliminary new X coordinate
int newX = e.getComponent().getX() + e.getX() - labelDisX;
//get preliminary new Y coordinate
int newY = e.getComponent().getY() + e.getY() - labelDisY;
//Not moved off edges of JFrame
if(newX > panel.getWidth() - CARD_WIDTH) {
newX = panel.getWidth() - CARD_WIDTH;
}
if(newY > panel.getHeight() - CARD_HEIGHT) {
newY = panel.getHeight() - CARD_HEIGHT;
}
if(newX < 0) { newX = 0; }
if(newY < 0) { newY = 0; }
e.getComponent().setLocation(newX, newY);
}
};
/**
* check to see if the JLabel is above the JPanel
* #return
*/
public static boolean abovePanel() {
return false;
}
/**
* Adds ability to drag to JLabel
* #param label
*/
public static void addDrag( JLabel label) {
System.out.println("Adding drag");
label.addMouseMotionListener(mouseHandler);
label.addMouseListener(mouseHandler);
}
public static void main(String[] args) {
// Create a JFrame
JFrame frame = new JFrame("Example Frame");
// JPanel to add JLabels to
JPanel panel = new JPanel();
// Add a drop target text area in the center of the frame
DropTargetArea dropPanel = new DropTargetArea();
dropPanel.setPreferredSize(new Dimension(CARD_WIDTH, CARD_HEIGHT));
dropPanel.setBackground(Color.gray);
panel.add(dropPanel);
// Add several draggable labels to the container
JLabel blue = new JLabel();
blue.setOpaque(true);
blue.setPreferredSize(new Dimension(CARD_WIDTH, CARD_HEIGHT));
blue.setBackground(Color.blue);
addDrag(blue);
panel.add(blue);
// Add the container to the frame
frame.add(panel);
// Display the frame
frame.setPreferredSize(new Dimension(400,400));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
}
I've done this using a JLayeredPane that holds a JPanel that itself holds a grid of JPanels using BorderLayout, with each smaller JPanel representing a chess square, and each smaller JPanel can accept a single JLabel. I added the MouseAdapter to the JLayeredPane itself, and when clicked, it checks to see if a moveable JLabel is located below the click. If so, the JLabel is raised up to the JLayeredPane's DRAG_LAYER, and then when released, check which JPanel the mouse cursor is over, and drop the JLabel if it is a valid square, otherwise return it to its original position. You can see my code here.

How to center a Window in Java?

What's the easiest way to centre a java.awt.Window, such as a JFrame or a JDialog?
From this link
If you are using Java 1.4 or newer,
you can use the simple method
setLocationRelativeTo(null) on the
dialog box, frame, or window to center
it.
This should work in all versions of Java
public static void centreWindow(Window frame) {
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int) ((dimension.getWidth() - frame.getWidth()) / 2);
int y = (int) ((dimension.getHeight() - frame.getHeight()) / 2);
frame.setLocation(x, y);
}
setLocationRelativeTo(null) should be called after you either use setSize(x,y), or use pack().
Note that both the setLocationRelativeTo(null) and Tookit.getDefaultToolkit().getScreenSize() techniques work only for the primary monitor. If you are in a multi-monitor environment, you may need to get information about the specific monitor the window is on before doing this kind of calculation.
Sometimes important, sometimes not...
See GraphicsEnvironment javadocs for more info on how to get this.
On Linux the code
setLocationRelativeTo(null)
Put my window to random location each time I launched it, in a multi display environment.
And the code
setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - getSize().width) / 2, (Toolkit.getDefaultToolkit().getScreenSize().height - getSize().height) / 2);
"cut" the window in half with placing it to the exact center, which is between my two displays.
I used the following method to center it:
private void setWindowPosition(JFrame window, int screen)
{
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] allDevices = env.getScreenDevices();
int topLeftX, topLeftY, screenX, screenY, windowPosX, windowPosY;
if (screen < allDevices.length && screen > -1)
{
topLeftX = allDevices[screen].getDefaultConfiguration().getBounds().x;
topLeftY = allDevices[screen].getDefaultConfiguration().getBounds().y;
screenX = allDevices[screen].getDefaultConfiguration().getBounds().width;
screenY = allDevices[screen].getDefaultConfiguration().getBounds().height;
}
else
{
topLeftX = allDevices[0].getDefaultConfiguration().getBounds().x;
topLeftY = allDevices[0].getDefaultConfiguration().getBounds().y;
screenX = allDevices[0].getDefaultConfiguration().getBounds().width;
screenY = allDevices[0].getDefaultConfiguration().getBounds().height;
}
windowPosX = ((screenX - window.getWidth()) / 2) + topLeftX;
windowPosY = ((screenY - window.getHeight()) / 2) + topLeftY;
window.setLocation(windowPosX, windowPosY);
}
Makes the window appear right at the center of the first display.
This is probably not the easiest solution.
Works properly on Linux, Windows and Mac.
I finally got this bunch of codes to work in NetBeans using Swing GUI Forms in order to center main jFrame:
package my.SampleUIdemo;
import java.awt.*;
public class classSampleUIdemo extends javax.swing.JFrame {
///
public classSampleUIdemo() {
initComponents();
CenteredFrame(this); // <--- Here ya go.
}
// ...
// void main() and other public method declarations here...
/// modular approach
public void CenteredFrame(javax.swing.JFrame objFrame){
Dimension objDimension = Toolkit.getDefaultToolkit().getScreenSize();
int iCoordX = (objDimension.width - objFrame.getWidth()) / 2;
int iCoordY = (objDimension.height - objFrame.getHeight()) / 2;
objFrame.setLocation(iCoordX, iCoordY);
}
}
OR
package my.SampleUIdemo;
import java.awt.*;
public class classSampleUIdemo extends javax.swing.JFrame {
///
public classSampleUIdemo() {
initComponents();
//------>> Insert your code here to center main jFrame.
Dimension objDimension = Toolkit.getDefaultToolkit().getScreenSize();
int iCoordX = (objDimension.width - this.getWidth()) / 2;
int iCoordY = (objDimension.height - this.getHeight()) / 2;
this.setLocation(iCoordX, iCoordY);
//------>>
}
// ...
// void main() and other public method declarations here...
}
OR
package my.SampleUIdemo;
import java.awt.*;
public class classSampleUIdemo extends javax.swing.JFrame {
///
public classSampleUIdemo() {
initComponents();
this.setLocationRelativeTo(null); // <<--- plain and simple
}
// ...
// void main() and other public method declarations here...
}
below is code for displaying a frame at top-centre of existing window.
public class SwingContainerDemo {
private JFrame mainFrame;
private JPanel controlPanel;
private JLabel msglabel;
Frame.setLayout(new FlowLayout());
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
System.exit(0);
}
});
//headerLabel = new JLabel("", JLabel.CENTER);
/* statusLabel = new JLabel("",JLabel.CENTER);
statusLabel.setSize(350,100);
*/ msglabel = new JLabel("Welcome to TutorialsPoint SWING Tutorial.", JLabel.CENTER);
controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
//mainFrame.add(headerLabel);
mainFrame.add(controlPanel);
// mainFrame.add(statusLabel);
mainFrame.setUndecorated(true);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.getRootPane().setWindowDecorationStyle(JRootPane.NONE);
mainFrame.setVisible(true);
centreWindow(mainFrame);
}
public static void centreWindow(Window frame) {
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int) ((dimension.getWidth() - frame.getWidth()) / 2);
int y = (int) ((dimension.getHeight() - frame.getHeight()) / 2);
frame.setLocation(x, 0);
}
public void showJFrameDemo(){
/* headerLabel.setText("Container in action: JFrame"); */
final JFrame frame = new JFrame();
frame.setSize(300, 300);
frame.setLayout(new FlowLayout());
frame.add(msglabel);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
frame.dispose();
}
});
JButton okButton = new JButton("Capture");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// statusLabel.setText("A Frame shown to the user.");
// frame.setVisible(true);
mainFrame.setState(Frame.ICONIFIED);
Robot robot = null;
try {
robot = new Robot();
} catch (AWTException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
final Dimension screenSize = Toolkit.getDefaultToolkit().
getScreenSize();
final BufferedImage screen = robot.createScreenCapture(
new Rectangle(screenSize));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ScreenCaptureRectangle(screen);
}
});
mainFrame.setState(Frame.NORMAL);
}
});
controlPanel.add(okButton);
mainFrame.setVisible(true);
}
public static void main(String[] args) throws Exception {
new SwingContainerDemo().showJFrameDemo();
}
Below is the ouput of above code-snippet:
The following doesn't work for JDK 1.7.0.07:
frame.setLocationRelativeTo(null);
It puts the top left corner at the center - not the same as centering the window. The other one doesn't work either, involving frame.getSize() and dimension.getSize():
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int) ((dimension.getWidth() - frame.getWidth()) / 2);
int y = (int) ((dimension.getHeight() - frame.getHeight()) / 2);
frame.setLocation(x, y);
The getSize() method is inherited from the Component class, and therefore frame.getSize returns the size of the window as well. Thus subtracting half the vertical and horizontal dimensions from the vertical and horizontal dimensions, to find the x,y coordinates of where to place the top-left corner, gives you the location of the center point, which ends up centering the window as well. However, the first line of the above code is useful, "Dimension...". Just do this to center it:
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension( (int)dimension.getWidth() / 2, (int)dimension.getHeight()/2 ));
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
frame.setLocation((int)dimension.getWidth()/4, (int)dimension.getHeight()/4);
The JLabel sets the screen-size. It's in FrameDemo.java available on the java tutorials at the Oracle/Sun site. I set it to half the screen size's height/width. Then, I centered it by placing the top left at 1/4 of the screen size's dimension from the left, and 1/4 of the screen size's dimension from the top. You can use a similar concept.
frame.setLocationRelativeTo(null);
Full example:
public class BorderLayoutPanel {
private JFrame mainFrame;
private JButton btnLeft, btnRight, btnTop, btnBottom, btnCenter;
public BorderLayoutPanel() {
mainFrame = new JFrame("Border Layout Example");
btnLeft = new JButton("LEFT");
btnRight = new JButton("RIGHT");
btnTop = new JButton("TOP");
btnBottom = new JButton("BOTTOM");
btnCenter = new JButton("CENTER");
}
public void SetLayout() {
mainFrame.add(btnTop, BorderLayout.NORTH);
mainFrame.add(btnBottom, BorderLayout.SOUTH);
mainFrame.add(btnLeft, BorderLayout.EAST);
mainFrame.add(btnRight, BorderLayout.WEST);
mainFrame.add(btnCenter, BorderLayout.CENTER);
// mainFrame.setSize(200, 200);
// or
mainFrame.pack();
mainFrame.setVisible(true);
//take up the default look and feel specified by windows themes
mainFrame.setDefaultLookAndFeelDecorated(true);
//make the window startup position be centered
mainFrame.setLocationRelativeTo(null);
mainFrame.setDefaultCloseOperation(mainFrame.EXIT_ON_CLOSE);
}
}
There's something really simple that you might be overlooking after trying to center the window using either setLocationRelativeTo(null) or setLocation(x,y) and it ends up being a little off center.
Make sure that you use either one of these methods after calling pack() because the you'll end up using the dimensions of the window itself to calculate where to place it on screen. Until pack() is called, the dimensions aren't what you'd think thus throwing off the calculations to center the window. Hope this helps.
Example: Inside myWindow() on line 3 is the code you need to set the window in the center of the screen.
JFrame window;
public myWindow() {
window = new JFrame();
window.setSize(1200,800);
window.setLocationRelativeTo(null); // this line set the window in the center of thr screen
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().setBackground(Color.BLACK);
window.setLayout(null); // disable the default layout to use custom one.
window.setVisible(true); // to show the window on the screen.
}
The following code center the Window in the center of the current monitor (ie where the mouse pointer is located).
public static final void centerWindow(final Window window) {
GraphicsDevice screen = MouseInfo.getPointerInfo().getDevice();
Rectangle r = screen.getDefaultConfiguration().getBounds();
int x = (r.width - window.getWidth()) / 2 + r.x;
int y = (r.height - window.getHeight()) / 2 + r.y;
window.setLocation(x, y);
}
You could try this also.
Frame frame = new Frame("Centered Frame");
Dimension dimemsion = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(dimemsion.width/2-frame.getSize().width/2, dimemsion.height/2-frame.getSize().height/2);
Actually frame.getHeight() and getwidth() doesnt return values , check it by System.out.println(frame.getHeight()); directly put the values for width and height ,then it will work fine in center. eg: as below
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x=(int)((dimension.getWidth() - 450)/2);
int y=(int)((dimension.getHeight() - 450)/2);
jf.setLocation(x, y);
both 450 is my frame width n height
public class SwingExample implements Runnable {
#Override
public void run() {
// Create the window
final JFrame f = new JFrame("Hello, World!");
SwingExample.centerWindow(f);
f.setPreferredSize(new Dimension(500, 250));
f.setMaximumSize(new Dimension(10000, 200));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void centerWindow(JFrame frame) {
Insets insets = frame.getInsets();
frame.setSize(new Dimension(insets.left + insets.right + 500, insets.top + insets.bottom + 250));
frame.setVisible(true);
frame.setResizable(false);
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int) ((dimension.getWidth() - frame.getWidth()) / 2);
int y = (int) ((dimension.getHeight() - frame.getHeight()) / 2);
frame.setLocation(x, y);
}
}
The order of the calls is important:
first -
pack();
second -
setLocationRelativeTo(null);
In addition to Donal's answer, I would like to add a small calculation that makes sure that the Java window is perfectly at the center of the window. Not just the "TOP LEFT" of the window is at the center of the window.
public static void centreWindow(JFrame frame, int width, int height) {
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int) ((dimension.getWidth() - frame.getWidth()) / 2);
int y = (int) ((dimension.getHeight() - frame.getHeight()) / 2);
// calculate perfect center
int perf_x = (int) x - width/2;
int perf_y = (int) y - height/2;
frame.setLocation(perf_x, perf_y);
}
If you want a simple answer for Java NetBeans:
Right click on the JFrame, go to properties, then go to code and select generate center option.
Look image for reference:
[1]: https://i.stack.imgur.com/RFXbL.png
If you want to push center of your app window, you can do solved to follow.
int x = (Toolkit.getDefaultToolkit().getScreenSize().width) - getSize().width) / 2;
int y = (Toolkit.getDefaultToolkit().getScreenSize().height) - getSize().height) / 2;
setLocation(x,y);
getSize() function is app frame size...
getScreenSize() is your pc screen size.
I'd like to modify Dónal's answer to accommodate a multiple display setup:
public static void centerWindow(Window frame) {
Rectangle bounds = frame.getGraphicsConfiguration().getBounds();
Dimension dimension = bounds.getSize();
int x = (int) (((dimension.getWidth() - frame.getWidth()) / 2) + bounds.getMinX());
int y = (int) (((dimension.getHeight() - frame.getHeight()) / 2) + bounds.getMinY());
frame.setLocation(x, y);
}

Categories