Java setBorder breaks component padding - java

When I set a border color to every item in a JPanel with GridBagLayout, the components collapse.
but when I remove the border off just one component, the padding stays as expected.
What am I doing wrong?
Border Setting:
setBorder(BorderFactory.createLineBorder(Color.decode("#"+Constants.Display.OPTIONS_BORDER_COLOR)));
JPanel:
public class OptionsPanel extends JPanel {
private AddMachineBtn addMachineBtn;
private SearchField searchField;
private SearchBtn searchBtn;
private GridBagConstraints gbc;
public OptionsPanel() {
init();
config();
build();
}
private void init() {
addMachineBtn = new AddMachineBtn("Add Machine");
searchField = new SearchField("Search...");
searchBtn = new SearchBtn("S");
gbc = new GridBagConstraints();
int i = Constants.Display.OPTIONS_PANEL_PADDING;
gbc.insets = new Insets(i, i, i, i);
}
private void config() {
setLayout(new GridBagLayout());
setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.decode("#"+Constants.Display.OPTIONS_BORDER_COLOR)));
setPreferredSize(new Dimension(0, Constants.Display.OPTIONS_PANEL_HEIGHT));
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.anchor = gbc.LINE_START;
}
private void build() {
gbc.gridx = 0;
add(addMachineBtn, gbc);
gbc.weightx = 0;
gbc.gridx = 1;
add(searchField, gbc);
gbc.gridx = 2;
add(searchBtn, gbc);
}
}

I'm not sure about how it affects GridBagLayout, but "In general, when you want to set a border on a standard Swing component other than JPanel or JLabel, we recommend that you put the component in a JPanel and set the border on the JPanel."—setBorder(). There's a related example here.

Yes, layout has no affect to components' size. You may try to change layout (for example to FlowLayout) but situation will be the same.
Swing components obtains its border during initialization from Look'n'Feel.
Insert System.out.println(addMachineBtn.getBorder()); after addMachineBtn creation. You will see that the border already exists
javax.swing.plaf.BorderUIResource$CompoundBorderUIResource
This border provides its own insets for component, and when you replace border by another ones you loose its insets.

If it's really important to keep original components insets and replace border, try to imitate native Swing borders.
For example something like this:
addMachineBtn.setBorder(new CompoundBorder(new LineBorder(Color.red), new EmptyBorder(5, 17, 5, 17)));
Instead of LineBorder put border what you need, EmptyBorder keep the same, just correct insets as needed.

The fix to this was changing the following
setSize(new Dimension(w,h));
setMinimumSize(new Dimension(w,h));
setMaximumSize(new Dimension(w,h));
to
setPreferredSize(new Dimension(w,h));
setMinimumSize(new Dimension(w,h));
setMaximumSize(new Dimension(w,h));

Related

Multiple custom JPanels inside JScrollPane - resizing/showing components on one resizes them all

So I've got a custom JPanel which I use multiple instances of to fill a wrapper Panel inside a JScrollPane. The number of custom JPanel elements I use is dependent on the size of a list. The problem I'm running across is a part of my Custom JPanel has another invisible JPanel which expands when I click on it's parent. The behavior I'm trying to mimic is that of an accordian UI element. Before I was on this project I was primarily a webdev and while I have worked with Java a lot, I'm still relatively new to Swing.
Here is an example of the behavior - the scroll pane with all elements closed. (forgive me for the quick paint-job comments. I tried to emphasize what I see going wrong).
Next, is the image of the first element expanded - which unexpectedly expands all other elements.
It must be noted that I'm only targeting the first panel and setting the visibility, yet all other repeating panels length grows when I do this, but obviously the components inside stay invisible.
Finally, here is my final deired result:
Is there some sort of constraint in the JScrollPane that resizes it's child JPanel's components to retain the same height at all times? I can't seem to figure a way around this and I've played with all sorts of different wrappers and layouts, all to no avail.
Please let me know if anyone wants to see code snippets, but they'll have to be heavily redacted and stripped down due to the nature of the project.
Thanks,
Marek
PS: yes, I absolutely must use Swing.
Edit: Here is a static, quick and dirty, stripped down implementation of my code as suggested by Roddy of the Frozen Peas
ExampleScrollPane:
public class ExampleSrollPane extends JPanel {
private static ExampleSrollPane instance = null;
private JScrollPane contentScrollPanel = new JScrollPane();
private Vector<ExamplePanel> exPanels;
private JPanel wrapPanel = new JPanel();
public ExampleSrollPane() {
super();
this.setLayout(new BorderLayout());
this.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.white,
Color.white, new Color(115, 114, 105), new Color(165, 163, 151)));
exPanels = new Vector<ExamplePanel>();
init();
}
private void init() {
contentScrollPanel.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
contentScrollPanel.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
contentScrollPanel.setBorder(new CompoundBorder(new EmptyBorder(5, 5, 5, 5), new SoftBevelBorder(BevelBorder.LOWERED)));
this.add(contentScrollPanel, BorderLayout.CENTER);
initPanels();
}
public void initPanels() {
int numUnits = 15;
// Init one empty panel at least
if (numUnits == 0) numUnits = 15;
wrapPanel.setLayout(new GridLayout(numUnits, 1));
for (int i = 0; i < numUnits; i++) {
ExamplePanel exPan = new ExamplePanel(i);
exPanels.add(i, exPan);
wrapPanel.add(exPan);
}
contentScrollPanel.setPreferredSize(new Dimension(575, 100));
contentScrollPanel.getViewport().add(wrapPanel);
}
/**
* Method: viewPanel()
*
*/
private static void viewPanel() {
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.setLocationRelativeTo(null);
frame.add(getInstance());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setSize(new Dimension(600, 350));
frame.setAlwaysOnTop(true);
frame.setVisible(true);
}
public static ExampleSrollPane getInstance() {
if (instance == null) {
instance = new ExampleSrollPane();
}
return instance;
}
/**
* The main method.
*
* #param args the arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
viewPanel();
}
});
}
}
It's here in the showHideTable method which creates the problem.
ExamplePanel (my custom JPanel):
public class ExamplePanel extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private static final Border STAT_BORDER = BorderFactory.createBevelBorder(BevelBorder.LOWERED, Color.white,
Color.white, new Color(115, 114, 105), new Color(165, 163, 151));
public static final EmptyBorder PAD_BORDER = new EmptyBorder(10, 10, 10, 10);
public int indx;
private JLabel unitLabel;
private JLabel statLabel;
private JLabel invLabel;
private JLabel targetLabel;
private JLabel timeLabel;
// Custom BasicArrowButton to expand/hide the "table"
private UnitToggleButton unitToggleButton;
// The expandable JPanel
public ExpanableTable elementTable;
private String id;
private String unitStatusString;
private String invStatusString;
private String targetString;
private String timeString;
public Color componentColor;
private JPanel topPanel = new JPanel();
public JPanel tablePanel = new JPanel();
public ExamplePanel(int index) {
super();
this.indx = index;
id = "Unit # 00000";
id = "Unit #00000";
unitStatusString = "PENDING";
invStatusString = "PENDING";
elementTable = new ExpanableTable();
targetString = "AZ501";
timeString = "11:18:27";
componentColor = this.getBackground();
init();
}
private void init() {
topPanel.setLayout(new GridBagLayout());
topPanel.setBorder(PAD_BORDER);
unitLabel = new JLabel(id); // TODO unit.getID();
statLabel = new JLabel(unitStatusString); // TODO: unit.getStatus();
invLabel = new JLabel(invStatusString); // TODO: unit.getInventoryStatus();
targetLabel = new JLabel(targetString);
timeLabel = new JLabel(timeString);
buildLabel(statLabel);
buildLabel(invLabel);
buildLabel(targetLabel);
buildLabel(timeLabel);
unitToggleButton = new UnitToggleButton(BasicArrowButton.EAST, indx);
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.fill = GridBagConstraints.FIRST_LINE_END;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = .1;
gbc.weighty = 1;
gbc.insets = new Insets(0, 0, 5, 0);
// Add toggle button far-left, row 1
topPanel.add(unitToggleButton, gbc);
// Add empty space far-left, row 2
gbc.gridy = 1;
topPanel.add(new JLabel(" "), gbc);
// Add unit label row 1 column 2
gbc.gridy = 0;
gbc.gridx = 1;
gbc.weightx = .3;
topPanel.add(unitLabel, gbc);
// Add Status label row 1 column 3
gbc.gridx = 2;
topPanel.add(statLabel, gbc);
// Add inventory label row 1 column 4
gbc.gridx = 3;
topPanel.add(invLabel, gbc);
// Add tasking label row 2 column 2
gbc.gridy = 1;
gbc.gridx = 1;
topPanel.add(new JLabel(" Tasking: "), gbc);
// Add target label row 2 column 3
gbc.gridx = 2;
topPanel.add(targetLabel, gbc);
// Add mission Label row 2 column 4
gbc.gridx = 3;
topPanel.add(timeLabel, gbc);
gbc.gridx = 0;
gbc.gridy = 2;
gbc.weighty = 1;
gbc.weightx = 1;
gbc.gridwidth = 4;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0, 0, 0, 0);
JSeparator sep = new JSeparator(JSeparator.HORIZONTAL);
topPanel.add(sep, gbc);
gbc.gridy = 3;
topPanel.add(elementTable, gbc);
revalidate();
this.setLayout(new BorderLayout());
this.add(topPanel, BorderLayout.NORTH);
this.add(tablePanel, BorderLayout.CENTER);
HSIUtils.setColoredBorder(tablePanel, Color.RED);
tablePanel.add(elementTable);
// Do NOT show the table on initialization
tablePanel.setVisible(false);
unitToggleButton.addActionListener(this);
}
/**
* Method: buildLabel()
*
* #param label
*/
private void buildLabel(JLabel label) {
label.setBorder(STAT_BORDER);
label.setMinimumSize(new Dimension(80, 20));
label.setPreferredSize(new Dimension(100, 25));
label.setOpaque(true);
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setHorizontalTextPosition(SwingConstants.CENTER);
label.setBackground(componentColor);
}
private void showHideTable(boolean show) {
tablePanel.setVisible(!show);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == this.unitToggleButton) {
showHideTable(unitToggleButton.isExpanded());
}
}
}
ExpandableTable:
public class ExpanableTable extends JPanel {
public ExpanableTable () {
super();
this.setLayout(new BorderLayout());
add(new JButton("Test1"), BorderLayout.WEST);
add(new JButton("Test2"), BorderLayout.CENTER);
add(new JButton("Test3"), BorderLayout.EAST);
}
}
Basically I want to be able expand/show/resize each Panel inside the scroll pane independently of the others. As it currently stands, if I show a hidden Panel on one, the other panel's height grows to match but does not show the component. Very strange to me but could be my ignorance of certain Swing components and the constraints they contain.
Is there some sort of constraint in the JScrollPane that resizes it's child JPanel's components to retain the same height at all times?
A scroll pane doesn't resize anything. It only displays the component added to the scroll panes and add scroll bars when the preferred size of the component added is greater than the size of the scroll pane.
wrapPanel.setLayout(new GridLayout(numUnits, 1));
On the other hand when you use a GridLayout, then yes all components added to the grid will be resized to the size of the largest component.
So you don't want to use a GridLayout for the wrapper panel.
I would suggest you could use a GridBagLayout or a BoxLayout. As the panel.
Then I would suggest that for your expandable panel you use a BorderLayout. You add the part that is always visible to the CENTER and the expandable part to the PAGE_END. Then when you want to make the panel expand you just change the visibility of the component in the PAGE_END.
Then the layout managers will do all the work recalculating the proper size of the all the panels.

JScrollPane set vertical size to not resize when maximize window

I have a JPanel using GridBagLayout inside a JScrollPane. The GridBagLayout, has line split borders set between some columns (colored in blue). The issue is I can't get the behavior to act correctly, while removing the unnecessary right scroll bar from the JScrollPane.
The Code...
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestGui extends JFrame {
//**************************************************************************************
//************************************** Variables *************************************
//**************************************************************************************
private String[] showHideComboBoxValue = {"Show hiddenLabel", "Hide hiddenLabel"};
private JComboBox showHideComboBox = createShowHideComboBox(showHideComboBoxValue);
private JLabel labelHiddenOrShown = createDefaultLabel("This label is hidden or shown depending on the status of the combo box", 14);
private JPanel topFrame = createTopFrame();
private JScrollPane topFrameScroll = createTopScrollPane();
private JScrollPane centerFrameScroll = createCenterScrollPane();
//**************************************************************************************
//************************************* Constructor ************************************
//**************************************************************************************
private TestGui() {
add(topFrameScroll, BorderLayout.NORTH);
add(centerFrameScroll, BorderLayout.CENTER);
setSize(800,600);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//**************************************************************************************
//*********************************** Support Method ***********************************
//**************************************************************************************
private static GridBagConstraints setGbc(int gridx, int gridy, int gridWidth, int gridHeight, int ipadx, int ipady, String anchorLocation, double weightx, double weighty, Insets insets, boolean fillCell){
GridBagConstraints gbc = new GridBagConstraints();
if (anchorLocation.toUpperCase().equals("NORTHWEST")){
gbc.anchor = GridBagConstraints.NORTHWEST;
} else if (anchorLocation.toUpperCase().equals("NORTH")){
gbc.anchor = GridBagConstraints.NORTH;
} else if (anchorLocation.toUpperCase().equals("NORTHEAST")){
gbc.anchor = GridBagConstraints.NORTHEAST;
} else if (anchorLocation.toUpperCase().equals("WEST")){
gbc.anchor = GridBagConstraints.WEST;
} else if (anchorLocation.toUpperCase().equals("EAST")){
gbc.anchor = GridBagConstraints.EAST;
} else if (anchorLocation.toUpperCase().equals("SOUTHWEST")){
gbc.anchor = GridBagConstraints.SOUTHWEST;
} else if (anchorLocation.toUpperCase().equals("SOUTH")){
gbc.anchor = GridBagConstraints.SOUTH;
} else if (anchorLocation.toUpperCase().equals("SOUTHEAST")){
gbc.anchor = GridBagConstraints.SOUTHEAST;
} else {
gbc.anchor = GridBagConstraints.CENTER;
}
gbc.gridx = gridx; // column
gbc.gridy = gridy; // row
gbc.gridwidth = gridWidth; // number of columns
gbc.gridheight = gridHeight; // number of rows
gbc.ipadx = ipadx; // width of object
gbc.ipady = ipady; // height of object
gbc.weightx = weightx; // shifts columns to side of set anchor
gbc.weighty = weighty; // shifts rows to side of set anchor
gbc.insets = insets; // placement inside cell
if (fillCell){
gbc.fill = GridBagConstraints.BOTH;
}
return gbc;
}
//**************************************************************************************
//*********************************** Object Methods ***********************************
//**************************************************************************************
private JComboBox createShowHideComboBox(String[] comboValues){
JComboBox comboBox = new JComboBox(comboValues);
comboBox.setPrototypeDisplayValue("X" + comboValues[0] + "X");
return comboBox;
}
private void createShowHideComboBoxAction(){
showHideComboBox.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
String selection = ((JComboBox) (e.getSource())).getSelectedItem().toString();
if (selection.equals(showHideComboBoxValue[1])){
labelHiddenOrShown.setVisible(false);
} else {
labelHiddenOrShown.setVisible(true);
}
}
}
);
}
private JLabel createDefaultLabel(String text, int textSize){
JLabel lbl = new JLabel(text);
lbl.setFont(new Font(text, Font.BOLD, textSize));
return lbl;
}
//**************************************************************************************
//************************************ Panel Methods ***********************************
//**************************************************************************************
private JPanel createTopFrame() {
JPanel pnl = new JPanel();
Border lineSplitterBoarder = BorderFactory.createMatteBorder(0, 0, 0, 5, Color.BLUE);
JLabel lineSplitterOne = new JLabel();
lineSplitterOne.setBorder(lineSplitterBoarder);
JLabel lineSplitterTwo = new JLabel();
lineSplitterTwo.setBorder(lineSplitterBoarder);
pnl.setLayout(new GridBagLayout());
createShowHideComboBoxAction();
pnl.add(showHideComboBox,setGbc(0,1, 1,1, 0,0,"CENTER", 0, 0, new Insets(10, 10, 10, 0), false));
pnl.add(createDefaultLabel("Label",14), setGbc(1,0,1,1,0,0,"CENTER",0,0,new Insets(10,10,0,10),false));
pnl.add(createDefaultLabel("Label",14), setGbc(1,1,1,1,0,0,"CENTER",0,0,new Insets(0,10,0,10),false));
pnl.add(createDefaultLabel("Label",14), setGbc(1,2,1,1,0,0,"CENTER",0,0,new Insets(0,10,0,10),false));
pnl.add(createDefaultLabel("Label",14), setGbc(1,3,1,1,0,0,"CENTER",0,0,new Insets(0,10,10,10),false));
pnl.add(lineSplitterOne, setGbc(2,0,1,4,0,0,"CENTER",0,0,new Insets(0,0,0,0),true));
pnl.add(createDefaultLabel("Hidden Label Below", 14), setGbc(3,0,8,1,9,9,"CENTER",0,0,new Insets(10,10,0,10),false));
JPanel labelHiddenOrShownPanel = new JPanel();
labelHiddenOrShownPanel.setLayout(new GridLayout(1,1));
labelHiddenOrShownPanel.add(labelHiddenOrShown);
pnl.add(labelHiddenOrShownPanel, setGbc(3,1,1,1,0,0,"WEST",0,0,new Insets(0,5,0,0),false));
pnl.add(lineSplitterTwo, setGbc(11,0,1,4,0,0,"CENTER",0,0,new Insets(0,5,0,0),true));
pnl.add(createDefaultLabel("Label",14), setGbc(12,0,1,1,0,0,"CENTER",0,0,new Insets(10,10,0,0),false));
pnl.add(createDefaultLabel("Label",14), setGbc(12,1,1,1,0,0,"CENTER",0,0,new Insets(0,10,0,0),false));
pnl.add(createDefaultLabel("Label",14), setGbc(12,2,1,1,0,0,"CENTER",0,0,new Insets(0,10,0,0),false));
pnl.add(createDefaultLabel("Label",14), setGbc(12,3,1,1,0,0,"CENTER",0,0,new Insets(0,10,10,0),false));
return pnl;
}
private JScrollPane createTopScrollPane(){
JScrollPane scrollPane = new JScrollPane();
Border raisedBevel = BorderFactory.createRaisedBevelBorder();
Border lineBorder = BorderFactory.createMatteBorder(2, 2, 2, 2, new Color(224,224,224));
Border loweredBevel = BorderFactory.createLoweredBevelBorder();
Border compoundSetup = BorderFactory.createCompoundBorder(raisedBevel, lineBorder);
Border compoundFinal = BorderFactory.createCompoundBorder(compoundSetup, loweredBevel);
//scrollPane.setPreferredSize(new Dimension(0, 160));
scrollPane.setBorder(compoundFinal);
scrollPane.getViewport().setView(topFrame);
return scrollPane;
}
private JScrollPane createCenterScrollPane(){
JScrollPane scrollPane = new JScrollPane();
Border raisedBevel = BorderFactory.createRaisedBevelBorder();
Border lineBorder = BorderFactory.createMatteBorder(2, 2, 2, 2, new Color(224,224,224));
Border loweredBevel = BorderFactory.createLoweredBevelBorder();
Border compoundSetup = BorderFactory.createCompoundBorder(raisedBevel, lineBorder);
Border compoundFinal = BorderFactory.createCompoundBorder(compoundSetup, loweredBevel);
scrollPane.setBorder(compoundFinal);
return scrollPane;
}
//**************************************************************************************
//************************************ Start Program ***********************************
//**************************************************************************************
public static void main(String[] args) {
new TestGui();
}
}
Steps to reproduce issue(s)...
Step 1: run the program and observe the unnecessary scroll bar on the right of the top JScrollPane...
Step 2: maximize the window, and watch both scroll bars disappear with the objects in the JPanel being put where they should be...
This behavior is good and we want to keep this. You can close the program now.
Step 3: Now to remove the right scroll bar (in Step 1), lets change a line of code (line#145) from //scrollPane.setPreferredSize(new Dimension(0, 160)); to scrollPane.setPreferredSize(new Dimension(0, 160));, and re-run the program...
Great! the right bar was removed. But wait a minute...
Step 4: Now lets maximize the window...
Notice extra space added between the border lines (we don't want this behavior).
Note 1: It's important to keep the option to show/hide hidden label without resizing the cells in the GridBagLayout. After researching, the only way I found to do this was to have the hidden JLabel in it's own JPanel using GridLayout.
Note 2: I noticed this behavior (in Step 1) started happening after the width became long enough to require the horizontal scroll bar to start appearing.
What I need is the behavior from image 3 (when window is not maximized), and image 2 (when window is maximized). If anyone has any idea to get these 2 combinations of behaviors working together, please help. Thanks
Update: due to complaints of code being too large, I shortened it to 169 lines. Every component in this code is required to monitor the 2 behaviors as mentioned above.

Can not figure out a simple 4 box JPanel layout

I have been trying for hours to get JPanel in Java to contain these 4 other panels in this configuration (see picture)
The blue box should never change size.
The white box should never change height, can get wider though.
The dark grey box should never change widths, can get taller though.
The light grey box can get taller or wider.
Seems pretty simple to me, I did it in C# the other day and it was a breeze. Set the position, the width, height, and whether a certain side was anchored or not, boom done, I was starting to like java more than C until I ran into this.
I've tried countless combinations of GridBagLayout, multiple nested BoxLayout instances. They all seem to do very strange things, like make each panel a tiny 4 x 4 square, or there is crazy padding around them, or the ones that need to re-size with the window, don't.
Is there some kind of magic combination that can achieve this? Does the null layout do anchoring or percent dimensions.
The closest I've gotten is the bottom image with GridBagLayout, which looks good when it loads, but does that when you re-size the window.
Here is the code that got the above images
class MainPanel extends JPanel {
public MainPanel(){
this.setBackground(new Color(216,216,216));
this.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JPanel topTitle = new JPanel();
topTitle.setPreferredSize(new Dimension(140, 40));
topTitle.setMinimumSize(new Dimension(140, 40));
topTitle.setBackground(new Color(174, 216, 249));
c.weightx = 0.5;
c.gridx = 0;
c.gridy = 0;
this.add(topTitle,c);
JPanel mainHeader = new JPanel();
mainHeader.setPreferredSize(new Dimension(1060, 40));
mainHeader.setMinimumSize(new Dimension(1060, 40));
mainHeader.setBackground(Color.WHITE);
c.gridx = 1;
c.gridy = 0;
this.add(mainHeader,c);
JPanel sideNav = new JPanel();
sideNav.setPreferredSize(new Dimension(140, 760));
sideNav.setMinimumSize(new Dimension(140, 760));
sideNav.setBackground(new Color(110,110,110));
c.gridx = 0;
c.gridy = 1;
this.add(sideNav,c);
JPanel dataPanel = new JPanel();
dataPanel.setPreferredSize(new Dimension(1060, 760));
dataPanel.setMinimumSize(new Dimension(1060, 760));
dataPanel.setBackground(new Color(216,216,216));
c.gridx = 1;
c.gridy = 1;
this.add(dataPanel,c);
}
}
GUI at minimum size
GUI stretched wider & taller
It's all about getting appropriate resize weights & fill values..
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class FourPanelLayout {
private JComponent ui = null;
FourPanelLayout() {
initUI();
}
public void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridBagLayout());
// It appears you don't want space around the panels.
// If not, commment out or remove this line.
ui.setBorder(new EmptyBorder(4,4,4,4));
// create the panels, each with a transparent image to suggest a size
JPanel bluePanel = new JPanel();
bluePanel.setBackground(Color.CYAN);
bluePanel.add(new JLabel(new ImageIcon(getTransparentImage(40, 20))));
JPanel darkGrayPanel = new JPanel();
darkGrayPanel.setBackground(Color.DARK_GRAY);
darkGrayPanel.add(new JLabel(new ImageIcon(getTransparentImage(40, 20))));
JPanel whitePanel = new JPanel();
whitePanel.setBackground(Color.WHITE);
whitePanel.add(new JLabel(new ImageIcon(getTransparentImage(40, 20))));
JPanel grayPanel = new JPanel();
grayPanel.setBackground(Color.GRAY);
grayPanel.add(new JLabel(new ImageIcon(getTransparentImage(360, 80))));
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 0.0f;
gbc.weighty = 0.0f;
gbc.gridx = 0;
gbc.gridy = 0;
ui.add(bluePanel, gbc);
gbc.weightx = .5f;
gbc.gridx = 1;
ui.add(whitePanel, gbc);
gbc.weighty = .5f;
gbc.gridy = 1;
ui.add(grayPanel, gbc);
gbc.weightx = 0f;
gbc.gridx = 0;
//gbc.gridy
ui.add(darkGrayPanel, gbc);
}
/* We use transparent images to give panels a natural size. */
private Image getTransparentImage(int w, int h) {
return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
}
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) {
}
FourPanelLayout o = new FourPanelLayout();
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);
}
}
To implement this, I recommended to use FormLayout.
FormLayout is a powerful, flexible and precise general purpose layout manager. It places components in a grid of columns and rows, allowing specified components to span multiple columns or rows. Not all columns/rows necessarily have the same width/height.
Note: It good to use Windowbuilder in Eclipse or GUI Form in Intellij to automatically place and set the components properties.

Swing : BoxLayout fill the entire JPanel

I am adding list of JTree items inside JPanel. I want the parent JPanel to have BoxLayout so that the tree can be added vertically one after another.
The parent JPanel is initialized using :
holder.setLayout(new BoxLayout(holder, BoxLayout.Y_AXIS));
holder.setMaximumSize(new java.awt.Dimension(32767, 24000));
holder.setMinimumSize(new java.awt.Dimension(600, 100));
holder.setPreferredSize(new java.awt.Dimension(600, 100));
The multiple JTree components are added inside :
holder.add(tree);
So i expect the JTree nodes to be occupying the entire width of my parent JPanel but somehow it is coming like this
So as you can see it coming in some portion of the parent JPanel. I want it to fill the entire parent Panel(width wise) and be aligned towards left.
EDIT
After trying the top-aligned approach mentioned by VGR I got this :
So the tree are not occupying the entire space still. And when i expand any tree then everything disappears.
I should have also mentioned this earlier that when the initilization of the parent panel(holder) is done in some other code like this
holder.setMaximumSize(new java.awt.Dimension(32767, 24000));
holder.setMinimumSize(new java.awt.Dimension(600, 100));
holder.setPreferredSize(new java.awt.Dimension(600, 100));
holder.setLayout(new java.awt.GridLayout(1, 0));
add(holder); // add to the top parent
This part is not reachable :( for me. I can only re-change the parent holder as per my requirement.
SSCCE after suggested changes from VGR. This is not compilable but i hope SSC.
public BasePanel() extends JPanel{
private javax.swing.JPanel holder;
private GridBagConstraints gbc;
private JPanel treesPanel;
BasePanel(){
init();
}
public init(){ can't access this method
holder.setMaximumSize(new java.awt.Dimension(32767, 25000));
holder.setMinimumSize(new java.awt.Dimension(600, 0));
holder.setPreferredSize(new java.awt.Dimension(600, 0));
holder.setLayout(new java.awt.GridLayout(1, 0));
add(holder);
}
public initTreeComponents(){ // i need to call this for each tree
this.holder.setLayout(new BorderLayout());
treesPanel = new JPanel(new GridBagLayout());
this.holder.add(treesPanel, BorderLayout.PAGE_START);
gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.VERTICAL;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
}
public addTree(JTree tree){// to be called for each tree
treesPanel.add(tree,gbc);
}
I don't think BoxLayout makes child components fill the container. From the documentation:
… for a vertical layout, BoxLayout attempts to make all components in the column as wide as the widest component.
So your JTrees will all be the same width, but that doesn't guarantee they'll be as wide as the container.
Instead, I would use a GridBagLayout:
holder.setLayout(new GridBagLayout());
// etc.
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
holder.add(tree, gbc);
That will result in the JTrees being vertically centered. If you want them top-aligned, you should put a GridBagLayout panel inside another panel:
holder.setLayout(new BorderLayout());
JPanel treesPanel = new JPanel(new GridBagLayout());
holder.add(treesPanel, BorderLayout.PAGE_START);
// etc.
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
treesPanel.add(tree, gbc);
Try adding JTrees inside a JScrollPane, ie
holder.add(new JScrollPane(tree));

How to make Java Swing components fill available space?

I cannot seem to get my Java Swing components to work together correctly.
What I want to do, is have a JPanel fill ALL the space available inside a JTabbedPane. At the moment, my setup is as follows:
public class Gui extends JFrame {
private final EventBus eventBus = EventBus.getInstance();
private final ToolkitUtil toolkitUtil;
private final Menu menu;
private final InfoBar infoBar;
private final JTabbedPane pane;
...
private void buildLayout() {
GridBagConstraints gbc = new GridBagConstraints();
setJMenuBar(menu);
add(pane, BorderLayout.CENTER);
add(infoBar, BorderLayout.SOUTH);
pane.addTab("Plugins", new PluginPanel());
}
}
public class PluginPanel extends JPanel {
private final JPanel modelPanel;
private final JPanel editorPanel;
public PluginPanel() {
setLayout(new GridBagLayout());
modelPanel = new JPanel(new GridBagLayout());
editorPanel = new JPanel(new GridBagLayout());
buildLayout();
}
private void buildLayout() {
GridBagConstraints gbc = new GridBagConstraints();
modelPanel.setBorder(BorderFactory.createTitledBorder("Models"));
editorPanel.setBorder(BorderFactory.createTitledBorder("Editors"));
gbc.gridx = 0;
gbc.fill = GridBagConstraints.BOTH;
modelPanel.add(new JLabel("test label"), gbc);
add(modelPanel, gbc);
gbc.gridx = 1;
add(editorPanel, gbc);
}
}
This creates a windows that is my desired size (dynamically proportional to the screen size, not included in above code). The tab panel that is placed in the center is expanded to fill all the space required, which is exactly what I want. But, the panels I add inside the tab panel are only as big as their content. If I add labels or anything, it only grows as big as the components. I want them to always be expanded to fill the tab panel.
The easiest way is to use a BorderLayout and put the component in the CENTER position.
Try setting the weights of the GridBagConstraints to non-zero values:
gbc.weightx = gbc.weighty = 1.0;
Set MinimumSize of your container to preferred size you want, then set ContentPane of container with your panel.
setMinimumSize(new Dimension(width,height));
setContentPane(new MyPanel());
This code works for all layouts.
Or simply call for your container:
setContentPane(new MyPanel());
This code works for BorderLayout or Free Design

Categories