Why doesn't my button position properly on my JFrame no layout? - java

So I've got a JFrame which uses setLayout(null) so I can position my elements by hand.
However, when accessing the content pane and getting the size for the frame, it says its height is 1.0.
Does anyone know how I can fix this?
Here is the code:
import javax.swing.*;
import java.awt.*;
public class Launcher extends JFrame
{
public Launcher(String title) {
super(title);
setLayout(null);
pack();
setSize(new Dimension(LauncherUtil.LAUNCHER_WIDTH, LauncherUtil.LAUNCHER_HEIGHT));
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
displayComponents();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Launcher launch = new Launcher(LauncherUtil.LAUNCHER_TITLE);
launch.setVisible(true);
}
});
}
private void displayComponents() {
Dimension size = getContentPane().getSize();
JButton launchButton = new JButton("Launch Game");
System.out.println(size.getHeight());
launchButton.setBounds(0, (int)size.getHeight() - 60, (int)size.getWidth(), 60);
add(launchButton);
}
}

may be if you try to get the screen size by using Toolkit would be work like you want
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
it brings you the screen size where java program is running. Hope it helps.

The content pane is a JPanel whose default size is 1x1px. Since you did not put any components into the content pane and have not set a preferred size for the panel, the content pane's size remains 1x1px.
One way to fix this is to call these three methods in the following order:
setLayout(null);
setPreferredSize(new Dimension(300, 400));
pack();
However, you should be using a layout manager instead of managing
the size and position of your components by hand.

Related

Java setResizable issue

package data;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JFrame implements Runnable {
private JPanel contentPane;
private JPanel pp = new JPanel();
Thread page = new Thread();
public void run() {
while (!Thread.interrupted()) {
}
}
public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 640 + 16, 480 + 39);
contentPane = new JPanel();
contentPane.setBounds(0, 0, 640, 480);
contentPane.setLayout(null);
setContentPane(contentPane);
pp.setBounds(0, 0, 640, 480);
pp.setBackground(Color.BLACK);
contentPane.add(pp);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
frame.setResizable(false);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
The above code works but setResizable causes an issue: http://i.stack.imgur.com/hQxPU.png
If I were to remove the setResizable then the grey at the bottom and right would be black like it's meant to. How can I disable resizing without causing this issue?
You're using an absolute layout (no LayoutManager set), and the black panel has fixed bounds. And that's exactly the reason the black panel won't fill its parent's bounds when the parent is resized.
Solution: use a LayoutManager which automatically recalculates the bounds of your content so it fills the available space.
// BorderLayout is your friend
contentPane.setLayout(new BorderLayout());
...
// delete this line, no need to set fixed bounds
// pp.setBounds(0, 0, 640, 480);
More on how to use layout managers in AWT/Swing:
The Java™ Tutorials - Using Layout Managers
Layout Managers have two purposes:
calculate the min/max/preferred size of a container
layout components by setting their bounds within the container.
If you want the black panel to have a size of 640x480, and the window to be non-resizable, you can set the preferred size and then pack the window, causing its size to become appropriate for the content's preferred dimensions:
pp.setPreferredSize(new Dimension(640, 480));
...
pack();

JFrame displaying white bars around content

So I've made a class WindowDisp which extends JFrame:
public class WindowDisp extends JFrame{
private static final long serialVersionUID = 3245091489595286109L;
private int height, width;
private JPanel panel;
private JLabel mainPane;
public WindowDisp(int a, int b, int pw, int ph){
height = a;
width = b;
Container c = getContentPane();
c.setPreferredSize(new Dimension(width, height));
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
mainPane = new JLabel();
mainPane.setPreferredSize(new Dimension(pw, ph));
mainPane.setFont(new Font("Monospaced", Font.PLAIN, 10));
panel = new JPanel();
panel.setPreferredSize(getSize());
panel.add(mainPane);
add(panel);
setVisible(true);
pack();
}
public static void main(String[] args){
WindowDisp win = new WindowDisp(400, 400, 400, 400);
}
}
From my Main class, I declare a WindowDisp where its height and width are equal to its ph and pw. The problem, however, is that, upon running my program, white 'bars' appear around the default background colored JPanel in the frame. They appear to be padding the panel from the right and the bottom, as though there is space in the frame that the panel is not occupying, although, if my coding is correct, the panel should be the same size as the frame's ContentPane, should it not?
I've found that removing either of the two pack(); commands does not remove these bars, although removing the first one changes them to black, and removing the second widens the one on the right. Of course, removing both of them causes the frame not to be the same size as its ContentPane. Furthermore, removing the add(panel); altogether has no effect.
I can't figure out what in this code is causing that seemingly empty space to appear in my frame, and, again, in my program, all four values being passed to the Window constructor are equal. What seems really strange is that, even if I just remove the add(panel);, nothing at all changes visa vi the white padding. In fact, I can comment out everything from mainPane =... to add(panel); and that doesn't affect it at all.
I can't seem to replicate the issue exactly, but I think I can replicate the desired results...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class WindowDisp extends JFrame {
private static final long serialVersionUID = 3245091489595286109L;
private JPanel panel;
private JLabel mainPane;
public WindowDisp(int width, int height) {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
mainPane = new JLabel();
mainPane.setBorder(new LineBorder(Color.BLUE));
mainPane.setFont(new Font("Monospaced", Font.PLAIN, 10));
panel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
};
panel.setLayout(new BorderLayout());
panel.setBorder(new EmptyBorder(4, 4, 4, 4));
panel.add(mainPane);
add(panel);
pack();
setLocationRelativeTo(null);
setVisible(true);
System.out.println(getSize());
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
WindowDisp win = new WindowDisp(400, 400);
}
});
}
}
Things that jump out at me (as been of issue)...
panel.setPreferredSize(getSize()); - The size of the window is generally larger than the window size, this is because the window has decorations which are painted WITHIN the frame boundaries. pack uses the layout information (and preferredSize of the components indirectly) to ensure that the content has the amount of space that it asks for, it then sizes the window around this to accommodate the frame decorations. By calling getContentPane().setPreferredSize you are superseding any information that the layout manager might provide and ignoring the requirements of the other components. This is one of the (many) reasons why we recommend that you NEVER call setPreferredSize, ever...
To reiterate...
Container c = getContentPane();
c.setPreferredSize(new Dimension(width, height));
Forces the viewable space of the window to be set to the width/height values (400x400). This container will no longer be able to react to changes to it's content and will ALWAYS prefer to be 400x400
mainPane.setPreferredSize(new Dimension(pw, ph));
Sets the preferred size of the mainPane to 400x400 (based on your example). Again, it will ALWAYS prefer to be 400x400, but the simple fact of setting the content pane, means that this value is actually ignored...
panel.setPreferredSize(getSize());
Now, the nail in the coffin. This sets the panel to be the same size of the frame, BUT, the frame is larger than the contentPane (400x400 + frame decorations), it is also offset within frame (it won't be positioned at 0x0, but will be offset so that it appears below the frame's title and right border), but could expand beyond the frames boundaries
This combination of issues are all working against you. Instead of worrying about the frame size, worry about the size needs/requirements of the what the frame displays.
Each OS uses different frame decorations, so the actual, physical, frame size will be different on different OSs, but if you focus on the requirements of the content, you won't care
See Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? (Yes.)
Instead use layout padding and borders for white space. Finally, call pack() to ensure the frame is exactly as large as (the smallest size) it needs to be in order to display the components and white space.
import java.awt.Font;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class WindowDisp extends JFrame {
private JPanel panel;
private JLabel mainLabel;
public WindowDisp(int t, int l, int b, int r, String title) {
super(title);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setResizable(false);
setLocationByPlatform(true);
mainLabel = new JLabel("Hello Padding!");
mainLabel.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 10));
mainLabel.setBorder(new EmptyBorder(t, l, b, r));
panel = new JPanel();
panel.add(mainLabel);
add(panel);
pack();
setVisible(true);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new WindowDisp(50, 150, 50, 150, "Window 1");
new WindowDisp(50, 100, 50, 100, "Window 2");
}
};
SwingUtilities.invokeLater(r);
}
}
So far the best patch for this annoying issue is the following. Doesn't matter where you call the setResizable(false) method. Just add this piece of code after you setVisible(true).
private void sizeBugPatch() {
while (frame.getWidth() > yourWidth) {
frame.pack();
}
}
Where yourWidth is the width you've set in any of the possible ways, either manually or by overriding setPreferredSize methods. The explanation is quite easy, frame.pack() seems to reset frame.setResizable(boolean b) somehow. You could use an if instead of the while loop but I prefer while to exclude the case the window would still be extra-sized even after a second pack().
One thing I have learned from swing days is to never mix setPreferred... with pack(). You either use one or the other.
Try this code:
import javax.swing.*;
import java.awt.*;
public class WindowDisp extends JFrame {
private int height, width;
private JPanel panel;
private JLabel mainPane;
public WindowDisp(int a, int b, int pw, int ph){
height = a;
width = b;
Container c = getContentPane();
// c.setPreferredSize(new Dimension(width, height));
mainPane = new JLabel("Hello from Pane");
mainPane.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 10));
panel = new JPanel();
// panel.setPreferredSize(new Dimension(pw, ph));
panel.add(mainPane);
c.add(panel, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
pack();
setVisible(true);
}
public static void main(String[] args){
WindowDisp win = new WindowDisp(400, 400, 400, 400);
}
}
Output:

How to adjust parent container size by the child container?

More specifically, how to adjust JFrame size by its contentPane.
Here is the case, I am doing a 400*400 JPanel and I need it to fit in the JFrame. However if I set JFrame setSize(400, 400), some part of the JPanel would be hid due to the space occupied by the upper windows title bar.
I know I can just measure the border and the size of the title bar. I just want to know if there is better way to do.
Here is the solution that takes both Hovercraft Full Of Eels and MadProgrammer answer.
public class Window extends JFrame {
private Window() {
createUI();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Window();
}
});
}
private void createUI() {
setContentPane(buildMainPanel());
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
private JPanel buildMainPanel() {
JPanel mainPanel = new JPanel();
mainPanel.setPreferredSize(new Dimension(500, 640));
mainPanel.setLayout(null);
mainPanel.add(new Canvas(0, 0));
return mainPanel;
}
}
However if I set JFrame setSize(400, 400), some part of the JPanel would be hid due to the space occupied by the upper windows title bar.
You're making things too hard for yourself since the easiest solution is to simply not set the JFrame size. Instead call pack() on the JFrame after adding all components and before calling setVisible(true) and let it size itself to the optimum size for its components and layout managers.
Override the panel's getPreferredSize method and return new Dimension(400, 400).
On the frame call pack. When called, pack will ask the content pane for it's preferred size, which is normally calculated by the layout manager (recursively ask each container for it's preferred size).
This will size the window so that's viewable area meets (as much as its possible to do so) the preferred size of it's content.

placing a transparent JPanel on top of another JPanel not working

I am trying to place a JPanel on top of another JPanel which contains a JTextArea and a button and i want to the upper apnel to be transparent. I have tried it by making the setOpaque(false) of the upper panel. but it is not working. Can anyone help me to get through this? Thanks in advance!
public class JpanelTest extends JPanel
{
public JpanelTest()
{
super();
onInit();
}
private void onInit()
{
setLayout(new BorderLayout());
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextArea(100,100),BorderLayout.CENTER);
panel.add(new JButton("submit"),BorderLayout.SOUTH);
JPanel glass = new JPanel();
glass.setOpaque(false);
add(panel,BorderLayout.CENTER);
add(glass,BorderLayout.CENTER);
setVisible(true);
}
public static void main(String args[])
{
new JpanelTest();
}
}
Indeed, it would be useful to tell the reason why you want panels one over another.
Starting with your code, and changing it a lot, I got it to work, but it might not do what you expect...
import java.awt.*;
import javax.swing.*;
public class Test extends JFrame
{
public Test()
{
super();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 200);
onInit();
setVisible(true);
}
private void onInit()
{
JLayeredPane lp = getLayeredPane();
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextArea(), BorderLayout.CENTER);
panel.add(new JButton("Submit"), BorderLayout.SOUTH);
panel.setSize(300, 150); // Size is needed here, as there is no layout in lp
JPanel glass = new JPanel();
glass.setOpaque(false); // Set to true to see it
glass.setBackground(Color.GREEN);
glass.setSize(300, 150);
glass.setLocation(10, 10);
lp.add(panel, Integer.valueOf(1));
lp.add(glass, Integer.valueOf(2));
}
public static void main(String args[])
{
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new Test();
}
});
}
}
If totally transparent, well, it is like it isn't here! When opaque, it just covers some of the GUI, but doesn't prevent mouse clicks, for example.
1) there are a few ways, there no issue to put JPanel, with covering full JFrames/JPanel area or only part of Rectangle / Dimension that returns JFrames/JPanel
use JLayer(Java7) based on JXLayer (Java6)
use GlassPane
use JViewport
use OverlayLayout
use transucent JDialog / JWindow
2) everything depends of if you want to protect against mouse and key events from the top layer to bottom, or not (to avoiding redispatch events from - to and vice versa)
Check out this tutorial on using Swing Root Panes.
The glass pane is useful when you want to be able to catch events or paint over an area that already contains one or more components. For example, you can deactivate mouse events for a multi-component region by having the glass pane intercept the events. Or you can display an image over multiple components using the glass pane.

Using scrollbars with absolute layout in Swing

I am not able to use scroll bars with absolute layout in Swing.
I don't wish to use this layout but I have to display dynamic objects on my panel on click of a button and align them using setBounds which can be done using this layout only (I guess).
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class clothes2 extends javax.swing.JFrame {
JTextField n=null;
JButton m=null;
public clothes2(){
initComponents();
}
public void initComponents() {
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
final JPanel jp = new JPanel();
contentPane.setPreferredSize(new Dimension(320,200));
jp.setLayout(null);
m=new JButton("add");
m.setBounds(0,0,50,50);
jp.add(m);
m.addMouseListener( new MouseAdapter() {
int x=0;
int y=0;
public void mouseClicked(MouseEvent me){
x+=100;
y+=100;
jp.add(n=new JTextField("Name"));
n.setBounds(x, y, 50, 50);
jp.add(n=new JTextField("code"));
x+=100;
n.setBounds(x,y, 50, 50);
jp.revalidate();
jp.repaint();
x=0;
}
});
int v = ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS;
int h = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS;
JScrollPane jsp = new JScrollPane(jp, v, h);
contentPane.add(jsp, BorderLayout.CENTER);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f= new clothes2();
f.setVisible(true);
f.setSize(640,320);
}
});
}
}
Set preferred size of the container.
JScrollBar uses the preferred size of the component inside it to determine how large the scroll bars should be, and if they should be displayed.
Usually, the layout manager handles this using the preferredLayoutSize method. This can be overriden by explicitly setting the preferred size of the component.
So either you have to set the preferred size, or use a custom layout manager that calculates it for you.
see also here
might help you.
display dynamic objects .. which can be done using this layout only (I guess).
You guess wrong.
See this GUI, that can not only change PLAFs at run-time, but also dynamically add new components1. Click to..
Add Another Label
This example adds the new labels to a GridLayout - but the principle is the same for any layout (or any component).
add layout
jp.setLayout(new FlowLayout());

Categories