• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Setting Border "none" changes Box Layout

 
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am trying to create a subclass of JPanel that contains a JSlider and another JPanel. Right now, the second, "inner" JPanel only contains a JTextField, but I will want it to contain two JTextFields later on.

I set the Layout Manager for both JPanels to the Box LM, and set the axis to PAGE_AXIS for each. I set the JSlider's orientation to VERTICAL. The effect I get at run-time is what I want it to be, a text field over a vertically aligned slider:



But, if I set the JTextField's border to null, the JTextField is no longer centered over the slider. Apparently, the outermost JPanel's Layout Manager aligns the left edge of the JTextField with the centerline of the JPanel, like this:



Here's my code, with the line that causes the bug flagged:



Also, the bug does not happen if the inner JPanel's Box Layout Manager is allowed to use its default LINE_AXIS axis (that is, the bug goes away if you comment out Line 47). That's no good to me, however, as I want to add another JTextField below the one I already have, so I need to use PAGE_AXIS.

Why would getting rid of the JTextField's border make this happen? Why does it only happen when the inner JPanel's Box Layout Manager is set to use PAGE_AXIS?
 
Rancher
Posts: 3324
32
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
First of all don't use setPreferredSize() to control the size of Swing components. Each component is responsible for determining its own preferred size.

So instead you should be using something like:



Not exactly sure what happens when playing with the Border although that will affect the preferredSize of the component.

Anyway the real problem is with the BoxLayout. There are two issues. A BoxLayout:

1. will attempt to expand the width of a component to fill the entire space up to the maximum size of the component. A JPanel doesn't have a maximum size so it will change in size as the frame is resized.
2. uses the "X" alignment of each component to determine its horizontal alignment. This values should be the same for all components.

So to fix the above to problems you can add the following at the end of your DText constructor:

       setMaximumSize( getPreferredSize() );
       setAlignmentX(CENTER_ALIGNMENT);

Note: a better solution is to actually override the getMaximumSize() method to return the preferred size of the component. This way the maximum size will dynamically change as the preferred size dynamically changes.

 
Stevens Miller
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rob Camick wrote:        setAlignmentX(CENTER_ALIGNMENT);


Now that is very interesting, as the actual value of CENTER_ALIGNMENT is 0.5f, which is the initial value when the JPanel is created. Setting the JPanel's Layout Manager to a new BoxLayout(this, BoxLayout.PAGE_AXIS) changes the alignmentX value to 0.0f (which is RIGHT_ALIGNMENT). Your fix, which explicitly sets it back, works. But why don't I need it when I use a border on my JTextField? The answer, partly, appears to be that adding the JTextField sets the alignmentX back to CENTER_ALIGNMENT, but only when the JTextField has a border. I discovered this with some debugging code:

The output is:
0.5
0.5
0.0
0.0
0.0
0.5


Something about adding the JTextField at Line 24, when it has a border, returns the alignmentX to 0.5f. But why? And, again, if we uncomment Line 20, the output becomes this:
0.5
0.5
0.0
0.0
0.0
0.0


Why should the border setting of the JTextField have any effect on the alignmentX value of a JPanel?

 
Stevens Miller
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Wow, this gets more confusing all the time. Adding the explicit call to setAlignmentX in the DText constructor solves the problem even if you do it at the beginning, before adding the JTextField:



And this time, the output is consistently 0.5:
0.5
textField 0.5
0.5
0.5
0.5
null
textField 0.5
0.5
0.5


It's quite baffling.
 
Rob Camick
Rancher
Posts: 3324
32
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

the actual value of CENTER_ALIGNMENT is 0.5f, which is the initial value when the JPanel is created.



Yes, as far as I can tell the default should be CENTER for all components.

Setting the JPanel's Layout Manager to a new BoxLayout(this, BoxLayout.PAGE_AXIS) changes the alignmentX value to 0.0f (which is RIGHT_ALIGNMENT



I don't know what is going on. I took a quick look at the JDK code and I can't see any code that invokes the setAlignmentX(...) method. So I don't know how it changes from 0.5f to 0.0f.

which is RIGHT_ALIGNMENT



Acutally 0.0f is left alignment.

Adding the explicit call to setAlignmentX in the DText constructor solves the problem even if you do it at the beginning



This sort of makes sense. The get/setAlignmentX(...) code is:

So if the alignment is manually set it prevents some kind of default processing from happening.

Problem is I can't find any code that sets the X alignment to 0, so I'm just as confused as you are.





Adding the explicit call to setAlignmentX in the DText constructor solves the problem even if you do it at the beginning,



The code for the setAlignmentX() method found in JComponent is:

 
Marshal
Posts: 28177
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It's possible that you've found a bug, or at least something which doesn't work right. (Sorry, I haven't done any research on this issue so I may be just making up stupid stuff here.) It's very possible that there's no (official) document which says how setting AlignmentY in the way you've demonstrated is supposed to work, in which case "bug" isn't the correct word. However "doesn't work right" does seem to be a valid description of the issue.
 
Rob Camick
Rancher
Posts: 3324
32
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Just realized that the Container class also overrides the getAlignmentX() method. Not sure how I missed it the first time




As you can see this method can potentially invoke the getLayoutAlignmentX() method of the LayoutManager2 interface.

Without looking into detail, the BoxLayout implementation method of this class appears to try to get the alignment of the child components added to the panel. When there are no children I think it uses an alignment of 0.0f.

The BasicTextUI class also implements the getLayoutayoutX() method and simply returns 0.5f. So I guess once the text field is added to the panel the alignment of the panel is reset to 0.5f since it now contains a child with an alignment of 0.5f.

So maybe when a text field doesn't have a Border the BasicTextUI code is never invoked and the panel alignment stays at 0.0f.  Or maybe the default size is (0, 0) since you didn't specify the number of columns in the text field. But as soon as you add a Border the size becomes non-zero since the insets of the Border as used to determine the size of the text field?

Anyway, getting in too deep. This is a mystery I won't be able to solve. Good luck if anybody else decides to follow up.

 
Stevens Miller
Bartender
Posts: 1464
32
Netbeans IDE C++ Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rob Camick wrote:...getting in too deep. This is a mystery I won't be able to solve. Good luck if anybody else decides to follow up.


Yup, came to the same conclusion. I traced into the same code you posted, and also added this.getAlignmentX() to my watchlist. When adding the JTextField, the stack at one point looks like this:

DText.<init>
Container.add
Container.addImpl
BoxLayout.addLayoutComponent
BoxLayout.invalidateLayout


And here's that last one:

Right after the above returns, this.getAlignmentX() returns 0.5. As you observed, the call is actually ultimately delegated to BoxLayout.getLayoutAlignmentX(), which returns xTotal.alignment. Somewhere between the above call to invalidateLayout and the return from add, xTotal acquires a new, non-null value, but I can't yet see where that happens.

I am going to agree with Paul and say that this is isn't working right. A bug, maybe. Undefined behavior, maybe. Certainly, I feel, the javadoc is inadequate regarding the application programmer's obligations regarding setting the alignment. If you do it explicitly, all this odd behavior goes away. Part of my problem is that I am using the NetBeans GUI editor, which only sets the alignment value explicitly if you choose some value other than 0.5f, since it believes that to be the default. Maybe the number of people who are:

1) Using BoxLayout
2) Along the PAGE_AXIS
3) With CENTER_ALIGNMENT
4) And JTextFields
5) With no borders

is small enough that this just fell through the cracks. Those of us who have encountered it may well all have just used some other layout solution. That's certainly what I'm going to do, as the rest of my life is predicted to be way too short to spend any of it debugging the JDK.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic