I have a problem with my GUI in that when I press a toggle button belonging to a certain panel, the panels buttons changes size and labels change positions. I've attached some screenshots to show the error in action. I believe its because the buttons are sharing the same panel but I'm unsure whether its fixable so that the buttons size remains static, as do the labels positions.
My code is below (sorry that its quite messy!. I have alot of nested BorderLayout JPanels and this could be where the problem is, but for me it was the easiest way to get the correct layout.
package v2;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
public class BmrCalcv2 extends JFrame {
// Frames and main panels
static JFrame mainFrame;
static JPanel mainPanel;
static JPanel combinedGAHWpanel; // combines genderPanel, agePanel, heightPanel, weightPanel - this
// is a BorderLayout, whereas
// gender/agePanel are FlowLayouts.
static JPanel weightHeightPanel; // Combines weight and height panel into out flowlayout panel, which is then combined into the above borderlayout panel
// Image components
static JPanel imgPanel;
private JLabel imgLabel;
// Menu-bar components
static JMenuBar menuBar;
static JMenu saveMenu, optionMenu, helpMenu;
// Age components
static JPanel agePanel;
private JLabel ageLabel;
private JLabel yearsLabel;
private JTextField ageTextField;
// Gender components
static JPanel genderPanel;
private JLabel genderLabel;
private JRadioButton genderMale;
private JRadioButton genderFemale;
// Height components
static JPanel heightPanel;
private JLabel heightLabel;
private JTextField heightCMField;
private JLabel heightFTLabel;
private JLabel heightINCHLabel;
private JTextField heightFTField;
private JTextField heightINCHField;
private JToggleButton cmButton;
private JToggleButton feetButton;
// Weight components
static JPanel weightPanel;
private JLabel weightLabel;
private JTextField weightField;
private JToggleButton kgButton;
private JToggleButton lbButton;
// TDEE and BMR Components
static JPanel tdeePanel;
static JPanel tdeeBMRPanel;
static JPanel activityLevelPanel;
static JPanel bmrTDEEValuesPanel;
static JPanel bmrValuePanel;
static JPanel tdeeValuePanel;
private JLabel tdeeQuestionLabel;
private JLabel activityLevelLabel;
private JComboBox activityLevelBox;
private JRadioButton tdeeYes;
private JRadioButton tdeeNo;
private JLabel bmrLabel;
private JLabel tdeeLabel;
// Default values for gender/weight/height
String[] activityLevels = {"Sedentary", "Lightly Active", "Moderately Active", "Very Active", "Extra Active"};
String genderSelection = "M";
String weightSelection = "kg";
String heightSelection = "cm";
String tdeeSelection = "no";
public BmrCalcv2(String title) {
// Main JFrame
setTitle("BMR/TDEE Calculator");
mainPanel = new JPanel();
// All JPanel declarations
menuBar = new JMenuBar();
imgPanel = new JPanel();
agePanel = new JPanel();
genderPanel = new JPanel();
heightPanel = new JPanel();
weightPanel = new JPanel();
weightHeightPanel = new JPanel(new BorderLayout());
combinedGAHWpanel = new JPanel(new BorderLayout()); // Create a new panel used to combine
// genderPanel, agePanel, weightPanel, heightPanel below
tdeeBMRPanel = new JPanel(new BorderLayout());
tdeePanel = new JPanel();
activityLevelPanel = new JPanel();
bmrTDEEValuesPanel = new JPanel(new BorderLayout());
bmrValuePanel = new JPanel();
tdeeValuePanel = new JPanel();
// Image panel declaration
imgLabel = new JLabel(new ImageIcon("filesrc//mainlogo.png"));
imgPanel.add(imgLabel);
// JPanel layout managers
agePanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
genderPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
// Menu JComponents
saveMenu = new JMenu("Save");
optionMenu = new JMenu("Options");
helpMenu = new JMenu("Help");
menuBar.add(saveMenu);
menuBar.add(optionMenu);
menuBar.add(helpMenu);
// Age JComponents
ageLabel = new JLabel("Age:");
yearsLabel = new JLabel("<html><i>years</i><html>");
ageTextField = new JTextField(5);
agePanel.add(ageLabel);
agePanel.add(ageTextField);
agePanel.add(yearsLabel);
// Gender JComponents
genderLabel = new JLabel("Gender:");
genderMale = new JRadioButton("Male", true);
genderFemale = new JRadioButton("Female");
genderPanel.add(genderLabel);
genderPanel.add(genderMale);
genderPanel.add(genderFemale);
ButtonGroup genderGroup = new ButtonGroup(); // groups male and female radio buttons together so that only one can be selected
genderGroup.add(genderMale);
genderGroup.add(genderFemale);
genderMale.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String genderSelection = "M";
}
});
genderFemale.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String genderSelection = "F";
}
});
// Height JComponents
heightLabel = new JLabel("Height:");
heightCMField = new JTextField(4);
heightFTField = new JTextField(3);
heightFTLabel = new JLabel("ft");
heightINCHLabel = new JLabel("inch");
heightINCHField = new JTextField(3);
cmButton = new JToggleButton("cm", true);
feetButton = new JToggleButton("feet");
heightPanel.add(heightLabel);
ButtonGroup heightGroup = new ButtonGroup();
heightGroup.add(cmButton);
heightGroup.add(feetButton);
heightPanel.add(heightCMField);
cmButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
heightSelection = "cm";
heightPanel.remove(heightCMField);
heightPanel.remove(cmButton);
heightPanel.remove(feetButton);
heightPanel.remove(heightFTField);
heightPanel.remove(heightFTLabel);
heightPanel.remove(heightINCHField);
heightPanel.remove(heightINCHLabel);
heightPanel.add(heightCMField);
heightPanel.add(cmButton);
heightPanel.add(feetButton);
weightHeightPanel.add(heightPanel, BorderLayout.CENTER);
combinedGAHWpanel.add(weightHeightPanel, BorderLayout.SOUTH);
mainPanel.add(combinedGAHWpanel);
add(mainPanel);
setVisible(true);
}
});
feetButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
heightSelection = "feet";
heightPanel.remove(heightCMField);
heightPanel.remove(cmButton);
heightPanel.remove(feetButton);
heightPanel.add(heightFTField);
heightPanel.add(heightFTLabel);
heightPanel.add(heightINCHField);
heightPanel.add(heightINCHLabel);
heightPanel.add(cmButton);
heightPanel.add(feetButton);
weightHeightPanel.add(heightPanel, BorderLayout.CENTER);
combinedGAHWpanel.add(weightHeightPanel, BorderLayout.SOUTH);
mainPanel.add(combinedGAHWpanel);
add(mainPanel);
setVisible(true);
}
});
heightPanel.add(cmButton);
heightPanel.add(feetButton);
// Weight JComponents
weightLabel = new JLabel("Weight:");
weightField = new JTextField(4);
kgButton = new JToggleButton("kg", true);
lbButton = new JToggleButton("lbs");
weightPanel.add(weightLabel);
weightPanel.add(weightField);
weightPanel.add(kgButton);
weightPanel.add(lbButton);
ButtonGroup weightGroup = new ButtonGroup();
weightGroup.add(kgButton);
weightGroup.add(lbButton);
kgButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
weightSelection = "kg";
}
});
lbButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
weightSelection = "lb";
}
});
// tdee JComponents
tdeeQuestionLabel = new JLabel("Calculate TDEE Also?");
tdeeYes = new JRadioButton("Yes");
tdeeNo = new JRadioButton("No", true);
ButtonGroup tdeeButton = new ButtonGroup();
tdeeButton.add(tdeeYes);
tdeeButton.add(tdeeNo);
tdeePanel.add(tdeeQuestionLabel);
tdeePanel.add(tdeeYes);
tdeePanel.add(tdeeNo);
// activitylevel JComponents
activityLevelLabel = new JLabel("Activity Level: ");
activityLevelBox = new JComboBox(activityLevels);
activityLevelBox.setSelectedIndex(0);
activityLevelPanel.add(activityLevelLabel);
activityLevelPanel.add(activityLevelBox);
activityLevelBox.setEnabled(false);
tdeeYes.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
tdeeSelection = "yes";
activityLevelBox.setEnabled(true);
}
});
tdeeNo.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
tdeeSelection = "no";
activityLevelBox.setEnabled(false);
}
});
// tdee and BMR value components
bmrLabel = new JLabel("BMR: ");
tdeeLabel = new JLabel("TDEE: ");
bmrLabel.setFont(new Font("Monotype Corsiva",1,20));
tdeeLabel.setFont(new Font("Monotype Corsiva",1,20));
bmrTDEEValuesPanel.add(new JButton("Calculate"), BorderLayout.NORTH);
bmrTDEEValuesPanel.add(bmrLabel, BorderLayout.CENTER);
bmrTDEEValuesPanel.add(tdeeLabel, BorderLayout.SOUTH);
// Adding sub JPanels to main JPanel
mainPanel.add(imgPanel);
combinedGAHWpanel.add(agePanel, BorderLayout.NORTH); // Combine genderPanel and agePanel (which are both flowLayouts) into a
// single BorderLayout panel where agePanel is given the Northern spot and
// genderPanel is given the center spot in the panel
weightHeightPanel.add(weightPanel, BorderLayout.NORTH); // Nested borderlayouts, the weightHeightPanel is another borderLayout which is nested
// into the southern position of the combinedGAHW border layout.
weightHeightPanel.add(heightPanel, BorderLayout.CENTER);
weightHeightPanel.add(tdeeBMRPanel, BorderLayout.SOUTH);
combinedGAHWpanel.add(genderPanel, BorderLayout.CENTER);
combinedGAHWpanel.add(weightHeightPanel, BorderLayout.SOUTH);
mainPanel.add(combinedGAHWpanel);
// adding to tdeeBMRPanel
tdeeBMRPanel.add(tdeePanel, BorderLayout.NORTH);
tdeeBMRPanel.add(activityLevelPanel, BorderLayout.CENTER);
tdeeBMRPanel.add(bmrTDEEValuesPanel, BorderLayout.SOUTH);
// Adding main JPanel and menubar to JFrame
setJMenuBar(menuBar);
add(mainPanel);
}
public static void main(String[] args) {
BmrCalcv2 gui = new BmrCalcv2("BMR/TDEE Calculator");
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setVisible(true);
gui.setSize(330, 500);
gui.setResizable(false);
}
}
This is combination of changes you are making to the UI (adding/removing labels/fields) and the compound use of a
BorderLayout
.You actually don't need to change the label/field when you toggle between "feet" and "CM", as this all the information that the user needs is already available to them (in the form of the buttons).
I'd get rid of the
heightFTField
,heightINCHField
and make this a single field, using theJToggleButton
'sselected
state to determine how you should calculate the values. I'd also get rid of theheightFTLabel
,heightINCHLabel
labels, they are adding little value to the UI that the toggle buttons are already doing.Now, having done, you can get rid of the
cmButton
andfeetButton
'sActionListener
s, as they provide no useful operations.In future, you may find changing component's visibility state easier.
Based on comments, a basic example
This demonstrates the use of a single field,
ButtonGroup
to manage the selection of theJToggleButton
s andJToggleButton#isSelected
to control the logic path