How to center the view by middle panel in swing - java

I have to build a UI with three panels, leftPanel, middlePanel and rightPanel, Panels should be aligned Horizontally
left and right panels should get the maximum and equal width as possible while the middle panel can get the minimum width as its child component required, once the panels are added view should be centered by middle panel.
I have done following test code to build the UI
import java.awt.Color;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SwingTest extends JFrame {
private static final long serialVersionUID = 1L;
public SwingTest() {
setTitle("Swing Test");
setSize(750, 350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(getParent());
// Rule used to find the component positions, for the testing purpose
Rule rule = new Rule(Rule.HORIZONTAL, true);
rule.setPreferredWidth(10);
rule.setPreferredHeight(40);
SidePanel leftPanel = new SidePanel("Left");
SidePanel rightPanel = new SidePanel("Right");
JPanel middlePanel = new JPanel();
middlePanel.setBorder(BorderFactory.createLineBorder(Color.black));
// Add left,right and middle panel horizontally
JPanel containerPanel = new JPanel();
containerPanel.setLayout(new BoxLayout(containerPanel, BoxLayout.X_AXIS));
containerPanel.add(leftPanel);
containerPanel.add(middlePanel);
containerPanel.add(rightPanel);
// Add rule and container panel Vertically
JPanel outerPanel = new JPanel();
outerPanel.setLayout(new BoxLayout(outerPanel, BoxLayout.Y_AXIS));
outerPanel.add(rule);
outerPanel.add(containerPanel);
add(outerPanel);
}
public static void main(String[] args) {
SwingTest test = new SwingTest();
test.setVisible(true);
}
private static class SidePanel extends JPanel {
private static final long serialVersionUID = 1L;
private SidePanel(String text) {
setLayout(new GridBagLayout());
add(new JLabel(text));
}
}
}
I have used Rule class from oracle swing tutorial site, it can be used to find the position of components. get Rule.java
The problem i have is as shown in the UI screen shot, view is not get centered by middle panel, Right now the view centered as width of `left + middle panel = right panel'
I don't want to set the panel height and width manually, It should be handled by the LayoutManager itself.
What i want is middle panel has to be get centered in a way left + middle/2 = middle/2 + right panel width.
I couldn't find a way to make the middle panel to get centered to view, Could someone help me to find a solution for this?.

You need to understand how the BoxLayout works.
First space is allocated at the preferred size of each component. Then if there is extra space, that space is allocated to each component.
The middle doesn't appear to be centered because the preferred size of the right label is larger than the left label. So when the extra space is allocated the right side is larger than the left side.
This is easy to test. Just change the text of the right side panel to "LEFT".
However, that leads to another question - Why doesn't the size of the middle panel change? I don't know the answer to this. Although for some reason the default FlowLayout seems to work different than the GridBagLayout. Again you can test this by changing the layout of the middle panel to be a GridBagLayout.
If you always want the left/right panels to be the same size then you might want to consider using the Relative Layout. Using this layout the basic code would be:
RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS);
JPanel panel = new JPanel( rl );
panel.add(leftPanel, new Float(1));
panel.add(middle, new Float(3));
panel.add(rightPanel, new Float(1));
Now the left/right panels will be the same size independent of the components added to each panel.

Related

JButton in GridBagLayout in a JPanel

I am learning swing from past week, I have some issue with GridBagConstraints to put one button in top left corner but all other buttons in default in GridBagConstraints ?
I am using code that like not original but states the problem
import java.awt.*;
import javax.swing.*;
#SuppressWarnings("serial")
class MyPanel extends JPanel
{
JButton menu = new JButton("Menu"), button = new JButton("Puzzle");
GridBagConstraints gbc1 = new GridBagConstraints(), gbc2 = new GridBagConstraints();
private void setup()
{
gbc1.anchor = GridBagConstraints.FIRST_LINE_START;
gbc2.anchor = GridBagConstraints.CENTER;
gbc2.weightx = 1.0;
gbc2.weighty = 1.0;
}
public MyPanel()
{
this.setLayout(new GridBagLayout());
this.setup();
this.button.setPreferredSize(new Dimension(250, 140));
this.add(menu, gbc1);
this.add(button, gbc2);
}
}
#SuppressWarnings("serial")
public class Test extends JFrame
{
public Test()
{
this.setTitle("Test");
this.setContentPane(new MyPanel());
this.setResizable(false);
this.setSize(800, 600);
this.setVisible(true);
}
public static void main(String args[])
{
SwingUtilities.invokeLater(() -> new Test());
}
}
output
I want menu is top corner.
I read from here but i did not understand this Could you please explain GridBagConstraints for how to do that.
I Hope that problem is clear to understand, if not please let me know in comments.
EDIT:
#camickr suggestion works but a little problem, the Puzzle Button is not in extract center.
Thanks.
By default the GridBagLayout will display all the components centered horizontally and vertically, unless one of the components has a weightx/weighty value not equal to 0. Then that component will fill the extra space in the frame.
So if you want one component at the "top/left" and one in the "center", you need to:
use the "anchor" constraint. It will be different for both components.
the component in the center will need to use the "weightx/weighty" constraints.
However, an easer solution might be to use a combination of panels with different layout managers.
For example:
JPanel menuPanel = new JPanel( new FlowLayout(FlowLayout.LEFT) );
menuPanel.add(menuButton);
JPanel centerPanel = new JPanel( new GridBagLayout() );
centerPanel.add(puzzle, new GridBagConstraints());
frame.add(menuPanel, BorderLayout.PAGE_START);
frame.add(centerPanel, BorderLayout.CENTER);
So now the "top" of the frame will contain a panel with components displayed from the left and the "center" of the frame will contain your puzzle centered in the remaining space of the frame.
Edit:
I solved it but put gridx and gridy to 0 in center component, but i did not completely understand the setttings
Well I mentioned that you would need to use the gridx/gridy constraints. You should always use those constraints as it is very obvious what grid you want to add the component to. The examples from the tutorial always specify those values.
Using gridx/gridy both equal to 0, does not really make sense. The effect is that you have two components trying to share the same grid.
Remove the setResizable(false) statement and shrink the size of the frame to see how the button repositions itself.
It is not normal that two components share the same grid. Normally you would have the menu on the first row and the button on the second row. This will center the button horizontally in the frame and vertically in the space below the menu.
What you are doi

Adding JPanels to regions other than CENTER

I am currently reading chapter 12 of Head First Java about making GUIs. They have just mentioned that JFrames are split into center, north, south, east and west. The book then uses the 2 argument add() method to add specified components to a specified region with that JFrame.
I can add a JButton to each of the five regions fine. I can also add my own JPanel to the center region with JButtons all around it. But then when I try to add a JPanel to any region other than center, the JPanel does not appear.
I really have searched all over the web and Stack Overflow for the past hour and I have not come across anything that mentions adding JPanels to any region other than center in a JFrame. So my question is: is it possible to add JPanels to the north, south, east or west regions of a JFrame?
Thanks in advance to anyone that can help me with this.
Here is the code that I've been trying to run with my JPanel in the north region:
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.BorderLayout;
public class StackQ {
JFrame frame;
public static void main(String [] args) {
StackQ gui = new StackQ();
gui.go();
}
public void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("location test");
JButton button2 = new JButton("location test");
JButton button3 = new JButton("location test");
JButton button4 = new JButton("location test");
myDrawPanel custom = new myDrawPanel();
frame.getContentPane().add(button, BorderLayout.CENTER);
frame.getContentPane().add(button2, BorderLayout.EAST);
frame.getContentPane().add(button3, BorderLayout.WEST);
frame.getContentPane().add(button4, BorderLayout.SOUTH);
frame.getContentPane().add(custom, BorderLayout.NORTH);
frame.setSize(300,300);
frame.setVisible(true);
}
}
class myDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color random = new Color(red, green, blue);
g.setColor(random);
g.fillOval(20,20,100,100);
}
}
It could be clearer but this is described in the BorderLayout documentation:
The components are laid out according to their preferred sizes and the constraints of the container's size.... the CENTER component may stretch both horizontally and vertically to fill any space left over.
Put another way, the CENTER component will be stretched (if needed) to fill the application, and any other components need to specify a preferred-size in order to take some of that from the CENTER.
JButton specifies a preferred size by default, based on the contents of the button. JPanel on the other hand does not - its preferred size depends on its contents, and your JPanel doesn't have any contents, therefore its preferred size is zero.
In short, specify a preferred size for your JPanel and the BorderLayout will try to allocate at least that much space for the panel.
Just for any potential future viewers of this post, to get the desired result, I first imported the Dimension class at the very top of my StackQ class (this is needed because the setPreferredSize() method used later on in the go() method accepts an argument of type Dimension):
import java.awt.Dimension;
And then I added this code to the go() method immediately after the instantiation of the myDrawPanel class:
Dimension dims = new Dimension(1366, 200);
custom.setPreferredSize(dims);
I chose 1366 as the width because that's how big my screen is.
Thanks everyone for your help!

Aligning components in Box

edit: if you downvote this question, you may leave a comment to explain why, that will be more constructive.
I obtain this unexpected result...
... using this code:
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class TestAlignment extends JFrame {
// Constructor
public TestAlignment() {
super("Test Alignment");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Components to show
JLabel leftLabel = new JLabel("Left");
JButton centerButton = new JButton("Middle");
JLabel rightLabel = new JLabel("Right");
// Add all to box
Box box = Box.createVerticalBox();
box.add(leftLabel);
box.add(centerButton);
box.add(rightLabel);
box.add(Box.createHorizontalStrut(180));
// Align content in box
leftLabel.setAlignmentX(LEFT_ALIGNMENT);
centerButton.setAlignmentX(CENTER_ALIGNMENT);
rightLabel.setAlignmentX(RIGHT_ALIGNMENT);
// Add box to frame, and show frame
box.setOpaque(true);
setContentPane(box);
setVisible(true);
}
// Main
public static void main(String[] args) {
// Create frame in EDT
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() { new TestAlignment(); }
});
}
}
I understand now this works as expected for JComponent.setAlignmentX(): this method tells which sides of the components must be aligned (top label leftmost side aligned with button center and bottom label rightmost side).
I would like to understand how to have each label aligned as expected intuitively (left label on the left, right label on the right), labels touching the vertical edges of the Box?
(I know how to do with putting each label in a Box embedded, and using Box.createHorizontalGlue() to force it to the left or the right side, but seems to me too much for the simple purpose of alignment. I'm looking for something more simple)
Don't think you can do this with a BoxLayout. Your example does show the intuitive code, which doesn't work as you would hope.
I would suggest you probably need to use a GridBagLayout. I think it supports the setAlignmentX(...) method the way you want to use it.
If not, then can use the Relative Layout. It is simple to use, like the BoxLayout and does support the alignment you want when you use:
setAlignment( RelativeLayout.COMPONENT );
You can use BoxLyout:
// Components to show
// Left
JLabel leftLabel = new JLabel("Left");
JPanel leftPanel = new JPanel();
leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.X_AXIS));
leftPanel.add(leftLabel);
leftPanel.add(Box.createHorizontalGlue());
// Center
JButton centerButton = new JButton("Middle");
// Right
JLabel rightLabel = new JLabel("Right");
JPanel rightPanel = new JPanel();
rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.X_AXIS));
rightPanel.add(Box.createHorizontalGlue());
rightPanel.add(rightLabel);
// Add all to box
Box box = Box.createVerticalBox();
box.add(leftPanel);
box.add(centerButton);
box.add(rightPanel);
box.add(Box.createHorizontalStrut(180));
// Align content in box
// leftLabel.setAlignmentX(LEFT_ALIGNMENT);
centerButton.setAlignmentX(CENTER_ALIGNMENT);
// rightLabel.setAlignmentX(RIGHT_ALIGNMENT);

Aligning JButton to the right

I am creating an interface in java and i want to align the button to the right. I have try but its not working. Can someone tell me how to do it?
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Button_Alignment extends JFrame{
public JPanel header,body,footer;
public JButton add1;
public JButton save;
public Button_Alignment(){
super("BUTTON");
GridLayout g1 = new GridLayout(3,1);
setLayout(g1);
//////
header = new JPanel();
JButton add1 = new JButton("add");
header.add(add1);
JButton save = new JButton("save");
header.add(save);
//////
add(header);
header.setBackground(Color.cyan);
}
public static void main(String[] args){
Button_Alignment ba = new Button_Alignment();
ba.setSize(400, 400);
ba.setVisible(true);
}
}
Your current layout manager (GridLayout) is being created with 3 rows and a single column. Hence, the components you add to the JFrame will appear vertically from top to bottom. Worse still, GridLayout will aportion space equally amongst all 3 components, meaning that your buttons will stretch in both directions, which is almost certainly not what you require.
I would consider using an alternative layout manager. For simple layouts I tend to favour BorderLayout or FlowLayout. For more complex layouts I lean towards GridBagLayout although there are others who prefer MigLayout.
More information here.
Try like this:
JButton save = new JButton ("save");
setLayout (new BorderLayout ());
add (save, BorderLayout.EAST);
you set GridLayout to the JFrame constructor instead of JPanel (JPanel has by default FlowLayout), I think that
header.setLayout(new GridLayout(3,1));
header.add(add1);
header.add(save);
notice ---> but GridLayout in current ComponentOrientations to start from left to right, then 3rd. grid is empty
then only to add JFrame#add(JPanel), in your case
add(header);
A quick and dirty way is to put the button [or a container immediatly wrapping the button, if you want to add other components on the right next to your button] it in a container that uses the BorderLayout and use the BorderLayout.EAST layout constraint for that button [or wrapping container].

Swing BoxLayout problem with JComboBox without using setXXXSize

here's an SSCCE:
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BoxLayoutTest extends JFrame {
public BoxLayoutTest(){
JPanel main = new JPanel();
main.setLayout(new BoxLayout(main, BoxLayout.Y_AXIS));
main.setBackground(Color.red);
this.add(main);
JPanel northPanel = new JPanel();
JPanel middle = new JPanel();
middle.setLayout(new BoxLayout(middle, BoxLayout.X_AXIS));
middle.add(new JButton("FOO"));
middle.add(Box.createHorizontalGlue());
JPanel aPanel = new JPanel();
aPanel.setBackground(Color.black);
JComboBox b = new JComboBox();
//b.setPreferredSize(new Dimension(100,16)); //uncomment this to see the layout I would like to achieve
//b.setMaximumSize(new Dimension(100,16));
//middle.add(b); //uncomment this line
middle.setBackground(Color.green);
northPanel.setBackground(Color.blue);
main.add(northPanel);
main.add(middle);
main.add(Box.createVerticalGlue());
this.setSize(800,600);
this.setResizable(true);
this.setVisible(true);
}
public static void main(String[] args) {
new BoxLayoutTest();
}
}
I'm trying to refactor some classes I wrote some time ago, when I didn't know that using setXXXSize methods on components is wrong.
Using a resizable frame ,the result I want to achieve is the following:
The northPanel should stay on top and change it's size accordingly to the frame size modifications (seems to work fine)
The green panel where I put the JButton should keep the maximum dimension of the JButton and stay just below the blue panel above (this works fine if I only put JButtons inside that panel).
The problem arise if I put a JComboBox inside the green panel (try to uncomment the line in the SSCCE). I guess JComboBox hasn't a maximum size specified, so it stretches with the frame. In the previous wrong version of my code I was using setxxxSize methods on the JComboBox to limit it's dimension(try to uncomment the line on setXXXSize methods to see it).
My question are:
Is it possible to achieve the same result using BoxLayout without invoking setXXXSize() methods?
If yes, how?
Is there any other LayoutManager that can I use to get that effect?
Please put me in the right direction
JComboBox is misbehaving (the same as JTextField) in reporting an unbounded max height: should never show more than a single line. Remedy is the same: subclass and return a reasonable height
JComboBox b = new JComboBox() {
/**
* #inherited <p>
*/
#Override
public Dimension getMaximumSize() {
Dimension max = super.getMaximumSize();
max.height = getPreferredSize().height;
return max;
}
};
just for fun, here's a snippet using MigLayout (which is my personal favorite currently :-)
// two panels as placeholders
JPanel northPanel = new JPanel();
northPanel.setBackground(Color.YELLOW);
JPanel southPanel = new JPanel();
southPanel.setBackground(Color.YELLOW);
// layout with two content columns
LC layoutContraints = new LC().wrapAfter(2)
.debug(1000);
AC columnContraints = new AC()
// first column pref, followed by greedy gap
.size("pref").gap("push")
// second
.size("pref");
// three rows, top/bottom growing, middle pref
AC rowContraints = new AC()
.grow().gap().size("pref").gap().grow();
MigLayout layout = new MigLayout(layoutContraints, columnContraints,
rowContraints);
JPanel main = new JPanel(layout);
main.setBackground(Color.WHITE);
// add top spanning columns and growing
main.add(northPanel, "spanx, grow");
main.add(new JButton("FOO"));
// well-behaved combo: max height == pref height
JComboBox combo = new JComboBox() {
#Override
public Dimension getMaximumSize() {
Dimension max = super.getMaximumSize();
max.height = getPreferredSize().height;
return max;
}
};
// set a prototype to keep it from constantly adjusting
combo.setPrototypeDisplayValue("somethingaslongasIwant");
main.add(combo);
// add top spanning columns and growing
main.add(southPanel, "spanx, grow");
I have always seen using the layout managers in the jdk are not easy. They are either too simple and inflexible or the gridbaglayout is just too much trouble. Instead I started using the jgoodies form layout and never looked back since.. Have a look at it. Its very simple and easy to use. Here's a link:
http://www.jgoodies.com/freeware/forms/
Make sure you go through the white paper.
And now, we also have google providing us a WYSISWG editor for the formlayout as a plugin for eclipse. This just makes life a lot lot easier.
http://code.google.com/javadevtools/wbpro/palettes/swing_palette.html

Categories