I created a Class that extends from JPanel which layout property is GridBagLayout. I basically need to display an array of JLabels (grid) but i'm not able to replace a component once it's created. I've tried to remove the component that I want to change, and then place the new one but the result is weird. For example i've created an array of 10x10 JLabels and want to replace position[0][0] and position[9][9] with this code:
//At first i have the jpanel layout completely filled
this.remove(0);
this.add((JLabel) start, 0); //This was created with GridBagLayout.gridx = 0 and GridBagLayout.gridy = 0 and it's fine
this.remove(99);
this.add((JLabel) end, 99); //This was created with GridBagLayout.gridx = 9 and GridBagLayout.gridy = 9 and it's out of grid
this.revalidate();
But only position[0][0] looks fine. What should i do to replace a component?
In GridBagLayout, each component is associated with GridBagConstraints. Simple removing a component and replacing it with a component at the same position won't work, as the new component will receive a new GridBagConstraints
What you can do, however, is get the constraints associated with a give component.
Component toRemove = getComponent(0);
GridBagLayout layout = (GridBagLayout)getLayout();
GridBagConstraints gbc = layout.getConstraints();
remove(toRemove);
add(new JLabel("Happy"), gbc, 0);
This will add the component using the same constraints as those used by the component you are removing.
This of course all assumes that you are assigning the gridx/gridy constraints...
I solve my problem by using:
this.setComponentZOrder(newItem, 0);
So, I actually didn't remove the object on Jpanel but I placed the new one over the old object.
Related
I am trying to create a program that sets JLabels, use the GridBagLayout.
I want to create a button that when pressed removes everything from a certain gridY location. How do I do this. Thanks.
Simple. When you add these components to their parent container keep them in a structure (maybe a List). Something like:
JPanel container = new JPanel(new GridBagLayout());
//...
List<Component> components = new ArrayList<>();
// Add components to container and to list...
for (Component c : components) {
container.remove(c);
}
container.revalidate();
container.repaint();
The Container class has a method getLayout(). This will allow you to get the GridBagLayout instance for your panel.
The Container class also has a method getComponents()
So once you get all the components in an array you iterate through the array. For each component you would:
Use the getConstraints() method of the GridBagLayout.
Then check the gridy value of the GridBagConstraints object to see what row the component is in.
Remove the component from the panel if it meets your criteria.
After the loop is finished you invoke revalidate() on the panel.
I have a JPanel that contains a bunch of small icons, and a JLabel containing a bigger icon.
First of all, I need clarification on something. By not setting panel.isOpaque, the said panel would have a transparent background and would properly overlap the icons of my JPanel and JLabel. Is this true?
Now to my problem. I've been following the LayeredPanes tutorial on the Oracle website, and I can't seem to make it right on my case.
JFrame window = new JFrame();
ImageIcon underIcon;
URL urlUnder = myClass.class.getResource("images/underImage.gif");
underIcon = new ImageIcon(urlUnder);
JLabel labelUnder = new JLabel(underIcon);
ImageIcon panelIcon;
URL urlAbove = myClass.class.getResource("images/aboveImage.gif");
panelIcon = new ImageIcon(urlAbove);
JLabel aboveIcon1 = new JLabel(panelIcon);
JLabel aboveIcon2 = new JLabel(panelIcon);
JPanel panelAbove = new JPanel(new BorderLayout());
panelAbove.setOpaque(false);
panelAbove.add(aboveIcon1, BorderLayout.WEST);
panelAbove.add(aboveIcon2, BorderLayout.EAST);
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setLayout(new BorderLayout());
layeredPane.add(labelUnder, BorderLayout.CENTER, 1);
layeredPane.add(panelAbove, BorderLayout.CENTER, 2);
layeredPane.setOpaque(true);
window.setContentPane(layeredPane);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.pack();
window.setVisible(true);
I only see the contents of the panel. And I'm 100% sure the images are there on getResource, so that's not the issue. Please advice on how to properly use Layered Panes.
The problem is you are setting a layout manager to the JLayeredPane
layeredPane.setLayout(new BorderLayout());
In of it self, this is not a problem, but your choice of layout manager is.
BorderLayout will only a single componet to occupy any of it's 5 predefined positions. This means when you add your second component, it, effectively, replaces the first.
Try using someone like GridBagLayout instead. Providing a single GridBagConstaint set so that the weightx/y values ara equal to 1, the fill property is set to BOTH and it's gridx/y properties are set to 0
Unlike BorderLayout, GridBagLayout will allow you to layout components to the same position
From the Java Tutorial:
layeredPane.add(dukeLabel, new Integer(2), 0);
This code uses the three-argument version of the add method. The third argument specifies the Duke label position within its depth, which determines the component's relationship with other components at the same depth.
Positions are specified with an int between -1 and (n - 1), where n is the number of components at the depth. Unlike layer numbers, the smaller the position number, the higher the component within its depth. Using -1 is the same as using n - 1; it indicates the bottom-most position. Using 0 specifies that the component should be in the top-most position within its depth. As the following figure shows, with the exception of -1, a lower position number indicates a higher position within a depth.
So your depth orders are the wrong way around, also start from 0.
I also found this in the Solving Common Component Problems Section
Problem: The components in my layered pane are not layered correctly. In fact, the layers seem to be inversed — the lower the depth the higher the component.
This can happen if you use an int instead of an Integer when adding components to a layered pane. To see what happens, in the LayeredPaneDemo class, change
layeredPane.add(label, new Integer(i));
to
layeredPane.add(label, i);.
ive got a JPane within a JScrolledPane. When i add content to JPane , JScrollPane doesnt show scrollbar. I tried repaint() and revalidate() but it didnt help.
static void ladowaniePaneli()
{
int b;
for(b=0;b<o;b++)
{
bgPanel[b] = new JBackgroundPanel();
nowyPanel[b] = new JPanel();
((FlowLayout)bgPanel[b].getLayout()).setVgap(0);
nowyPanel[b].setPreferredSize(new Dimension(790,518));
nowyPanel[b].setOpaque(false);
vertical[b] = new JScrollPane(nowyPanel[b]);
vertical[b].setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
vertical[b].setPreferredSize(new Dimension(789,517));
vertical[b].setOpaque(false);
vertical[b].getViewport().setOpaque(false);
bgPanel[b].add(vertical[b]);
}
}
It makes sense that scrollbars are never seen since you restrict the size of the contained component so that it's always trivially larger than the scrollopane's viewport:
nowyPanel[b].setPreferredSize(new Dimension(790,518));
Solution: don't do that.
if i dont use setPreferredSize method components wont warp to another line
You can try the Wrap Layout.
pairs should be warped to new line if they exceed JScrollPane width
Components are layed out individually. I you want a group of components to wrap then you would need to add the components to a separate panel first. Then add the panel to the panel using the WrapLayout.
I need to display account names for my program and I want to do this using JTree inside a JScrollPane.
Here is my code:
public void loadAccounts() {
accountsRoot = new DefaultMutableTreeNode("Accounts"); //create root
accountsRoot.add(new DefaultMutableTreeNode("Fred")); //add one element
//for testing
accounts = new JTree(accountsRoot);
accountsPane = new JScrollPane(accounts);
accountsPane.add(accounts); //don't think this is necessary
canvas.add(accountsPane);
accounts.setBounds(0, 0, accountsPane.getWidth(), accountsPane.getHeight());
accountsPane.setBounds(460, 270, 240, 410);
accounts.setVisible(true);
accountsPane.setVisible(true);
}
Because I am not using a layout I set the bounds manually.
I can't seem to get it to show. I want to eventually end up loading the accounts from a while so I figure JTree would be pretty easy for that,
accountsPane = new JScrollPane(accounts);
accountsPane.add(accounts); //don't think this is necessary
Not only is that not necessary but it will mess things up as this in effect adds your accounts JTree to multiple containers -- to the JScrollPane's viewport (good) and to the JScrollPane itself (bad). Don't do that. Add it to the JScrollPane's viewport only either through the JScrollPane's constructor as shown on the first line above, or by calling setViewportView(...) on the JScrollPane object after creating it.
Edit: another problem is your use of setBounds(...). You shouldn't be doing this but rather should be using layout managers to allow the proper viewing of your components. You will also need to call revalidate() and repaint() on whatever container is accepting the JScrollPane.
I'm working on a little applet that has a list of items in a JScrollPane on the left.
the user will be able to add and remove elements from this list.
therefore I need to create a scrollable list.
this part is easy.
I'm usually tempted to do most of the GUI resizing by hand but I read in the doc of the JScrollPane that it is better to let swing handle it rather than manually changing the dimension.
the problem is that I keep adding element and the inside panel doesn't change size.
any ideas?
here is some of the code I'm using:
constructor:
public SideBarView(Dimension d) {
super(d);
Dimension d2 = new Dimension(100,300);
this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
//INSIDE VIEW (zone that is being scrolled)
container = new SideBarContainer(d2);
// container.setSize(d2);
// container.setPreferredSize(d2);
// container.setMaximumSize(d2);
// container.setMinimumSize(d2);
scrollPane = new MyJScrollPane(container);
new ImageLoaderWorker(this,menuButton).execute();
Dimension d3 = new Dimension(d.width, d.height-d.width);
scrollPane.setSize(d3);
scrollPane.setMaximumSize(d3);
scrollPane.setMinimumSize(d3);
scrollPane.setPreferredSize(d3);
add(scrollPane,BorderLayout.PAGE_START);
setBorder(BorderFactory.createEmptyBorder());
}
Adding to container:
element = new JPanel();
Dimension d2 = new Dimension(100,100);
element.setSize(d2);
element.setPreferredSize(d2);
element.setMaximumSize(d2);
element.setMinimumSize(d2);
element.setBackground((panelcount++%2==0)?Color.BLUE:Color.RED);
cointainer.add(element);
any idea what I'm missing ? or should I just resize the container by hand as I go along?
You need to tell the container to lay out the components. This is done by revalidating the panel:
container.add(element);
container.revalidate();
panel.setSize(d2);
panel.setPreferredSize(d2);
panel.setMaximumSize(d2);
panel.setMinimumSize(d2);
This let's no option to resize for swing, since you tell the layout manager to use exactly the size of d2 (100/100).
Try without setMaximumSize and setPreferredSize. You might need to invalidate the panel or scrollpane after adding/removing content as well.
Edit:
I think I considered panelto be your containter. Could you provide the setup code for your scrollpane and the container?
Did you set a layout manager for the container?
Another possibility, if you don't have to do it yourself, could be to use some SwingX component (like TaskPane etc.). Unfortunately, they seem to be in a transition over to java.net and thus many resources are not available as of now. However, there's a basic download page.