I'm making a simple GUI where there are multiple JPanels under a GridBag layout manager. The problem is I want to add a drag-and-drop feature by moving around child JPanels under those in the GridBag layout, but for whatever reason it seems setLocation() is not working. I suspect that the layout manager is interfering with this. I don't want to completely take out the layout manager because I need it to help organize the elements, so is there any way to set a number of specific elements to ignore the layout manager?
Just add a new jPanel with a transparent background (if it's not transparent by default use setOpaque(false)) to your GridBag layout, and set its layout to null:
myPanel.setLayout(null);
Also, set its size to an appropriate value, because null layouts by default shrink to nothing with no coordinates.
myPanel.setMinSize(int x, int y);
Any components added to your overlaying jPanel wilL not be affected by a layout and will be able to be moved around freely.
Related
I have two JPanel instances in a JLayeredPane, on different z-orders. I want both of my child JPanels to always fill the space of the LayeredPane.
The idea is for me to toggle the display of a 2nd panel over top of the first to display a modal-like dialog. Yes, I could just use a JDialog, but I thought it would be fun to try and create some transparancy overtop of the covered JPanel for a nice effect.
I find that using a layout manager on the JLayeredPane, like BorderLayout, and trying to set both children to CENTER conflicts since both panels can't be in the Center.
Is there a trick that I'm not seeing?
The idea is for me to toggle the display of a 2nd panel over top of the first
The easiest way to do this is to use a Glass Pane.
Check out the Disabled Glass Pane for an example of this approach.
There are two ways to create some "Glass Panel like" overlay for JPanels with JLayeredPane:
Add a ComponentListener to the JLayeredPane and update the sizes of all child components whenever the size of the JLayeredPane changes
Create a simple FillLayout, which expands the size of its child Components to the size of the Layout Container (In our case the JLayeredPane). You need to keep a list of children Components. During layoutContainer you copy the dimensions of the Container to these child Components. I wrote this and its really simple, but unfortunately I can't post it, since it's corporate. But if anyone is interested just ask in the comments. The implementation basically consists of one-liners.
For both solutions you need to make sure, that the panels on top are transparent, by setting setOpaque to false. This ensures that underlying panels render their content.
In my JPanel, I have 6 buttons laid out in a row (using FlowLayout as of now). The default size of the panel is enough to accommodate these buttons in one row. But, when the frame is resized it gets stuck at the size that is the sum of the minimum sizes of each button.
I need a layout manager that simply puts the buttons in a new row on re-sizing of the panel.
I'm pretty new to Java Swing so I apologize in advance if this is a trivial question.
MigLayout is by far the best layout manager I've ever used. Things that used to require nested containers and lots of hard to understand code can be done in a single container with simple to understand (and maintain) string constraints.
The flow layout is capable of your desired behavior (moving components into new row if they cannot fit). Check out the swing tutorial (run FlowLayoutDemo). You'll have to show us your source code to find out, whether there is some other constrain which prevents it.
FlowLayout does actually paint components on a new row, but the problem is that the preferred size of the panel doesn't change so in many cases you can't see the components (unless you happen to add the panel to the CENTER of a BorderLayout).
One solution is to use the Wrap Layout, which extends FlowLayout to recalculate the preferred size of the panel so that you see the buttons on a new row.
I have a JFrame.
I also have a Box class which extends Component.
This box class has a paint method which makes a filled rectangle.
When I add multiple of these Box components to my JFrame, only the most recently added one is displayed when I call repaint on the JFrame.
I took a look at the layout managers, but I am not sure that's what I want. All I want is to be able to make an animation of whole bunch of rectangles wherever I want on the screen.
(I also tried creating a panel, adding the panel to the JFrame, and then adding all the Box components to the panel. This did not work either).
Thanks in advance!
You have 2 choices.
You can change the layout of your frame:
JFrame frame;
frame.setLayout(new FlowLayout());
Now, if you add more than one box, it will show up on the frame.
The other option is to do what you said you tried. (Adding a panel to the frame)
JPanel pane = new JPanel();
frame.add(pane);
(add the boxes to 'pane')
Also, you should be careful with the sizing of your Box. You will probably want a call to setPreferredSize() somewhere in the creation of the Box. This will tell Java what size to make the box when it is added to the layout.
You should also take a look at the Java Layout Manager Tutorials. There is lots of great info there.
And, one more thing. The reason only one box at a time was being displayed on the frame was because JFrame's layout manager is BorderLayout. And, when you call add on a component that has a BorderLayout, the component is automatically added to the center of the component. Subsequent calls to add will overwrite the center component, leaving only one component in the middle.
You do need to check out other layout managers. JFrame by default uses BorderLayout and without specifying the "place" a component is added, they get added to CENTER. Depending on what you want your UI to look like depends on the layout manager to use. I would suggest maybe using Netbeans GUI builder.
EDIT: Missed the part about what you want to add but the concept is still the same, if you just add these components to the default layout manager, they will get overwritten. Sounds like you may need to do your painting inside of just one of your Box components or create a JPanel and set the layout to null but then you would have to place them explicitly. Really depends on what you want to do with it exactly.
Do your layout on paper first, then read up on Swing layout managers.
Be aware that some Swing components only allow one component to be added to them. I've run across this when using Tabbed panes. Each tab can only accept one control (JPane?) so you have to create a separate panel with a layout to arrange the related controls and then as a unit add the pane to the tab. There are similar arrangements in the Swing library.
You could set the frame layout to null and then use setBounds() to position your boxes exactly where you want.
Thank you for all your answers.
Since I am using my own custom class, Box, I have the ability of setting the position of my the rectangle through the paint method.
I realized my Box class was extending the wrong thing. It should have been extending javax.swing.Jcomponent.
If I now use a panel with an OverlayLayout, add my components to that panel, they all show up properly.
How would I go about making the length of the tabs automatically resize based on how much room is left in that row of tabs.
Picture:
As you can see the tab's width is based off the text in the tab.
If you need me to explain what I want better then just ask me because I don't know if I made it clear enough.
You can use a custom component and set it's preferred size. For example, in ButtonTabComponent of TabComponentsDemo:
label.setPreferredSize(new Dimension(...));
You have to choose an appropriate dimension based on other aspects of your layout, so it won't be automatic.
I want to define a size for the actual tabbed pan.
The size of the JTabbedPane is a function of the dimensions and LayoutManager of the Container to which it has been added. In the example cited, the default layout of the frame's content pane is BorderLayout, and add(pane) adds it to the center by default.
To accomplish your goal, I see two approaches:
Divide the current width of the enclosing Container among the existing tabs and repaint the tabbed pane, as shown in this example.
Develop your own implementation of TabbedPaneUI and interpret SCROLL_TAB_LAYOUT accordingly.
In which Swing layout manager it is possible to change layout areas programmatically? And how to do this with lowest cost?
I have to create component with functionality similar to JSplitPane but with three panels from scratch. One of the moments is to Expand/Collapse one of the panels after clicking oneTouchExpandable button on the divider. But the problem is that I don't know how to implement this collapse action. I tried just setting panels width to 0, but the layout area which contains this panel doesn't shrink after the component. I tried to do this in all Layout Managers, but effect is the same.
Thanks.
When making a change that affects the layout of a panel after the GUI is visible you need to revalidate() the panel which essentially invoke the layout on the panel. In your case it might be easier to simply make the component invisible:
component.setVisible(false);
panel.revalidate();
panel.repaint(); // this is only required sometimes
All layout managers resize dynamically. However, the width and height properties are the result of the layouting, and will be overwritten.
The properties you should look at are preferredSize, minimumSize, and maximumSize - the layout managers base their calculations on those properties, though the exact effect depends on the layout manager (e.g. BorderLayout will give the NORTH, SOUTH, WEST and EAST components their preferred size if possibe and assign the remainder to the CENTER component).
Once you've changed the size properties, you have to call revalidate() on the container, then you should see the changes.
I'm with the revalidate()/preferredSize answers but just wanted to suggest this: don't re-invent the wheel! Use the JideSplitPane (part of JIDE's free "Common Layer") - it supports more than two splits.
Thanks to all for the answers. Finally I ended up with combining solutions from several answers.
My final solution is following:
I use BorderLayout, set West, Center and East panels and then manipulate their sizes by setting PreferredSize to West and East panels. The scheme of rendering is following: while laying out the components BorderLayout gives East and West panels their PreferredSize and rest of the space to Center panel. So with a bit of easy calculations I can manipulate size of each of three panels painlessly.
I also added dividers(originally just JPanel components with fixed size) to West and East panels(their size is also considered while calculating). For dynamic resize I handle dragging events on this dividers and recalculate panel sizes.
Refreshing is done with following snippet:
container.setVisible(false);
container.revalidate();
container.repaint();
container.setVisible(true);
I'd like to put this code somewhere to be available for others, but don't know where exactly to do this. So if you know such place, please point me to it in the comments.