I recently decided to start using GridLayout because FlowLayout seems somewhat amateur. However, I need help. The parameters when creating the GridLayout are (rows,columns,row space,column space). I have a variable for the row amount and 4 for the column amount, but when I try to add a JButton after everything else, there are 5 columns.
Here is my code:
byte i = 0;
while(i < main.componentNum)
{
comp[i] = new JLabel("component #" + (i+1));
box[i] = new JComboBox();
field[i] = new JTextField(5);
edit[i] = new JButton("edit");
comp[i].setBackground(Color.WHITE);
box[i].setBackground(Color.WHITE);
field[i].setBackground(Color.WHITE);
edit[i].setBackground(Color.WHITE);
add(comp[i]);
add(box[i]);
add(field[i]);
add(edit[i]);
i++;
}
When I run the above code, I get four columns and it works fine. But when I add a button to the end, I get five. Can anyone tell me how to give one button an entire row?
From the Java Docs
One, but not both, of rows and cols can be zero, which means that any
number of objects can be placed in a row or in a column.
Now, without your actual code the sets up the GridLayout, it's difficult to say, but, if your after maintaining only 4 columns, I would create a GridLayout as follows, new GridLayout(0, 4)
If you want something more flexible, look into GridBagLayout
Related
I am creating a GUI in java using gridLayout 6 x elevatorNum. My purpose is to create the number of columns based on the user input "elevatorNum" so that it can automatically be expanded. My problem now is that I want to populate each column with the same 6 JLabel fields and then be able to use these fields to change their values whenever I want to.
I am not able to do this since I will have to create a new set of 6 JLabels for each column but for that I would need to either hardcode each column or automatically expand them using user input. I want to automatically expand them using userInput but I don't know how to name each set of 6 JLabels without hardcoding them.
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setLayout(new GridLayout(7,elevatorNum));
JLabel totalFloors = new JLabel("Total floors: " + floorNum);
JLabel currentFloor = new JLabel("CurrentFloor : N/A");
JLabel destFloor = new JLabel("Destination Floor: N/A");
JLabel doorStatus = new JLabel("Doors Status: N/A");
JLabel motorStatus = new JLabel("Motor Status: N/A");
JLabel passengerStatus = new JLabel("Passenger Status: N/A");
JLabel elevatorStatus = new JLabel("Elevator Direction: N/A");
frame.add(totalFloors);
frame.add(currentFloor);
frame.add(destFloor);
frame.add(doorStatus);
frame.add(motorStatus);
frame.add(passengerStatus);
frame.add(elevatorStatus);
Now i want to create another 6 set of JLabels but I will have to use different name but I don't know the userinput so I cannot hardcode the 6 JLabels. I also want to use each set of JLabels later on to update/edit their values.
I would greatly appreciate your help.
I had a similar experience of populating the layout with buttons and need to change their values anytime I want. I think you don't need to have user input to create labels, try simply create JLabels in a for loop, and track them by adding each of them to a List. you could find exactly that label through its index in array.
for example, create a list to track them:
List<JLabel> labelList = new ArrayList<>();
then create a method to create JLabels:
private JLabel createLabel() {
JLabel newLabel = new JLabel("give_it_an_initial_name");
// maybe do something on each label
return newButton;
}
finally add them to frame:
for(int i = 0; i < 6 * elevatorNum; i++) {
JLabel addLabel = createLabel();
frame.add(addLabel);
labelList.add(addLabel);
}
when you want to change something on label, fetch it from list and edit, no need to give each of them a name.It's a very simple way, might not be very good, but it works.
With the Java GridBagLayout why is there a large space to the right of the first JTextField (Labeled A) before the column but the last two JTextField's B and C behave as expected without unwanted spaces between them and how can I eliminate the space?
I've attached an image below to show the problem along with the code.
/* Label digital timer */
gbcRightPanel.gridx = 0;
gbcRightPanel.gridy = 0;
rightPanel.add(labelDitigalTimer, gbcRightPanel);
/* Text Field Hours */
gbcRightPanel.gridx = 0;
gbcRightPanel.gridy = 1;
gbcRightPanel.weighty = 1;
rightPanel.add(jtxtFieldHours, gbcRightPanel);
/* Label colon */
gbcRightPanel.gridx = 1;
gbcRightPanel.gridy = 1;
rightPanel.add(new JLabel(":"), gbcRightPanel);
/* Text Field Minuites */
gbcRightPanel.gridx = 2;
gbcRightPanel.gridy = 1;
rightPanel.add(jtxtFieldMinuites, gbcRightPanel);
/*Colon*/
gbcRightPanel.gridx = 3;
gbcRightPanel.gridy = 1;
rightPanel.add(new JLabel(":"), gbcRightPanel);
/* Text Field Seconds */
gbcRightPanel.gridx = 4;
gbcRightPanel.gridy = 1;
rightPanel.add(jtxtFieldSeconds, gbcRightPanel);
A GridBagLayout works with cells consisting of row/columns.
The first row has a single column. The second row has 5 columns.
So the width of column 1 is the width of the largest component in all the rows of the first column which happens to be your label so you see the extra space.
One way to change this is to have the label take up 5 columns. So before you add the label you need to use:
gbcRightPane.gridWidth = 5;
rightPanel.add(labelDitigalTimer, gbcRightPanel);
gbcRightPane.gridWidth = 1; // reset for the other components.
Now the label will appear above all 5 of the components. You can then determine whether you want the label centered or left justified by specifying an appropriate constraint.
Read the section from the Swing tutorial on How to Use GridBagLayout for more information about the constraints and working examples.
Another approach is to use nested panels. So you can create a separate panel for the text fields and colon labels. Then in the GridBagPanel you add the label and the panel as two separate components.
Read up on the other layout managers from the tutorial to get an idea how each layout manager works to you can effectively nest panels to get the desired layout.
gbcRightPanel.weighty = 1;
Makes the panel have a multiplicator / weigth of 1.0, so any space on x-axis which is left over after all other elements have been placed, go to the first column.
Try to add an fourth column and give this column a bigger weight.
I have a program that at one part demands a user to determine the amount of days per week in 40 weeks (def = 5).
The user firstly fills in the amount of days the 40 weeks will have, to then set the days per week.
Now, I have both JLabel (KEY) and JTextfield (VALUE) stored in a LinkedHashMap,
LinkedHashMap<JLabel, JTextField> weeksMap = new LinkedHashMap<JLabel,JTextField>();
for (int i=1; i<=40; i++) {
JLabel weekL = new JLabel("Week "+i);
JTextField weekF = new JTextField(10);
weekF.setText("5");
//SetWeekAction sWA = new SetWeekAction(mainPane, weekL, weekF);
//weekF.addActionListener(sWA);
weeksMap.put((weekL), weekF);
}
and they will be added to the panel after user sets the total amount of days in the certain year.
EDIT - NOTE: the reason for having these two in a HashMap is I cannot create elements on lick, otherwise I could create infinite labels and text fields and I do not wish to work with buttonpressed=true or such. I need both text fields and labels 'prepared' before the 'click' happens.
for (Map.Entry<JLabel, JTextField> entry : weeksMap.entrySet()) {
index++;
weeksPane.add(entry.getKey());
weeksPane.add(entry.getValue());
}
The GUI view
How do I get the text field of for example 'Week 23'? The for loop goes through the List and adds the Objects correctly, but I have no reference to that certain object anymore.
You can use one ArrayList for storing text field and label text
ArrayList<JTextField> weeks = new ArrayList<JTextField>();
for (int i=1; i<=40; i++) {
JTextField weekF = new JTextField(10);
weekF.setName("Week "+i);
weekF.setText("5");
JLabel weekL = new JLabel(weekF.getName());
weekL.setLabelFor(weekF);
weeks.put(weekF);
}
On update event you can invalidate and redraw weeks panel
I can think of one simple solution of making two separate LinkedHashMap one as LinkedHashMap < integer, JLabel> and another as LinkedHashMap
Now in your loop you can add value in both the LinkedHashMap using the int value from loop as key for JLabel and JTextField while storing them in your both LinkedHashMap.
Since both JLabel and JTextField are now attached with the integer value according to the loop number in which they were created you can access them using those integer value.
Hope this can solve your problem.
i want to ask if anything goes wrong with my code. i've set my frame with borderlayout . and on the center part, i want to use gridlayout with 7rows and 2 cols inside them.
paneltengah= new JPanel();
paneltengah.setLayout(new GridLayout(7,2));
labelname = new JLabel(lbl_name,SwingConstants.LEFT);
labelusername = new JLabel(lbl_username,SwingConstants.LEFT);
labelpassword = new JLabel(lbl_password,SwingConstants.LEFT);
labelgender = new JLabel(lbl_gender,SwingConstants.LEFT);
labelemail = new JLabel(lbl_email,SwingConstants.LEFT);
labelhobby = new JLabel(lbl_hobby,SwingConstants.LEFT);
labelrole = new JLabel(lbl_role,SwingConstants.LEFT);
textname = new JTextField(20);
textusername = new JTextField(20);
textpassword = new JPasswordField(20);
textemail = new JTextField(20);
comboboxhobby = new JComboBox();
comboboxrole = new JComboBox();
radiobuttonmale = new JRadioButton("Male");
radiobuttonfemale = new JRadioButton("Female");
ButtonGroup btngroup = new ButtonGroup();
btngroup.add(radiobuttonmale);
btngroup.add(radiobuttonfemale);
paneltengah.add(labelname);
paneltengah.add(labelusername);
paneltengah.add(labelpassword);
paneltengah.add(labelgender);
paneltengah.add(labelemail);
paneltengah.add(labelrole);
paneltengah.add(labelhobby);
//// paneltengah.add(textname); when i open this, the layout become awkward
//// paneltengah.add(textusername);
//// paneltengah.add(textpassword);
//// paneltengah.add(radiobuttonmale);
//// paneltengah.add(radiobuttonfemale);
//// paneltengah.add(comboboxhobby);
//// paneltengah.add(comboboxrole);
pane.add(paneltengah, BorderLayout.CENTER);
the following pictures is shown without opening the comment
the following picture is shown with uncomment
what is wrong with my code ?
First of all, a GridLayout sizes all components evenly in its associated Container, which explains why your labels and fields are all the same size. For example, if you had a JTextArea 200 columns × 20 lines in your JPanel, then even the tiniest label would occupy that huge a space as well!
Next, according to the GridLayout Javadoc, when a GridLayout instance is constructed with two non-zero arguments, the number of rows gets fixed and the number of columns is adjusted according to the number of components put into the parent Container.
What I suggest is using a BorderLayout to set up your main form layout. Put your title at NORTH and keep the CENTER for your labels and fields (your current JPanel).
For your labels and fields, the simplest solution might be using a GridLayout(0, 2) (fixed number of columns). But all your components will still be equally sized.
If you need more control over the size of your components (e.g., fields wider than labels), then I suggest using another layout manager such as GridBagLayout. I know it's more complex to manage but using a GridBagLayout formatting preview utility should help. Such a program may be named something like GridBagLab (I know David Geary's book Graphic Java volume 2 — Swing features one on its companion CD).
There is also a GridBagLayout tutorial at https://www.youtube.com/watch?v=Ts5fsHXIuvI.
Hello guys and ladies,
as I let the Eclipse WindowBuilder create me a JPanel with a FormLayout, I wanted to make this creation to be dynamical, because the program I'm writing needs it that way in order to avoid 1000 row long from. I used the following code:
JPanel pData = new JPanel();
pData.setBounds(10, 232, 381, 163);
FormLayout fLayout= new FormLayout(new ColumnSpec[]{}, new RowSpec[]{});
int numCols = 5;
int numRows = 10;
for(int i=1;i<=numCols;i+=2)
{
fLayout.insertColumn(i, FormFactory.RELATED_GAP_COLSPEC);
fLayout.insertColumn(i+1, FormFactory.DEFAULT_COLSPEC);
}
for(int j=1;j<=numRows;j+=2)
{
fLayout.insertRow(j, FormFactory.RELATED_GAP_ROWSPEC);
fLayout.insertRow(j+1, FormFactory.DEFAULT_ROWSPEC);
}
pData.setLayout(fLayout);
getContentPane().add(pData);
But starting the program, I get a stack of errors starting with:
"The column index 1 must be in the range [1, 0]"
Changing the index in the for-loop(s) simply changes the number in the middle of this error text, but the rest stays the same.
What am I doing wrong? Is it even possible to create a FormLayout dynamically? I'd really appreciate your help!
Additional Information:
The reason I'm using a FormLayout is the fact, the columns have different sizes. I know GridBagLayout can do so as well, but it needs many more lines and numbers to have the same result concerning insets and position. But if it's the only sensible alternative, I'll accept it ... as long as it's dynamical ;-)
It has to do with how the "insertRow()/insertColumn()" work. To insert something you must already have row/columns to insert in between. You should instead use the ".appendRow()/.appendColumn()" which just add a new row or column at the bottom of any existing rows or to the right of any existing columns.
EX:
int numCols = 2;
int numRows = 10;
for(int i=1;i<=numCols;i++)
{
fLayout.appendColumn(FormFactory.RELATED_GAP_COLSPEC);
fLayout.appendColumn(FormFactory.DEFAULT_COLSPEC );
}
for(int j=1;j<=numRows;j++)
{
fLayout.appendRow(FormFactory.RELATED_GAP_ROWSPEC);
fLayout.appendRow(FormFactory.DEFAULT_ROWSPEC);;
}
this.setLayout(fLayout);
This would add 4 columns(2 default and 2 related gaps) and 4 rows(2 default and 2 related gaps) to whatever already exists.