tpavek's bloghttp://www.java.net/blogs/tpavek
enGetting to know GroupLayout, part 2http://www.java.net/blog/tpavek/archive/2006/03/getting_to_know.html
<!-- 1017 | 301 --><img src="/images/people/tomas_pavek.jpg" border="0", align="left" /><style type="text/css">
<cs_comment
.java-block-comment {color: #737373}
.java-string-literal {color: #99006b}
.java-layer-method {font-weight: bold}
.java-keywords {color: #000099; font-weight: bold}
.java-numeric-literals {color: #780000}
.java-highlighted { background-color: #d0d0d0}
-->
</style><p><i><b>Note:</b> Since Java 6 release, an updated version of this text, including the code samples, is available as part of the Swing trail of Java Tutorial:<br />
<a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/group.html">How to Use GroupLayout</a>, <a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/groupExample.html">GroupLayout example</a></i></p>
<hr width="20%" align="left">
<p>The <a href="http://weblogs.java.net/blog/tpavek/archive/2006/02/getting_to_know_1.html"> first part</a> of this article provided the theory behind <code class="prettyprint">GroupLayout</code>. Now it's time to try it on a real example.<br />
So let's create a layout for this<br />
dialog:</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/find.png" width="348" height="121"></p>
<p>A good way to analyze the layout is to use a top-down decomposition. I'll<br />
describe<br />
the procedure that proved useful to me; step by step to make it clear. Once you get used to<br />
"group thinking", you'll be able to proceed much<br />
faster.</p>
<p><i>Horizontal layout</i></p>
<p>Examining the horizontal dimension <i> from left to right</i>, we<br />
can see there are 3 groups in a sequence. The first one is actually not a group,<br />
just a component -- the label. The second one is a group containing the text field and<br />
the checkboxes (we'll decompose it later). And the third is a group of the two<br />
buttons. As illustrated here:</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/find_a1.PNG" width="348" height="105"></p>
<p>Let's sketch out the sequential group in code. Note that<br />
<code class="prettyprint">GroupLayout.LEADING</code> corresponds to left alignment in the horizontal dimension. Also note we don't specify gaps, assuming the <i>gap auto-insertion</i> feature is turned on.</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">setHorizontalGroup</span>(layout.createSequentialGroup()<br /> .<span class="java-layer-method">add</span>(label)<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING))<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING))<br /> );</code></pre>
<p>Now let's decompose the group in the middle. This is the hardest one. There's a text field in<br />
parallel with a sequence of two parallel groups each containing two checkboxes.<br />
See the following illustration:</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/find_a2.PNG" width="210" height="111"></p>
<p>Let's add the corresponding code:</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">setHorizontalGroup</span>(layout.createSequentialGroup()<br /> .<span class="java-layer-method">add</span>(label)</code></pre><br />
<span class="java-highlighted"><pre class="prettyprint"><code> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(textField)<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(caseCheckBox)<br /> .<span class="java-layer-method">add</span>(wholeCheckBox))<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(wrapCheckBox)<br /> .<span class="java-layer-method">add</span>(backCheckBox))))</code></pre></span><br />
<pre class="prettyprint"><code> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING))<br /> );</code></pre>
<p>Note we want the text field to be resizable, but that happens automatically<br />
since <code class="prettyprint">JTextField</code> returns the right maximum size by default.</p>
<p>The remaining group on the right is trivial: it contains just two buttons. We even don't need the picture ;-) Here's the code:</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">setHorizontalGroup</span>(layout.createSequentialGroup()<br /> .<span class="java-layer-method">add</span>(label)<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(textField)<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(caseCheckBox)<br /> .<span class="java-layer-method">add</span>(wholeCheckBox))<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(wrapCheckBox)<br /> .<span class="java-layer-method">add</span>(backCheckBox))))</code></pre><br />
<span class="java-highlighted"><pre class="prettyprint"><code> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(findButton)<br /> .<span class="java-layer-method">add</span>(cancelButton))</code></pre></span><br />
<code class="prettyprint"> );</code>
<p>And finally, we'd like the buttons to have always the same size, so let's link<br />
them:</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">linkSize</span>(<span class="java-keywords">new</span> Component[] { findButton, cancelButton },<br /> GroupLayout.HORIZONTAL);</code></pre>
<p>Now we are done with the horizontal dimension. Let's switch to the vertical dimension. From now,<br />
we'll only need to think about the y<br />
axis.</p>
<p><i>Vertical layout</i></p>
<p>In the vertical dimension, we examine the layout from <i>top to bottom</i>. We<br />
definitely want all the components on the first line aligned on baseline. So<br />
along the vertical axis there is a sequence of the baseline group, followed by a<br />
group of the remaining components. See the following picture.</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/find_a3.PNG" width="384" height="94"></p>
<p>Let's sketch out the code. First, we need to define two parallel groups. Note that<br />
<code class="prettyprint">GroupLayout.LEADING</code> corresponds to the top alignment in the<br />
vertical dimension.</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">setVerticalGroup</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.BASELINE))<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING))<br /> );</code></pre>
<p>We can fill the baseline group right away:</p>
<code class="prettyprint"> layout.<span class="java-layer-method">setVerticalGroup</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()</code><br />
<span class="java-highlighted"><pre class="prettyprint"><code> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.BASELINE)<br /> .<span class="java-layer-method">add</span>(label)<br /> .<span class="java-layer-method">add</span>(textField)<br /> .<span class="java-layer-method">add</span>(findButton))</code></pre></span><br />
<pre class="prettyprint"><code> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING))<br /> );</code></pre>
<p>Now let's look at the bottom group. Note the Cancel button is not on a shared<br />
baseline with<br />
the checkboxes; it is aligned at the top. So the second parallel group comprises<br />
the button and a sequential group of two baseline groups with checkboxes:</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/find_a4.PNG" width="332" height="51"></p>
<p>The corresponding code looks as follows:</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">setVerticalGroup</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.BASELINE)<br /> .<span class="java-layer-method">add</span>(label)<br /> .<span class="java-layer-method">add</span>(textField)<br /> .<span class="java-layer-method">add</span>(findButton))</code></pre><br />
<span class="java-highlighted"><pre class="prettyprint"><code> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.BASELINE)<br /> .<span class="java-layer-method">add</span>(caseCheckBox)<br /> .<span class="java-layer-method">add</span>(wrapCheckBox))<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.BASELINE)<br /> .<span class="java-layer-method">add</span>(wholeCheckBox)<br /> .<span class="java-layer-method">add</span>(backCheckBox)))<br /> .<span class="java-layer-method">add</span>(cancelButton))</code></pre></span><br />
<code class="prettyprint"> );</code>
<p>So, that's it! We've created a<br />
complete layout including resize behavior without specifying a single<br />
number in pixels. That's a true cross platform layout! Note that we don't<br />
need to specify gaps between components, we get correct spacing automatically<br />
and according to the look and feel guidelines. Here's the complete code for<br />
the Find dialog's layout:</p>
<pre class="prettyprint"><code> GroupLayout layout = <span class="java-keywords">new</span> <span class="java-layer-method">GroupLayout</span>(<span class="java-layer-method">getContentPane</span>());<br /> <span class="java-layer-method">getContentPane</span>().<span class="java-layer-method">setLayout</span>(layout);<br /> layout.<span class="java-layer-method">setAutocreateGaps</span>(<span class="java-keywords">true</span>);<br /> layout.<span class="java-layer-method">setAutocreateContainerGaps</span>(<span class="java-keywords">true</span>);<br /><br /> layout.<span class="java-layer-method">setHorizontalGroup</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(label)<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(textField)<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(caseCheckBox)<br /> .<span class="java-layer-method">add</span>(wholeCheckBox))<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(wrapCheckBox)<br /> .<span class="java-layer-method">add</span>(backCheckBox))))<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(findButton)<br /> .<span class="java-layer-method">add</span>(cancelButton))<br /> );<br /> layout.<span class="java-layer-method">linkSize</span>(<span class="java-keywords">new</span> Component[] { findButton, cancelButton },<br /> GroupLayout.HORIZONTAL);<br /><br /> layout.<span class="java-layer-method">setVerticalGroup</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.BASELINE)<br /> .<span class="java-layer-method">add</span>(label)<br /> .<span class="java-layer-method">add</span>(textField)<br /> .<span class="java-layer-method">add</span>(findButton))<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.BASELINE)<br /> .<span class="java-layer-method">add</span>(caseCheckBox)<br /> .<span class="java-layer-method">add</span>(wrapCheckBox))<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.BASELINE)<br /> .<span class="java-layer-method">add</span>(wholeCheckBox)<br /> .<span class="java-layer-method">add</span>(backCheckBox)))<br /> .<span class="java-layer-method">add</span>(cancelButton))<br /> );</code></pre>
<p>Here is the complete <a href="http://weblogs.java.net/blog/tpavek/Find.java">Find.java</a> file. You can compile<br />
it and run against the Swing Layout Extensions library. Try resizing the dialog<br />
horizontally to see how the layout automatically adjusts to the new size.</p>
<blockquote><p> The easiest way to test <code class="prettyprint">GroupLayout</code> is to use it with NetBeans 5.0<br />
where it is bundled (just make sure "Swing Layout Extensions" library<br />
is added in the libraries of the working project).</p>
<p>The layout manager and related extensions are hosted on <a href="http://swing-layout.dev.java.net">http://swing-layout.dev.java.net</a><br />
as one of the <a href="http://swinglabs.dev.java.net/"> Swing Labs</a><br />
projects (see the earlier Scott Violet's <a href="http://weblogs.java.net/blog/zixle/archive/2005/06/index.html">announcement</a>).<br />
You can get the latest version from the <a href="http://swing-layout.dev.java.net/servlets/ProjectDocumentList">download<br />
page</a>.</p>
</blockquote>
<hr width="20%" align="left">
<p>That's all for now. In future articles, I'll take a look at dynamic changes of the<br />
layout, compare <code class="prettyprint">GroupLayout</code> with other layout managers, describe its limitations,<br />
and I'll cover other topics of interest based on your feedback.</p>
http://www.java.net/blog/tpavek/archive/2006/03/getting_to_know.html#commentsJava DesktopWed, 01 Mar 2006 14:43:49 +0000tpavek234959 at http://www.java.netGetting to know GroupLayout, part 1http://www.java.net/blog/tpavek/archive/2006/02/getting_to_know_2.html
<!-- 5654 | 301 --><img src="/images/people/tomas_pavek.jpg" border="0", align="left" /><style type="text/css">
<cs_comment
.java-block-comment {color: #737373}
.java-string-literal {color: #99006b}
.java-layer-method {font-weight: bold}
.java-keywords {color: #000099; font-weight: bold}
.java-numeric-literals {color: #780000}
.java-highlighted { background-color: #e0e0e0}
-->
</style><p><i><b>Note:</b> Since Java 6 release, an updated version of this text, including the code samples, is available as part of the Swing trail of Java Tutorial:<br />
<a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/group.html">How to Use GroupLayout</a>, <a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/groupExample.html">GroupLayout example</a></i></p>
<hr width="20%" align="left">
<code class="prettyprint">GroupLayout</code> is a new layout manager that was developed as a<br />
Swing Labs project in conjunction<br />
with Matisse, the new GUI builder in NetBeans 5.0. There is a chance that<br />
<code class="prettyprint">GroupLayout</code> will become a part of JDK in the future. Though the layout manager was<br />
originally designed to suit the GUI builder needs, it is also quite handy for manual coding. This<br />
article will help you get up to speed with how <code class="prettyprint">GroupLayout</code> works and shows you<br />
how you can start building GUIs using <code class="prettyprint">GroupLayout</code>, whether you choose to<br />
use Matisse or write your own code.</p>
<p>In this article, I'm going to cover some of the theory behind <code class="prettyprint">GroupLayout</code>. If you prefer to start with<br />
examples, you can skip this part and wait for the next post which will bring<br />
a complete example with detailed explanation.</p>
<p><b>Design principle: independent dimensions</b></p>
<p>The first thing you need to know about <code class="prettyprint">GroupLayout</code> is that it works with</p>
<p>horizontal and vertical layout separately. This is not that uncommon, but<br />
unlike other layout managers <code class="prettyprint">GroupLayout</code> does not use a single <i>constraints</i><br />
object or method to completely specify a component's layout; the layout is defined for<br />
each dimension independently. This might seem a bit unusual at first<br />
sight, but<br />
it actually makes things easier because the definition is simpler. When defining the <i> horizontal</i><br />
layout, you don't need to worry about the <i> vertical</i><br />
dimension, and vice versa. The layout along the horizontal axis is quite independent<br />
of the layout along the vertical axis. By focusing just on one dimension at a<br />
time you only have to solve half the problem,<br />
the other dimension can be solved later. The downside of this approach is that each component needs to be defined twice in the layout.<br />
You'll soon find out if you forgot to do this, because <code class="prettyprint">GroupLayout</code> will generate<br />
an exception ;-)</p>
<p>This dimension independence is quite a powerful concept, similar to <code class="prettyprint">SpringLayout</code>,<br />
because it provides flexibility other<br />
layouts can't offer. We'll get back to this topic later; but first let's see what makes <code class="prettyprint">GroupLayout</code> <i>different</i> from <code class="prettyprint">SpringLayout</code><br />
and other layout managers.</p>
<p><b>Layout organization: hierarchical groups</b></p>
<code class="prettyprint">GroupLayout</code> uses two types of arrangements -- sequential and parallel, combined with<br />
hierarchical composition. These<br />
principles are quite basic and well known from Swing.</p>
<p>(1) With <b>sequential</b> arrangement, the components are simply placed<br />
one after another. Just like <code class="prettyprint">BoxLayout</code> or <code class="prettyprint">FlowLayout</code> would do along one<br />
axis. The position of each component is defined as being relative to the<br />
preceding component. This is important for platform independent layout.</p>
<p>(2) The second way places the components in <b>parallel</b>, on top of each other in the same space,<br />
and aligned<br />
along a common reference point. For example, the components can be right-aligned along<br />
the horizontal<br />
axis, or baseline-aligned along the vertical axis, etc.</p>
<p>Usually, components placed in parallel in one dimension are in a sequence in<br />
the other, so they don't overlap. See the examples below.</p>
<p>What makes these two principles powerful is that they can be combined (nested)<br />
hierarchically. For this purpose <code class="prettyprint">GroupLayout</code> defines <b>layout<br />
groups</b>.<br />
A group is either sequential or parallel and may contain components, gaps and other groups.<br />
The size of a sequential group is the sum of the sizes of the contained elements,<br />
and the size of a parallel group corresponds to the size of the largest element.<br />
Defining a<br />
layout means defining how the components should be grouped by combining the<br />
sequential and parallel arrangements. This resembles nested panels with<br />
<code class="prettyprint">BoxLayout</code>, but the groups are quite lightweight compared to panels. There is also a difference in the independent dimensions as<br />
described above. Panels do nesting in both dimensions at once, while groups can<br />
be nested as needed, for each dimension separately.</p>
<p>That's enough theory for now, let's take a look at how it works in practice<br />
with a simple example.</p>
<p><b>Example</b></p>
<p>Let's start with something really simple, just three components in a row:</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/example1a.PNG" width="151" height="31"></p>
<p>We would like to express this layout using groups. Starting with the horizontal<br />
axis it's easy to see there is a <i>sequential<br />
group</i> of 3 components arranged from left to right. Along the vertical axis there is a <i> parallel group</i><br />
of the same 3 components (at the same coordinate); let's say they are aligned<br />
along a baseline. See this picture:</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/groups1a.PNG" width="397" height="69"></p>
<p>In pseudo code, the layout specification might look like this (the real code is further below):</p>
<pre class="prettyprint"><code>horizontal layout = sequential group { c1, c2, c3 }<br />vertical layout = parallel group (BASELINE) { c1, c2, c3 }</code></pre>
<p>Note this illustrates a principle I mentioned earlier; components grouped sequentially in one<br />
dimension usually form a parallel group in the orthogonal dimension.</p>
<p>Now let's add one more component (C4):</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/example1b.PNG" width="160" height="62"></p>
<p>Along the horizontal axis the new component forms a parallel group with C3 (because it occupies the same horizontal space as C3),<br />
let's say we want the components left aligned.<br />
Along the vertical axis C4 forms a sequential group with the<br />
original parallel group of the three components.</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/groups1b.PNG" width="413" height="112"></p>
<p>In pseudo code, the layout specification now looks like this:</p>
<pre class="prettyprint"><code>horizontal layout = sequential group { c1, c2, <b>parallel group (LEFT) { </b>c3,<b> c4 }</b> }<br />vertical layout = <b>sequential group {</b> parallel group (BASELINE) { c1, c2, c3 }, <b>c4 }</b></code></pre>
<p>Now that you understand the principle of groups, you know the most important<br />
thing about designing layouts with <code class="prettyprint">GroupLayout</code>! There are just a few more details<br />
to explain: how to add gaps, how to define<br />
resize behavior, how to write real code, etc.</p>
<p><b>Gaps</b></p>
<p>A gap can be thought of as an invisible component of certain size. Gaps of<br />
arbitrary size can be added to groups just like components or other<br />
groups. Using gaps you can precisely control the distance<br />
between components or from the container border.</p>
<code class="prettyprint">GroupLayout</code> also defines a symbolic <i>default gap</i> that corresponds to a<br />
<i> preferred<br />
distance</i> between neighboring components (or between a component and container border).<br />
The size of such a gap is not defined by an explicit number, but computed dynamically based on the look and feel the<br />
application is using (the <code class="prettyprint">LayoutStyle</code> class is used for this). There<br />
are two advantages to using <b>preferred gaps</b>: you don't have to specify the<br />
pixel sizes of the gaps, and they automatically adjust to the environment the UI runs in,<br />
reflecting the actual platform guidelines.</p>
<code class="prettyprint">GroupLayout</code> distinguishes between (a) the preferred gap between two components and<br />
(b) the preferred gap between a component and the<br />
container border. There are corresponding methods in the <code class="prettyprint">GroupLayout</code> API for adding these<br />
gaps (<code class="prettyprint">addPreferredGap</code> and <code class="prettyprint">addContainerGap</code>). There are<br />
three types of component gaps: <b>related</b>, <b> unrelated</b> and <b>indented</b>.<br />
The <code class="prettyprint">LayoutStyle</code><br />
class defines corresponding constants (to be used as the first parameter of the <code class="prettyprint">addPreferredGap</code><br />
method): <code class="prettyprint">RELATED</code>, <code class="prettyprint">UNRELATED</code> and <code class="prettyprint">INDENT</code>. The difference between<br />
related and unrelated gap is just in size (the distance between unrelated components is a bit<br />
bigger). Indented represents a preferred horizontal distance of two<br />
components where one of them is positioned underneath the second with an indent.</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/gaps.PNG" width="340" height="77"></p>
<p>To make things easier, <code class="prettyprint">GroupLayout</code> can <b>insert gaps<br />
automatically</b>. If you don't add your<br />
own gaps explicitly, it adds the <i>related</i> preferred gaps for you. This is not the<br />
default behavior, you have to turn this feature on by invoking <code class="prettyprint">setAutocreateGaps(true)</code> and <code class="prettyprint">setAutocreateContainerGaps(true)</code> on the layout.<br />
Then you'll get correct spacing almost for free!</p>
<p><b>How to write code</b></p>
<p>Now, let's take a look at the actual code to create the layout described<br />
above.</p>
<p>Let's assume we have a container named <code class="prettyprint">panel</code> and four<br />
components (<code class="prettyprint">c1</code>, <code class="prettyprint">c2</code>, <code class="prettyprint">c3</code>, <code class="prettyprint">c4</code>)<br />
which are already set up. First, we create a new <code class="prettyprint">GroupLayout</code> object and<br />
associate it with the panel:</p>
<pre class="prettyprint"><code> GroupLayout layout = <span class="java-keywords">new</span> <span class="java-layer-method">GroupLayout</span>(panel);<br /> panel.<span class="java-layer-method">setLayout</span>(layout);</code></pre>
<p>We specify automatic gap insertion:</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">setAutocreateGaps</span>(<span class="java-keywords">true</span>);<br /> layout.<span class="java-layer-method">setAutocreateContainerGaps</span>(<span class="java-keywords">true</span>);</code></pre>
<p>Finally, we define groups and add the components. We establish a root group<br />
for each dimension using<br />
<code class="prettyprint">setHorizontalGroup</code> and <code class="prettyprint">setVerticalGroup</code> methods.<br />
Groups are created via <code class="prettyprint">createSequentialGroup</code> and <code class="prettyprint">createParallelGroup</code><br />
methods. Components are added to groups by using a variant of the <code class="prettyprint">add</code> method.</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">setHorizontalGroup</span>(<br /> layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(c1)<br /> .<span class="java-layer-method">add</span>(c2)<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING)<br /> .<span class="java-layer-method">add</span>(c3)<br /> .<span class="java-layer-method">add</span>(c4))<br /> );<br /> layout.<span class="java-layer-method">setVerticalGroup</span>(<br /> layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.BASELINE)<br /> .<span class="java-layer-method">add</span>(c1)<br /> .<span class="java-layer-method">add</span>(c2)<br /> .<span class="java-layer-method">add</span>(c3))<br /> .<span class="java-layer-method">add</span>(c4)<br /> );</code></pre>
<p>Note that default alignment must be specified for parallel groups. It can be<br />
one of the following constants defined in the <code class="prettyprint">GroupLayout</code> class: <code class="prettyprint">LEADING</code>,<br />
<code class="prettyprint">TRAILING</code> and <code class="prettyprint">CENTER</code>. These constants are used for both dimensions; in the<br />
horizontal dimension <code class="prettyprint">LEADING</code> means "left", while in the vertical dimension it<br />
means "top". Similarly <code class="prettyprint">TRAILING</code> maps to "right" or "bottom". The <code class="prettyprint">BASELINE</code><br />
alignment is valid only in the vertical dimension.</p>
<p>Some notes about the code:</p>
<ul>
<li>
<p>Components are not added to the container directly, they<br />
are added to groups.<br />
<code class="prettyprint">GroupLayout</code> adds the components to the container automatically<br />
for you.</p>
</li>
<li>
<p>Note the chained calls of the <code class="prettyprint">add</code> methods used to fill the groups.<br />
The <code class="prettyprint">add</code> method always returns the group on which it is called.<br />
Thanks to this you don't need to use local variables to hold the groups.</p>
</li>
<li>
<p>It is a good idea to indent the code so it is easy to see the hierarchical structure of the groups. Give<br />
each component a new line, add one<br />
level of indent for each new group in the hierarchy. A decent source editor will<br />
help you with pairing the parenthesis to close the <code class="prettyprint">createXXXGroup</code> methods.<br />
By following these simple<br />
rules it is easier to add a new component, or remove an existing one.</p>
</li>
</ul>
<p><b>Size of components and resizability</b></p>
<p>The size of each component in a <code class="prettyprint">GroupLayout</code> is constrained by three values;<br />
minimum size, preferred size and maximum size. These sizes control how the<br />
component resizes within the layout. The <code class="prettyprint">GroupLayout.add(...)</code> method allows the size<br />
constraints to be specified. There is no limit on the number of resizable<br />
components in a layout.</p>
<p>If not specified explicitly, the layout asks the component for its default<br />
sizes (by using the component's <code class="prettyprint">getMinimumSize()</code>, <code class="prettyprint">getPreferredSize()</code><br />
and <code class="prettyprint">getMaximumSize()</code> methods). Thus you don't need to<br />
specify anything for most of the components, e.g. to make <code class="prettyprint">JTextField</code><br />
resizable or <code class="prettyprint">JButton</code> fixed, because the components have the desired resizing<br />
behavior as default. On the other hand you can override the default behavior.<br />
For example you can make a<br />
<code class="prettyprint">JTextField</code> fixed or <code class="prettyprint">JButton</code> resizable.</p>
<code class="prettyprint">GroupLayout</code> defines constants that provide precise control over<br />
resize behavior. They can be used as parameters in the <code class="prettyprint">add(Component comp, int min, int pref, int max)</code> <br />
method. Here are two examples:</p>
<p>1) To force a component to be resizable (allow shrinking and growing):</p>
<code class="prettyprint"> <i>group</i>.<span class="java-layer-method">add</span>(component, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ...</code>
<p>This allows the component to resize between zero size (minimum) to any size (<code class="prettyprint">Short.MAX_VALUE</code><br />
as maximum size means "infinite"). If we wanted the component not to shrink<br />
below its<br />
default minimum size, we'd use <code class="prettyprint">GroupLayout.DEFAULT_SIZE</code> instead of <code class="prettyprint">0</code><br />
in the second parameter.</p>
<p>2) To make a component fixed size (suppress resizing):</p>
<pre class="prettyprint"><code> <i>group</i>.<span class="java-layer-method">add</span>(component, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE,<br /> GroupLayout.PREFERRED_SIZE) ...</code></pre>
<p>In these examples the initial size of the component is not altered, its<br />
default size is the component's preferred size. If we<br />
wanted a specific size for the component, we would specify it in the second<br />
parameter instead of using <code class="prettyprint">GroupLayout.DEFAULT_SIZE</code>.</p>
<p><b>Resizable gaps</b></p>
<p>Specifying size and resizability applies to gaps as well, including the preferred ones.<br />
For example, you can specify a preferred gap<br />
between two components that acts like a <i> spring</i> pushing the components away<br />
from each other (to the opposite sides of the container). The preferred distance<br />
of the two components is only used as the minimum size of the gap. See the<br />
following snippet:</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">createSequentialGroup</span>()<br /> .<span class="java-layer-method">add</span>(c1)<br /> .<span class="java-layer-method">addPreferredGap</span>(LayoutStyle.RELATED,<br /> GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)<br /> .<span class="java-layer-method">add</span>(c2);</code></pre>
<p><b>Justified layout</b></p>
<p>Resizable elements placed in a parallel group are stretched to fill the<br />
space of the group determined by the largest element in the group, so they end up<br />
aligned with the same size. <code class="prettyprint">GroupLayout</code><br />
also provides control over whether the enclosing parallel group itself should<br />
resize. If group resizing is suppressed, it prevents the contained elements from<br />
growing over the preferred size of the group. This way you can make a block of components<br />
align on both sides, or constrain individual components to have the same size.</p>
<p>Let's try to achieve the same size for two components from our example (<code class="prettyprint">c3</code> and <code class="prettyprint">c4</code> in the horizontal<br />
dimension):</p>
<pre class="prettyprint"><code> layout.<span class="java-layer-method">createParallelGroup</span>(GroupLayout.LEADING, <span class="java-keywords">false</span>)<br /> .<span class="java-layer-method">add</span>(c3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)<br /> .<span class="java-layer-method">add</span>(c4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);</code></pre>
<p>The underlying mechanism works as follows:</p>
<ol>
<li>The size of the parallel group is set to the preferred size of the largest<br />
element; so to the preferred size of <code class="prettyprint">c4</code> in our example.</li>
<li>Resizable elements are stretched to the size of the group. In our example,<br />
only <code class="prettyprint">c3</code> is effectively stretched, the size of <code class="prettyprint">c4</code> already corresponds to the size of the<br />
group.</li>
</ol>
<p>As a result, <code class="prettyprint">c3</code> and <code class="prettyprint">c4</code> would have the same width.<br />
The components would not resize further because the parallel group itself is not<br />
resizable.</p>
<p><img border="0" src="http://weblogs.java.net/blog/tpavek/same_size_stretched.PNG" width="160" height="62"></p>
<p>Question for attentive readers: Why do we define both components in the<br />
parallel group as resizable in this example? It seems enough to have just <code class="prettyprint">c3</code><br />
resizable since <code class="prettyprint">c4</code> is not stretched anyway...</p>
<p>(The answer is simple: because of platform and localization independence.<br />
Otherwise we<br />
would have to rely on that <code class="prettyprint">c4</code> component is always bigger than <code class="prettyprint">c3</code>. But this<br />
may change when the application runs on different platform or is translated to<br />
another language. By having both components resizing they adjust to each other,<br />
no matter which one is bigger at the moment.)</p>
<p><b>Same size of components</b></p>
<p>The previous case is special because the components are in the same parallel<br />
group. But what if we wanted unrelated components to have the same size?<br />
Clearly, the same size can't always be ensured by grouping. The OK and Cancel buttons<br />
in a row at the bottom of a dialog are a good example. For this purpose<br />
<code class="prettyprint">GroupLayout</code> provides a <code class="prettyprint">linkSize</code> method. This method allows<br />
the size of<br />
arbitrary components to be linked regardless of where they are placed. The resulting size<br />
of the linked components is set<br />
according to the largest component. For example:</p>
<code class="prettyprint"> layout.<span class="java-layer-method">linkSize</span>(<span class="java-keywords">new</span> Component[] { c3, c4 }, GroupLayout.HORIZONTAL);</code>
<p>Note that in this example the size is linked selectively for the horizontal dimension.</p>
<hr width="20%" align="left">
<p>That's all for today. Now you should know enough about <code class="prettyprint">GroupLayout</code> to<br />
start using it!</p>
<blockquote><p>Note: The easiest way to test <code class="prettyprint">GroupLayout</code> is to use it with NetBeans 5.0<br />
where it is bundled (just make sure "Swing Layout Extensions" library<br />
is present in the libraries of the working project).</p>
<p>The layout manager and related extensions are hosted on <a href="http://swing-layout.dev.java.net">http://swing-layout.dev.java.net</a><br />
as one of the <a href="http://swinglabs.dev.java.net/"> Swing Labs</a><br />
projects (see the earlier Scott Violet's <a href="http://weblogs.java.net/blog/zixle/archive/2005/06/index.html">announcement</a>).<br />
You can get the latest version from the <a href="http://swing-layout.dev.java.net/servlets/ProjectDocumentList">download<br />
page</a>.</p>
</blockquote>
<p>Would you like to see more examples of using <code class="prettyprint">GroupLayout</code>? In the continuation of this article<br />
I will show how to create a layout for a sample dialog, with detailed<br />
explanation of each step, illustrations, code samples, etc.</p>
http://www.java.net/blog/tpavek/archive/2006/02/getting_to_know_2.html#commentsJava DesktopWed, 22 Feb 2006 16:58:12 +0000tpavek234917 at http://www.java.net