I am having problems with the gridbag layout, I am trying to get the images to be on one line horizontally, however when I add images to the left of the original one, it will go down vertically instead of going horizontally to the left.
I have tried to specify the gridY to be the same, however this did not work, also I have tried the GridBayConstarints.Horizontal however that was irrelevant.
So far I have
import java.awt.GridBagConstraints;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
public class main {
public static void main(String[] args)
{
GUI g = new GUI();
int turnCounter = 1;
for(int i = 0; i<6; i++)
{
String image = "src/resources/bone"+0+i+".png";
GridBagConstraints c = new GridBagConstraints();
//ADDS IMAGE TO THE LEFT
if(turnCounter%2 == 0)
{
c.gridy = c.gridy;
c.gridx = c.gridx-1;
ImageIcon icon1 = new ImageIcon(image);
JLabel label1 = new JLabel((ImageIcon) icon1);
g.add(label1,c);
g.revalidate();
turnCounter++;
}
//ADD IMAGES TO THE RIGHT
else if(turnCounter%2 == 1)
{
c.gridy = c.gridy;
c.gridx = c.gridx+1;
ImageIcon icon1 = new ImageIcon(image);
JLabel label1 = new JLabel((ImageIcon) icon1);
g.add(label1,c);
g.revalidate();
turnCounter++;
}
}
}
}
What the image looks like at the moment.
The [2|0] and [3|0] should be to the left of [0|0] in that order so it will look like this
[4|0][2|0][0|0][1|0][3|0][5|0] all in one line.
The code you used for putting things to the right is correct, but as the default value of gridx is 0, what you are doing when you try to add a component to the left is giving a value to gridx of -1, an incorrect value for gridx, seems like the problem is there.
The solution I can give right now, is making an array with a lenght of how many images you want to display, in this case it would be a:
int yourLenght = 5; //Sounds dirty lol
JLabel[] yourArray;
yourArray = new JLabel[myLenght]
After this, only select the place of the array where you want to place it, I would recommend it in the middle.
Why does this work?
Now your images can only be on the 5th or 1st column (gridx = 0), but not on -1, altough we haven't finished yet, if you leave it like this, and you add or quit one to "yourLenght" your images could only be placed on the 2nd column or the 4th one, cause you can only add or quit one to 3. To avoid these what we are going to do is declare another int.
int magicInt = 1;
And then after each component is added we will add 1 to the "magicInt" value.
//You already added the object rather on the left or on the right
magicInt++;
And that way each time you add an object you can advance one place to the left or to the right more.
Notes:
1-Anchors won't work if you don't give a value to weighty. You can read more about these variables here.
2-I discourage using
c.gridy = c.gridy;
If you are only going to use that loop for adding things on one row, better use:
c.gridy = 0;
That way your code is easier to read.
3- Solution listed above only works if objects are added consitently with the following pattern : left, right, left, right... or right, left, right, left...
(It was a quick solution, but you will find your solution just think...)
Hope, this helped you, if you have any doubts don't mind commenting that way I can help :)
Related
To start with -- I'm not sure, that I have properly formulated the question (I'm new in Java and in making programs with GUI).
It is the following thing, I'm trying to do. I have a window with several similar parameters (numbers are just for distinction between lines and it ist just very simplified example, of what should my GUI be):
Initial Window
Then, by clicking on the "+"-button I would like to add an new line, like here:
Line 35 is added
It should be also possible to delete lines, like here: Line 30 was deleted, by pressing "-"-Button.
As I wrote at the beginning, it is possible, that there was such a question, but I couldn't find anything (probably, because I do not now the keywords or I was looking with a wrong ones).
How such window can be done? The only idea I have is to draw a new window after every +/-.
Addition: Code (not working in the part of changing the number of rows).
import javax.swing.*;
import java.awt.event.*;
public class Test extends JFrame {
public Test() {
setSize(200, 600);
JButton plusButton[] = new JButton[100];
JButton minusButton[] = new JButton[100];
JTextField fields[] = new JTextField[100];
JPanel panel1 = new JPanel();
for (int i=0; i<plusButton.length; i++) {
plusButton[i]=new JButton("+");
minusButton[i]=new JButton("-");
fields[i] = new JTextField("Text "+ i);
}
for (int i=1; i<4; i++) {
panel1.add(plusButton[i*10]);
plusButton[i*10].setActionCommand("add after " +String.valueOf(i));
panel1.add(minusButton[i*10]);
minusButton[i*10].setActionCommand("remove " +String.valueOf(i));
panel1.add(fields[i*10]);
}
panel1.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
this.getContentPane().add(panel1);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
for (int i=0; i<100; i++) {
String stand1 = "add after "+String.valueOf(i);
String stand2 = "remove "+String.valueOf(i);
if (stand1.equals(e.getActionCommand())) {
//add "row" of elements
panel1.add(plusButton[i]);
plusButton[i+1].setActionCommand("add");
panel1.add(minusButton[i+1]);
minusButton[i+1].setActionCommand("remove");
panel1.add(fields[i+1]);
} else if (stand2.equals(e.getActionCommand())) {
//delete "row" of elements
}
}
}
public static void main(String[] args) {
Test a = new Test();
}
}
The Problem, that is obvious -- when I want to add 2 rows (i think it is proper definition) of buttons after button 20, there will be an doubling of numbers. As a solution I see here a creation of a new panel for each new row. But it is sounds wrong for me.
P.S. Unfortunately I do not have time to end this topic or to post a working example. I actually found some kind of solution, beginning from the Question here, on Stack Overflow:
Adding JButton to JTable as cell.
So, in case somebody will be looking for such topic, it should sounds like "jButton in jTable".
There are multiple GUI frameworks for Java. First decide which one you wanna use.
As for your particular query
Add functionality to the + and - such that it will create an instance of a field object (that line with parameters as you call them) or destroy that particular instance of the object.
+ is clicked -> Create new object on consecutive line and increase the pointer-count(?) of the following fields.
- is clicked -> Call destructor for the particular object and decrease the pointer-count of the following fields.
I had my layout perfect until I couldn't figure out how to make drag and drop work. So to make the coding easier, I switched my labels on the bottom right side of my program to buttons to allow single clicking to generate an object in the main panel.
Now that I switched them, using BoxLayout, the buttons are not able to be sized for the image to fit perfectly in them, leaving edge space as seen in the photo. I also have a horizontal scroll bar now which I didn't have before with the labels.
I have tried several different layouts to try and fix the size of these buttons, but I can't get things to work right. I just need a vertical scroll bar and I want the buttons to be the exact size of the images, like they are in the panel above them. I tried setting the layout to null like I have in all the other panels and using the setBounds() method and that works perfectly for placement, but then the scroll bar disappears and won't scroll.
Anyone have any suggestions?
Edit: Here is what happens when I use the null layout.
I'd really recommend that you use GridBag layout if you're using swing. The other layouts leave a lot to be desired. It is all a matter of preference and you can lay it out manually if you want--there's no right answer.
The reason I prefer GridBag (or MigLayout--to each their own) is that you have a concept of preferred size for the component and the concept of fills. It has been a while since I coded up Swing (and I'll try to keep it that way!) but you're basically looking for something like:
{
//Pseudo Code, I'd have to go read the API again, I wrote a set of utilities so I wouldn't have to think about it.
GridBagConstraints constraints = ....;
constraints.weightX = 1.0; //fill the area by X
constraints.weightY = 1.0; //fill by Y
constraints.fill = GridBagConstraints.BOTH; //or one...
component.setPreferredSize(image.size());
layout.add(component, constraints);
}
Basically what you're doing is saying "use my preferred size as a minimum" but fill based on these rules.
The alternative--which doesn't use a layout is simply position the components yourself (there's absolutely nothing wrong with this).
{
JPanel panel =...;
panel.setLayout(null);
...
myButton3.setX(0);
myButton3.setY(2 * buttonHeight); //third button
myButton.setSize(myButton.getPreferredSize()); //which I assume you set
...
panel.add(myButton3);
...
}
Anyhow, there's a lot of options. Don't feel like you need to use a layout, write your own. You should care about these things and make it work but you shouldn't suffer. A layout is generally very simple to implement and you shouldn't be afraid to walk away from this.
All that said, GridBag will do what you want. Alternatively, Mig is great and has some nice GUI editors.
UPDATE -> -------------------------------
Here's a concise example--I sincerely do not advocate this style of programming, I just didn't want class spam for the example.
package _tests;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Grids extends JFrame
{
private static final long serialVersionUID = 1L;
public static void main(String ... args)
{
new Grids().setVisible(true);
}
public Grids()
{
//Null layout example
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(250, 300);
setMinimumSize(new Dimension(285, 300)); //Windows 8 ~ border size + scrollbar
setTitle("Test layouts");
JPanel scrollTarget = new JPanel()
{
private static final long serialVersionUID = 1L;
{
setSize(250, 1000);
setPreferredSize(new Dimension(250, 1000));
//setLayout(null); -- uncomment for absolute
setLayout(new GridBagLayout());
int lastX = 0;
int lastY = 0;
for(int i = 0; i < 5; i++)
{
final String label = "Button " + i;
JButton tmp = new JButton()
{
private static final long serialVersionUID = 1L;
{
setText(label);
setPreferredSize(new Dimension(250, 200)); //Preferred
}
};
tmp.setSize(tmp.getPreferredSize()); //What you're layout usually does..
//add(tmp);
//tmp.setLocation(lastX, lastY);
//lastY += tmp.getHeight();
add(tmp, getButtonConstraint(0, i));
}
}
};
add(new JScrollPane(scrollTarget));
}
private GridBagConstraints getButtonConstraint(int x, int y)
{
GridBagConstraints tmp = new GridBagConstraints();
tmp.fill = GridBagConstraints.BOTH;
tmp.weightx = 1.0;
tmp.weighty = 1.0;
tmp.gridx = x;
tmp.gridy = y;
tmp.anchor = GridBagConstraints.NORTHEAST;
return tmp;
}
}
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.
I have a small question for you, I have this JScrollPane I am working on, and it only expands in width. But instead, I would like it to expand in height.
private void setImageLibPanel() {
ExtraScrollPanel = new JPanel();
MidLeftPanel.removeAll();
if (project.getImgCount() > 0) {
for (int i = 0; i < project.getImgCount(); i++) {
JLabel temp = new JLabel();
ImageIcon tempIcon = project.getNextImage();
temp.setIcon(tempIcon);
ExtraScrollPanel.add(temp);
}
}
JScrollPane imageLibScrollPane = new JScrollPane();
imageLibScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
imageLibScrollPane.setAutoscrolls(true);
imageLibScrollPane.setViewportView(ExtraScrollPanel);
MidLeftPanel.add(imageLibScrollPane, BorderLayout.CENTER);
How can I do this?
With regards,
Black Magic
Use standard Java naming conventions. Variable names should not start with an upper case character.
You are adding JLabels to a JPanel. A JPanel uses a FlowLayout by default.
Instead I would use a JList. Add the icons the list. See How to Use Lists for more information.
In the future post a proper SSCCE when you ask a question. You have been given this advice before. Next time I will not read your question unless a SSCCE is posted.
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