So I set the setSize(500,500).. add some panels, the sum of panels Y is 500 like the JFrame but executing it shows an count Y of 525 am I missing something?
JPanel panel = new JPanel();
panel.setLayout(null);
getContentPane().add(panel);
//--------------------
JPanel top_panel = new JPanel();
top_panel.setLayout(null);
top_panel.setBackground(Color.blue);
top_panel.setBounds(0, 0, 500, 40);
panel.add(top_panel);
//------------------------------
JPanel middle_panel = new JPanel();
middle_panel.setLayout(null);
middle_panel.setBackground(Color.yellow);
middle_panel.setBounds(0, 40, 500, 385);
panel.add(middle_panel);
//-----------------------------
JPanel bottom_panel = new JPanel();
bottom_panel.setLayout(null);
bottom_panel.setBackground(Color.black);
bottom_panel.setBounds(0, 425, 500, 75);
panel.add(bottom_panel);
setSize(500,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
40+385+75 = 500 but to show all the panels i must
setSize(500,525);
then it fits
here's an image:
The frame size is the light blue rectangle outside bounds including the title bar. Your panels are appearing in the inner bounds which is frame size less than the frame border and frame title bar. Do you see how your marked space at the bottom is strangely the same height as the title bar?
After adding your panels/component to the frame and just before calling frame.setVisible(true), call frame.pack().
It would be also preferable if you embrace a layout manager (such as FlowLayout) and when necessary call setPreferredSize and let the layout manager do the layout. Normally one would call setPreferredSize over setBound, setSize, setMininumSize, setMaximumSize.
import javax.swing.*;
import java.awt.*;
public class FrameSize {
private JFrame frame;
FrameSize create() {
frame = createFrame();
frame.getContentPane().add(createContent());
return this;
}
private JFrame createFrame() {
JFrame frame = new JFrame(getClass().getName());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
return frame;
}
void show() {
// frame.setSize(500, 500);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private Component createContent() {
JPanel panel = new JPanel(null);
JPanel topPanel = new JPanel(null);
topPanel.setBackground(Color.blue);
topPanel.setBounds(0, 0, 500, 40);
panel.add(topPanel);
JPanel middlePanel = new JPanel(null);
middlePanel.setBackground(Color.yellow);
middlePanel.setBounds(0, 40, 500, 385);
panel.add(middlePanel);
JPanel bottomPanel = new JPanel(null);
bottomPanel.setBackground(Color.black);
bottomPanel.setBounds(0, 425, 500, 75);
panel.add(bottomPanel);
panel.setPreferredSize(new Dimension(500, topPanel.getBounds().height + middlePanel.getBounds().height + bottomPanel.getBounds().height));
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new FrameSize().create().show();
}
});
}
}
You shouldn't be setting size or calling setSize(...) or setBounds(...) as that's setting you up for similar problems in the future, or worse problems when you try to show your GUI on a different platform. Instead let the preferredSizes of your components and the layout managers do this work for you. If you absolutely must set the size of a component, then override getPreferredSize() and return a Dimension that is calculated to work for you. And yes, as per javajon, you should call pack() on the JFrame before displaying it.
For more discussions on the null layout, please read what one of the best Swing experts on this site, MadProgrammer, has to say in his answer here.
Related
I'm dealing with a very specific issue. When I remove all the components of a transparent JPanel (background color with 0 alpha) and add new components, the removed elements are still displayed in the JPanel. Here is an example of the behavior.
And here is the code to generate it:
class MyPanel extends JPanel {
public MyPanel() {
this.setLayout(new FlowLayout());
this.setBackground(new Color(0, 0, 0, 0));
}
public void updateComponents() {
this.removeAll();
this.revalidate();
int n = new Random().nextInt(10);
for (int i = 0; i < n; i++) {
this.add(new JButton("Dummy Button"));
}
}
}
public class Runner {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1280, 720);
MyPanel panel = new MyPanel();
JButton btUpdate = new JButton("Update");
btUpdate.addActionListener(actionEvent -> {
panel.updateComponents();
});
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(btUpdate, BorderLayout.NORTH);
frame.getContentPane().add(panel, BorderLayout.SOUTH);
frame.setVisible(true);
}
}
Can somebody help me?
this.revalidate();
The point of invoking revalidate() is to invoke the layout manager.
You need to invoke that method AFTER you add all the components to the panel.
You also need to make sure the components are painted so the code should be:
this.revalidate();
this.repaint();
I have even tried using the AlphaContainer
How? Post your code showing what you attempted.
The usage should be:
//frame.getContentPane().add(panel, BorderLayout.SOUTH);
frame.getContentPane().add(new AlphaContainer(panel), BorderLayout.SOUTH);
When I run the below code, I am unable to see the background color as red. It's showing default one. Is there anything that I have to add to these lines?
import java.awt.*;
import java.awt.Graphics;
import javax.swing.*;
public class gfix extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(80, 100, 150, 75);
}
public static void main(String[] args){
gfix gg=new gfix();
JFrame frame = new JFrame("RISK");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(null);
frame.add(panel);
JButton button = new JButton("test");
button.setBounds(100, 100, 150, 150);
panel.add(button);
frame.setVisible(true);
}
}
Your are overriding painGraphics() in gfix class so add gfix class object into your frame not Java provided JPanel class object.
gfix gg=new gfix();
JFrame frame = new JFrame("RISK");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//JPanel panel = new JPanel(); Not needed
//panel.setLayout(null);
frame.add(gg);
JButton button = new JButton("test");
button.setBounds(100, 100, 150, 150);
gg.add(button);
frame.setVisible(true);
for g.fillRect(80, 100, 150, 75); give proper panel bounds to fill complete panel background. OR use int width = getWidth();
int height = getHeight(); in paintGraphics to get actual height and width.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class gfix {
public static void main(String[] args) {
JFrame frame = new JFrame("RISK");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBackground(Color.RED);
frame.add(panel);
JButton button = new JButton("test");
// adjust numbers as needed
button.setMargin(new Insets(20,40,20,40));
panel.add(button);
// adjust numbers as needed
panel.setBorder(new EmptyBorder(10,40,50,200));
frame.pack();
frame.setVisible(true);
}
}
Other tips:
Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or combinations of them along with layout padding and borders for white space.
Provide ASCII art or a simple drawing of the intended layout of the GUI at minimum size, and if resizable, with more width and height - to show how the extra space should be used.
Please learn common Java nomenclature (naming conventions - e.g. EachWordUpperCaseClass, firstWordLowerCaseMethod(), firstWordLowerCaseAttribute unless it is an UPPER_CASE_CONSTANT) and use it consistently.
The problem is that I can't position the button where I want to. So I wrote this code to set again the location:
button.setLocation(new Point(100, 60));
import javax.swing.*;
import java.awt.*;
public class gui {
public static void main(String [] args){
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBackground(Color.ORANGE);
frame.add(panel);
JButton button = new JButton("Button");
button.setPreferredSize(new Dimension(200,25));
button.setLocation(new Point(100, 60));
panel.add(button);
frame.setSize(new Dimension(500,400));
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("GUI App");
frame.setResizable(false);
frame.setVisible(true);
}
}
You have to use the method setBounds()! This method requires 4 parameters: The x & y coordinate and the width and height your button should have. Also you have to set the Layout to null... So try this:
button.setBounds(100, 60, 100, 50) //just an example
frame.setLayout(null)
add below to your component:
//JPanel layout
panel.setLayout(null);
// postioning
button.setLocation(100,60);
As panel.setLayout(null) set your content panel to use absolute layout. Which you'd always have to set your component's bounds explicitly by using setBounds method.
Better to choose here the most suitable layout than using absolute layout.
ex:panel.setLayout(new FlowLayout());
There is a specific UI that I am trying to create for a Java program and I have been having trouble choosing the adequate Layout Managers. I would like my program to have a top panel with three elements (Two JTextFields and one JButton) and a lower JPanel that has another JPanel inside. The inner panel should always be a square, centered according to its container and adapt to the maximum height or width of its container. I have tried using a ComponentAdapter to achieve the effect of always staying a square, but the program does not seem to act the way I want it to, also the top Panel seems to get squeezed to the top
JPanel maincontainer = new JPanel();
maincontainer.setLayout(new BoxLayout(maincontainer, BoxLayout.PAGE_AXIS));
JPanel jpanel2 = new JPanel();
jpanel2.setLayout(new GridLayout(0, 3));
JTextField txt = new JTextField();
txt.setFocusable(false);
JButton btn = new JButton();
btn.setFocusable(false);
JTextField txt2 = new JTextField();
txt2.setFocusable(false);
jpanel2.add(txt);
jpanel2.add(btn);
jpanel2.add(txt2);
maincontainer.add(jpanel2);
JPanel masterPane = new JPanel(new GridBagLayout());
JPanel centerPane = new JPanel();
masterPane.add(centerPane);
masterPane.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
if(masterPane.getHeight()<masterPane.getWidth())
centerPane.setSize(masterPane.getHeight(), masterPane.getHeight());
else
centerPane.setSize(masterPane.getWidth(), masterPane.getWidth());
}
});
centerPane.setBackground(Color.blue);
masterPane.add(centerPane);
maincontainer.add(masterPane);
JFrame frame = new JFrame("");
frame.getContentPane().add(maincontainer);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setMinimumSize(new Dimension(300,300));
frame.setSize(500, 500);
I would like my program to have a top panel with three elements (Two JTextFields and one JButton) and a lower JPanel that has another JPanel inside.
The easiest way to do this is to keep using the default layout manager of the frame which is a BorderLayout. You add the panel with the text fields and buttons to the BorderLayout.PAGE_START. Then you add the panel that changes dynamically to the BorderLayout.CENTER.
The inner panel should always be a square, centered according to its container and adapt to the maximum height or width of its container
The easiest way to center a component on a panel is to use a GridBagLayout on the panel. The default GridBagConstraints will cause the component to be displayed at it preferred size centered both vertically and horizontally. So you will need a wrapper panel using the GridBagLayout to contain your center panel.
You would then want to override the getPreferredSize() method of your center panel to dynamically change as the size of the parent panel changes. This is a better approach than using a ComponentListener.
Something like:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class SSCCE extends JPanel
{
SSCCE()
{
setLayout( new BorderLayout() );
JPanel top = new JPanel( new GridLayout(0, 3) );
top.add( new JTextField(10) );
top.add( new JButton("Button") );
top.add( new JTextField(10) );
add(top, BorderLayout.PAGE_START);
JPanel center = new JPanel()
{
#Override
public Dimension getPreferredSize()
{
Dimension parent = getParent().getSize();
if (parent.width < parent.height)
return new Dimension(parent.width, parent.width);
else
return new Dimension(parent.height, parent.height);
}
};
center.setBackground( Color.BLUE );
JPanel wrapper = new JPanel( new GridBagLayout() );
wrapper.add(center, new GridBagConstraints());
add(wrapper, BorderLayout.CENTER);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
static class DragListener extends MouseInputAdapter
{
Point location;
MouseEvent pressed;
public void mousePressed(MouseEvent me)
{
pressed = me;
}
public void mouseDragged(MouseEvent me)
{
Component component = me.getComponent();
location = component.getLocation(location);
int x = location.x - pressed.getX() + me.getX();
int y = location.y - pressed.getY() + me.getY();
component.setLocation(x, y);
}
}
}
For some reason i am having problems centering my panel vertically that is located inside another panel. I do exactly as the examples i studied but still no luck.
Down there is my code. Despite using setAlignmentY(0.5f) on my container panel, it still wont center when i resize the window.
Also the components inside container panel wont center either, despite setAligenmentX(0.5f).
I wonder if there is a solution for this, I pretty much tried everything out there but couldnt find a solution.
JLabel idLabel;
JLabel passLabel;
JTextField id;
JTextField pass;
JButton enter;
JPanel container;
public JournalLogin()
{
//setLayout(new FlowLayout());
//setPreferredSize(new Dimension(500, 500));
//setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
container = new JPanel();
container.setLayout(new MigLayout());
container.setAlignmentX(0.5f);
container.setAlignmentY(0.5f);
container.setPreferredSize(new Dimension(300, 300));
container.setBorder(BorderFactory.createTitledBorder("Login"));
add(container);
idLabel = new JLabel("ID:");
idLabel.setAlignmentX(0.5f);
container.add(idLabel);
id = new JTextField();
id.setText("id");
id.setAlignmentX(0.5f);
id.setPreferredSize(new Dimension(80, 20));
container.add(id, "wrap");
setAlignmentX and Y are not the way to go about doing this. One way to center a component in a container is to have the container use GridBagLayout and to add the component without using any GridBagConstraints, a so-called default addition. There are other ways as well.
For example to alter Nick Rippe's example (1+ to him):
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import javax.swing.*;
public class UpdatePane2 extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = 200;
public UpdatePane2() {
JPanel innerPanel = new JPanel();
innerPanel.setLayout(new BorderLayout());
innerPanel.add(new JLabel("Hi Mom", SwingConstants.CENTER),
BorderLayout.NORTH);
innerPanel.add(new JButton("Click Me"), BorderLayout.CENTER);
setLayout(new GridBagLayout());
add(innerPanel);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("UpdatePane2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new UpdatePane2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Alignments tend to be pretty picky in Swing - they do [usually] work... but if all you're looking for is a panel that's centered, I'd recommend using Boxes in the BoxLayout (My personal favorite LayoutManager). Here's an example to get you started:
import java.awt.Dimension;
import javax.swing.*;
public class UpdatePane extends JPanel{
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
//Create Buffers
Box verticalBuffer = Box.createVerticalBox();
Box horizontalBuffer = Box.createHorizontalBox();
verticalBuffer.add(Box.createVerticalGlue()); //Top vertical buffer
verticalBuffer.add(horizontalBuffer);
horizontalBuffer.add(Box.createHorizontalGlue()); //Left horizontal buffer
//Add all your content here
Box mainContent = Box.createVerticalBox();
mainContent.add(new JLabel("Hi Mom!"));
mainContent.add(new JButton("Click me"));
horizontalBuffer.add(mainContent);
horizontalBuffer.add(Box.createHorizontalGlue()); //Right horizontal buffer
verticalBuffer.add(Box.createVerticalGlue()); //Bottom vertical buffer
// Other stuff for making the GUI
verticalBuffer.setPreferredSize(new Dimension(300,200));
JFrame frame = new JFrame();
frame.add(verticalBuffer);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
You will need to get the LayoutManager to center the layout for you. Currently it looks like the implementation of "MigLayout" does not honor the Alignment. Try changing it or creating a subclass.