I'm using a FlowLayout JPanel. The panel looks ugly when child component heights are different. I'm looking for a solution to make them top-align (similar to valign="top" with table cells in HTML).
I realize this question was asked over a year ago, but like me, I thought many would stumble across this forum post and be left attempting to make a workaround like that one suggested in the bug report (failed to work for me just fyi).
Either way there is a better answer since JDK 1.6. Flowlayout has the following method:
public void setAlignOnBaseline(boolean alignOnBaseline)
If you use this method on your flowlayout and set it to true, then when flowlayout lays out the components it will check each component's baseline and align the component along this baseline.
But that's not all you need to do.
The component in question must override the following two methods in this way:
#Override
public Component.BaselineResizeBehavior getBaselineResizeBehavior() {
return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
}
#Override
public int getBaseline(int width, int height) {
return 0;
}
They are methods in JComponent and layouts and layoutmanagers use these methods to determine how to layout the component.
If you take the steps mentioned above all the components will align themselves along the top of each row. Of course if you just want to use a component like JButton you will obviously have to extend it in order to achieve your desired goal... but it's not as much work as overriding layoutcontainer with a workaround that you have to debug. At least I think so.
Good luck,
-Asaf
Someone else has wished for this, in the form of a bug-report (which also lists a workaround).
Have a look at
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4295966
You should be able to use a BoxLayout. It supports vertical alignment. The only problem is you need to manually insert horizontal strut components.
Or you could try using the Relative Layout. In your case you would use:
RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS, 5);
rl.setBorderGap(5);
rl.setAlignment(RelativeLayout.LEADING);
JPanel panel = new JPanel( rl );
panel.add(...);
Related
Is there any thing I can do to make my JPanel pack like a JFrame, or do something like that. I want to do this instead of giving it dimensions. Please comment if any addition info is needed. Thanks.
Please try JPanel.updateUI and let me know if that helps.
You should make GUI calls in the Event Dispatcher Thread:
EventQueue.invokeLater(() -> {
someJPanel.updateUI();
});
If I understand you correctly, your JPanel is not being automatically (re)sized, correct? In that case, you can use Component.validate (or JComponent.revalidate())
Let me explain my use case, so that my answer will make sense.
I have a game board G on which I am absolutely positioning tiles Ts and some other property panels say P, Q and R.
Only the Game board G doesn't use a layout. However, for all the tiles and other panels, I do want to use layout management. For the
tiles, I want to calculate and set both position and size based on how many tiles are there. So, the setBounds method works great.
The problem is with the other panels like P where I know the x and y where I want to place them, however, I would like it if they figured out their own preferred sizes. This becomes a problem because setBounds insists on setting both position and size, and setLocation doesn't seem to work.
The solution which worked for me is putting a slightly oversized panel Outer-P and setting opaque to false and then placing P inside it. Note that Outer-P has a layout manager which allows P to be its preferred size. Personally, I used new MigLayout("insets 0","[]","[]") which lets the child take its preferred width and height.
As far as the user is concerned, P is in the top left, and looks packed. The wrapper panel is invisible.
I am having quite a problem in regards to a proper way to handle 'packing' a JPanel and allowing a scroll bar.
I left out a bit of the code, but I believe what is provided should suffice.
The issue, is that the JScrollBar either doesn't show up, or can't be interacted with (if I set the scroll bar to always have the vertical bar).
Here is an image depicting this:
![No Scroll Bar Present][1]
The ProjectPanel (extends JPanel) are of fixed size and, as you can see, extend farther than the visible view port. There is NO way of getting the calculated height of the JPanel (ProjectSelector), as the ProjectPanels can also be transitioned as so:
![They need to fill as a grid][2]
If anyone could help provide some insight on how to do this, that would be great. As of now, I would like at all costs not to use an external API, as that would cause more harm than good.
Question:
How can I set the height for the preferred size to be 'flexible', so as I add components it can expand? If that wouldn't be ideal / no possible, how could I properly allow the JScrollPane to show all components of the JPanel efficiently?
if I do not, then the Flow Layout organizes them horizontally
Maybe you should be using a GridLayout.
If not then you can try the Wrap Layout which is a FlowLayout that wraps to a new line as required.
If you are looking for a different layout, why don't you try MiGLayout? It is a very powerful and flexible layout manager.
See a detailed example here.
From that link, rewrite the initUI method to see the behavoir interesting to your problem:
public void initUI() {
this.setPreferredSize(new Dimension(100, 100));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setJMenuBar(initMenuBar());
this.getContentPane().add(new JScrollPane(mainPanel = initMainPanel()));
this.setLocationByPlatform(true);
this.pack();
}
I need solution similar to GridLayout but without resizing components in JPanel.
Everything works great with JFrame, but I need to put those components into JPanel instead JFrame.
I've seen two approaches that may suit your requirement:
Nest each component in a JPanel having FlowLayout, which respects the component's preferred size, as shown here.
Use the HORIZONTAL_WRAP or VERTICAL_WRAP orientation of JList, as shown here.
The following link might help you to choose the most appropriate layout for your needs. Its the Java Tutorial called "A Visual Guide to Layout Manager", which shows nice pictures of each layout and what they look like...
http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
Otherwise, if you say GridLayout is similar to what you need, you could always write your own MyGridLayout class (that extends GridLayout) and overwrite the method that does the autoresizing.
I stumbled upon this question myself and even though I think using z JList might be a good solution, there's an even simpler way of doing it with a customized FLowLayout, called WrapLayout, available here: https://tips4java.wordpress.com/2008/11/06/wrap-layout/
I ended up using it in my project and it works very well. The only issue I run into is when I set my window to the full screen mode the layout did not update correctly. I used a simple workaround, which was this:
//int targetWidth = target.getSize().width;
int targetWidth = target.getParent().getSize().width; // FIXME: this is a hack for getting the correct size when switching between full screen modes on Mac
With that small hack it works perfectly.
Just Override preferredLayoutSize() in flowlayout and set Maximum size to it. set Alignment as LEADING and set it to your JPanel. You'll get what you want
private FlowLayout getFlowLayout(int maximumSize)
{
if (flowLayout == null)
{
flowLayout = new FlowLayout()
{
#Override
public Dimension preferredLayoutSize(Container target)
{
Dimension dimension = super.preferredLayoutSize(target);
dimension.width = Math.min(maximumSize, dimension.width);
return dimension;
}
};
flowLayout.setAlignment(FlowLayout.LEADING);
}
return flowLayout;
}
I'm trying to get the Layout of a JDialog of mine to fit a particular look that a program in which I'm porting to Java has, I've used several LayoutManagers before with great success yet for some reason I cannot seem to get this working at all. My goal is to have the Right (East) side of the JDialog contain a "Find Next" and "Cancel" button in a top-down order and then any extra space below so that the two buttons are always at the top of the JDialog, yet for some reason BoxLayout is continously ignoring any attempts at changing (this is where I'm lost) the width of a JButton. Code follows.
JButton findNext = new JButton("Find Next");
JButton cancel = new JButton("Cancel");
cancel.setPreferredSize(new Dimension((int)findNext.getPreferredSize().getWidth(),
(int)cancel.getPreferredSize().getHeight()));
JPanel example = new JPanel();
example.setLayout(new BoxLayout(example, BoxLayout.Y_AXIS));
example.add(findNext);
example.add(cancel);
example.add(Box.createGlue());
No matter what I try, cancel always retains it's normal size. I've tried setMinimumSize() and setMaximumSize() with the same parameters as setPreferredSize with no luck. I've even tried cancel.setPreferredSize(new Dimension(500, 500)); and the buttons height was the only thing adjusted, it STILL retained the default width it was given.
To clear up any questions, here is what it looks like (now that I've finished it) and you'll see that the "Find Next" and "Cancel" buttons are not the same size.
I know this is an old question but I don't really see a good explanation. So for the sake of searchers that stumble upon this I will add my two cents.
There are three methods associated with sizing components in Swing: setPreferredSize(), setMinimumSize(), and setMaximumSize(). However, the important point is that it is up to the particular layout manager being used as to whether or not it honors any of these methods.
For BoxLayout (the layout the original poster is using):
setMinimumSize() -- BoxLayout honors this
setMaximumSize() -- BoxLayout honors this
setPreferredSize() -- if X_AXIS is being used width is honored, if Y_AXIS is being used height is honored
The OP is using a Y_AXIS BoxLayout which is why only his height was being changed.
Update: I put together a page with this same information for all of the layout managers. Hopefully it can help some searchers out: http://thebadprogrammer.com/swing-layout-manager-sizing/
You may not want Box.createGlue(), which "grows as necessary to absorb any extra space in its container." Instead, use Box.createVerticalStrut() between the buttons, as shown below and in the ControlPanel of this simulation.
example.setLayout(new BoxLayout(example, BoxLayout.Y_AXIS));
example.add(findNext);
Box.createVerticalStrut(10);
example.add(cancel);
Addendum:
adding in setMaximumSize() made it work.
This is the expected behavior for components having identical maximum widths in a vertical BoxLayout, as described in Box Layout Features. The preferred width of the container becomes that of the (equally wide) children, and the X alignment becomes irrelevant.
example.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JButton findNext = new JButton("Find Next");
JButton cancel = new JButton("Cancel");
Dimension d = findNext.getMaximumSize();
cancel.setMaximumSize(new Dimension(d));
example.add(findNext);
example.add(cancel);
As mentioned in the comments on the question, you were able to fix it by switching to setMaximumSize(). However, as you noted, setPreferredSize() doesn't work. So, what's up with that?
With many things Swing, the properties used to determine the actual component size when using the BoxLayout are somewhat random (in my opinion). When determining how to render the components, Swing calls layoutComponent() on the layout manager, which is figures out where to position everything.
BoxLayout's implementation of layoutComponent() involves a call to a method that creates SizeRequirements objects for the width and height of each of the components you add to the JPanel, based on their getMinimum/Preferred/MaximumSize() methods.
Later, it calls SizeRequirements.calculateAlignedPositions() for determining the correct width values for each component, because your orientation is BoxLayout.Y_AXIS (The heights are calculated using a different method). Taking snippets from the source, the relevant implementation of this method is as follows:
for (int i = 0; i < children.length; i++) {
SizeRequirements req = children[i];
//...
int maxAscent = (int)(req.maximum * alignment);
int maxDescent = req.maximum - maxAscent;
//...
int descent = Math.min(totalDescent, maxDescent);
//...
spans[i] = (int)Math.min((long) ascent + (long)descent, Integer.MAX_VALUE);
}
Note that totalDescent is the available width, so descent is always set to maxDescent, which is based on SizeRequirements.maximum, which was taken from JButton.getMaximumSize(). The value of spans[i] is then used later in a call to JButton.setBounds() as the width. As you'll note, getPreferredSize() was never involved here, which is why setting it has no impact in this case.
Usually if want to ensure a size of the component in Swing you need to call setMinimumSize(), setMaximumSize(), and SetPrefferedSize() with the same value.
button.setMaximumSize(getMaximumSize());
If you put your buttons in a GridLayout panel they will be the same width.
Is there a simply layout manager I can use in a JPanel to create something akin to a bar chart? FlowLayout almost meets this need. The added component orientation needs to be left to right (default for FlowLayout), but they need to "rest" on the bottom of the panel with excess space at the top (not available in FlowLayout). Also, the components will all the be the same height and width.
Thanks.
A BoxLayout will do the trick as demonstrated in this posting
If you are going to do something like a bar chart, you might want to consider not using Components at all. Just have a single JComponent that overrides (IIRC) paintComponent. It'll be easier to do the calculations in a manner appropriate to a bar chart rather than trying to use an inappropriate layout manager abstraction.
FWIW, I default to GridBagLayout, even if a simpler layout manager will do, on this basis that the code can be more consistent.
You can do exactly what you want in GridBagLayout. Yes, I know everyone hates GBL; yes, I know I'll get down-voted. But it really is not difficult to understand and you can use it for almost any layout goal.
The trick to get a component to "stick" to the bottom is to use the anchor and fill properties of the GridBagConstraints object properly (i.e. SOUTH and NONE)
A BoxLayout might work for you. It lets you layout components left-to-right or top-to-bottom, with the tightly coupled Box class to force spacing constraints.
I actually prefer the FormLayout, since it is very flexible but you have to write a lot of code though. And in the beginning its a little bit confusing with its percentage and pixel parameters.
But you can for example tell a control that it is 5 pixels left of another control (thats the main part...it layouts controls in relation to neighbors), then it takes 100% of the lasting space availabel including a border space of 5 pixels (you need to use -5 then).
I think it looks somewhat similar to this
FormData data = new FormData();
data.left = new FormAttachement(neighborControl, 5);
data.right = new FormAttachement(100, -5);
...
button.setLayoutData(data);
This example is for JFace, but there are Swing implementations as well.
I will look up my old code later this day to check if the code I wrote is right :)
HereĀ“s a additional link