N
nukleus
This is a repost of the original post with
Subject: Nested GridBagLayout and its pitfals.
I decided that the subject would be easier to find
if the first word was GridBagLayout.
Secondly, I'd like to fix some obvious errors
in the original post and I hope that the followups,
if any, would be on this thread.
- - - - - - - - - - - - - - - - - - - - - -
Original post:
I am working on one app that has few frames
to get/set various program parameters.
Some of those frames have several buttons,
several text fields with labels, several checkboxes,
a text area and, status field and a choice boxes.
To make it all look nice and clear from the standpoint
of GUI element layout, you would have to get into
some pretty hairy issues.
Working with it, what I was seeing is nothing less
than magic. Buttons would dissapear in run time,
text fields would have Y size several times smaller
than the font Y size and on and on an on.
I could not believe my eyes seeing all that madness,
and I ended up spending probably 10 times more time
on it all, than it should have taken me, or any
mortal for that matter.
I decided to use my gadget and review the 25000
article archive of this group, going back at least
half a year, and see if this issue was ever discussed.
The result was nothing but shock. There were but a
handful of articles, most in Sept. 2006, addressing
this issue, and even there, the advices were so
scetchy, that they were virtually useless,
in case of just about any realistic frame imaginable
having more than a few similar GUI elements.
So, let us attempt to fix that problem
and put an end to the whole GridBagLayout debate.
I was recomended by one of people here to read the
Sun's tutorial on GridBagLayout. Yes, I agree, it
is humanly readable, but, unfortunately, the example
it provides is nothing more than a childish invention,
and there is very little chance it is going to be of
any use in any realistic sutuation.
It does not address ANY of subtleties of realistic layouts,
having not just a bunch of buttons,
filling the entire frame, but a mix of various GUI
elements.
Finally, what i came up with, was a realization
that about the easiest and the best way of doing it,
was to use nested layouts.
Here is summary of what I have found.
It is all out of memory as I do not want to load
another piece of bloatware and wait for days
when I want to switch some tab. So, some things
may be named incorrectly, but that is not significant
as the very underlying meaning should be clear.
1. In just about any realistic GUI frame,
you are likely to have a mix of various elements.
If you try to lay them all out using a single
GridBagLayout, you'll waste half of your life,
being blown out of the chair when you change
any parameters.
You may try to cheat and create more grid cells,
trying to properly position various unrelated
groups of elements, trying to make one GUI element
to occupy more than one cell in X/Y dimension,
trying to accomodate for your positioning requirements,
but it will likely to und up in nothing less than
utter frustration.
So, use nested layout instead.
Meaning: Organize all of your similar GUI
elements into logically related areas on your
frame. Group buttons in one group, labels and
text fields in another group, and so the checkboxes,
text areas and the rest of it.
2. Create separate panels for each group of related GUI elements
Use GridBagLayout for each of those panels.
For the group of checkboxes, GridBagLayout is not
the best choice as it does not guarantee the equal
X offsets between the checkboxes.
So, for check box panel, use GridLayout instead
as it guarantees the equal X size distribution
between all the checkboxes.
Use GridBagLayout for the frame itself, and put
all those panels into separate cells of the frame's
GridBagLayout.
3. Avoid using fills and weights as much as possible
as their effect may be such that you'll never have
a handle on your layout. Say, for example, you have
a group of labels, in Y dimension, that label the
corresponding text fields. The entire row of labels
will be dimensioned at run time to have an X size
of the label having the longest text string.
(In fact, in each row, you don't have to worry
about the size of each column. At run time,
the largest size will be used for the entire column).
If you use fills to pad the label column size,
and, later on, decide to change the text of your
longest label and make it much smaller, all of a
sudden, your whole layout will change.
Fills are not the absolute size of some GUI element.
They are what needs to be added to the size of a
text string, that element contains, be it label,
button, text field. That is why their are called
paddings, which should immediately turn the warning
lights on.
That means that if you use fills hoping to maximize
the size of some row or a column, you'll be sweating
half of your life to make it all work, especially if you
try to resize that frame in run time.
Use insets instead. Those are guaranteed not to change
regardless of the size of your GUI element. The easiest
thing to think of them is margins. They are expressed
in absolute terms - pixels.
4. Minimize the number of constraint parameters used
Try to keep all the values of constraints structures
at zero instead of filling them with values you THINK
will make it look better. Use only those parameters
that you feel are absolutely necessary, such as insets.
The exception is the row/column numbers and a number
of cells you want your GUI element to occupy in X or Y
dimension.
5. Paddings of labels, text fields and text related elements
On all labels, use a small X padding of 3 - 6 pixels
for the labels so that the text field, following that
label in X position have some margin and does not run
into the end of the label string.
Do not use fills or weights on labels, because you will
probably want them to stay of exactly the same size and
remain the same margins in between when you resize the
frame unless they label some elements that will change
their position with resizing.
6. Using fills and paddings
Try not to use paddings for any of constraints structures
for each of your GUI elements, hoping to increase the
column width, unless it is absolutely necessary in such
cases as when you want to guarantee the minimum length of
a text field in X dimension.
Paddings are only used to guarantee you extra space
in your text fields, text areas, labels, buttons, etc.
They should not be used in hope to adjust the column widths
as, during the render time, the effects may be utterly
different than those you thought you achieved during design
time. Secondly, if you change the text of your label or your
text field, the effect of padding may end up being something
utterly different than what you were hoping to achive.
For example, using paddings on your text fields in Y dimension,
will increase the Y margin between the different label/text
fields in a group, but when you consider weights, the run time
behavior may be simply unpredictable.
You would probably want your fields and labels to stay equally
positioned regardless of the size of your frame
and to be guaranteed their minimum size as limited by the
font you are using and the length of your string.
7. Testing frame during run time
Try to make your frame resizable and resize it in
run time. If all the GUI elements and groups keep sane
proportions, it means you've got all your constraints
and structure of your nested layout correctly configured.
8. Using off the shelf GUI designer
If you use a GUI designer, and it generates Java code
for your constraints, panels, etc., do not modify that
code by hand. You'll waste half of your life if you
ever need to change your layout in the future, which
is pretty much inevitable. All your hand coded stuff
will be either overwritten, or might cause unpredictable
behavior of your new version.
The same exact code as generated by the GUI designer
should work like a champ in just about ANY situation
imaginable.
Forget about the minimum and preferred sizes.
They are virtually useless. You can put some
reasonable values in them, but when you try to
resize your frame, and hope they mean something,
you may be suprised that the minimum and preferred
sizes are simply ignored, as far as having anything
to do with the look and feel of your frame.
I just set them to some reasonable values and forget
about them. Even if they are set to 0, and frame
is correctly designed, you won't have problems
with it in run time.
9. Simplicity of proper structuring
If you do your design correctly, you'll have the
absolute minimum of various parameters to be set
as far as boundaries, sizes, etc.,
behaving in the most predictable way
possible under the Sun.
10. Separation of GUI and the even handling code
Separate your GUI related code for the frame
and do not add anything to that class beyond
get/set methods for each element.
Make a superclass that extends that frame and that
is where you can add the keyboard and mouse listeners,
and all the bells and whistes to your frame. That
superclass has access to its underlying frame's
variables and has the right to do anything it pleases
with those variable, even though it should not attempt
to modify the sizes, constraints etc.
It all has to be done by the code generated by your
GUI designer.
11. Proprietary layout managers
Try not to use some proprietary layout managers
because they are not guaranteed to work with the
future versions, unless they rely on the existing
basic layouts, which you can do yourself.
Futhermore, they'll end up doing the same thing
the GridBagLayout or other basic layouts do, and,
if you are trying to be lazy, hoping to save some
time or effort, you are likely to regret it at the end,
it is all just a matter of time.
Also, think about the platform compatibility.
Are you sure you will be able to compile your code
under different compiler or even a different version
of the same compiler? Will it work with different version
of jre?
Some claim that by using some proprietary layouts,
they can save half the amount of code lines,
which is about the funniest argument possible.
Your frame look and feel is about one of the most
important aspects of your entire application.
Just about ALL the users will see with your app
is those very frames. Trying to save a few hundred
bytes or code lines is simply foolish.
Instead, let your gui designer generate as many
constraints in wants. It does not matter at this
state of affairs. A few hundred bytes extra
won't change anything even worth mentioning,
compared to overall look and feel benefits.
But trying to hand tweak the automatically generated
code could cost you a bundle at the end.
12. Spend enough time on making sure your frame
behaves in a very predictable way regardless of
its size. All the GUI elemenents have to look
consistent and corresponding margins and offsets
should not change when frame is resized, unless
you want them to and use weights to tell the
proportional relationships.
If your elements keep consistent behavior while
resizing frame, it implies that all your
constraints and the entire logical structure
of your frame are correct.
13. Try not to use weights, if at all possible.
If your frame has several groups of GUI elements,
each having several elements, then what you think
is space distribution may end up being utterly
different in run time and you'll waste hours if
not days, trying to play with those weights.
Even if you use weights with such elements as
buttons, you may be unpleasantly suprised at
how it looks during the render time, especially
when you resize your frame.
Weights refer to relative distribution of space,
within the group of gui elements, they call
"display area" - ugggghhhh,
and not the frame as such.
They do have meaning on a main frame's
GridBagLayout, where you can adjust the
proportional relationships between different
groups.
So, if you only have one group of elements
in your frame, weights may work fine,
but, as in any realistically complex frame,
where you have more than one row/column of
your main GridBagLayout, the things may and WILL
become simply bizzare. You'll sooner go nuts
than get the results you expect from all that
mess. By changing any element in a different
group of elements, the whole frame may look
utterly ugly.
Even to use weights for each cell of the main
gridbag of your frame, hoping that relationship
between groups will remain consistent, you may
be very unpleasantly surprised with the results
while resizing that frame or adding/removing
some elements.
Weights is probably close to useless if you consider
all the remifications of using them in relatively
complex frames. But yes, they do work. Only the
consequences of them are much harder to predict
than it may look at first glance.
Summary:
Instead of using a single GridBagLayout on just about
any realistically complex frame, that has several
different types of GUI elements, group the related
elements and put them into separate panels.
Select the layout for each panel that suits your
frame design concepts in the easiest and most
natural way. Do not try to make things more complex
than necessary hoping to make it look better,
as about ALL you are going to get at the end
is a royal grade pain on the neck.
It won't work. Trust me.
Try to use GridBagLayout for all those panels
whenever possible as this is the most general
purpose layout having all the power to do just
about anyting imaginable. But it has its limitations
and unpredictability of behavior if you expect
some rows or columns to be of equal size
regarless of the label, text field or button text
string sizes.
GridBagLayout is not a good choice for that because the
column size relationships may change in run time when
user tries to resize the frame, and your columns will
end up of not equal size, and, trying to make them of
equal size, by using paddings or weights, could end up
being a pain on the neck and of a grand proportions.
Use as few parameters in your constraints structure
as possible.
By using nested gridbags, your design will end up
being the simpliest possible with WAY more predictable
results, the most powerful and flexible, have the smallest
amount of various cells possible, and with the smallest
amount of various constraint parameters, which will
eventually translate into the most stable, predictable
and flexible run time behavior that assures minimal amount
of maintenance efforts of your code and provide for ease
of future modifications.
If you follow these few simple advises,
you'll be amazed at how much power and flexibility
you can achieve with nested GridBagLayout.
Good luck.
Finally, if any experts around have any comments,
it would probably be a good idea to clarify some
more subtle points and issues, or correct some
errors or philosophical fine points as this information
will become a permanent reference on this issue
and will be available through argives for generations
to come.
Simmply sending people to read some Sun "tutorial",
you are effectively sending them to hell,
as those "tutorials" cover only the most primitive
and most basic concepts having virtually nothing
to do with a realistic application.
Instead, you can spend half an hour of your time
and spill out the fine points of this most important
thing there is in the entire concept of GUI design,
GridLayout, which all would have to learn eventually
no matter what.
Subject: Nested GridBagLayout and its pitfals.
I decided that the subject would be easier to find
if the first word was GridBagLayout.
Secondly, I'd like to fix some obvious errors
in the original post and I hope that the followups,
if any, would be on this thread.
- - - - - - - - - - - - - - - - - - - - - -
Original post:
I am working on one app that has few frames
to get/set various program parameters.
Some of those frames have several buttons,
several text fields with labels, several checkboxes,
a text area and, status field and a choice boxes.
To make it all look nice and clear from the standpoint
of GUI element layout, you would have to get into
some pretty hairy issues.
Working with it, what I was seeing is nothing less
than magic. Buttons would dissapear in run time,
text fields would have Y size several times smaller
than the font Y size and on and on an on.
I could not believe my eyes seeing all that madness,
and I ended up spending probably 10 times more time
on it all, than it should have taken me, or any
mortal for that matter.
I decided to use my gadget and review the 25000
article archive of this group, going back at least
half a year, and see if this issue was ever discussed.
The result was nothing but shock. There were but a
handful of articles, most in Sept. 2006, addressing
this issue, and even there, the advices were so
scetchy, that they were virtually useless,
in case of just about any realistic frame imaginable
having more than a few similar GUI elements.
So, let us attempt to fix that problem
and put an end to the whole GridBagLayout debate.
I was recomended by one of people here to read the
Sun's tutorial on GridBagLayout. Yes, I agree, it
is humanly readable, but, unfortunately, the example
it provides is nothing more than a childish invention,
and there is very little chance it is going to be of
any use in any realistic sutuation.
It does not address ANY of subtleties of realistic layouts,
having not just a bunch of buttons,
filling the entire frame, but a mix of various GUI
elements.
Finally, what i came up with, was a realization
that about the easiest and the best way of doing it,
was to use nested layouts.
Here is summary of what I have found.
It is all out of memory as I do not want to load
another piece of bloatware and wait for days
when I want to switch some tab. So, some things
may be named incorrectly, but that is not significant
as the very underlying meaning should be clear.
1. In just about any realistic GUI frame,
you are likely to have a mix of various elements.
If you try to lay them all out using a single
GridBagLayout, you'll waste half of your life,
being blown out of the chair when you change
any parameters.
You may try to cheat and create more grid cells,
trying to properly position various unrelated
groups of elements, trying to make one GUI element
to occupy more than one cell in X/Y dimension,
trying to accomodate for your positioning requirements,
but it will likely to und up in nothing less than
utter frustration.
So, use nested layout instead.
Meaning: Organize all of your similar GUI
elements into logically related areas on your
frame. Group buttons in one group, labels and
text fields in another group, and so the checkboxes,
text areas and the rest of it.
2. Create separate panels for each group of related GUI elements
Use GridBagLayout for each of those panels.
For the group of checkboxes, GridBagLayout is not
the best choice as it does not guarantee the equal
X offsets between the checkboxes.
So, for check box panel, use GridLayout instead
as it guarantees the equal X size distribution
between all the checkboxes.
Use GridBagLayout for the frame itself, and put
all those panels into separate cells of the frame's
GridBagLayout.
3. Avoid using fills and weights as much as possible
as their effect may be such that you'll never have
a handle on your layout. Say, for example, you have
a group of labels, in Y dimension, that label the
corresponding text fields. The entire row of labels
will be dimensioned at run time to have an X size
of the label having the longest text string.
(In fact, in each row, you don't have to worry
about the size of each column. At run time,
the largest size will be used for the entire column).
If you use fills to pad the label column size,
and, later on, decide to change the text of your
longest label and make it much smaller, all of a
sudden, your whole layout will change.
Fills are not the absolute size of some GUI element.
They are what needs to be added to the size of a
text string, that element contains, be it label,
button, text field. That is why their are called
paddings, which should immediately turn the warning
lights on.
That means that if you use fills hoping to maximize
the size of some row or a column, you'll be sweating
half of your life to make it all work, especially if you
try to resize that frame in run time.
Use insets instead. Those are guaranteed not to change
regardless of the size of your GUI element. The easiest
thing to think of them is margins. They are expressed
in absolute terms - pixels.
4. Minimize the number of constraint parameters used
Try to keep all the values of constraints structures
at zero instead of filling them with values you THINK
will make it look better. Use only those parameters
that you feel are absolutely necessary, such as insets.
The exception is the row/column numbers and a number
of cells you want your GUI element to occupy in X or Y
dimension.
5. Paddings of labels, text fields and text related elements
On all labels, use a small X padding of 3 - 6 pixels
for the labels so that the text field, following that
label in X position have some margin and does not run
into the end of the label string.
Do not use fills or weights on labels, because you will
probably want them to stay of exactly the same size and
remain the same margins in between when you resize the
frame unless they label some elements that will change
their position with resizing.
6. Using fills and paddings
Try not to use paddings for any of constraints structures
for each of your GUI elements, hoping to increase the
column width, unless it is absolutely necessary in such
cases as when you want to guarantee the minimum length of
a text field in X dimension.
Paddings are only used to guarantee you extra space
in your text fields, text areas, labels, buttons, etc.
They should not be used in hope to adjust the column widths
as, during the render time, the effects may be utterly
different than those you thought you achieved during design
time. Secondly, if you change the text of your label or your
text field, the effect of padding may end up being something
utterly different than what you were hoping to achive.
For example, using paddings on your text fields in Y dimension,
will increase the Y margin between the different label/text
fields in a group, but when you consider weights, the run time
behavior may be simply unpredictable.
You would probably want your fields and labels to stay equally
positioned regardless of the size of your frame
and to be guaranteed their minimum size as limited by the
font you are using and the length of your string.
7. Testing frame during run time
Try to make your frame resizable and resize it in
run time. If all the GUI elements and groups keep sane
proportions, it means you've got all your constraints
and structure of your nested layout correctly configured.
8. Using off the shelf GUI designer
If you use a GUI designer, and it generates Java code
for your constraints, panels, etc., do not modify that
code by hand. You'll waste half of your life if you
ever need to change your layout in the future, which
is pretty much inevitable. All your hand coded stuff
will be either overwritten, or might cause unpredictable
behavior of your new version.
The same exact code as generated by the GUI designer
should work like a champ in just about ANY situation
imaginable.
Forget about the minimum and preferred sizes.
They are virtually useless. You can put some
reasonable values in them, but when you try to
resize your frame, and hope they mean something,
you may be suprised that the minimum and preferred
sizes are simply ignored, as far as having anything
to do with the look and feel of your frame.
I just set them to some reasonable values and forget
about them. Even if they are set to 0, and frame
is correctly designed, you won't have problems
with it in run time.
9. Simplicity of proper structuring
If you do your design correctly, you'll have the
absolute minimum of various parameters to be set
as far as boundaries, sizes, etc.,
behaving in the most predictable way
possible under the Sun.
10. Separation of GUI and the even handling code
Separate your GUI related code for the frame
and do not add anything to that class beyond
get/set methods for each element.
Make a superclass that extends that frame and that
is where you can add the keyboard and mouse listeners,
and all the bells and whistes to your frame. That
superclass has access to its underlying frame's
variables and has the right to do anything it pleases
with those variable, even though it should not attempt
to modify the sizes, constraints etc.
It all has to be done by the code generated by your
GUI designer.
11. Proprietary layout managers
Try not to use some proprietary layout managers
because they are not guaranteed to work with the
future versions, unless they rely on the existing
basic layouts, which you can do yourself.
Futhermore, they'll end up doing the same thing
the GridBagLayout or other basic layouts do, and,
if you are trying to be lazy, hoping to save some
time or effort, you are likely to regret it at the end,
it is all just a matter of time.
Also, think about the platform compatibility.
Are you sure you will be able to compile your code
under different compiler or even a different version
of the same compiler? Will it work with different version
of jre?
Some claim that by using some proprietary layouts,
they can save half the amount of code lines,
which is about the funniest argument possible.
Your frame look and feel is about one of the most
important aspects of your entire application.
Just about ALL the users will see with your app
is those very frames. Trying to save a few hundred
bytes or code lines is simply foolish.
Instead, let your gui designer generate as many
constraints in wants. It does not matter at this
state of affairs. A few hundred bytes extra
won't change anything even worth mentioning,
compared to overall look and feel benefits.
But trying to hand tweak the automatically generated
code could cost you a bundle at the end.
12. Spend enough time on making sure your frame
behaves in a very predictable way regardless of
its size. All the GUI elemenents have to look
consistent and corresponding margins and offsets
should not change when frame is resized, unless
you want them to and use weights to tell the
proportional relationships.
If your elements keep consistent behavior while
resizing frame, it implies that all your
constraints and the entire logical structure
of your frame are correct.
13. Try not to use weights, if at all possible.
If your frame has several groups of GUI elements,
each having several elements, then what you think
is space distribution may end up being utterly
different in run time and you'll waste hours if
not days, trying to play with those weights.
Even if you use weights with such elements as
buttons, you may be unpleasantly suprised at
how it looks during the render time, especially
when you resize your frame.
Weights refer to relative distribution of space,
within the group of gui elements, they call
"display area" - ugggghhhh,
and not the frame as such.
They do have meaning on a main frame's
GridBagLayout, where you can adjust the
proportional relationships between different
groups.
So, if you only have one group of elements
in your frame, weights may work fine,
but, as in any realistically complex frame,
where you have more than one row/column of
your main GridBagLayout, the things may and WILL
become simply bizzare. You'll sooner go nuts
than get the results you expect from all that
mess. By changing any element in a different
group of elements, the whole frame may look
utterly ugly.
Even to use weights for each cell of the main
gridbag of your frame, hoping that relationship
between groups will remain consistent, you may
be very unpleasantly surprised with the results
while resizing that frame or adding/removing
some elements.
Weights is probably close to useless if you consider
all the remifications of using them in relatively
complex frames. But yes, they do work. Only the
consequences of them are much harder to predict
than it may look at first glance.
Summary:
Instead of using a single GridBagLayout on just about
any realistically complex frame, that has several
different types of GUI elements, group the related
elements and put them into separate panels.
Select the layout for each panel that suits your
frame design concepts in the easiest and most
natural way. Do not try to make things more complex
than necessary hoping to make it look better,
as about ALL you are going to get at the end
is a royal grade pain on the neck.
It won't work. Trust me.
Try to use GridBagLayout for all those panels
whenever possible as this is the most general
purpose layout having all the power to do just
about anyting imaginable. But it has its limitations
and unpredictability of behavior if you expect
some rows or columns to be of equal size
regarless of the label, text field or button text
string sizes.
GridBagLayout is not a good choice for that because the
column size relationships may change in run time when
user tries to resize the frame, and your columns will
end up of not equal size, and, trying to make them of
equal size, by using paddings or weights, could end up
being a pain on the neck and of a grand proportions.
Use as few parameters in your constraints structure
as possible.
By using nested gridbags, your design will end up
being the simpliest possible with WAY more predictable
results, the most powerful and flexible, have the smallest
amount of various cells possible, and with the smallest
amount of various constraint parameters, which will
eventually translate into the most stable, predictable
and flexible run time behavior that assures minimal amount
of maintenance efforts of your code and provide for ease
of future modifications.
If you follow these few simple advises,
you'll be amazed at how much power and flexibility
you can achieve with nested GridBagLayout.
Good luck.
Finally, if any experts around have any comments,
it would probably be a good idea to clarify some
more subtle points and issues, or correct some
errors or philosophical fine points as this information
will become a permanent reference on this issue
and will be available through argives for generations
to come.
Simmply sending people to read some Sun "tutorial",
you are effectively sending them to hell,
as those "tutorials" cover only the most primitive
and most basic concepts having virtually nothing
to do with a realistic application.
Instead, you can spend half an hour of your time
and spill out the fine points of this most important
thing there is in the entire concept of GUI design,
GridLayout, which all would have to learn eventually
no matter what.