JScrollPane set vertical size to not resize when maximize window - java

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.

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.

JComboBox.setModel keep selection during action

I am going to have some behavior I want to be coupled with some other jcomboboxes, so I am using setModel() to fill in the arrays as values. While doing this and running the gui, I noticed after selecting a different element than the first one, that other element is not showing in the combo box. For example...
As you can see it doesn't say charTwo, even though that is what I selected. Here is the code.
Note: Line#101 is where the setModel() happens...
import org.apache.commons.lang3.ArrayUtils;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
public class TestGui extends JFrame {
private final String[] guiCharSelDefault = {"--- Select Character ---"};
private final String[] characters = {"charOne", "charTwo", "charThree", "charFour"};
private final String[] GuiCharSel = (String[]) ArrayUtils.addAll(guiCharSelDefault, characters);
private JComboBox charCombo = createStandardCombo(GuiCharSel);
private BackgroundPanel backgroundFrame = createBackgroundFrame("../images/Background.png");
private JPanel topFrame = createTopFrame();
private JScrollPane topFrameScroll = createTopScrollPane();
private JPanel centerFrame = createCenterFrame();
//**************************************************************************************
// Constructor
TestGui(){
setContentPane(backgroundFrame);
add(topFrameScroll, BorderLayout.NORTH);
add(centerFrame, BorderLayout.CENTER);
setSize(800,600);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//**************************************************************************************
// Support Methods
private static GridBagConstraints setGbc(int gridx, int gridy, int gridWidth, int gridHeight, int ipadx, int ipady, String anchorLocation, double weightx, double weighty, Insets insets){
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 rows to side of set anchor
gbc.weighty = weighty; // shifts columns to side of set anchor
gbc.insets = insets; // placement inside cell
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.fill = GridBagConstraints.VERTICAL;
return gbc;
}
private Insets setInsets(int top, int left, int bottom, int right){
Insets insets = new Insets(top,left,bottom,right);
return insets;
}
//**************************************************************************************
// Interactive Object Methods
private JComboBox createStandardCombo(String[] defaultValues){
JComboBox comboBox = new JComboBox(defaultValues);
DefaultListCellRenderer dlcr = new DefaultListCellRenderer();
dlcr.setHorizontalAlignment(DefaultListCellRenderer.CENTER);
comboBox.setRenderer(dlcr);
comboBox.setPrototypeDisplayValue("X" + guiCharSelDefault + "X");
return comboBox;
}
//**************************************************************************************
// Object Action Methods
private void setCharComboAction(){
charCombo.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
String charName = ((JComboBox)(e.getSource())).getSelectedItem().toString();
if (!(charName.equals(guiCharSelDefault[0]))){
charCombo.setModel(new DefaultComboBoxModel(characters));
}
}
}
);
}
//**************************************************************************************
// Panel Methods
private BackgroundPanel createBackgroundFrame(String imgLocName){
Image backgroundImg = null;
try {
backgroundImg = ImageIO.read(getClass().getResource(imgLocName));
System.out.println("File: " + imgLocName.toString());
} catch (Exception e) {
System.out.println("Cannot read file: " + e);
}
BackgroundPanel bgPanel = new BackgroundPanel(backgroundImg, BackgroundPanel.SCALED, 0.0f, 0.0f);
return bgPanel;
}
private JPanel createTopFrame(){
JPanel pnl = new JPanel();
pnl.setLayout(new GridBagLayout());
setCharComboAction();
pnl.add(charCombo, setGbc(0,0, 1,1, 0,0, "WEST", 0, 0, setInsets(0, 10, 0, 0)));
pnl.setOpaque(false);
return pnl;
}
private JScrollPane createTopScrollPane(){
JScrollPane scrollPane = new JScrollPane(backgroundFrame);
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);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
scrollPane.getViewport().setView(topFrame);
return scrollPane;
}
private JPanel createCenterFrame() {
JPanel pnl = new JPanel();
Border raisedBevel = BorderFactory.createRaisedBevelBorder();
Color lineColor = new Color(224, 224, 224);
Border lineBorder = BorderFactory.createMatteBorder(5, 5, 5, 5, lineColor);
Border loweredBevel = BorderFactory.createLoweredBevelBorder();
Border compoundSetup = BorderFactory.createCompoundBorder(raisedBevel, lineBorder);
Border compoundFinal = BorderFactory.createCompoundBorder(compoundSetup, loweredBevel);
TitledBorder topFrameTitle = BorderFactory.createTitledBorder(compoundFinal, "Stuff");
topFrameTitle.setTitleJustification(TitledBorder.CENTER);
pnl.setBorder(topFrameTitle);
pnl.setLayout(new GridBagLayout());
pnl.setOpaque(false);
return pnl;
}
//**************************************************************************************
public static void main(String[] args) {
new TestGui();
}
}
Is there a way I can have it keep the selected item after selecting it?
Why you don't restore the selection???
private void setCharComboAction(){
charCombo.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
String charName = ((JComboBox)(e.getSource())).getSelectedItem().toString();
if (!(charName.equals(guiCharSelDefault[0]))){
DefaultComboBoxModel model = new DefaultComboBoxModel(characters);
model.setSelectedItem(charName);
charCombo.setModel(model);
}
}
}
);
}

Java setBorder breaks component padding

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));

BoxLayout misunderstanding strut

I'm prgramming a simple input diagram in Swing. I use boxLayout to create a simple GUI of user input. Problem is that creating a horizontal strut between the JPanel of all the labels and the JPanel of the JTextFields causes the whole panel to shift downwards (weird) this is the whole panel:
private JPanel secondCard() {
//main panel. set the boxlayout
secondCard = new JPanel();
secondCard.setLayout(new BoxLayout(secondCard,BoxLayout.Y_AXIS));
// create vertical strut for looks
secondCard.add(Box.createVerticalStrut(20));
// create title. center it.
JLabel title = new JLabel("Configure main network parameters ");
title.setAlignmentX(CENTER_ALIGNMENT);
secondCard.add(title);
// create vertical strut for looks
secondCard.add(Box.createVerticalStrut(20));
// create panel for the description labels
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new BoxLayout(labelPanel,BoxLayout.Y_AXIS));
labelPanel.setAlignmentX(LEFT_ALIGNMENT);
JLabel inPut =new JLabel("number of inputs");
inPut.setAlignmentX(LEFT_ALIGNMENT);
labelPanel.add(inPut);
inPut =new JLabel("number of outputs");
inPut.setAlignmentX(LEFT_ALIGNMENT);
labelPanel.add(inPut);
inPut =new JLabel("number of layers");
inPut.setAlignmentX(LEFT_ALIGNMENT);
labelPanel.add(inPut);
JPanel textFieldPanel = new JPanel();
textFieldPanel.setLayout(new BoxLayout(textFieldPanel,BoxLayout.Y_AXIS));
textFieldPanel.setAlignmentX(LEFT_ALIGNMENT);
JTextField inputTextField = new JTextField();
inputTextField.setAlignmentX(LEFT_ALIGNMENT);
textFieldPanel.add(inputTextField);
inputTextField.setMinimumSize(new Dimension(0,0));
inputTextField = new JTextField();
inputTextField.setAlignmentX(LEFT_ALIGNMENT);
textFieldPanel.add(inputTextField);
inputTextField.setMinimumSize(new Dimension(0,0));
inputTextField = new JTextField();
inputTextField.setAlignmentX(LEFT_ALIGNMENT);
textFieldPanel.add(inputTextField);
inputTextField.setMinimumSize(new Dimension(0,0));
textFieldPanel.setMaximumSize(new Dimension(50, labelPanel.getMaximumSize().height));
JPanel inputPanel = new JPanel();
inputPanel.setLayout(new BoxLayout(inputPanel,BoxLayout.X_AXIS));
inputPanel.setAlignmentX(CENTER_ALIGNMENT);
inputPanel.add(labelPanel);
//this is the problem strut!! it causes inputPanel to shift downwards
inputPanel.add(Box.createHorizontalStrut(20));
inputPanel.add(textFieldPanel);
secondCard.add(inputPanel);
return secondCard;
}
without the strut it looks like:
With strut it looks like (I know I suck at picture editing):
You are adding a Box strut to a BoxLayout.
As the javadoc states, createHorizontalStrut(int width):
Creates an invisible, fixed-width component. In a horizontal box, you
typically use this method to force a certain amount of space between
two components. In a vertical box, you might use this method to force
the box to be at least the specified width. The invisible component
has no height unless excess space is available, in which case it takes
its share of available space, just like any other component that has
no maximum height.
As such, it is filling the height between your title JLabel and the bottom of the JPanel.
You might want to consider using Box.createRigidArea(new Dimension(20, height)) instead, where height could be specified or set to the height of labelPanel.
Or, you could reconsider the layout for your JPanel - take a look at the visual guide.
For future reference, if you cannot make sense of your Swing layout, try putting adding a coloured LineBorder to the JComponents you're unsure of. In this case, the Box struts are not JComponents but Components, so you'd have to put them into a JPanel, but this would at least have shown you what space each component was taking up in your top-level JPanel.
use Cardlayout for wizard logics
put JLabel(Configure ...., JLabel.CENTER) to the BorderLayout.NORTH
put JPanel with JButtons to the BorderLayout.SOUTH
put JPanel with SpringLayout, GridLayout, or GridBagLayout to the BorderLayout.CENTER
Top-Level Container have got implemened BorderLayout by default, then there no reason to re_define BorderLayout
above mentioned steps are called NestedLayout
alternative are put all JComponents by using GridBagLayout, SpringLayout or todays MigLayout to the one JPanel, but why bothering
Example of a nested layout, one using BorderLayout, FlowLayout (JPanel's default), and GridBagLayout:
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
public class LayoutFoo {
private static final String TITLE = "Configure Main Foobar Parameters";
private static final String[] LABEL_TEXTS = {
"Number of Spams", "Number of Frapzats", "Number of Zignuts"
};
private static final int TEXTFIELD_SIZE = 10;
private static final Insets WEST_INSETS = new Insets(5, 5, 5, 10);
private static final Insets EAST_INSETS = new Insets(5, 10, 5, 5);
private static final int EB_GAP = 5;
private Map<String, JTextField> textFieldMap = new HashMap<String, JTextField>();
public JPanel getConfigFooPanel() {
JPanel textFieldPanel = new JPanel(new GridBagLayout());
for (int i = 0; i < LABEL_TEXTS.length; i++) {
addTextAndField(textFieldPanel, LABEL_TEXTS[i], i);
}
int blVertGap = 20;
JPanel borderLayoutPanel = new JPanel(new BorderLayout(0, blVertGap));
borderLayoutPanel.setBorder(BorderFactory.createEmptyBorder(EB_GAP, EB_GAP,
EB_GAP, EB_GAP));
JLabel titleLabel = new JLabel(TITLE, JLabel.CENTER);
borderLayoutPanel.add(titleLabel, BorderLayout.PAGE_START);
borderLayoutPanel.add(textFieldPanel, BorderLayout.CENTER);
JPanel outerWrapperFlowPanel = new JPanel();
outerWrapperFlowPanel.add(borderLayoutPanel);
return outerWrapperFlowPanel;
}
public String getFieldText(String labelText) {
JTextField field = textFieldMap.get(labelText);
if (field == null) {
return ""; // ?? throw exception
} else {
return field.getText();
}
}
private void addTextAndField(JPanel panel, String text, int i) {
JLabel label = new JLabel(text, JLabel.LEFT);
JTextField textField = new JTextField(TEXTFIELD_SIZE);
textFieldMap.put(text, textField);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = i;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = WEST_INSETS;
panel.add(label, gbc);
gbc.gridx = 1;
gbc.anchor = GridBagConstraints.EAST;
gbc.insets = EAST_INSETS;
panel.add(textField, gbc);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("LayoutFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new LayoutFoo().getConfigFooPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Java Swing - JLabel width changed when icon or text added?

Same Question, different context
It seems I was too hasty in my accepting before, since the problem is still there. The problem? JLabel takes the liberty of expanding its parent panel when content is added to it.
It's time for reproducing it per "Hovercraft full of eels"-ses suggestion, and here it is:
import java.awt.*;
import javax.swing.*;
public class TestLabel {
public static void main(String[] args) {
// Var inits
JFrame frame;
JPanel panel;
JLabel label;
Container pane;
GridBagConstraints gbc = new GridBagConstraints();
// Frame, content pane, layout inits
frame = new JFrame("Label Tester");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pane = frame.getContentPane();
pane.setLayout(new GridBagLayout());
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
// Add panels (note gbc weighty and fill carries over all instances)
gbc.weightx = 0.3;
gbc.gridx = 0;
gbc.gridy = 0;
panel = new JPanel();
panel.setBackground(Color.GREEN);
frame.add(panel,gbc);
label = new JLabel("THE PANEL IS NOW DISTORTED TO FIT THIS LABEL WHY IS THIS HAPPENING");
//label = new JLabel("");
label.setOpaque(true);
label.setBackground(Color.WHITE);
panel.add(label);
gbc.weightx = 0.7;
gbc.gridx = 1;
gbc.gridy = 0;
panel = new JPanel();
panel.setBackground(Color.RED);
frame.add(panel,gbc);
gbc.weightx = 0.3;
gbc.gridx = 0;
gbc.gridy = 1;
panel = new JPanel();
panel.setBackground(Color.BLUE);
frame.add(panel,gbc);
gbc.weightx = 0.7;
gbc.gridx = 1;
gbc.gridy = 1;
panel = new JPanel();
panel.setBackground(Color.YELLOW);
frame.add(panel,gbc);
frame.pack();
frame.setSize(800,600);
frame.setVisible(true);
}
}
Results:
As you can see, the green panel is forced wider and throws off my whole layout when text (or, in the original question, and icon) is added to it. I want my layout to remain the same weights, regardless of the content. The reason this came up is because I'm trying to add a scaled image as an icon to the label, as seen in the original question.
Incidentally, setPreferredSize() doesn't seem to work.
Is there a way to fix this?
Original Question
My JLabel element expands dramatically when I add an Icon to it. Why is this happening? Here's the applicable portion of the code:
// Show label and BG color
redLabel.setBackground(Color.RED);
redLabel.setOpaque(true);
// Grab stretched image (already loaded elsewhere in the code) and turn to icon
Img = Img.getScaledInstance(redLabel.getWidth(),12,Image.SCALE_REPLICATE);
ImageIcon icon = new ImageIcon(Img);
// This line throws everything off!
//It's commented out in the first pic, and included in the second.
redLabel.setIcon(icon);
As you can see from the first pic, I've got a label (in red) of width W. What I'm trying to do is stretch my icon to width W and put it in the label.
When I do this, the label expands (by exactly 50 pixels, I think) and also squeezes over the left edge (green). Does anyone have any idea why this is happening?
I've tried several things that are too verbose to explain but can't find the problem :-/
Your component expands because it allocates the necessary space for its Icon.
public class JLabelDemo {
private static BufferedImage bi;
public static void main(String[] args) throws IOException{
loadImage();
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
createAndShowGUI();
}
});
}
private static void loadImage() throws IOException{
bi = ImageIO.read(JLabelDemo.class.getResource("../resource/forever-alone.jpg"));
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel();
panel.setBackground(Color.YELLOW);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
final JLabel emptyLabel = new JLabel();
final JLabel textLabel = new JLabel("This label has text only");
final JLabel textAndImageLabel = new JLabel("This label has text and image");
textAndImageLabel.setIcon(new ImageIcon(bi));
panel.add(emptyLabel);
panel.add(textLabel);
panel.add(textAndImageLabel);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
System.out.println("Empty label dimensions - " + emptyLabel.getSize());
System.out.println("Text only label dimensions - " + textLabel.getSize());
System.out.println("Image width: " + bi.getWidth() + ", Image height: " + bi.getHeight());
System.out.println("Text and image label dimensions - " +textAndImageLabel.getSize());
}
}
The following is outputted to console:
Empty label dimensions - java.awt.Dimension[width=0,height=0]
Text only label dimensions - java.awt.Dimension[width=129,height=16]
Image width: 194, Image height: 180
Text and image label dimensions - java.awt.Dimension[width=363,height=180]
Consider using a JLayeredPane to add components in layers. There are trips and traps though when doing this in matters of opacity, size and position of components added.
For example,
import java.awt.*;
import javax.swing.*;
public class TestLabel {
private static final Dimension SIZE = new Dimension(800, 600);
public static void main(String[] args) {
GridBagConstraints gbc = new GridBagConstraints();
JPanel defaultPane = new JPanel();
defaultPane.setLayout(new GridBagLayout());
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
// Add panels (note gbc weighty and fill carries over all instances)
gbc.weightx = 0.3;
gbc.gridx = 0;
gbc.gridy = 0;
JPanel panel = new JPanel();
panel.setBackground(Color.GREEN);
defaultPane.add(panel, gbc);
gbc.weightx = 0.7;
gbc.gridx = 1;
gbc.gridy = 0;
panel = new JPanel();
panel.setBackground(Color.RED);
defaultPane.add(panel, gbc);
gbc.weightx = 0.3;
gbc.gridx = 0;
gbc.gridy = 1;
panel = new JPanel();
panel.setBackground(Color.BLUE);
defaultPane.add(panel, gbc);
gbc.weightx = 0.7;
gbc.gridx = 1;
gbc.gridy = 1;
panel = new JPanel();
panel.setBackground(Color.YELLOW);
defaultPane.add(panel, gbc);
defaultPane.setSize(SIZE);
JLabel label = new JLabel("THE PANEL IS NOW DISTORTED TO FIT THIS LABEL WHY IS THIS HAPPENING");
label.setOpaque(true);
label.setBackground(Color.WHITE);
JPanel northPalettePanel = new JPanel();
northPalettePanel.setOpaque(false);
northPalettePanel.add(label);
JPanel palettePanel = new JPanel(new BorderLayout());
palettePanel.setOpaque(false);
palettePanel.setSize(SIZE);
palettePanel.setLocation(0, 0);
palettePanel.add(northPalettePanel, BorderLayout.NORTH);
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(SIZE);
layeredPane.add(defaultPane, JLayeredPane.DEFAULT_LAYER);
layeredPane.add(palettePanel, JLayeredPane.PALETTE_LAYER);
JFrame frame = new JFrame("Label Tester");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(layeredPane, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
Java swing is pretty old for me but if I remember well, setting a preferred size (setPreferredSize()) sometime solve these kind of problem ... Also try top lay with setMaximumSize and setMinimumSize.
You can maybe find more information in java documentation:
http://download.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment
Regards!

Categories