I made a new class that extended JFrame and new class that extended JPanel to make the swing GUI. It is great, I like this due to its ease of readability.
However, when it comes to event handling things started getting complex. What I did really doesn't really seem like a solution; just like breaking good habit to make something work. How do I make this work properly?
This is my JFrame class
public class MainFrame extends JFrame{
private JTextArea textArea;
public MainFrame(String title){
super(title);
//set layout
setLayout(new BorderLayout());
//create components
JButton buttonOne = new JButton("click me");
textArea = new JTextArea();
JPanel detailedPanel = new leftPanel();
//add to panel
Container c = getContentPane();
c.add(buttonOne, BorderLayout.SOUTH);
c.add(textArea, BorderLayout.CENTER);
c.add(detailedPanel, BorderLayout.WEST);
//Event Listening
leftPanel.buttonAdd.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
textArea.setText(textArea.getText() + " " + leftPanel.fieldName.getText() + " : " + leftPanel.fieldOccupation.getText());
}
});
}
}
this is my JPanel
public class leftPanel extends JPanel {
public static JTextField fieldName;
public static JTextField fieldOccupation;
public static JButton buttonAdd;
public leftPanel(){
Dimension panelSize = getPreferredSize();
panelSize.width = 250;
setPreferredSize(panelSize);
setBorder(BorderFactory.createTitledBorder("Personal Info"));
//labels
JLabel labelName = new JLabel("name: ");
JLabel labelOccupation = new JLabel("Occupation: ");
//textFields
fieldName = new JTextField(10);
fieldOccupation = new JTextField(10);
//buttons
buttonAdd = new JButton("Add !");
//actions
buttonAdd.addActionListener(new ActionListener(){
//on click
public void actionPerformed(ActionEvent e) {
String name = fieldName.getText();
String occupation = fieldOccupation.getText();
System.out.print(name + ": " + occupation);
}
});
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
//// First Y add //////////////////////////////////////
//label NAME
gbc.anchor = GridBagConstraints.FIRST_LINE_END;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.gridx = 0;
gbc.gridy = 0;
add(labelName, gbc);
//label Occupation
gbc.anchor = GridBagConstraints.FIRST_LINE_END;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.gridx = 0;
gbc.gridy = 1;
add(labelOccupation, gbc);
//// SECOND Y add /////////////////////////////////////
//text field name
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.weightx = 2;
gbc.weighty = 1;
gbc.gridx = 1;
gbc.gridy = 0;
add(fieldName, gbc);
//text feld occupation
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.weightx = 2;
gbc.weighty = 1;
gbc.gridx = 1;
gbc.gridy = 1;
add(fieldOccupation, gbc);
//// THIRD Y add //////////////////////////////////////
//add button
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.gridx = 1;
gbc.gridy = 3;
gbc.weightx = 1;
gbc.weighty = 10;
add(buttonAdd, gbc);
}
}
For the most part, you component should be as self contained as possible, this would suggest that the component should be responsible for handling the events generated by it's immediate children.
This doesn't mean that the component won't then generate it's own events, but that the component manages it's immediate children itself.
You should try and avoid exposing your child components directly (using public fields or getters) or indirectly (through event objects), this invites possible misuse of those components by external sources, which is never going to be pleasant.
In your example, your first class only wants to known when something happens that would require it to update the text area.
This would suggest that the LeftPanel needs to generate some kind of event (maybe a ActionEvent) and provide a getter for anybody who might be interested to gain access to the information that the LeftPanel is managing.
For example...
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class LeftPanel extends JPanel {
private JTextField fieldName;
private JTextField fieldOccupation;
private JButton buttonAdd;
public LeftPanel() {
setBorder(BorderFactory.createTitledBorder("Personal Info"));
//labels
JLabel labelName = new JLabel("name: ");
JLabel labelOccupation = new JLabel("Occupation: ");
//textFields
fieldName = new JTextField(10);
fieldOccupation = new JTextField(10);
//buttons
buttonAdd = new JButton("Add !");
//actions
buttonAdd.addActionListener(new ActionListener() {
//on click
public void actionPerformed(ActionEvent e) {
fireActionPerformed();
}
});
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
//// First Y add //////////////////////////////////////
//label NAME
gbc.anchor = GridBagConstraints.FIRST_LINE_END;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.gridx = 0;
gbc.gridy = 0;
add(labelName, gbc);
//label Occupation
gbc.anchor = GridBagConstraints.FIRST_LINE_END;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.gridx = 0;
gbc.gridy = 1;
add(labelOccupation, gbc);
//// SECOND Y add /////////////////////////////////////
//text field name
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.weightx = 2;
gbc.weighty = 1;
gbc.gridx = 1;
gbc.gridy = 0;
add(fieldName, gbc);
//text feld occupation
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.weightx = 2;
gbc.weighty = 1;
gbc.gridx = 1;
gbc.gridy = 1;
add(fieldOccupation, gbc);
//// THIRD Y add //////////////////////////////////////
//add button
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.gridx = 1;
gbc.gridy = 3;
gbc.weightx = 1;
gbc.weighty = 10;
add(buttonAdd, gbc);
}
public void addActionListener(ActionListener listener) {
listenerList.add(ActionListener.class, listener);
}
public void removeActionListener(ActionListener listener) {
listenerList.remove(ActionListener.class, listener);
}
protected void fireActionPerformed() {
ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
if (listeners.length > 0) {
ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "PropertiesSet");
for (ActionListener listener : listeners) {
listener.actionPerformed(evt);
}
}
}
public String getPersonName() {
return fieldName.getText();
}
public String getPersonOccupation() {
return fieldOccupation.getText();
}
}
The LeftPanel here now manages the internal state of it's components (no static or public fields). It also provides a ActionListener support to provide notification to interested parties who can obtain the information the component is managing via getters
The MainFrame then simply uses an instance of LeftPanel and registers a ActionListener to it so it can be notified when the panel has been updated and uses the getters to obtain the information it's interested in.
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
public class MainFrame extends JFrame {
private JTextArea textArea;
public MainFrame(String title) {
super(title);
//set layout
setLayout(new BorderLayout());
//create components
JButton buttonOne = new JButton("click me");
textArea = new JTextArea();
LeftPanel detailedPanel = new LeftPanel();
//add to panel
Container c = getContentPane();
c.add(buttonOne, BorderLayout.SOUTH);
c.add(textArea, BorderLayout.CENTER);
c.add(detailedPanel, BorderLayout.WEST);
//Event Listening
detailedPanel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.append(textArea.getText() + " " + detailedPanel.getPersonName() + " : " + detailedPanel.getPersonOccupation() + "\n");
}
});
}
}
In OO, you want to encapsulate the logic and responsibility to the object and then, as required, from callbacks (such as a Observer Pattern) to provide notification to interested parties that some predefined state has changed. Then simply expose the information that the object is managing via getters (and where required, setters for others to change the information as required)
Related
I'd like to decorate a JPanel with a JLayer, but am failing to understand why doing so messes up this panel being laid out inside a JScrollPane. The decorated component is supposed to act as a drop in replacement, but it does not appear to work in this case.
The following code creates two equivalent JPanels and puts them into another panel with CardLayout (so you may switch between them using the buttons). The only difference is that in one case the panel is decorated with a JLayer.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
public class JLayerScroll extends JFrame {
public JLayerScroll() {
setTitle("Jumpy border");
setLayout(new BorderLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
createGui();
setSize(400, 200);
setLocationRelativeTo(null);
}
private void createGui() {
JPanel mainPanel = new JPanel(new CardLayout());
// two panels ("label panels"), first one decorated, second one not
mainPanel.add(createSingleScrolledComponent(new JLayer<JPanel>(createLabelPanel(), new LayerUI<JPanel>())), WITH_JLAYER);
mainPanel.add(createSingleScrolledComponent(createLabelPanel()), WITHOUT_JLAYER);
add(mainPanel);
createButtons(mainPanel);
}
private JPanel createSingleScrolledComponent(Component component) {
GridBagConstraints gbc;
JScrollPane scroll;
JPanel panel = new JPanel(new GridBagLayout());
scroll = new JScrollPane(component);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0d;
gbc.weighty = 1.0d;
panel.add(scroll, gbc);
return panel;
}
private JPanel createLabelPanel() {
GridBagConstraints gbc;
JPanel panel = new JPanel(new GridBagLayout());
JPanel entry = new JPanel(new GridBagLayout());
entry.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.red));
JLabel label = new JLabel("Some input:");
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
entry.add(label, gbc);
JTextField field = new JTextField(20);
field.setMinimumSize(new Dimension(field.getPreferredSize().width, field.getMinimumSize().height));
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
entry.add(field, gbc);
gbc = new GridBagConstraints();
gbc.gridx = 2;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0d;
entry.add(Box.createHorizontalGlue(), gbc);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0d;
panel.add(entry, gbc);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.VERTICAL;
gbc.weighty = 1.0d;
panel.add(Box.createVerticalGlue(), gbc);
return panel;
}
private static final String WITH_JLAYER = "with-jlayer";
private static final String WITHOUT_JLAYER = "no-jlayer";
private void createButtons(final JPanel mainPanel) {
GridBagConstraints gbc;
JButton button;
JPanel actionsPanel = new JPanel(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0d;
actionsPanel.add(Box.createHorizontalGlue(), gbc);
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
button = new JButton("With JLayer");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
CardLayout layout = (CardLayout) mainPanel.getLayout();
layout.show(mainPanel, WITH_JLAYER);
}
});
actionsPanel.add(button, gbc);
gbc.gridx = 2;
gbc.gridy = 0;
button = new JButton("Without JLayer");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
CardLayout layout = (CardLayout) mainPanel.getLayout();
layout.show(mainPanel, WITHOUT_JLAYER);
}
});
actionsPanel.add(button, gbc);
add(actionsPanel, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JLayerScroll().setVisible(true);
}
});
}
}
If you pay attention to the red border in the two cases, you will notice that in one case it spans the whole available horizontal space (as expected), while in the other case, it only spans around visible components (label and text field).
Why is this happening and how do I achieve the same behavior as in the undecorated case (spanning through all available horizontal space)?
The only difference is that in one case the panel is decorated with a JLayer.
A difference between a JPanel and a JLayer is that the JLayer implements the Scrollable interface but a JPanel does not.
The getScrollableTracksViewportWidth() method controls whether the component added to the viewport should be displayed at its preferred size or the width of the viewport. The JLayer delegates to the JPanel, but since JPanel doesn't implement the Scrollable interface the JLayer implementation will return "false" which means the component should be displayed at its preferred width.
So a way to get around this is to use a wrapper panel for the JLayer:
//scroll = new JScrollPane(component);
JPanel wrapper = new JPanel( new BorderLayout() );
wrapper.add( component );
scroll = new JScrollPane(wrapper);
Now the component added to the viewport of the scrollpane is a JPanel in both cases, so they should behave the same way.
The IDE I use is Intellij.
Here I created a small program of converting currency.
I used BorderLayout as the root panel and flowLayout for the bottom buttons. For west and east panel I used GridLayout(Intellij).
When I run the program, it can display normally like this:
After changing its size, the gap between elements begin to expand like this:
How do I make them adjust the distance automatically?
Here are my codes:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Created by Bob on 2017/5/11.
*/
public class layout {
private JPanel converterRootPanel;
private JPanel westPanel;
private JLabel selectNationPanel;
private JLabel currencyToConvett;
private JLabel currencyConverted;
private JComboBox currencyType;
private JTextField input;
private JTextField output;
private JPanel eastPanel;
private JPanel southPanel;
private JButton convertButton;
private JButton clearButton;
private JLabel convertToLabel;
private JComboBox convertType;
private JPanel northPanel;
public int selection1;
public int selection2;
public Double toConvert;
public double[][] rate1={{0,0.1335,0.1449,16.5172,163.4922},{7.4927,0,1.0857,123.7900,
1225.0380},{6.9029,0.9382,0,114.01,1129.19},{0.06053,0.00808,0.008771,0,9.9043},{0.006112,
0.0008158,0.0008856,0.101,0}};
public layout() {
currencyType.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
selection1 = currencyType.getSelectedIndex();
}
});
convertType.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
selection2 = convertType.getSelectedIndex();
}
});
convertButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(selection1==selection2){
JOptionPane.showConfirmDialog(null, "You have to choose different currency types!", "Error Alert", JOptionPane.CANCEL_OPTION);
}
output.setText("");
toConvert = Double.parseDouble(input.getText().toString());
Double convertResult = toConvert*rate1[selection1][selection2];
output.setText(convertResult.toString());
}
});
clearButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
output.setText("");
input.setText("");
convertType.setSelectedIndex(0);
currencyType.setSelectedIndex(0);
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame("layout");
frame.setContentPane(new layout().converterRootPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
//layout lay = new layout();
}
private void createUIComponents() {
// TODO: place custom component creation code here
}
}
What you want to do is done through a layout manager. There are several of these for Java that are part of the standard library and there are also other custom ones such as MigLayout.
The Java tutorials have a whole section on layout managers here
A basic example of the GridBagLayout would be the following.
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Basic {
JFrame frame;
JPanel panel;
JLabel label;
JButton button;
public void createAndRun() {
frame = new JFrame("Basic Example");
setUp();
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void setUp() {
panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
label = new JLabel("I am a JLabel");
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.BOTH;
c.weightx = 0.5;
c.weighty = 0;
panel.add(label, c);
button = new JButton("I am a JButton");
c.gridx = 0;
c.gridy = 1;
c.weighty = 0.5;
panel.add(button, c);
}
public static void main(String[] args) {
Basic b = new Basic();
b.createAndRun();
}
}
However, as the tutorials put it.
"GridBagLayout is one of the most flexible — and complex — layout managers the Java platform provides."
So if you are having problems with GridBagLayout it may be worth looking at other layout managers beforehand.
Finally, I would like to suggest some ways that you might look at improving your code.
The part that caught my eye the most was this line.
frame.setContentPane(new layout().converterRootPanel);
I would recommend not creating the JFrame and initialising you Layout class in the main method. Instead, it would be worth initialising the class first and then calling a method to create the frame.
Layout l = new Layout();
l.createFrame();
This is shown in the example code above.
A GridBagLayout uses the weightx and weighty properties of GridBagConstraints to determine how extra space is distributed. GridBagLayout uses the largest weightx of all cells in a column to determine the column’s actual horizontal weight for all cells in that column, and similarly, the largest weighty of all cells in a row determines that row’s vertical weight. If all columns have a zero weightx, they are all centered horizontally. If all rows have a zero weighty, they are all centered vertically.
Usually a good design is to have the input fields stretch horizontally, while the labels remain the same size at all times. You probably want the rows to have same vertical spacing at all times, and have all extra space appear above or below the entire set of rows.
To make all cells of a particular column stretch, you only need to set the weightx of one cell in that column:
JPanel buttonPanel = new JPanel();
buttonPanel.add(convertButton);
buttonPanel.add(clearButton);
converterRootPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_END;
// First row
converterRootPanel.add(selectNationPanel, gbc);
gbc.weightx = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
converterRootPanel.add(currencyType, gbc);
gbc.weightx = 0;
gbc.insets.top = 3;
// Second row
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.NONE;
converterRootPanel.add(convertToLabel, gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
converterRootPanel.add(convertType, gbc);
// Third row
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.NONE;
converterRootPanel.add(currencyToConvett, gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
converterRootPanel.add(input, gbc);
// Fourth row
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.NONE;
converterRootPanel.add(currencyConverted, gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
converterRootPanel.add(output, gbc);
// Button row
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
converterRootPanel.add(buttonPanel, gbc);
I'd like to ask something about GridBagLayout because whenever I try to put the lblStudentID under lblName it just makes an output wherein it stays in the right side of lblName
import javax.swing.*;
import java.awt.*;
public class Student extends JPanel {
JLabel picture;
JLabel lblStudentID = new JLabel("Student ID:");
JLabel lblName = new JLabel("Name:");
JLabel lblProg = new JLabel("Program:");
JLabel lblGen = new JLabel("Gender:");
JPanel panel = new JPanel();
JRadioButton rbtn1 = new JRadioButton("Male");
JRadioButton rbtn2 = new JRadioButton("Female");
JComboBox cmbProg = new JComboBox();
TextField txtStudentID = new TextField();
TextField txtName = new TextField();
GridBagConstraints gbc = new GridBagConstraints();
public void setName() {
}
public Student() {
setLayout(new GridBagLayout());
picture = new JLabel(createImageIcon("images/student.jpg"));
picture.setSize(100, 100);
add(picture);
add(lblName, gbc);
gbc.gridx = 0;
gbc.gridy = 0;
add(txtName, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
add(lblStudentID, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
add(txtStudentID, gbc);
gbc.gridx = 1;
gbc.gridy = 1;
}
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("Student");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
// Display the window.
Student LoginPane = new Student();
LoginPane.setOpaque(true); // content panes must be opaque
LoginPane.setLayout(new FlowLayout());
LoginPane.setBackground(Color.white);
frame.setContentPane(LoginPane);
frame.setVisible(true);
}
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = Student.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
First you change the GridBagConstraints too late.
gbc.gridx = 0;
gbc.gridy = 0;
add(lblName,gbc);
gbc.gridx = 1;
gbc.gridy = 0;
add(txtName,gbc);
gbc.gridx = 0;
gbc.gridy = 1;
add(lblStudentID,gbc);
gbc.gridx = 1;
gbc.gridy = 1;
add(txtStudentID,gbc);
Second you change the layout back to FlowLayout of your LoginPane.
Edit
I have stripped-down your code. Maybe this will help you:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.TextField;
import java.net.URL;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Student extends JPanel {
private static final long serialVersionUID = 8923497527096438302L;
private JLabel picture;
private JLabel lblStudentID = new JLabel("Student ID:");
private JLabel lblName = new JLabel("Name:");
TextField txtStudentID = new TextField();
TextField txtName = new TextField();
public Student() {
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setBackground(Color.WHITE);
JPanel formPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
formPanel.setOpaque(false);
picture = new JLabel(createImageIcon("images/student.jpg"));
picture.setPreferredSize(new Dimension(100, 100));
picture.setBorder(BorderFactory.createLineBorder(Color.black));
gbc.fill = GridBagConstraints.BOTH;
gbc.gridy = 0;
formPanel.add(picture, gbc);
gbc.gridy = 1;
gbc.gridwidth = 1;
formPanel.add(lblName, gbc);
gbc.gridy = 1;
gbc.weightx = 1;
formPanel.add(txtName, gbc);
gbc.weightx = 0;
gbc.gridy = 2;
formPanel.add(lblStudentID, gbc);
gbc.gridy = 2;
formPanel.add(txtStudentID, gbc);
add(formPanel, BorderLayout.PAGE_START);
}
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("Student");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
// Display the window.
new Student().setBackground(Color.white);
frame.setContentPane(new Student());
frame.setVisible(true);
}
protected static ImageIcon createImageIcon(String path) {
URL imgURL = Student.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
This is my first question inhere, so please bear with me :)
Im working on a dynamic part of a GUI, and for some reason its teasing me.
The class is opened in a new window after login.
What I want, is for a new JPanel to be built and added to 'container' every time the "add player" button is clicked. It is supposed to put them below eachother, yet all it does is to add one button on the first click, and then the rest of the clicks afterwards does nothing.
Any help is appreciated :)
package Gui;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
//import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
#SuppressWarnings("serial")
public class TeamManagerGUI extends JFrame implements ActionListener
{
// private JLabel pNameLabel = new JLabel("Player Name: "),
// pSchoolLabel = new JLabel("School: ");
// private JTextField pNameField = new JTextField(),
// pSchoolField = new JTextField();
private JButton addButton = new JButton("Add Player"),
removeButton = new JButton("Remove player");
private JPanel container = new JPanel(),
playerContainer = new JPanel();
int frameCounter = 1;
public TeamManagerGUI()
{
super("Team Manager User Interface");
setSize(1200,800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
container.setLayout(new GridBagLayout());
playerContainer.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(3,3,3,3);
addButton.addActionListener(this);
container.add(addButton,gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.insets = new Insets(3,3,3,3);
container.add(removeButton,gbc);
this.add(container);
}
public void playerFrame()
{
GridBagConstraints gbc = new GridBagConstraints();
playerFrameArr.add(new JPanel());
gbc.gridx = 0;
gbc.gridy = 0;
playerContainer.add(new JButton("LABEL"),gbc);
gbc.gridx = 1;
gbc.gridy = 0;
playerContainer.add(new JButton("BUTTON"),gbc);
gbc.gridx = 0;
gbc.gridy = frameCounter+1;
container.add(playerContainer,gbc);
System.out.println(frameCounter);
frameCounter++;
}
public void addPlayerRow()
{
playerFrame();
container.revalidate();
container.repaint();
}
public void removePlayerRow()
{
//Not yet implemented
}
public void actionPerformed(ActionEvent ae)
{
if(ae.getSource() == addButton)
{
addPlayerRow();
}
if(ae.getSource() == removeButton)
{
//Not yet implemented
}
}
}
You are adding the playerContainer again and again. I think you should actually use the newly created JPanel. This one should be populated and added to the main container.
Adding a single panel multiple times will not render properly as this screws up the layout. I think you need to keep a reference to the new JPanel and fill this one with your layout and the buttons.
I am thinking something like this:
public void playerFrame()
{
GridBagConstraints gbc = new GridBagConstraints();
JPanel newPanel = new JPanel(new GridBagLayout());
playerFrameArr.add(newPanel);
gbc.gridx = 0;
gbc.gridy = 0;
newPanel.add(new JButton("LABEL"), gbc);
gbc.gridx = 1;
gbc.gridy = 0;
newPanel.add(new JButton("BUTTON"), gbc);
gbc.gridx = 0;
gbc.gridy = frameCounter + 1;
container.add(newPanel, gbc);
System.out.println(frameCounter);
frameCounter++;
}
So I'm trying to create a series of radio buttons and check boxes that are displayed as follows:
Radio Button
Check Box
Radio Button
Check Box
Radio Button
However, I'm still in the learning process for java and I was wondering if anyone could solve this problem. At the moment the buttons and boxes are being displayed in the correct location, however the first radio button ("Courier") is not being displayed for some reason. If you could perhaps describe the reason and a possible solution that'd be great.
Thanks
Updated Code:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
public class Question2 {
public static void main(String[] args) {
MyFrame f = new MyFrame("Font Chooser");
f.init();
}
}
class MyFrame extends JFrame {
MyFrame(String title) {
super(title);
}
private JPanel mainPanel;
private GridBagConstraints gbc = new GridBagConstraints();
private GridBagLayout gbLayout = new GridBagLayout();
void init() {
mainPanel = new JPanel();
mainPanel.setLayout(gbLayout);
mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));
this.setContentPane(mainPanel);
gbc.gridx = 0;
gbc.gridy = 1;
JCheckBox cb = new JCheckBox("Bold");
gbLayout.setConstraints(cb, gbc);
mainPanel.add(cb);
gbc.gridy = 3;
gbLayout.setConstraints(cb, gbc);
cb = new JCheckBox("Italic");
mainPanel.add(cb);
gbc.gridx = 1;
gbc.gridy = 0;
JRadioButton rb = new JRadioButton("Times");
gbLayout.setConstraints(rb, gbc);
mainPanel.add(rb, gbc);
gbc.gridy = 2;
rb = new JRadioButton("Helvatica");
mainPanel.add(rb, gbc);
rb = new JRadioButton("Courier");
gbc.gridy = 4;
mainPanel.add(rb, gbc);
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}
3 issues
Y Coordinate not re-assigned to different value causing last 2 radio buttons to exist at same location
GridBagConstraints not being used for left-hand side components
setConstraints erroneously being used to set constraints
Resultant code:
public class GoodGridBagApp {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Font Chooser");
frame.add(getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private JPanel getMainPanel() {
JPanel mainPanel = new JPanel();
GridBagConstraints gbc = new GridBagConstraints();
mainPanel.setLayout(new GridBagLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));
gbc.gridx = 1;
gbc.gridy = 2;
JCheckBox cb = new JCheckBox("Bold");
mainPanel.add(cb, gbc);
gbc.gridy = 4;
cb = new JCheckBox("Italic");
mainPanel.add(cb, gbc);
gbc.gridx = 2;
gbc.gridy = 1;
JRadioButton rb = new JRadioButton("Times");
mainPanel.add(rb, gbc);
gbc.gridy = 3;
rb = new JRadioButton("Helvatica");
mainPanel.add(rb, gbc);
rb = new JRadioButton("Courier");
gbc.gridy = 5;
mainPanel.add(rb, gbc);
return mainPanel;
}
});
}
}
Read: How to Use GridBagLayout