GridBagLayout overwrting previos row - java

I have this piece of code to add a series of questions and 4 answers for each question.However when i add 3rd question it overwrites the previous row.Can anypne help me to solve this problem.I just need a hint about why it is doing this
package Generators;
/**
*
* #author samim
*/
import java.awt.Dimension;
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 java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
public class CreateFormFields
{
// Field members
static JPanel panel = new JPanel();
static Integer indexer = 1;
// static List<JLabel> question = new ArrayList<JLabel>();
static List<JTextField> question = new ArrayList<JTextField>();
static List<JTextField> ans1 = new ArrayList<JTextField>();
static List<JTextField> ans2 = new ArrayList<JTextField>();
static List<JTextField> ans3 = new ArrayList<JTextField>();
static List<JTextField> ans4 = new ArrayList<JTextField>();
static List<JTextField> result = new ArrayList<JTextField>();
public static void main(String[] args)
{
// Construct frame
JFrame frame = new JFrame();
frame.setLayout(new GridBagLayout());
frame.setPreferredSize(new Dimension(990, 990));
frame.setTitle("Form Creator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Frame constraints
GridBagConstraints frameConstraints = new GridBagConstraints();
// Construct button
JButton addButton = new JButton("Add");
addButton.addActionListener(new ButtonListener());
// Add button to frame
frameConstraints.gridx = 0;
frameConstraints.gridy = 0;
frame.add(addButton, frameConstraints);
// Construct panel
panel.setPreferredSize(new Dimension(950, 400));
panel.setLayout(new GridBagLayout());
JScrollPane scrollPane = new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setPreferredSize(new Dimension(900, 400));
frameConstraints.gridx = 0;
frameConstraints.gridy = 1;
frame.add(scrollPane, frameConstraints);
// Pack frame
frame.pack();
// Make frame visible
frame.setVisible(true);
}
static class ButtonListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent arg0)
{
// Clear panel
panel.removeAll();
panel.setPreferredSize(new Dimension(950,panel.getHeight()+200));
// Create label and text field
JTextField jTextField = new JTextField();
JTextField jTextField2 = new JTextField();
JTextField jTextField3 = new JTextField();
JTextField jTextField4 = new JTextField();
JTextField jTextField5 = new JTextField();
JTextField jTextField6 = new JTextField();
question.add(jTextField);
ans1.add(jTextField2);
ans2.add(jTextField3);
ans3.add(jTextField4);
ans4.add(jTextField5);
result.add(jTextField6);
// Create constraints
GridBagConstraints textFieldConstraints = new GridBagConstraints();
GridBagConstraints labelConstraints = new GridBagConstraints();
GridBagConstraints gridans1 = new GridBagConstraints();
GridBagConstraints temp = new GridBagConstraints();
// Add labels and text fields
for(int i = 1; i <= indexer; i++)
{
int R = (int) (Math.random() * 255);
int G = (int) (Math.random() * 255);
int B = (int) (Math.random() * 255);
String total = "rgb(" + R + "," + G + "," + B + ")";
// Label constraints
labelConstraints.gridx = 0;
labelConstraints.gridy = i * 7;
labelConstraints.insets = new Insets(5, 300, 5, 300);
panel.add(new JLabel("<html><font color='" + total + "'>Question " + i + "<font></html>"),
labelConstraints);
temp.gridx = 0;
temp.gridy = i * 8;
temp.insets = new Insets(10, -550, 10, 2);
panel.add(new JLabel("Question :"), temp);
// Text field constraints
textFieldConstraints.fill = 1;//GridBagConstraints.HORIZONTAL;
textFieldConstraints.insets = new Insets(10, -550, 10, 0);
textFieldConstraints.gridy = i * 8;
panel.add(question.get(i - 1), textFieldConstraints);
gridans1.fill = 1;//GridBagConstraints.HORIZONTAL;
gridans1.insets = new Insets(10, -550, 10, 290);
gridans1.gridy = i * 9;
temp.gridy = i * 9;
panel.add(new JLabel("Answer 1 :"), temp);
panel.add(ans1.get(i - 1), gridans1);
gridans1.gridy = i * 10;
temp.gridy = i * 10;
panel.add(new JLabel("Answer 2 :"), temp);
panel.add(ans2.get(i - 1), gridans1);
gridans1.gridy = i * 11;
temp.gridy = i * 11;
panel.add(new JLabel("Answer 3:"), temp);
panel.add(ans3.get(i - 1), gridans1);
gridans1.gridy = i * 12;
temp.gridy = i * 12;
panel.add(new JLabel("Answer 4:"), temp);
panel.add(ans4.get(i - 1), gridans1);
gridans1.gridy = i * 13;
temp.gridy = i * 13;
panel.add(new JLabel("Good Result :"), temp);
panel.add(result.get(i - 1), gridans1);
}
// Align components top-to-bottom
// Increment indexer
indexer++;
panel.updateUI();
}
}
}

Four GridBagConstrains, many components with looping: the performance is poor, the code read style is too complex. It is better you change your design of your code:
While working with group of similar type of component, try enclose them inside another Container Component:
MyQuestionPanel extends JPanel
{
public JLabel questionLab;
public JTextField qAnsField1;
public JTextFeild qAnsField2;
MyQuestionPanel(int questionNo)
{
setLayout(/* GridBagLayout any layout relevant to your design */);
//add your compoenents suing add(component, gridBagConstraint),
//or with relevant add() method e.g., questionLab, qAnsField1, qAnsField2
}
}
Now, assuming that you have root panel which is going to maintain the Question panel(which is container the question label and answer input field), has necessary layout(BoxLayout or other relevant to your design), create a new instance of MyQuestionPanel and add them to the root panel. You don't need to remove all the question panel and re-add them to the root panel on Button Click, as you were doing, rather simply put the root.add(MyQuestionPanel)
You don't need to call updateUI(); in fact you should not in this case, because it will first uninstall all the properties you had of the calling component and then reinstall the UI with extra call revalidate() and repaint(). Just call root.revalidate() and then root.repaint() to reflect the changes for adding and removing component.
If you do these, you will see your code will be much shorter, simpler and nicer. Give it a try.

Related

Is there a way to place JButtons with different spaces in the begining at the GridBagLayout?

I'm trying to do something like this:
But I can't leave spaces before the buttons. I have tried to add invisible buttons, but nothing has changed.
for (int i = 0; i < gameSize; i++ ){
c.gridwidth = (i+1)*2;
c.gridx = 0;
c.gridy = 4*i;
JRadioButton temp = new JRadioButton();
temp.setVisible(false);
board.add(temp,c);
for(int j = 0; j < gameSize; j++){
c.gridwidth = 4;
c.gridx = 2+(4*j);
c.gridy = 2+(4*i);
cells[i][j] = new JButton();
cells[i][j].setBackground(Color.white);
board.add(cells[i][j],c);
}
}
It's look like [this:
when I made them visible. I didn't get why width of them is still 4 even though I'm assigning it to (i+1)*2.
I'm new to Java and very very new to Java GUI. So, maybe I didn't figure out the most basic thing. Thanks for advices!
I created the following GUI.
In order to do this, I had to use a combination of Swing layouts.
The buttons on each row are created in a JPanel with a GridLayout. The row is created with a row JPanel with a FlowLayout, using a dummy JLabel and the button row JPanel.
The main JPanel uses a GridLayout of (0, 1) to create the staggered effect. The dummy JLabel in each row gets bigger by half the size of the JButtons.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GridBagLayoutStaggeredGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new GridBagLayoutStaggeredGUI());
}
#Override
public void run() {
JFrame frame = new JFrame("Staggered Layout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
int gameSize = 8;
int buttonSize = 50;
int inset = 2;
JButton[][] cells = new JButton[gameSize][gameSize];
JPanel panel = new JPanel(new GridLayout(0, 1));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
for (int i = 0; i < gameSize; i++) {
JPanel innerPanel = new JPanel(
new FlowLayout(FlowLayout.LEADING, 0, 0));
JLabel label = new JLabel();
label.setPreferredSize(new Dimension(inset, buttonSize));
innerPanel.add(label);
innerPanel.add(createRowPanel(cells[i], buttonSize));
panel.add(innerPanel);
inset += buttonSize / 2;
}
return panel;
}
private JPanel createRowPanel(JButton[] cells, int buttonSize) {
JPanel panel = new JPanel(new GridLayout(0, cells.length, 0, 0));
for (int i = 0; i < cells.length; i++) {
cells[i] = new JButton();
cells[i].setBackground(Color.white);
cells[i].setPreferredSize(new Dimension(buttonSize, buttonSize));
panel.add(cells[i]);
}
return panel;
}
}
The GridBagLayout can only calculate the width of a column if there is a component added to the column with a "gridwidth" of 1.
In your example you have 6 button each with a "gridwidth" of 2, implying you really want 12 columns. But what should the width of each column be?
The example below shows how to allocate a minimum width for each column. Now each of the 12 columns will have a minimum width based on the value specified.
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class GridBagLayoutMRE extends JPanel
{
public GridBagLayoutMRE()
{
int gameSize = 6;
int columnsNeeded = (gameSize * 3);
int cellSize = 30;
Dimension buttonSize = new Dimension(cellSize * 2, cellSize);
GridBagLayout gbl = new GridBagLayout();
setLayout( gbl );
int[] columnWidths = new int[columnsNeeded];
Arrays.fill(columnWidths, cellSize);
gbl.columnWidths = columnWidths;
GridBagConstraints gbc = new GridBagConstraints();
for (int i = 0; i < gameSize; i++)
{
gbc.gridx = 0;
gbc.gridy = i;
gbc.gridwidth = 1;
JRadioButton rb = new JRadioButton();
rb.setPreferredSize( new Dimension(60, cellSize) );
add(rb, gbc);
gbc.gridx = i + 1;
gbc.gridwidth = 2;
for (int j = 0; j < gameSize; j++)
{
JButton button = new JButton();
button.setPreferredSize( buttonSize );
add(button, gbc);
gbc.gridx = gbc.gridx + gbc.gridwidth;
}
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("GridBagLayoutMRE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout( new GridBagLayout() );
frame.add(new GridBagLayoutMRE());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}

Adding multiple sets of JLabel and JTextBox to the same line in Java

I'm building an equation solver that allows the user to enter a system of equations and then get the answer. So, I need to build a GUI that allows the user to enter the set of equations. I decided to go about doing this from scratch. Here's what my code looks like:
private JFrame frame;
private JTextField[][] text;
private JLabel label;
private JLabel equalLabel;
private JLabel plusLabel;
private JTextField answerText;
private void displayGetEquations(int total)
{
frame = new JFrame("Enter Equations");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
equalLabel = new JLabel();
equalLabel.setText(" = ");
plusLabel = new JLabel();
plusLabel.setText(" + ");
answerText = new JTextField();
answerText.setColumns(2);
frame.setLayout(new GridLayout(0,10));
text = new JTextField[3][3];
for(int i = 0 ; i < 3 ; i++)
{
panel = new JPanel();
panel.setLayout(new FlowLayout());
for(int j = 0 ; j < 3 ; j++)
{
text[i][j] = new JTextField();
text[i][j].setColumns(2);
label = new JLabel();
Font font = label.getFont();
Font boldFont = new Font(font.getFontName(), Font.BOLD, font.getSize());
label.setFont(boldFont);
label.setText("x");
panel.add(text[i][j]);
panel.add(label);
panel.add(plusLabel);
}
panel.add(equalLabel);
panel.add(answerText);
frame.add(panel);
frame.revalidate();
frame.repaint();
}
frame.pack();
frame.setVisible(true);
}
This is what I get when I run the above code:
But I am not getting the desired output, which, I would like to be something like this:
This was made using the drag and drop feature of NetBeansWhat am I doing wrong? Is what I want even possible?
Any help would be appreciated.
Thanks !
(This was made using the drag and drop feature of NetBeans)
Your code is a little bit confusing and the one posted here isn't a MCVE, as it lacks a main method and imports and a variable panel, as well as it's giving me a different output than the one you posted:
From your example-output images I made 2 approaches, one which uses multiple JPanel with a FlowLayout inside another one with BoxLayout and another one which uses a single JPanel with a GridLayout. Another approach could be using GridBagLayout
I used x, y and z variable names because I thought you were using an equation solving program or something like that.
Here's the code that produces the above outputs:
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class MultipleComponentsInRow {
public static final int ROWS = 3;
public static final int COLS = 4;
private JFrame frame;
private JPanel flowLayoutPanel;
private JPanel gridLayoutPanel;
private JTextField[][] flowFields;
private JTextField[][] gridFields;
private void createAndShowGui() {
frame = new JFrame("Multiple Components In Row");
flowFields = new JTextField[ROWS][COLS];
gridFields = new JTextField[ROWS][COLS];
flowLayoutPanel = new JPanel();
flowLayoutPanel.setLayout(new BoxLayout(flowLayoutPanel, BoxLayout.PAGE_AXIS));
gridLayoutPanel = new JPanel();
gridLayoutPanel.setLayout(new GridLayout(ROWS, 7));
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
flowFields[i][j] = new JTextField(2);
gridFields[i][j] = new JTextField(2);
}
}
//FlowLayout approach
for (int i = 0; i < ROWS; i++) {
JPanel pane = new JPanel();
pane.setLayout(new FlowLayout());
for (int j = 0; j < COLS; j++) {
pane.add(flowFields[i][j]);
switch (j) {
case 0:
pane.add(new JLabel(" x + "));
break;
case 1:
pane.add(new JLabel(" y + "));
break;
case 2:
pane.add(new JLabel(" z = "));
break;
default:
break;
}
}
flowLayoutPanel.add(pane);
}
//GridLayout approach
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
gridLayoutPanel.add(gridFields[i][j]);
switch (j) {
case 0:
gridLayoutPanel.add(new JLabel(" x + "));
break;
case 1:
gridLayoutPanel.add(new JLabel(" y + "));
break;
case 2:
gridLayoutPanel.add(new JLabel(" z = "));
break;
default:
break;
}
}
}
frame.setLayout(new GridLayout(1, 2, 5, 5));
flowLayoutPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.BLACK), "Flow Layout"));
gridLayoutPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.RED), "Grid Layout"));
frame.add(flowLayoutPanel);
frame.add(gridLayoutPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new MultipleComponentsInRow().createAndShowGui();
}
}
Think about the theory here. Big picture view: You have a frame with a panel right? Why not have a frame with 3 panels? The frame layout will be a vertical stackpane and the each panel will be a horizontal layout with the 4 textfields. You may want consider using JavaFX where you could do something like:
...
HBox hBox1 = new Hbox();
hBox1.getChildern.addAll(new Textfield(), new Textfield(), new Textfield());
... //repeat 2 more times
Vbox vbox = new VBox(hBox1, hBox2, hBox3);
...
Then you have 3x horizontal layouts contained in 1 vertical layout.

Issue when using Java Swing in a For-Loop

I have created a simple for-loop that changes the amount of JTextFields and JLabels based on the value of a JSpinner, as seen in the following code:
public static ArrayList<ArrayList<JTextField>> ChangeQuestionAnswerFields(int numberOfQuestions){
ArrayList<ArrayList<JTextField>> txtFieldArray = new ArrayList<ArrayList<JTextField>>();
JPanel scrollPanel = new JPanel(new GridBagLayout());
//JScrollPane scrollPane = new JScrollPane(scrollPanel);
frame.add(scrollPanel, BorderLayout.CENTER);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
for(int i = 0; i != numberOfQuestions; i++){
JTextField tempQuestion = new JTextField(10);
JTextField tempAnswer = new JTextField(10);
JLabel tempQuestionHeader = new JLabel("Question " + (i + 1)+ " ");
JLabel tempQuestionLbl = new JLabel("Question: ");
JLabel tempAnswerLbl = new JLabel("Answer: ");
ArrayList<JTextField> tempArrayList = new ArrayList<>();
tempArrayList.add(tempQuestion);
tempArrayList.add(tempAnswer);
txtFieldArray.add(tempArrayList);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempQuestionHeader, c);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempQuestionLbl, c);
c.gridx = 1;
c.gridwidth = 3;
scrollPanel.add(tempQuestion, c);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempAnswerLbl, c);
c.gridx = 1;
c.gridwidth = 3;
scrollPanel.add(tempAnswer, c);
}
return txtFieldArray;
}
}
The value of the Spinner is passed into the method, and the method is called using a change listener (where noQuestions is the value of the JSpinner):
noQuestions.addChangeListener(e -> {
ChangeQuestionAnswerFields((int) noQuestions.getValue());
frame.revalidate();
frame.repaint();
});
This method is first called in the code when the screen first appears, and works properly. However, whenever the value of the spinner changes the original labels and fields stay on the screen and more text fields simply appear, or disappear on top.
http://i.imgur.com/GBY8L3u.png - JSpinner has a value of 2
http://i.imgur.com/pSQsA3G.png - JSpinner has a value of 3
Is there any way to fix this? Any help is much appreciated.
Thanks,
Tom
Minimal Runnable Example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
public class MainGUI {
static JFrame frame = new JFrame("Math Reviser");
public static void main(String[] args) {
frame.setSize(400, 600);
frame.setVisible(true);
createScreen();
frame.revalidate();
frame.repaint();
public static void createScreen(){
frame.getContentPane().removeAll();
JSpinner noQuestions = new JSpinner(new SpinnerNumberModel(1, 1, 10, 1));
frame.add(noQuestions, BorderLayout.NORTH);
);
changeQuestionAnswerFields(1);
frame.revalidate();
frame.repaint();
noQuestions.addChangeListener(e -> {
changeQuestionAnswerFields((int) noQuestions.getValue());
frame.revalidate();
frame.repaint();
});
}
public static ArrayList<ArrayList<JTextField>> changeQuestionAnswerFields(int numberOfQuestions){
ArrayList<ArrayList<JTextField>> txtFieldArray = new ArrayList<ArrayList<JTextField>>();
JPanel scrollPanel = new JPanel(new GridBagLayout());
frame.add(scrollPanel, BorderLayout.CENTER);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
for(int i = 0; i != numberOfQuestions; i++){
JTextField tempQuestion = new JTextField(10);
JTextField tempAnswer = new JTextField(10);
JLabel tempQuestionHeader = new JLabel("Question " + (i + 1)+ " ");
JLabel tempQuestionLbl = new JLabel("Question: ");
JLabel tempAnswerLbl = new JLabel("Answer: ");
ArrayList<JTextField> tempArrayList = new ArrayList<>();
tempArrayList.add(tempQuestion);
tempArrayList.add(tempAnswer);
txtFieldArray.add(tempArrayList);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempQuestionHeader, c);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempQuestionLbl, c);
c.gridx = 1;
c.gridwidth = 3;
scrollPanel.add(tempQuestion, c);
c.gridy++;
c.gridx = 0;
scrollPanel.add(tempAnswerLbl, c);
c.gridx = 1;
c.gridwidth = 3;
scrollPanel.add(tempAnswer, c);
}
return txtFieldArray;
}
}
Using static variables and methods is an indication of a poorly designed application. There is no need for the static variables or methods. I suggest you read the section from the Swing tutorial on How to Use Labels. The LabelDemo.java code will show you how to create a panel containing all the components. This panel will then be added to the frame. This panel will also contain all the instance variables you need for your program.
Not only that the example will show you how to create the GUI components on the EDT which is something you should always do to prevent random errors since Swing was designed to be single threaded.
However, the main problem with your existing code is that you continue to create and add new panels to the content pane of the frame. Try changing the spinner to 2 and then resize the frame. Then try changing the spinner to 3 and resize the frame. After the resizing the first panel is displayed. This is because Swing will paint the last component added first so the first panel added will be painted on top of the last panel you created.
You can change this in your existing code by removing the old panel before adding the new panel:
static JFrame frame = new JFrame("Math Reviser");
static JPanel scrollPanel = new JPanel();
...
frame.remove(scrollPanel);
//JPanel scrollPanel = new JPanel(new GridBagLayout());
scrollPanel = new JPanel(new GridBagLayout());
However, I do not recommend this approach. As I initially suggestion you need to redesign the entire class. When you do the redesign I would use a BorderLayout on your panel and then you can add your spinner to the PAGE_START and then add a JScrollPane to the CENTER of the panel.
Then when you want to create a new panel you add the panel to the scrollpane using code like:
scrollPane.setViewportView( scrollPanel );
The scrollpane will refresh itself and you don't need to worry about revalidate() or repaint() or anything else.

JPanel component placement

I am trying to get a basic GUI program. It doesnt have to do much but the buttons at the bottom have to work. I am having trouble placing the components (The text, combobox, etc) in the proper spot. Using the GridBag I am able to change the location with the c.gridx and c.gridy but in a very weird way. If I put the gridy values 0-7 with x being 0 everything is on top of eachother. I try putting the combo box next to the text by changing the gridx value and everything gets messed up. The alignment is off on the components after the one I was trying to move over. How do I fix this? I tried the BorderLayout.DIRECTION with no luck. The actual change doesn't take effect at all (moving then to the bottom). How do I fix this? Thanks
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javaredesign;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
/**
*
* #author
*/
public class Window extends JFrame {
//Default global variables
private JButton submit;
private JButton cancel;
private JButton reset;
private JPanel panel = new JPanel(new GridBagLayout());
private String searchOutput = "";
//Default constructor
public Window() {
//Title of the window
super("LIBSYS: Search");
//Creating the flow layout to which we can work on and adding panel to frame
setLayout(new FlowLayout());
add(panel, BorderLayout.SOUTH);
//Creating the grid to location of the parts
GridBagConstraints c = new GridBagConstraints();
//Initializing the buttons
submit = new JButton("Submit");
c.insets = new Insets(10, 10, 10, 5);
c.gridx = 1;
c.gridy = 20;
panel.add(submit, c);
reset = new JButton("Reset");
c.gridx = 2;
c.gridy = 20;
panel.add(reset, c);
cancel = new JButton("Cancel");
c.gridx = 3;
c.gridy = 20;
panel.add(cancel, c);
//Handler constructor to do the actionlistening
Handler handler = new Handler();
submit.addActionListener(handler);
reset.addActionListener(handler);
cancel.addActionListener(handler);
//Creating the two dropdowns with the words next to them
JLabel chooseCollection = new JLabel("Choose Collection");
String[] ccString = {"All", "Mostly", "Some", "Few"};
JComboBox ccComboBox = new JComboBox(ccString);
JLabel searchUsing = new JLabel("Search Using");
String[] suString = {"Title", "Artist", "Arthor", "Type"};
JComboBox suComboBox = new JComboBox(suString);
//Adding all the text and dropdown menus to the panel
c.gridx = 0;
c.gridy = 24;
panel.add(chooseCollection, c);
c.gridx = 0;
c.gridy = 25;
panel.add(ccComboBox, c);
c.gridx = 1;
c.gridy = 25;
panel.add(searchUsing, c);
c.gridx = 0;
c.gridy = 27;
panel.add(suComboBox, c);
c.gridx = 1;
c.gridy = 27;
//Setting up the text inputbox
JLabel keyword = new JLabel("Keyword or phrase");
JTextField textField = new JTextField(20);
//Adding lable and text box to the panel
panel.add(keyword);
panel.add(textField);
}
}
I would not try and force the buttons into the same layout as the other components. They are independant and should be free floating evenly spaced.
The button panel should be in a panel set with flowlayout. Then this panel should be added to the frame with borderlayout at SOUTH.
The rest of the components should go into a panel with gridbaglayout and added to the frame at CENTER.
The gridbaglayout panel then should have all its components set at the coordinates listed in the picture. If the component covers more than two cells (ie combo) then set the gridWidth property to 2.
I'd do it by having an outer BorderLayout. In the CENTER would be a GroupLayout for the label/control pairs. In the PAGE_END would be a FlowLayout for the buttons.
This uses a TitledBorder instead of the JLabel to show LIBSYS Search. If it really needs a label, put it in the PAGE_START of the border layout.
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
import javax.swing.border.*;
public class LibSysSearch {
private JComponent ui = null;
LibSysSearch() {
initUI();
}
public void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
// Here is our control. This puts a titled border around it,
// instead of using a label in the PAGE_START
JPanel libSysSearchControl = new JPanel(new BorderLayout());
ui.add(libSysSearchControl);
JPanel actionPanel = new JPanel(
new FlowLayout(FlowLayout.CENTER, 15, 15));
libSysSearchControl.add(actionPanel, BorderLayout.PAGE_END);
String[] actionNames = {"Search", "Reset", "Cancel"};
for (String name : actionNames) {
actionPanel.add(new JButton(name));
}
// Use GroupLayout for the label/cotrnl combos.
// make the arrays for the factory method
String[] labels = {
"Choose Collection", "Search Using",
"Keyword or phrase", "Adjacent words"
};
String[] ccString = {"All", "Mostly", "Some", "Few"};
String[] suString = {"Title", "Artist", "Arthor", "Type"};
JPanel confirmAdjacent = new JPanel(new FlowLayout(FlowLayout.LEADING,5,0));
confirmAdjacent.add(new JRadioButton("Yes", true));
confirmAdjacent.add(new JRadioButton("No"));
JComponent[] controls = {
new JComboBox(ccString),
new JTextField(20),
new JComboBox(suString),
confirmAdjacent
};
libSysSearchControl.add(getTwoColumnLayout(labels, controls));
// throw in a few borders for white space
Border border = new CompoundBorder(
new EmptyBorder(10, 10, 10, 10),
new TitledBorder("LIBSYS Search"));
border = new CompoundBorder(
border,
new EmptyBorder(10, 10, 10, 10));
libSysSearchControl.setBorder(border);
}
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) {
}
LibSysSearch o = new LibSysSearch();
JFrame f = new JFrame("Library System Search");
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);
}
/**
* Provides a JPanel with two columns (labels & fields) laid out using
* GroupLayout. The arrays must be of equal size.
*
* Typical fields would be single line textual/input components such as
* JTextField, JPasswordField, JFormattedTextField, JSpinner, JComboBox,
* JCheckBox.. & the multi-line components wrapped in a JScrollPane -
* JTextArea or (at a stretch) JList or JTable.
*
* #param labels The first column contains labels.
* #param fields The last column contains fields.
* #param addMnemonics Add mnemonic by next available letter in label text.
* #return JComponent A JPanel with two columns of the components provided.
*/
public static JComponent getTwoColumnLayout(
JLabel[] labels,
JComponent[] fields,
boolean addMnemonics) {
if (labels.length != fields.length) {
String s = labels.length + " labels supplied for "
+ fields.length + " fields!";
throw new IllegalArgumentException(s);
}
JComponent panel = new JPanel();
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
// Turn on automatically adding gaps between components
layout.setAutoCreateGaps(true);
// Create a sequential group for the horizontal axis.
GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup();
GroupLayout.Group yLabelGroup = layout.createParallelGroup(GroupLayout.Alignment.TRAILING);
hGroup.addGroup(yLabelGroup);
GroupLayout.Group yFieldGroup = layout.createParallelGroup();
hGroup.addGroup(yFieldGroup);
layout.setHorizontalGroup(hGroup);
// Create a sequential group for the vertical axis.
GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup();
layout.setVerticalGroup(vGroup);
int p = GroupLayout.PREFERRED_SIZE;
// add the components to the groups
for (JLabel label : labels) {
yLabelGroup.addComponent(label);
}
for (Component field : fields) {
yFieldGroup.addComponent(field, p, p, p);
}
for (int ii = 0; ii < labels.length; ii++) {
vGroup.addGroup(layout.createParallelGroup().
addComponent(labels[ii]).
addComponent(fields[ii], p, p, p));
}
if (addMnemonics) {
addMnemonics(labels, fields);
}
return panel;
}
private final static void addMnemonics(
JLabel[] labels,
JComponent[] fields) {
Map<Character, Object> m = new HashMap<Character, Object>();
for (int ii = 0; ii < labels.length; ii++) {
labels[ii].setLabelFor(fields[ii]);
String lwr = labels[ii].getText().toLowerCase();
for (int jj = 0; jj < lwr.length(); jj++) {
char ch = lwr.charAt(jj);
if (m.get(ch) == null && Character.isLetterOrDigit(ch)) {
m.put(ch, ch);
labels[ii].setDisplayedMnemonic(ch);
break;
}
}
}
}
/**
* Provides a JPanel with two columns (labels & fields) laid out using
* GroupLayout. The arrays must be of equal size.
*
* #param labelStrings Strings that will be used for labels.
* #param fields The corresponding fields.
* #return JComponent A JPanel with two columns of the components provided.
*/
public static JComponent getTwoColumnLayout(
String[] labelStrings,
JComponent[] fields) {
JLabel[] labels = new JLabel[labelStrings.length];
for (int ii = 0; ii < labels.length; ii++) {
labels[ii] = new JLabel(labelStrings[ii]);
}
return getTwoColumnLayout(labels, fields);
}
/**
* Provides a JPanel with two columns (labels & fields) laid out using
* GroupLayout. The arrays must be of equal size.
*
* #param labels The first column contains labels.
* #param fields The last column contains fields.
* #return JComponent A JPanel with two columns of the components provided.
*/
public static JComponent getTwoColumnLayout(
JLabel[] labels,
JComponent[] fields) {
return getTwoColumnLayout(labels, fields, true);
}
}
The problem is that you need to understand GridBagLayout. You need to layout your components onto a proper grid:
So you should have 5 rows and 12 columns to layout the way you described in your picture. Don't mind the padding (I tried to add that to make it more illustrative). Your first three rows should each have elements of gridwidth = 6 and the first should be at gridx = 0 and the second at gridx = 6. Then your "yes" and "no" buttons should each have gridwidth = 3 at gridx = 6 and gridx = 9, respectively. Finally your last row, the buttons, should each have gridwidth = 2 and gridx = 1, gridx = 5, and gridx = 9, respectively. Instead of using padding, I would just use gbc.anchor = GridBagConstraints.CENTER (for all of the components) so that the components are centered inside of their grid.
I would suggest using gbc.fill = GridBagConstraints.HORIZONTAL for the text field and combo boxes so that they line up "nice and pretty" but don't forget to set that back to gbc.fill = GridBagConstraints.NONE for the radio buttons and regular buttons (unless you want them to stretch as well).
I very haphazardly changed your code (which appeared to be in no logical order):
// Creating the grid to location of the parts
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.CENTER;
// Initializing the buttons
submit = new JButton("Submit");
c.insets = new Insets(10, 10, 10, 5);
c.gridx = 1;
c.gridy = 5;
c.gridwidth = 2;
panel.add(submit, c);
reset = new JButton("Reset");
c.gridx = 5;
// c.gridy = 20;
panel.add(reset, c);
cancel = new JButton("Cancel");
c.gridx = 9;
// c.gridy = 20;
panel.add(cancel, c);
// Handler constructor to do the actionlistening
Handler handler = new Handler();
submit.addActionListener(handler);
reset.addActionListener(handler);
cancel.addActionListener(handler);
// Creating the two dropdowns with the words next to them
JLabel chooseCollection = new JLabel("Choose Collection");
String[] ccString = { "All", "Mostly", "Some", "Few" };
JComboBox ccComboBox = new JComboBox(ccString);
JLabel searchUsing = new JLabel("Search Using");
String[] suString = { "Title", "Artist", "Arthor", "Type" };
JComboBox suComboBox = new JComboBox(suString);
// Adding all the text and dropdown menus to the panel
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 6;
c.anchor = GridBagConstraints.WEST;
panel.add(chooseCollection, c);
c.gridx = 6;
// c.gridy = 25;
c.fill = GridBagConstraints.HORIZONTAL;
panel.add(ccComboBox, c);
c.gridx = 0;
c.gridy = 2;
c.fill = GridBagConstraints.NONE;
panel.add(searchUsing, c);
c.gridx = 6;
// c.gridy = 27;
c.fill = GridBagConstraints.HORIZONTAL;
panel.add(suComboBox, c);
// Setting up the text inputbox
JLabel keyword = new JLabel("Keyword or phrase");
JTextField textField = new JTextField(20);
// Adding lable and text box to the panel
c.gridx = 0;
c.gridy = 1;
c.fill = GridBagConstraints.NONE;
panel.add(keyword, c);
c.gridx = 6;
panel.add(textField, c);
Which produced the following layout:
i would probably do it like this:
public class Test {
public Test() {
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel(new GridLayout(0, 1));
JPanel chooseCollectionPanel = new JPanel(new BorderLayout());
JPanel keywordPanel = new JPanel(new BorderLayout());
JPanel searchCategoryPanel = new JPanel(new BorderLayout());
// ...
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
chooseCollectionPanel.setBorder(BorderFactory.createEmptyBorder(5, 0,
5, 0));
keywordPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
searchCategoryPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5,
0));
JLabel chooseCollectionLabel = new JLabel("Choose Collection: ");
JComboBox<String> chooseCollectionCB = new JComboBox<String>();
chooseCollectionCB.addItem("All");
chooseCollectionPanel.add(chooseCollectionLabel, BorderLayout.WEST);
chooseCollectionPanel.add(chooseCollectionCB, BorderLayout.CENTER);
JLabel chooseCollectionkeywordLabel = new JLabel("Choose Collection: ");
JTextField keywordCB = new JTextField(10);
keywordPanel.add(chooseCollectionkeywordLabel, BorderLayout.WEST);
keywordPanel.add(keywordCB, BorderLayout.CENTER);
// ...
mainPanel.add(chooseCollectionPanel);
mainPanel.add(keywordPanel);
mainPanel.add(searchCategoryPanel);
// ...
frame.add(mainPanel);
frame.setSize(400, 400);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Test();
}
}

Adding a JLabel in relative position to buttons

OK, this is the relative code I have so far.
for (int i = gameLines - 1; i > 0; i--)
{
for (int j = 0; j < i; j++)
{
JButton jButton = new JButton();
jButton.setSize(buttonWidth, buttonHeight);
jButton.setText("" + line[i].charAt(j));
int x = ((buttonWidth / 2 * gameLines + 1) - (buttonWidth / 2 * i) + (buttonWidth * j));
int y = (gameLines - (i + 1)) * buttonHeight;
jButton.setLocation(x, y);
panel.add(jButton);
button[i][j] = jButton;
button[i][j].setActionCommand(Integer.toString(i) + "." + Integer.toString(j));
button[i][j].addActionListener(this);
}
}
The code creates and places all my buttons where I want them to be. This took me a while to figure out. I'm originally an AppleSoft BASIC programmer, I'm sorry about the i & j variable names.
Now for the fun. To the right of the bottom 3 rows of buttons, I want to place a jLabel. The right edge of the jLabel is to align with the right edge of the rightmost button in the top row. The text in each will be right justified, ending with a : and an up-to 4 digit number.
I'm thinking I can simply calculate the position like I did the button positions. The text, I was going to add based on a switch/case.
I'm having an trouble understanding JLabels, so I'd appreciate ANY help I can get.
My current thoughts are: to be inserted after the j loop
if (i < 4)
{
JLabel jLable = new JLabel();
JLabel.setSize(???, buttonHeight);
Calculate value of X;
int y = (gameLines - (i +1)) * buttonHeight;
jLabel.setLocation(x,y);
switch (i)
{
case 3:
jLabel.setText("Buttons Clicked: " + buttonsClicked);
break;
case 2:
etc.
}
panel.add(jLabel);
}
HELP please
For a bag of reasons, I would avoid absolute layouts. The moment you run it on some other PC, the whole thing begins to fall apart, instead, you should rely on the layout manager API available in Swing.
The following example uses a compound layout approach. Each row is it's own container (JPanel) and each row is then added to the main panel.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ButtonPyramid {
public static void main(String[] args) {
new ButtonPyramid();
}
public ButtonPyramid() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private String[] lines;
public TestPane() {
lines = new String[]{
"AAFITQPNXBE",
"?AXOPKMSUR",
"TGKFREUDI",
"DFEAAEOY",
"ZDE?VIF",
"G#RMLC",
"YUJGO",
"NSCP",
"KO#",
"MI",
"Y",
"B",
};
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.gridy = 1;
gbc.gridx = 0;
for (String line : lines) {
JPanel panel = new JPanel(new GridBagLayout());
for (char ch : line.toCharArray()) {
JButton btn = new JButton(Character.toString(ch));
btn.setMargin(new Insets(10, 10, 10, 10));
panel.add(btn);
}
add(panel, gbc);
gbc.gridy++;
}
JLabel label = new JLabel(":1234");
gbc.gridy -= 3;
gbc.gridx++;
gbc.anchor = GridBagConstraints.NORTH;
add(label, gbc);
}
}
}
If you would prefer the text not to take up another column, there is a little trick you can try, change the label layout constraints to look like the following instead...
JLabel label = new JLabel(":1234");
gbc.gridy -= 3;
gbc.anchor = GridBagConstraints.NORTHEAST;
add(label, gbc);
Check out Laying out Components within a Container for ideas and details
lines = new char[][]{...};
for (int outter = 0; outter < lines.length; outter++) {
JPanel panel = new JPanel(new GridBagLayout());
for (int inner = 0; inner < lines[outter].length) {
char ch = lines[outter][inner];
JButton btn = new JButton(Character.toString(ch));
btn.setMargin(new Insets(10, 10, 10, 10));
panel.add(btn);
}
add(panel, gbc);
gbc.gridy++;
}

Categories