Changing width of GridLayout elements - java

I want to change each buttons width but it's not working (i'am new in swing)
Panel = new JPanel();
gl = new GridLayout(2, 1);
Panel.setLayout(gl);
add(Panel, BorderLayout.EAST);
Up= new JButton("Btn1");
Up.addActionListener(this);
Up.setPreferredSize(new Dimension(200,150));
Panel.add(Up);
Down = new JButton("Btn2");
Down.addActionListener(this);
Down.setPreferredSize(new Dimension(200,300));
Panel.add(Down);

For this case I would use the GridBagLayout. This can be adapted very well with the GridBagConstraints.
In your case the weighty parameter would be responsible for controlling the height of the button in the panel. This is given as a percentage.
The code would look like this:
panel = new JPanel(new GridBagLayout());
add(panel, BorderLayout.EAST);
up = new JButton("Btn1");
up.addActionListener(this);
up.setPreferredSize(new Dimension(200, 150));
panel.add(up, new GridBagConstraints(0, 0, 1, 1, 100, 33, GridBagConstraints.NORTH, GridBagConstraints.VERTICAL, new Insets(0,0,0,0), 0,0));
down = new JButton("Btn2");
down.addActionListener(this);
down.setPreferredSize(new Dimension(200, 300));
panel.add(down, new GridBagConstraints(0, 1, 1, 1, 100, 66, GridBagConstraints.NORTH, GridBagConstraints.VERTICAL, new Insets(0,0,0,0), 0,0));
The result looks like this:

This question already has an accepted answer, but just wanted to put some 'tweaks' into an answer.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class BigWideButtons {
private JComponent ui = null;
static int upCodepoint = 9206; // upward triangle
static int downCodepoint = 9207; // downward triangle
Insets insets = new Insets(0, 75, 0, 75); // wide insets
Font font = getCompatibleFont().deriveFont(120f); // big font
BigWideButtons() {
initUI();
}
public void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridLayout(0, 1, 10, 10));
ui.setBorder(new EmptyBorder(4,4,4,4));
addButton(upCodepoint);
addButton(downCodepoint);
}
private void addButton(int codepoint) {
JButton b = new JButton(new String(Character.toChars(codepoint)));
b.setFont(font);
b.setMargin(insets);
ui.add(b);
}
private static Font getCompatibleFont() {
Font[] fonts = GraphicsEnvironment.
getLocalGraphicsEnvironment().getAllFonts();
for (Font font : fonts) {
if (font.canDisplay(upCodepoint) &&
font.canDisplay(downCodepoint)) {
System.out.println("Font: " + font.getFamily());
return font;
}
}
return null; // No installed font supports these characters!
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
BigWideButtons o = new BigWideButtons();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
This answer:
Uses a GridLayout, as seen in the question.
Avoids the need to guess a required size - it simply makes the font and button margin large, then packs the frame to fit them.
Given the meaning of the buttons 'up & down' it uses triangles pointing in those directions, as available in the Unicode character set.
But fonts do not typically have glyphs for every Unicode character (the character set is huge), so it adds a method which finds a font (the first available) which supports those glyphs. Here it uses "Segoe UI Symbol".

Related

How to add to a JFrame 3 JPanels: The 1st JPanel to take up 90% of the frame, the second to be on skinny top, 3rd to be drawer panel that can close

I am stuck on getting this swing UI to act the way I was hoping. I wrote this demo code to showcase what it is doing and I will now explain what I was hoping to make it do.
I have a JFrame and 3 JPanels
https://i.stack.imgur.com/B82tF.png
I want the JFrame to have an image in the background on the JFrame, like a world map, then on top of that I was trying to have: a top nav bar with buttons, then on top of the map, I want buttons that a player can click on for different areas of the map on the layer below, then I want to have a drawer that opens and closes if the user clicks on the show/hide drawer button that gives info about the action they performed by clicking the buttons.
What I have so far is three panels all aligned side by side and that is not what I want.
How can i get this UI to act like I described above?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class TestFrame extends JFrame {
static JFrame frame;
static JButton btnExit, btnShowHide;
static JPanel gridPanel, drawerPanel;
public static void main(String[] args)
{
GridLayout layout = new GridLayout(1,1,0,0);
frame = new JFrame("Main Frame");
frame.setLayout(layout);
// 1: Creating grid panel
gridPanel = new JPanel();
gridPanel.setBackground(Color.yellow);
gridPanel.setLayout(new GridLayout(5, 5, 0, 0));
gridPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY));
gridPanel.setOpaque(false);
gridPanel.setBorder(BorderFactory.createLineBorder(Color.gray));
placeButtons();
// 2: Creating button panel
JPanel buttonPanel = new JPanel();
buttonPanel.setBackground(Color.red);
// add buttons
btnExit = new JButton("Exit");
buttonPanel.add(btnExit);
btnExit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
System.exit(0);
} catch (Exception err) {
System.out.println("doh");
}
}
});
// 3: Creating button panel
drawerPanel = new JPanel();
drawerPanel.setBackground(Color.blue);
btnShowHide = new JButton("show drawer");
buttonPanel.add(btnShowHide);
btnShowHide.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
System.out.println("show drawer");
drawerPanel.setVisible(true);
} catch (Exception err) {
System.out.println("Could not close the DB: " + err);
}
if(btnShowHide.getText().equals("show drawer")){
btnShowHide.setText("hide drawer");
} else{
btnShowHide.setText("show drawer");
drawerPanel.setVisible(false);
}
}
});
// Adding panels to frame
frame.add(gridPanel);
frame.add(buttonPanel);
frame.add(drawerPanel);
frame.setSize(500, 500);
frame.setVisible(true);
}
public static void placeButtons(){
System.out.println("place buttons");
int dbx = 0;
int dby = 0;
for(int xCnt = 0; xCnt < 5; xCnt++){
dby = 0;
for(int yCnt = 0; yCnt < 5; yCnt++) {
JButton click = new JButton("x:"+xCnt+" y:"+yCnt);
gridPanel.add(click);
dby++;
}
dbx++;
}
}
}```
A common strategy to solve complex computing tasks is to break them into small, well-defined manageable tasks. Divide and conquer.
This also applies to gui: break the design into small, easy-to-layout containers and take it step by step.
First step: to have a background image implement a main panel, override its paintComponent to draw the image:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class TestFrame /*extends JFrame*/ {
private static final String imageURL = "https://previews.123rf.com/images/pingebat/pingebat1710/pingebat171000035/88604429-great-detail-illustration-of-the-world-map-in-vintage-style-.jpg";
public static void main(String[] args) throws IOException {
URL url = new URL(imageURL);
BufferedImage image = ImageIO.read(url);
JFrame frame = new JFrame("Main Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPane(image));
frame.pack();
frame.setVisible(true);
}
}
class MainPane extends JPanel{
private final Image background;
private final Dimension size;
MainPane(Image background) {
this.background = background;
size = new Dimension(background.getWidth(null), background.getHeight(null));
}
#Override
public Dimension preferredSize() {
return size;
}
#Override //Override to paint image at the background
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, null);
}
}
Second step: add controls buttons at the top. Define the buttons panel:
class ControlsPane extends JPanel{
public ControlsPane(ActionListener listener) {
setOpaque(false);
JButton btnShowHide = new JButton("Show Drawer");
add(btnShowHide);
btnShowHide.addActionListener(listener);
JButton btnExit = new JButton("Exit");
add(btnExit);
btnExit.addActionListener(e-> System.exit(0));
}
}
and modify MainPane constructor to use BorderLayout and add the buttons panel as suggested by #camickr:
MainPane(Image background) {
this.background = background;
size = new Dimension(background.getWidth(null), background.getHeight(null));
setLayout(new BorderLayout(5,5));
//action listener for show drawer button
ActionListener listener = e-> System.out.println("Show Drawer clicked");
add(new ControlsPane(listener), BorderLayout.PAGE_START);
}
Now take it to the next step (for example add a drawer).
Something like this?
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
JToolBar toolBar = new JToolBar(JToolBar.HORIZONTAL);
toolBar.setFloatable(false);
frame.add(toolBar, new GridBagConstraints(0, 0, 2, 3, 0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
JPanel drawer = new JPanel();
drawer.setBackground(Color.BLUE);
drawer.setOpaque(true);
drawer.setVisible(false);
JPanel content = new JPanel();
content.setBackground(Color.GREEN);
content.setOpaque(true);
frame.add(drawer, new GridBagConstraints(0, 1, 1, 2, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(4, 4, 4, 4), 0, 0));
frame.add(content, new GridBagConstraints(1, 1, 1, 2, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(4, 4, 4, 4), 0, 0));
Action toggleDrawer = new AbstractAction("Toggle Drawer") {
#Override
public void actionPerformed(ActionEvent e) {
drawer.setVisible(!drawer.isVisible());
frame.revalidate();
frame.repaint();
}
};
toolBar.add(new JButton(toggleDrawer));
frame.pack();
frame.setSize(300, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

JLabel not positioning correctly

I am just throwing together a quick and dirty GUI to display some data when I ran into an odd issue. The last label I add to the JFrame doesn't want to be positioned or display the border I put on it, so it looks like this:
Here is my code:
public DisplayData (Connection tConn)
{
ID = tID;
conn = tConn;
setupObjects();
setupFrame();
}
private void setupObjects()
{
JLabel caseLabel = new JLabel ("Case #:");
JLabel dateLabel = new JLabel ("Date:");
JLabel reportLabel = new JLabel ("Report:");
JLabel offenceLabel = new JLabel ("Offence:");
JLabel descriptionLabel = new JLabel ("Description:");
this.add(caseLabel);
this.add(dateLabel);
this.add(reportLabel);
this.add(offenceLabel);
this.add(descriptionLabel);
caseLabel.setBounds(50, 50, 130, 25); //x, y, width, height
dateLabel.setBounds(50, 100, 130, 25);
reportLabel.setBounds(50, 150, 130, 25);
offenceLabel.setBounds(50, 200, 130, 25);
descriptionLabel.setBounds(100, 50, 130, 25);
caseLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
dateLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
reportLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
offenceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
descriptionLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
}
private void setupFrame()
{
this.setTitle("Data Display");
this.setSize (650, 700); //Width, Height
this.setLocation(300, 10);
this.setResizable(false);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLayout(null);
}
Yes, I know I should be using a proper layout manager, but like I said i just wanted something quick and dirty. Plus, I will not be beaten by something that should be this simple. Any ideas would be appreciated.
EDIT:
As Compass and Neophyte pointed out, my order of operations was off. Flipped my method calls and all is good again in the world. Thanks for the 2nd pair of eyes.
Contrary to the original poster's strategy, or any of the answers so far, the best approach to this problem is to use layouts.
Here is an example that shows how easy it is to position fields using layouts, and to change the GUI on later updates to the specification.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class CourtDetailsGUI {
private JComponent ui = null;
static final String[] FIELD_NAMES = {
"Case #:",
"Date:",
"Report:",
"Offence:",
"Plaintiff:",
"Defendant:"
};
CourtDetailsGUI(int num) {
initUI(num);
}
public void initUI(int num) {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
ui.add(getFieldsPanel(num), BorderLayout.PAGE_START);
JTextArea ta = new JTextArea(5, 40);
JScrollPane sp = new JScrollPane(ta);
JPanel p = new JPanel(new GridLayout());
p.add(sp);
p.setBorder(new TitledBorder("Details"));
ui.add(p);
}
private JPanel getFieldsPanel(int num) {
JPanel outerPanel = new JPanel(new FlowLayout());
JPanel innerPanel = new JPanel(new GridLayout(0, 1, 15, 15));
outerPanel.add(innerPanel);
for (int ii=1; ii<num; ii++) {
JLabel l = new JLabel(FIELD_NAMES[ii]);
l.setBorder(new LineBorder(Color.BLACK));
innerPanel.add(l);
}
return outerPanel;
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
for (int ii=0; ii<FIELD_NAMES.length; ii++) {
CourtDetailsGUI o = new CourtDetailsGUI(ii+1);
JFrame f = new JFrame("Data " + (ii+1));
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
}
};
SwingUtilities.invokeLater(r);
}
}
Your order of operations is incorrect.
You initially call setupObjects();
This plays your objects out onto a JFrame, which has the default LayoutManager of BorderLayout.
By using the default add(Component comp) method, with BorderLayout, you end up putting the component into null for BorderLayout, which is not supposed to be normal. Furthermore, the reason you can't see the border for this object is because the border is actually the size of the frame. If you explicitly set a region for BorderLayout, then you'll see it work, but setting to no region seems to just break BorderLayout.
Additional add calls appear to free the previous item from the BorderLayout null management, allowing the bounds to take over.
Afterwards, you call setupFrame(); which removes the layout manager, but does not refresh what is currently rendered.
This sets the layout to null, which does nothing to how the frame is displayed, but just removes the layout.
To avoid this issue, call setupFrame(); prior to setupObjects();, and then setVisible(true) can be called at the end of setupObjects();

Java swing not drawing paintComponent

Im trying to draw a simple rectangle on a frame with some scrollbars and textfields(just testing) but the paintComponent its not showing, ive seen some similar cases here but i cant manage to make it work, any help please?
package appletdeslizadores;
import java.awt.*;
import javax.swing.*;
public class frame extends JPanel {
JFrame f1;
JPanel p1, p2;
JLabel lbl1, lbl2, lbl3;
JTextField txtfld1, txtfld2, txtfld3;
JScrollBar sbar1, sbar2, sbar3;
public frame() {
f1 = new JFrame("Applet ScrollBars");
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f1.setSize(380, 350);
f1.setLayout(new FlowLayout());
p1 = new JPanel(new GridLayout(3,3,10,10));
lbl1 = new JLabel("Scroll Bar 1");
lbl2 = new JLabel("Scroll Bar 2");
lbl3 = new JLabel("Scroll Bar 3");
sbar1 = new JScrollBar(JScrollBar.HORIZONTAL, 0, 10, 0, 255);
sbar2 = new JScrollBar(JScrollBar.HORIZONTAL, 0, 10, 0, 255);
sbar3 = new JScrollBar(JScrollBar.HORIZONTAL, 0, 10, 0, 255);
txtfld1 = new JTextField(3);
txtfld1.setText(String.valueOf(sbar1.getValue()));
txtfld1.setEditable(false);
txtfld2 = new JTextField(3);
txtfld2.setText(String.valueOf(sbar2.getValue()));
txtfld2.setEditable(false);
txtfld3 = new JTextField(3);
txtfld3.setText(String.valueOf(sbar3.getValue()));
txtfld3.setEditable(false);
p1.add(lbl1);
p1.add(lbl2);
p1.add(lbl3);
p1.add(sbar1);
p1.add(sbar2);
p1.add(sbar3);
p1.add(txtfld1);
p1.add(txtfld2);
p1.add(txtfld3);
f1.add(p1);
f1.setVisible(true);
}
public void paintComponent(Graphics2D g) {
g.drawRect(50,50,70,100);
g.setColor(Color.red);
}
public static void main(String[] args) {
new frame();
}
}
Problem
You're not sticking to conventions. This is causing problems small mistakes. Your frame class is actually a JPanel, not a JFrame.
There are two main problems: You never added the panel to the frame, and the paintComponent() method has a Graphics object, not a Graphics2D object as a parameter.
The changes to your code are at the bottom of this answer.
Solution
Stick to conventions. (You should also rename your class to a more appropriate name, but that is your choice.) Add the #Override annotation to your paintComponent() method since you wish to override this method from the original JPanel. If it crashes because of the annotation, it means you are not overriding correctly.
Change the paintComponent() parameter from Graphics2D to Graphics.
Add the JPanel to the JFrame.
Make sure you call setPreferredSize() on your JPanel and specify a size.
Call pack() on the JFrame right before making it visible so the layout manager can place everything accordingly.
Now I'm sure by the end of all this you are still not going to be happy with what you see because the code still needs some work, but at least this should give you a boost into the right direction. Also, you may want to call setColor() before drawing the rectangle. ;)
Hope this helped.
Code
public class frame extends JPanel {
JFrame f1;
JPanel p1, p2;
JLabel lbl1, lbl2, lbl3;
JTextField txtfld1, txtfld2, txtfld3;
JScrollBar sbar1, sbar2, sbar3;
public frame() {
f1 = new JFrame("Applet ScrollBars");
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f1.setSize(380, 350);
f1.setLayout(new FlowLayout());
p1 = new JPanel(new GridLayout(3,3,10,10));
lbl1 = new JLabel("Scroll Bar 1");
lbl2 = new JLabel("Scroll Bar 2");
lbl3 = new JLabel("Scroll Bar 3");
sbar1 = new JScrollBar(JScrollBar.HORIZONTAL, 0, 10, 0, 255);
sbar2 = new JScrollBar(JScrollBar.HORIZONTAL, 0, 10, 0, 255);
sbar3 = new JScrollBar(JScrollBar.HORIZONTAL, 0, 10, 0, 255);
txtfld1 = new JTextField(3);
txtfld1.setText(String.valueOf(sbar1.getValue()));
txtfld1.setEditable(false);
txtfld2 = new JTextField(3);
txtfld2.setText(String.valueOf(sbar2.getValue()));
txtfld2.setEditable(false);
txtfld3 = new JTextField(3);
txtfld3.setText(String.valueOf(sbar3.getValue()));
txtfld3.setEditable(false);
p1.add(lbl1);
p1.add(lbl2);
p1.add(lbl3);
p1.add(sbar1);
p1.add(sbar2);
p1.add(sbar3);
p1.add(txtfld1);
p1.add(txtfld2);
p1.add(txtfld3);
f1.add(p1);
setPreferredSize(new Dimension(512, 512));
f1.add(this);
f1.pack();
f1.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
g.drawRect(50,50,70,100);
g.setColor(Color.red);
}
public static void main(String[] args) {
new frame();
}
}

How to create custom panel layout with Swing? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
public class BattleShipsMain {
public static void main(String[] args) {
// JButton arrays to hold buttons
JButton[] userButtons = new JButton[100];
JButton[] compButtons = new JButton[100];
// Text for ships label
String shipsText = "Ships Size (Squares)" + "Carrier 5"
+ "Battleship 4" + "Destroyer 3"
+ "Patrol Boat 2";
// Draw main window and set layout
JFrame window = new JFrame("Battle Ships");
window.setSize(1200, 1900);
window.getContentPane().setLayout(new BorderLayout());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Draw top game panel
JPanel gridPanTop = new JPanel();
gridPanTop.setLayout(new BorderLayout());
gridPanTop.setPreferredSize(new Dimension(1300, 400));
gridPanTop.setBackground(Color.GRAY);
// Top panel text
JLabel ships = new JLabel();
ships.setText(shipsText);
// Bottom panel buttons
JButton submit = new JButton("Submit");
Dimension submitSize = new Dimension(20, 20);
submit.setSize(submitSize);
// Draw bottom game panel
JPanel panBottom = new JPanel();
panBottom.setBackground(Color.WHITE);
panBottom.setLayout(new BorderLayout());
panBottom.setPreferredSize(new Dimension(200, 200));
panBottom.add(submit);
// Set position of game panels
window.getContentPane().add(gridPanTop, BorderLayout.PAGE_START);
window.getContentPane().add(panBottom, BorderLayout.CENTER);
// Set border for grid buttons
Border border = new LineBorder(Color.gray);
// Draw panel for grids
JPanel user = new JPanel();
JPanel comp = new JPanel();
user.setBackground(Color.gray);
comp.setBackground(Color.gray);
user.setBorder(border);
comp.setBorder(border);
// Set layout for grid panels
user.setLayout(new GridLayout(10, 10));
comp.setLayout(new GridLayout(10, 10));
int x = userButtons.length;
// Set user buttons as JButtons, set size and add to grid
for (int i = 0; i < x; i++) {
userButtons[i] = new JButton();
userButtons[i].setPreferredSize(new Dimension(40, 40));
user.add(userButtons[i]);
}
// Set computer buttons as JButtons, set size and add to grid
for (int i = 0; i < x; i++) {
compButtons[i] = new JButton();
compButtons[i].setPreferredSize(new Dimension(40, 40));
comp.add(compButtons[i]);
}
// Add panels to main frame and set visible
window.pack();
window.add(gridPanTop);
window.add(panBottom);
gridPanTop.add(user, BorderLayout.WEST);
gridPanTop.add(comp, BorderLayout.EAST);
gridPanTop.setVisible(true);
panBottom.setVisible(true);
window.setVisible(true);
user.setVisible(true);
comp.setVisible(true);
// Start main game
MainGame start = new MainGame();
}
}
I have an assignment and am having lot of trouble creating the below panel layout in Java Swing. I have had no luck using any of the layouts.
Could anyone help my with this layout?
At present the code displays the following output:
You can probably tell I am a beginner so please excuse rookie errors. The panel layout I have at the moment LOOKS like the ideal one I attached but clearly is not the correct layout as I'd like.
You can achive this with different layouts and compound of layouts (using subpanels). I would have used GridBagLayout, that is definitely one of the most versatile layouts.
Example code
public class TestLayout extends JFrame {
private static final long serialVersionUID = -7619921429181915663L;
public TestLayout(){
super("TestLayout");
super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
init();
}
private void init() {
this.getContentPane().setLayout(new GridBagLayout());
//Setup some test panel with labels
JPanel panel1 = new JPanel(new BorderLayout());
panel1.setBorder(BorderFactory.createEtchedBorder());
JLabel label1 = new JLabel("Panel 1");
label1.setHorizontalAlignment(SwingConstants.CENTER);
panel1.add(label1,BorderLayout.CENTER);
JPanel panel2 = new JPanel(new BorderLayout());
panel2.setBorder(BorderFactory.createEtchedBorder());
JLabel label2 = new JLabel("Panel 2");
label2.setHorizontalAlignment(SwingConstants.CENTER);
panel2.add(label2,BorderLayout.CENTER);
JPanel panel3 = new JPanel(new BorderLayout());
panel3.setBorder(BorderFactory.createEtchedBorder());
JLabel label3 = new JLabel("Panel 3");
label3.setHorizontalAlignment(SwingConstants.CENTER);
panel3.add(label3,BorderLayout.CENTER);
JPanel panel4 = new JPanel(new BorderLayout());
panel4.setBorder(BorderFactory.createEtchedBorder());
JLabel label4 = new JLabel("Panel 4");
label4.setHorizontalAlignment(SwingConstants.CENTER);
panel4.add(label4,BorderLayout.CENTER);
//Here goes the interesting code
this.getContentPane().add(panel1, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.6, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(2, 2,
2, 2), 0, 0));
this.getContentPane().add(panel2, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.6, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(2, 2,
2, 2), 0, 0));
this.getContentPane().add(panel3, new GridBagConstraints(2, 0, 1, 1, 1.0, 0.6, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(2, 2,
2, 2), 0, 0));
//next row
this.getContentPane().add(panel4, new GridBagConstraints(0, 1, 3, 1, 1.0, 0.4, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(2, 2,
2, 2), 0, 0));
this.setPreferredSize(new Dimension(400, 200));
this.pack();
}
public static void main(String[] args) {
TestLayout frame = new TestLayout();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Generated output
The key part of the GridBagLayout is the GridBagConstraints
new GridBagConstraints(columnNumber, rowNumber, columnSpan, rowSpan, columnWeigth, rowWeigth, alignment, fillType, insets, padX, pady)
see in example how rowWeigth is set to 0.6 for first row and 0.4 to second row so that first row takes up some more space (60%). Adjust them as you like (if you like same space, just set 0.5 to both).

How returns XxxSize from JComponent(s) added to the JLabel

how can I correctly returns XxxSize from JComponent(s) added to the JLabel
1st. figure >> lets LayoutManager works like as for JPanel, JLabel returns Size(0, 0)
2nd. figure >> added some PreferredSize to the JLabel
3rd. figure >> calculated PreferredSize from JComponent(s) added to the JLabel
4th. figure >> lets LayoutManager works changed JLabel to JPanel, now LayoutManager correctly calculated Dimension without using any XxxSize
notice sice there is used Nimbus L&F, same output is there for all accesible L&F
import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
import java.util.Queue;
import javax.swing.*;
public class NimbusBorderPainterDemo extends JFrame {
private static final long serialVersionUID = 1L;
private JFrame frame = new JFrame();
private JPanel fatherPanel = new JPanel(), titlePanel = new JPanel();
private JLabel buttonPanel = new JLabel();
//figure ---> 4th. switch JLabel with JPanel
//private JPanel buttonPanel = new JPanel();
private Queue<Icon> iconQueue = new LinkedList<Icon>();
public NimbusBorderPainterDemo() {
iconQueue.add(UIManager.getIcon("OptionPane.errorIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.informationIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.warningIcon"));
JButton button0 = createButton();
JButton button1 = createButton();
JButton button2 = createButton();
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(1);
}
});
int gap = 5;
buttonPanel.setLayout(new GridLayout(0, 3, gap, 0));
buttonPanel.add(button0);
buttonPanel.add(button1);
buttonPanel.add(button2);
// figure 1st. ---> without PreferredSize
// figure 2nd. --->
//buttonPanel.setPreferredSize(new Dimension(160, 30));
// figure 3rd. --->
/*Dimension dim = button0.getPreferredSize();
int w = dim.width;
int h = dim.height;
w = (w + 5) * 3;
h += 4;
dim = new Dimension(w, h);
buttonPanel.setPreferredSize(dim);*/
titlePanel.setLayout(new BorderLayout());
titlePanel.add(new JLabel(nextIcon()), BorderLayout.WEST);
titlePanel.add(new JLabel("My Frame"), BorderLayout.CENTER);
titlePanel.setBorder(BorderFactory.createLineBorder(Color.GRAY));
titlePanel.add(buttonPanel, BorderLayout.EAST);
fatherPanel.setLayout(new BorderLayout());
fatherPanel.add(titlePanel, BorderLayout.CENTER);
frame.setUndecorated(true);
frame.add(fatherPanel);
frame.setLocation(50, 50);
frame.pack();
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setVisible(true);
}
private JButton createButton() {
JButton button = new JButton();
button.setBorderPainted(false);
button.setBorder(null);
button.setFocusable(false);
button.setMargin(new Insets(0, 0, 0, 0));
button.setContentAreaFilled(false);
button.setIcon(nextIcon());
//button.setRolloverIcon(nextIcon());
//button.setPressedIcon(nextIcon());
//button.setDisabledIcon(nextIcon());
nextIcon();
return button;
}
private Icon nextIcon() {
Icon icon = iconQueue.peek();
iconQueue.add(iconQueue.remove());
return icon;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception fail) {
}
UIManager.getLookAndFeelDefaults().put("nimbusFocus", Color.RED);
NimbusBorderPainterDemo nimbusBorderPainterDemo = new NimbusBorderPainterDemo();
}
});
}
}
The default preferred size calculation is to use the layout manager to determine the preferred size of a component. This means the layout manager iterates through all the child components to determine the preferred size of each. For a JPanel, which is meant to be used as a Container this calculation is used.
However, for other Swing components, the getPreferredSize() method is always overridden to provide a reasonable size for the given component.
In the case of a JLabel, the preferred size calculation takes into account the text and the icon used. Since you didn't provide either the preferred size is zero. Of course if you manually override this calculation by using the setPreferredSize() method then the component will have a preferred size.
So even though Swing allows you to add components to any component and use a layout manager to layout the child components, these child components are not used in the preferred size calculation.
This is not just a Nimbus issue.

Categories