I guess this is a simple question... basically it's about layout considerations. So let consider the code below, I get this:
.
public class TestCode_Web {
public static void main(String[] args) {
JFrame window = new JFrame("Test");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(200, 300);
// Inner panel ---------------------------------------------------------
JPanel innerPanel = new JPanel(new BorderLayout());
innerPanel.setBackground(new Color(250, 250, 200));
window.add(innerPanel);
// Northern panel ------------------------------------------------------
JPanel panelN = new JPanel(new BorderLayout());
JLabel labelN = new JLabel("Label");
panelN.add(labelN, BorderLayout.WEST);
panelN.setBackground(new Color(200, 250, 250));
innerPanel.add(panelN, BorderLayout.NORTH);
// Center panel --------------------------------------------------------
JPanel panelC = new JPanel();
panelC.setBackground(new Color(250, 200, 250));
JPanel panelCheckBoxes = new JPanel(new GridLayout(0, 1));
final JCheckBox c1 = new JCheckBox("C1");
final JCheckBox c2 = new JCheckBox("C2");
final JCheckBox c3 = new JCheckBox("C3");
panelCheckBoxes.add(c1);
panelCheckBoxes.add(c2);
panelCheckBoxes.add(c3);
int width = panelCheckBoxes.getPreferredSize().width;
int height = panelCheckBoxes.getPreferredSize().height;
panelCheckBoxes.setPreferredSize(new Dimension(width, height));
panelC.add(panelCheckBoxes);
innerPanel.add(panelC, BorderLayout.CENTER);
// Southern panel --------------------------------------------------------
JPanel panelS = new JPanel(new BorderLayout());
JLabel labelS = new JLabel(String.valueOf(width) + "/" + String.valueOf(height));
panelS.add(labelS, BorderLayout.WEST);
panelS.setBackground(new Color(250, 250, 200));
innerPanel.add(panelS, BorderLayout.SOUTH);
// ...
window.setVisible(true);
}
}
What I would like is to have this:
How could I achieve that ? I guesss there are several ways, I'm waiting for your diverse proposals...
One way to do this would be to overwrite the getPreferredSize() method of panelCheckBoxes to return panelC's width. This way, panelCheckBoxes' size will automatically adapt to the width of panelC.
final JPanel panelC = new JPanel();
// [...]
JPanel panelCheckBoxes = new JPanel(new GridLayout(0, 1)) {
public Dimension getPreferredSize() {
return new Dimension(panelC.getWidth(),
super.getPreferredSize().height);
}
};
For accessing panelC inside the anonymous inner class, it has to be final (i.e., after initialization, the panelC variable can not be assigned a new value, which is no problem in your case).
Just setting the preferredSize at that point in the constructor will not work, since (1) the size is not known yet, and (2) it might change when the window is resized. You could, however, use setPreferredSize after the call to window.setVisible(true);, when panelC got a size:
// after window.setVisible(true);
panelCheckBoxes.setPreferredSize(new Dimension(panelC.getWidth(),
panelCheckBoxes.getHeight()));
However, note that this way panelCheckBoxes still won't resize when you resize the window.
If you just want the checkboxes to be aligned to the left (but not necessarily stretch over the whole width), a simpler way would be to put panelC into the WEST container of the BorderLayout. Assuming that the colors are only for debugging and in the end everything will be the same color, you won't see a difference.
Finally, for more complex layouts you might want to check out GridBadLayout. It takes some getting used to, but once mastered, it's worth the effort.
Related
Panel Alignment Practice
Panel alignment practice. Each panel is a color. I haven't been able to resize using new Dimension() or flexibly manipulate the panels. I've tried frm.setLayout(null) with setBounds() and GridBagConstraints.
frm = new JFrame();
frmLayout = new BorderLayout();
frmLayout.layoutContainer(frm.getContentPane());
mainPnl = new MainPanel();
sP = new SecondPanel();
tP = new ThirdPanel();
getContentPane().add(mainPnl, BorderLayout.WEST);
getContentPane().add(sP, BorderLayout.EAST);
getContentPane().add(tP, BorderLayout.SOUTH);
To change the LayoutManager of a JPanel use :
frm.getContentPane().setLayout(frmLayout);
Don’t set it to null, a null-layout isn’t resized with the JFrame.
I was able to arrange the panels.
It seems if I add panels to a main panel setBounds() works. I'm probably violating all of your favorite swing conventions but hey, I'll learn just like you all at some point. Only issue with setBounds() so far is resizing the window. getWidth() or getHeight() cause the panel to disappear.
public class MainPanel extends JPanel {
SecondPanel sP;
ThirdPanel tP;
FourthPanel fP;
public MainPanel()
{
setBackground(Color.ORANGE);
setLayout(null);
sP = new SecondPanel();
sP.setBounds(0, 0, 90, 90);
tP = new ThirdPanel();
tP.setBounds(90, 0, 410, 90);
fP = new FourthPanel();
fP.setBounds(0, 400, 500, 100);
add(sP);
add(tP);
add(fP);
}
}
I am trying to add a scrollbar in jpanel with null layout.
I want to create a form. This should should display few buttons at the bottom at all times.Any content inside form should maintain it's size and ratio even if the parent container is resized.
Here is what I've come with. I have a panel with borderlayout and added buttons at the south of border. Then created another jpanel to contain form that is added at the center of parent jpanel. Since I want form to maintain it's ratio I went with null layout for inner panel. But I want it to display scrollbar when content is not fully visible. enter image description here
Now adding inner jpanel into scrollpane and adding scrollpanel into parent panel (.add(scrollpane, BorderLayout.CENTER)) doesn't give desired format.
Is there any thing that I can do to get desired format?
Here is code Sample:
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(new Dimension(1000, 700));
Container c = jFrame.getContentPane();
c.setLayout(new BorderLayout());
bottomPanel(c);
centerPanel(c); //scrollbar should go in this panel
jFrame.setVisible(true);
}
private static void centerPanel(Container c) {
JPanel centerPanel = new JPanel();
centerPanel.setLayout(null);
JButton button = new JButton("This jObject should not resize when window resizes and also should maintain relative position.");
button.setBounds(new Rectangle(10, 10, 600, 50));
JButton button1 = new JButton("Just like it works in this code. Just Add ScrollPane to centerPanel That is in green backround");
button1.setBounds(new Rectangle(10, 70, 600, 50));
JButton button2 = new JButton("For clearity");
button2.setBounds(new Rectangle(10, 130, 600, 50));
centerPanel.add(button);
centerPanel.add(button1);
centerPanel.add(button2);
centerPanel.setBackground(Color.GREEN);
c.add(centerPanel, BorderLayout.CENTER);
}
private static void bottomPanel(Container c) {
JPanel bottomPanel = new JPanel(); //Buttons that goes at the bottom of screen will go in here
JPanel bottomInnerPanel = new JPanel();
bottomInnerPanel.setLayout(new BorderLayout());
bottomPanel.setLayout(new GridLayout());
bottomInnerPanel.add(new JButton("Add"), BorderLayout.WEST);
bottomInnerPanel.add(new JButton("Search"), BorderLayout.EAST);
bottomPanel.add(bottomInnerPanel);
bottomPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
c.add(bottomPanel, BorderLayout.SOUTH);
}
I have main JPanel which is Borderlayout with added 4 JPANELS: NORTH(Green), WEST(Red), CENTER(Gray), SOUTH(Blue). I want to reduce width size of WEST(Red) Jpanel, or increase width size of Center(Grey) Jpanel.
Screenshot:
Here is my code:
frame = new JFrame("FreshPos baza podataka");
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
// Main paneel
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.setBorder( BorderFactory.createEmptyBorder(10,10,10,10) );
frame.getContentPane().add(panel);
//West panel;
JPanel panelWest = new JPanel(new GridLayout(14,0,0,2));
panelWest.setPreferredSize(new Dimension(300, 300));
panelWest.setBorder( BorderFactory.createEmptyBorder(100,0,0,0) );
panel.add(panelWest, BorderLayout.WEST);
panelWest.setBackground(Color.red);
for (int i = 0; i < MAX_TABLES; i++) {
buttonsTables[i] = new JButton(tables[i]);
buttonsTables[i].setMaximumSize(new Dimension(Integer.MAX_VALUE, buttonsTables[i].getMinimumSize().height));
panelWest.add(buttonsTables[i]);
panelWest.add(Box.createVerticalStrut(10));
}
//South panel;
JPanel southPanel = new JPanel(); // Donji layout za dugmice
southPanel.setBorder( BorderFactory.createEmptyBorder(20,0,0,0) );
panel.add(southPanel, BorderLayout.SOUTH);
southPanel.setBackground(Color.BLUE);
JButton buttonDodaj = new JButton("Dodaj");
southPanel.add(buttonDodaj);
JButton buttonIzmeni = new JButton("Izmeni");
southPanel.add(buttonIzmeni);
JButton butonObrisi = new JButton("Obrisi");
southPanel.add(butonObrisi);
//North panel;
JPanel northPanel = new JPanel(); // Donji layout za dugmice
northPanel.setBorder( BorderFactory.createEmptyBorder(0,10,0,0) );
panel.add(northPanel, BorderLayout.NORTH);
northPanel.setBackground(Color.green);
JButton buttonImport = new JButton("Importuj fajl");
buttonImport.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
importActionPerformed(evt);
}
});
northPanel.add(buttonImport, BorderLayout.WEST);
JButton ButtonRecord = new JButton("Snimi fajl");
northPanel.add(ButtonRecord, BorderLayout.WEST);
// Central panel
JPanel centerPanel = new JPanel(new BorderLayout());
centerPanel.setBackground(Color.GRAY);
panel.add(centerPanel, BorderLayout.CENTER);
I want to reduce width size of WEST(Red) Jpanel
panelWest.setBorder( BorderFactory.createEmptyBorder(100,0,0,0) );
So why is the width of your Border so large?
A Border is for "extra" space around the components.
So the width of your panel is the width of the buttons plus the width of the border.
Edit:
panelWest.setPreferredSize(new Dimension(300, 300));
Don't hardcode a preferred size. The layout manager will calculate the size based on the above logic. Get rid of that statement.
Edit 2:
// buttonsTables[i].setMaximumSize(new Dimension(Integer.MAX_VALUE, buttonsTables[i].getMinimumSize().height));
Get rid of any logic that attempts to control the size of a component. The point of using layout managers is to let the layout manager do the size calcualtions.
So for your buttons panel you need to nest panels to prevent the buttons from taking all the space.
You can do something like:
JPanel wrapper = new JPanel();
wrapper.add(buttonsPanel);
...
//panel.add(panelWest, BorderLayout.WEST);
panel.add(wrapper, BorderLayout.WEST);
By default a JPanel uses a FlowLayout which will respect the preferred size of any component added to it.
Another option is to use a GridBagLayout with the wrapper panel. By default the panel will then be displayed in the "center" of the available space. So it will be vertically centered and you won't need the EmptyBorder.
I want to create a JInternalFrame with some components in it.
My aim is to design a bash console in Java.
My frame is made of 4 components:
JTextArea included into a JScrollPane
JLabel with the text "Cmd:"
JTextField
JButton with the text "Send"
And I have the following code:
Box box = Box.createHorizontalBox();
box.add(Box.createVerticalStrut(5));
box.add(this.cmd_label);
box.add(Box.createVerticalStrut(5));
box.add(this.cmd_input);
box.add(Box.createVerticalStrut(5));
box.add(this.submit);
box.add(Box.createVerticalStrut(5));
Box mainBox = Box.createVerticalBox();
mainBox.add(Box.createHorizontalStrut(5));
mainBox.add(this.result_scroll);
mainBox.add(Box.createHorizontalStrut(5));
mainBox.add(box);
mainBox.add(Box.createHorizontalStrut(5));
add(mainBox);
So when the frame has not been maximized, I have a correct look:
But when I maximize it, all components are incorrectly located:
So, here is my question: How can I set a weight to the components to fix their location every time, or, how can I fix it?
Thanks.
I think this would be better done with a BorderLayout. In a BorderLayout, the component specified as the center component will expand to fill as much space as possible, and the other components will remain at their preferred sizes.
int hgap = 5;
int vgap = 5;
internalFrame.getContentPane().setLayout(new BorderLayout(hgap, vgap));
internalFrame.getContentPane().add(this.result_scroll, BorderLayout.CENTER);
JPanel bottomPanel = new JPanel();
bottomPanel.add(this.cmd_label);
bottomPanel.add(this.cmd_input);
bottomPanel.add(this.submit);
internalFrame.getContentPane().add(bottomPanel, BorderLayout.SOUTH);
Here try this code, is this behaviour exceptable :
import java.awt.*;
import javax.swing.*;
public class LayoutExample
{
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("LAYOUT EXAMPLE");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new BorderLayout(5, 5));
centerPanel.setBorder(
BorderFactory.createEmptyBorder(2, 2, 2, 2));
JTextArea tarea = new JTextArea(10, 10);
tarea.setBackground(Color.DARK_GRAY.darker());
tarea.setForeground(Color.WHITE);
tarea.setCaretColor(Color.WHITE);
tarea.setLineWrap(true);
JScrollPane scrollPane = new JScrollPane(tarea);
centerPanel.add(scrollPane, BorderLayout.CENTER);
JPanel footerPanel = new JPanel();
footerPanel.setLayout(new BorderLayout(5, 5));
footerPanel.setBorder(
BorderFactory.createEmptyBorder(2, 2, 2, 2));
JLabel cmdLabel = new JLabel("Cmd : ");
JTextField tfield = new JTextField(10);
JPanel buttonPanel = new JPanel();
buttonPanel.setBorder(
BorderFactory.createEmptyBorder(2, 2, 2, 2));
JButton sendButton = new JButton("SEND");
footerPanel.add(cmdLabel, BorderLayout.LINE_START);
footerPanel.add(tfield, BorderLayout.CENTER);
buttonPanel.add(sendButton);
footerPanel.add(buttonPanel, BorderLayout.LINE_END);
frame.getContentPane().add(centerPanel, BorderLayout.CENTER);
frame.getContentPane().add(footerPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new LayoutExample().createAndDisplayGUI();
}
});
}
}
OUTPUT :
Base problem here is what I consider a bug in JTextField's max layout hint: it's unbounded in both horizontal and vertical dimension. The latter is pure nonsense for a component designed for showing a single line of text. To fix, subclass and let it return its pref for the height, like:
JTextField cmdInput = new JTextField() {
#Override
public Dimension getMaximumSize() {
Dimension max = super.getMaximumSize();
max.height = getPreferredSize().height;
return max;
}
};
As BoxLayout respects maxSize, the excess height now will be given to the top box only.
On the long run, consider switching to a third party manager which allows fine-tuning in a all-in-one-panel approach. Yeah, here comes my current favourite: MigLayout. Compare the following lines to all the nesting and border tricks above and have fun :-)
MigLayout layout = new MigLayout("wrap 3, debug",
"[][grow, fill][]", // 3 columns, middle column filled and allows growing
"[grow, fill][]"); // two rows, first filled and allows growing
JComponent content = new JPanel(layout);
// the scrollPane in the first row spanning all columns
// and growing in both directions
content.add(new JScrollPane(new JTextArea(20, 20)), "span, grow");
// auto-wrapped to first column in second row
content.add(new JLabel("Cmd:"));
content.add(new JTextField());
content.add(new JButton("Submit"));
Here is my problem
How can I get rid of the gap from the inner rectangle box (it is actually the border of the middle JPanel)?
The outter rectangle is a extends JCompoment. Inside it contains three JPanels. Each of them use GridLayout. I even try to setHgap to a negative value in the big rectangle, but it doesn't change anything.
Edit: Sorry the question is not clear. I do want the border, but I don't want the gap between the inner border and outer border. If there is no gap in between, the whole rectangle will represent a class diagram class.
You may mean this way:
import java.awt.*;
import javax.swing.*;
public class GridBadFrame {
private JFrame frame;
private JPanel pnlCenter;
private JPanel pnl1;
private JPanel pnl2;
private JPanel pnl3;
public GridBadFrame() {
pnl1 = new JPanel();
pnl1.setBackground(Color.red);
pnl2 = new JPanel();
pnl2.setBackground(Color.blue);
pnl3 = new JPanel();
pnl3.setBackground(Color.red);
JLabel lblWest = new JLabel();
lblWest.setPreferredSize(new Dimension(50, 150));
JLabel lblEast = new JLabel();
lblEast.setPreferredSize(new Dimension(50, 150));
JLabel lblNorth = new JLabel();
lblNorth.setPreferredSize(new Dimension(600, 50));
JLabel lblSouth = new JLabel();
lblSouth.setPreferredSize(new Dimension(600, 50));
pnlCenter = new JPanel();
pnlCenter.setBackground(Color.black);
pnlCenter.setLayout(new java.awt.GridLayout(3, 0, 10, 10));
pnlCenter.setPreferredSize(new Dimension(600, 400));
pnlCenter.add(pnl1);
pnlCenter.add(pnl2);
pnlCenter.add(pnl3);
frame = new JFrame();
frame.add(pnlCenter, BorderLayout.CENTER);
frame.add(lblNorth, BorderLayout.NORTH);
frame.add(lblSouth, BorderLayout.SOUTH);
frame.add(lblWest, BorderLayout.WEST);
frame.add(lblEast, BorderLayout.EAST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(100, 100);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
GridBadFrame gridBadFrame = new GridBadFrame();
}
});
}
}
it is actually the border of the middle JPanel
If it is the border, remove that (setBorder(null)).
I think if you try setBorderPainted(false) it may get rid of the unwanted border.
The issue is probably to do with the preferred height and width set by the GridLayout on the JPanel.
Excerpt from the documentation:
The preferred width of a grid layout is the largest preferred width of
any of the components in the container times the number of columns,
plus the horizontal padding times the number of columns plus one, plus
the left and right insets of the target container.
The preferred height of a grid layout is the largest preferred height
of any of the components in the container times the number of rows,
plus the vertical padding times the number of rows plus one, plus the
top and bottom insets of the target container.