I'm new to Swing so I read through Java tutorials and API. I've been playing around with a subclass of JComponent (DTPicture-supports drag and drop). Basically I create a panel with a GridLayout. Then I populate the panel with DTPicture objects. DTPicture has inherited getLocation(). Upon calling this however, the value is 0. When I run the GUI however, I see DTPicture objects spanning vertically. So why is getLocation returning 0?
Thanks.
Below is my code:
*everything else has been initialized, declared, implemented.
public class RackBuilderTool extends JPanel{
//maps rack slot # to DTPicture location on JPanel
public static Point[] slotIDArray = new Point[42];
public RackBuilderTool() {
super(new GridLayout(42, 1));
//DTPicture[] rackSlotArray = new DTPicture[42];
for (int i = 0; i < 42; i++) {
//add(new ComponentLabel());
DTPicture temp = new DTPicture(null);
System.out.println(add(temp).getLocation());
//address of DTPicture Component
slotIDArray[i] = temp.getLocation();
}
}
Upon calling this however, the value is 0.
The size (and location) of a component defaults to 0 when a component is created.
When I run the GUI however, I see DTPicture objects spanning vertically
The layout manager(s) are responsible for determining the size/location of a component. However, the layout manager is only invoked when you use pack() or setVisible(true) on a frame.
If you add a component to a visible frame, then you must use the revalidate() method to invoke the layout manager.
Think about it, the layout manager can't do its job until all components have been added to the panel since it will not know how to size every component. Especially in the case of a GridLayout all components are made the same size as the largest component. So how do you know what the largest component is until all components have been added? It would not be very efficient to do the layout every time a component is added.
Related
The only way, as far as I know, to put a JButton or a JLabel is via creating the GUI structure through Containers and placing those components on it.
Are there other methods to add components randomly into the frame and resize accordingly ,as can be done in Visual C# for example? What is the method to do it?
Yes.
You could use a null Layout and then place components using setBounds().
For example:
JPanel panel = new JPanel(null);
for (int i = 0; i < 4; i++) {
JButton b = new JButton("JButton-"+i);
b.setBounds(50+i*10, 50+i*10, 100, 100);
panel.add(b);
}
If you want random placing, you could random the first 2 (x,y) values.
You will need to provide on your own valid values to be placed inside the parent container.
I'm adding a quantity of JTextField to a panel, and all of them are added but, the last one added takes the whole panel and seems all other text boxes added on the last one..... here is the code
public JPanel crearCartonFormulario() {
panel = new JPanel();
panel.setLayout(new BorderLayout());
JTextField[] textBoxes = new JTextField[25];
int cont = 0;
int posX = 10;
int posY = 0;
llenarArreglo();
while (cont <= 4) {
for (int i = 0; i <= 4; i++) {
if (cont == 2 && i == 2) {
textBoxes[i] = new JTextField("");
} else {
textBoxes[i] = new JTextField(String.valueOf(numeros[cont][i]));
}
textBoxes[i].setBounds(i + posX, 15 + posY, 40, 40);
textBoxes[i].setEditable(false);
panel.add(textBoxes[i]);
posX += 50;
}
posY += 50;
posX = 10;
cont++;
}
return panel;
}
This is returned at a panel where I keep multiple panels of this one, it works but in this one the last JTextField takes the whole panel space....
The new JFrame that contains the panels created by the method, adopt the last JTextField size and that text box doesn't take the bounds indicated by the method, but all the other text boxes still inside and correctly added.
panel.setLayout(new BorderLayout());
You are using a BorderLayout.
panel.add(textBoxes[i]);
When you use the add() method the default is to add the component to the CENTER of the BorderLayout. However, only a single component can be added to the center so the layout manager will only manage the size/location of the last component added. The rules of the BorderLayout is to make the component take up all the available space.
However, you have also used the setBounds() methods for the other text fields which is causing a problem. You should NOT attempt to use a layout manager and manage the bounds of the components yourself.
The solution is to just use a layout manager and let the layout manager do its job. Read the section from the Swing tutorial on Using Layout Managers for more information and use a more appropriate layout manager.
Update:
its a bingo table
Then maybe you shouldn't even be using JTextFields. Maybe a JTable would be a better component to use. The tutorial also has a section on How to Use Tables.
Your problem is here:
panel.setLayout(new BorderLayout());
You set the layout to BorderLayout and yet add components to the JPanel as if it were a GridLayout. Understand that when you add components to a BorderLayout-using container in a default way, the components get added in the BorderLayout.CENTER position which fills this position, covering anything added prevsiously.
Perhaps you wish to use a GridLayout instead? You will want to read the layout manager tutorial for more.
This is because you are using BorderLayout and BorderLaout Always requires a parameter like BorderLayout.CENTER, BorderLayout.WEST, BorderLayout.EAST, BorderLayout.NORTH and BorderLayout.SOUTH.
So basically BorderLayout only has 5 position where a component can go. And if you do not specify where when adding a component it defaults to BorderLayout.CENTER. And as there can only be one component at a time in the BorderLayout.CENTER position it only really adds the last one. So I'd suggest an other layout manager like GridLayout( if you want all the components to be equally sized).
I hope this helps :).
P.S. If you want me to give some explination on GridLayout just ask.
Hi I am fairly new to Java. I have JPanel which added other JPanel. The number of the inside JPanel is depend on the list. If the list is delete or add then I remove all inside JPanel and add JPanel according updated list. The inside panel will have different height depend of the data of the list. My problem is the height of the inside panel will change to fit the outside JPanel because of the total amount of inside panel change. I want the height of the inside panel will not be affected when I delete or add the new inside JPanel. I use BoxLayout for the outside panel. Would someone tell me how to solve it. Thanks in advance.
There is the code I add the inside JPanel into the outsider JPanel
jpListCommentPane=new JPanel();
jpListCommentPane.setLayout(new BoxLayout(jpListCommentPane,
BoxLayout.Y_AXIS));
//sortPage
Component[] components = jpListCommentPane.getComponents();
for (Component component : components) {
jpListCommentPane.remove(component);
jpListCommentPane.repaint();
}
sortComment= lstComment;
Collections.sort(sortComment,CommentItem.sortPage);
for(CommentItem comm: sortComment){
DivCommentJPane d=new DivCommentJPane(comm, this);
jpListCommentPane.add(d);
}
jpListCommentPane.revalidate();
There is the screen shot for comparison:
I am trying to write a form in java, but after dynamically inserting JLabels to the current JDialog and doing a pack() the windows is resized to minimum. The JLabels are displayed, but I have to resize the window manually.
Here is the part where the JLabels are inserted:
public void displayQuizz(Test quiz){
int xLable = 44;
int yLable = 41;
int widthLable = 403;
int heightLable = 70;
int noOfQuestion = 1;
for(Question question : quiz.getQuestions()){
JLabel lblNewLabel = new JLabel(Integer.toString(noOfQuestion) + ". " + question.getStatement());
lblNewLabel.setBounds(xLable, yLable, widthLable, heightLable);
contentPanel.add(lblNewLabel);
contentPanel.revalidate();
contentPanel.repaint();
this.pack();
noOfQuestion++;
yLable += heightLable;
}
}
The pack() method sets the size of a Window (where JFrame and JDialog are subclasses from) to the preferred size.
The preferred size is determined by
The LayoutManager, which takes the arrangement of the components and
their preferred size into account
The component itself, if it does not have a layout manager
As you don't use a layout manager in your example (and set the bounds of the label manually), you also have to specify the preferred size yourself (see getPreferredSize(), the default is 0x0, that's the problem you encountered).
I'd encourage you to get used to always use layout managers (there's quite a lot of them, and you can easily write your own layout manager strategy if none suffices your needs).
I have a JScrollPane containing a JPanel. I fill this JPanel with many buttons.
Is there any possibility to get the currently shown buttons?
I know I can access the children of a JPanel via jpanel.getComponents() but those are all components in this pane; I want only the ones that are currently on screen.
As already commented to #mKorbel's answer:
it's correct that you need the child bounds
it's correct that you need to intersect those bounds with "something"
it's wrong that you need the containing viewport (nor the scrollpane)
JComponents have an API to get their currently visible part independently of how/where exactly they are currently shown, so the "something" is the JComponent's visibleRect:
Rectangle visibleRect = myPanel.getVisibleRect();
for (Component child : myPanel.getComponents()) {
Rectangle childBounds = child.getBounds();
if (childBounds.intersects(visibleRect)) {
// do stuff
}
}
I assume that this container is already visible on the screen, then I suggest
1) to extract JViewPort from JScrollPane,
2) addChangeListener to JViewPort
3) each visible JComponent(s) returns Rectangle
4) and Rectangle#intersects returns Boolean value if is JComponent(s) visible or not in JViewPort
How about asking the components if they're visible:
for ( Component component : jpanel.getComponents() ) {
if ( component instanceof JButton && component.isShowing() ) {
// We've found a button that is showing...
}
}
Component#isShowing()
scrollPane.getViewport().getView()
scrollPane.getViewport().getViewRect()