The Source for Java Technology Collaboration
User: Password:



John O'Conner

John O'Conner's Blog

Better GUIs are one step closer

Posted by joconner on October 05, 2006 at 12:58 AM | Comments (35)

How many times have you walked away from a problem, beaten and worn down, only to return with the solution in hand? I knew I'd figure out my layout problem eventually. It didn't happen immediately, but it did happen. The situation just required a little breathing room. I'm still using NetBeans 5.5, even upgraded to the RC1 version today, and NetBeans is still my favorite IDE.

Just yesterday (it was yesterday, right?), I had to give up temporarily on a maddening GUI layout problem using NetBeans 5.5 and the Matisse GUI builder. The GUI Builder was in control, and it did things that I couldn't understand or predict. It tore up my UI whenever I tried to adjust a particular component's position or size. I finally got the panel layout that I wanted, and I even used the new "Free Design" layout. I suspect user error for all the problems. I just wasn't using the tool properly. I eventually created the simple panel that I wanted. This panel resizes all the components horizontally whenever the panel size changes:

addresspanel.png

What were some of my mistakes? Well, I finally realized that I just couldn't get the txtCity field (City's text field) to automatically line up with Phone's text field on the right side. The GUI Builder had done such a great job helping me anchor things and align edges, so I just assumed it could align components that were separated by other components. Boy was that a big mistake. Finally, I had to just "eyeball" it, make an estimate about the alignment. When I finally accepted that I couldn't align components across other elements (Address 1 and 2), most of my troubles went away. Another example...At first I wanted First Name, Email, and Postal Code to all be anchored to the right as if they were in the same column. Of course, that didn't work either.

In case you're curious about how this looks in code, here it is. The layout manager is javax.swing.GroupLayout, which is new in Java SE 6:

layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(lblPhone)
                    .addComponent(lblLastName)
                    .addComponent(lblAddress1)
                    .addComponent(lblCountry)
                    .addComponent(lblAddress2)
                    .addComponent(lblCity)
                    .addComponent(lblState))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(txtCountry, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 115, Short.MAX_VALUE)
                            .addComponent(txtState, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 115, Short.MAX_VALUE)
                            .addComponent(txtCity, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 115, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(lblPostalCode)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(txtPostalCode, javax.swing.GroupLayout.DEFAULT_SIZE, 118, Short.MAX_VALUE))
                    .addComponent(txtAddress2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 327, Short.MAX_VALUE)
                    .addComponent(txtAddress1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 327, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(txtLastName, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE)
                            .addComponent(txtPhone, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(lblFirstName)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(txtFirstName, javax.swing.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(lblEmail)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(txtEmail, javax.swing.GroupLayout.DEFAULT_SIZE, 156, Short.MAX_VALUE)))))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblLastName)
                    .addComponent(txtLastName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lblFirstName)
                    .addComponent(txtFirstName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblPhone)
                    .addComponent(txtPhone, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lblEmail)
                    .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblAddress1)
                    .addComponent(txtAddress1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblAddress2)
                    .addComponent(txtAddress2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblCity)
                    .addComponent(txtCity, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblState)
                    .addComponent(txtState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(lblPostalCode)
                    .addComponent(txtPostalCode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(lblCountry)
                    .addComponent(txtCountry, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

Whew, that's definitely not something I want to hand code. I've heard the NetBeans and Swing folks say that this manager was designed to work well with tools. I've always used GridbagLayout for my UIs. You can do a lot of good work by hand with GridbagLayout. It did what I needed, and I tried to keep things pretty simple. Nothing was ever perfect, but perfectly formed UIs were never a priority. I think this new layout manager and the NetBeans GUI Builder have helped me pay more attention to GUIs. I think this tool offers me a way to create better GUIs. I hope I'll never need to hand code any of this, but who knows...

The NetBeans GUI Builder and the new "Free Design" layout manager are supposed to enable me to create great GUIs that look right on every target platform. The layout manager is supposed to help you get the component spacing correct, and it resizes components correctly when you localize. There are a lot of good reasons to try this new GUI Builder and the new layout manager. I don't doubt that the GUI Builder and "Free Design" deliver perfectly on their goals and promises. However, powerful tools don't solve problems on their own. They do require someone to use them skillfully. I'm not done with this tool, and I realize that using it is not as simple as dragging and dropping widgets. I don't think it should be either, and I realize that unfair expectations almost always lead to disappointment.

I'm going to investigate this tool a little more this month...before the NB 5.5 final release. I hope to become proficient with it. I'll let you know how it goes.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Mikael Grev's Miglayout is another new layout manager with a lot of promise, although as it's so new, there's no tool support yet (as far as I know).

    Posted by: chris_e_brown on October 05, 2006 at 04:07 AM

  • I experienced some problems with Matisse, when using a lot of customized components..., and I thought about hand coding some of the layout using GroupLayout. It's not so difficult and doesn't look so bad once done. An article in Netbeans Magazine can help to "learn" this layout : http://www.netbeans.org/download/magazine/01/nb01_group_layout.pdf

    Posted by: turquoise3232 on October 05, 2006 at 05:32 AM

  • Hmm. Overly complicated generated code and constraints that you just can't enforce with unobvious failures in the tool. More reminders to me that I don't want to use WYSIWYG GUI builders yet. Maybe they'll get there someday. (Notice nothing personal against Matisse here.)

    Posted by: tompalmer on October 05, 2006 at 08:32 AM

  • I hate to tout my own horn, but may I suggest that if you want clean code for your GUIs, PageLayout must be one of the alternatives that you look at. There are many examples available with the distribution, the algorithm is all clearly spelled out, and it's free. You can even add extend the framework by using the concepts described in the tutorial. As I said, someone here should do a review.

    Posted by: varan on October 05, 2006 at 09:18 AM

  • Chris, Two IDE vendors have said they will add support asap. :)

    To show how this panel would look like with the String constraint version of MiG Layout I paste the code here:


    JPanel p = new JPanel(new MigLayout("fillx", "[right][fill,grow]unrel[grow]", ""));

    JTextField lastNameTF = new JTextField();
    JTextField firstNameTF = new JTextField();
    JTextField phoneTF = new JTextField();
    JTextField emailTF = new JTextField();
    JTextField address1TF = new JTextField();
    JTextField address2TF = new JTextField();
    JTextField cityTF = new JTextField();
    JTextField stateTF = new JTextField();
    JTextField postalCodeTF = new JTextField();
    JTextField countryTF = new JTextField();

    p.add(new JLabel("Last Name"));
    p.add(lastNameTF);
    p.add(new JLabel("First Name"), "split 2");
    p.add(firstNameTF, "gap rel, growx, wrap");
    p.add(new JLabel("Phone"));
    p.add(phoneTF);
    p.add(new JLabel("Email"), "split 2");
    p.add(emailTF, "gap rel, growx, wrap");
    p.add(new JLabel("Address 1"));
    p.add(address1TF, "span, growx");
    p.add(new JLabel("Address 2"));
    p.add(address2TF, "span, growx");
    p.add(new JLabel("City"));
    p.add(cityTF, "wrap");
    p.add(new JLabel("State"));
    p.add(stateTF);
    p.add(new JLabel("Postal Code"), "split 2");
    p.add(postalCodeTF, "gap rel, growx, wrap");
    p.add(new JLabel("Country"));
    p.add(countryTF);

    Cheers,
    Mikael Grev

    Posted by: mikaelgrev on October 05, 2006 at 09:52 AM

  • Mikael, any word on the MigLayout license yet? Hope it's not (L)GPL...

    Posted by: kirillcool on October 05, 2006 at 10:00 AM

  • The following code is for PageLayout:

    //Layout
    Row row1=new Row(Cell.NO_ALIGNMENT,Cell.CENTER,
    lastName,lastNameE,firstName,firstNameE);
    Row row2=new Row(Cell.NO_ALIGNMENT,Cell.CENTER,
    phone,phoneE,email,emailE);
    Row row3=new Row(Cell.NO_ALIGNMENT,Cell.CENTER,
    address1,address1E);
    Row row4=new Row(Cell.NO_ALIGNMENT,Cell.CENTER,
    address2,address2E);
    Row row5=new Row(Cell.NO_ALIGNMENT,Cell.CENTER,
    city,cityE);
    Row row6=new Row(Cell.NO_ALIGNMENT,Cell.CENTER,
    state,stateE,postal,postalE);
    Row row7=new Row(Cell.NO_ALIGNMENT,Cell.CENTER,
    county,countyE);

    Column column=new Column(Cell.LEFT,Cell.CENTER,
    row1,row2,row3,row4,row5,row6,row7);

    // Size Constraints
    Component[] editors=
    new Component[]
    {lastNameE,firstNameE,phoneE,emailE,cityE,stateE,
    countyE,postalE};

    column.linkWidth(lastName,editors,2.0);
    column.setFixedWidth(editors,false);
    column.setFixedWidth(address1,false);
    column.setFixedWidth(address2,false);

    // Constrain width of labels
    Component[] labels=
    new Component[]
    {lastName,phone,city,state,
    address1,address2,county,
    };
    column.linkWidth(lastName,labels,1);
    column.linkWidth(postal,new Component[]{firstName,email},1);


    column.createLayout(container);

    Posted by: varan on October 05, 2006 at 10:02 AM

  • The cause of the problems with Matisse is not the layout manager, it's the GUI builder in NetBeans. It tries to guess what components you want constraints between by looking at the relative position of the components, and whilst overall it does a pretty good job, sometimes it gets it wrong - and there's no way to fix it. A common problem I keep tripping over is where you've some nested panels, and you want to resize them, say to add more components to the inner one. What you really want is for the position and sizes of the nested panels to be defined relative to each other. What often happens is that the GUI builder puts a space constraint between a component inside the inner panel (usually the one nearest the edge of the panel) and the panel. Then when you try resizing the panel subsequently, all the components inside the panel leap around the screen.


    Seems to me the fix is relatively simple - allow you to manually create and delete the constraints between components. As I said, Matisse mostly gets it right, but in the cases where it doesn't you've no way of fixing it other than deleting and recreating components and/or spending an age dragging stuff around the screen until you get the contraints right.

    Posted by: alanbur on October 05, 2006 at 10:03 AM

  • Kirill,
    It will most probably be BSD. That should be the least restrictive right? It would be good if I knew projects used it though...

    I'm also talking with Richard and Joshua about adding it to SwingLabs. Looks promising.

    The source code will be available when the new API-part is done. Hopefully before Sunday.

    Cheers,
    Mikael

    Posted by: mikaelgrev on October 05, 2006 at 01:48 PM

  • Mikael, BSD is the least restrictive one for the users which still requires to bundle the original license and mention the copyright. I'd vote against putting it in SwingLabs if that would involve LGPL'ing it - but that's your decision of course. For now i'm using it in Substance test app since it's not a part of the BSD library and i have your explicit permission to do so :)

    Posted by: kirillcool on October 05, 2006 at 02:04 PM

  • For comparison, here's the same layout using ZoneLayout.

    If you have your mind set on hand coding your layouts (which I highly recommend), I still think ZoneLayout is the easiest to use. Especially when it comes to refactoring layouts.


    ZoneLayout layout = ZoneLayoutFactory.newZoneLayout();

    layout.addRow("a>a2b-~b2c>c2d-~d", "normalRow");
    layout.addRow(".........6.......", "normalRow");
    layout.addRow("e>e2f-~.........f", "wideRow");
    layout.addRow(".........6.......", "wideRow");

    JPanel basePanel = new JPanel(layout);
    layout.insertTemplate("normalRow");
    basePanel.add(new JLabel("Last Name"), "a");
    basePanel.add(lastNameTF, "b");
    basePanel.add(new JLabel("First Name"), "c");
    basePanel.add(firstNameTF, "d");
    layout.insertTemplate("normalRow");
    basePanel.add(new JLabel("Phone"), "a");
    basePanel.add(phoneTF, "b");
    basePanel.add(new JLabel("Email"), "c");
    basePanel.add(emailTF, "d");
    layout.insertTemplate("wideRow");
    basePanel.add(new JLabel("Address 1"), "e");
    basePanel.add(address1TF, "f");
    layout.insertTemplate("wideRow");
    basePanel.add(new JLabel("Address 2"), "e");
    basePanel.add(address2TF, "f");
    layout.insertTemplate("normalRow");
    basePanel.add(new JLabel("City"), "a");
    basePanel.add(cityTF, "b");
    layout.insertTemplate("normalRow");
    basePanel.add(new JLabel("State"), "a");
    basePanel.add(stateTF, "b");
    basePanel.add(new JLabel("Postal Code"), "c");
    basePanel.add(postalCodeTF, "d");
    layout.insertTemplate("normalRow");
    basePanel.add(new JLabel("Country"), "a");
    basePanel.add(countryTF, "b");

    Posted by: bnahas on October 05, 2006 at 02:24 PM

  • John,
    Personally, I use Matisse for drafting a layout only. I put method initComponents() into /* */ comments, and then I do some manual tweaking on a copy of the generated code.
    As you have noted: there are lot of important features in GroupLayout, that Matisse does not support yet (e.g. using unrelated and indent spacings, grouping of components across other elements, baseline alignments between component groups). I am confident, that Matisse is maturing quickly, but until then manual tweaking is essential.
    For example, your address panel is just "filled" with components. There should be a "related" space around components that belong together, and a "unrelated" space between component groups that are separate.Also, he alignments and non-alignments of components should be "obvious" to the eye. I find the slight non-alignment of the left edges of the first name text field with the post code text field very disturbing.
    Last, but not least, I think, the generated code is not portable accross look and feels. It shouldn't contain any integer values.
    e.g. like the following line of code:
    .addComponent(txtCountry, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 115, Short.MAX_VALUE)
    Lines like these shouldn't be in the code. It is possible to get rid of these with Matisse. But its not easy.

    With best regards, I like reading your blogs very much!
    Werner

    Posted by: wrandelshofer on October 05, 2006 at 02:37 PM

  • bnahas, as Cypher said once about the Matrix code "All I see now is blonde, brunette, redhead." I look at ZoneLayout and all i see is the random letters. How is it easier to refactor? When i change "a>a" in the layout definition, you'd have to go and change all those references in the code. Not that PageLayout is simpler to refactor, since it requires multiple references to the same row/control.

    Posted by: kirillcool on October 05, 2006 at 02:38 PM

  • krillicool

    You must have meant that 'Not that GroupLayout' is easier to refactor.

    In PageLayout, for the layout you make only one reference to each component.

    Only if you want to apply size constrainst do you ahve to refer to them again. I think this separation of the layout process and the specification of size constraints is better than the other methods.

    Using strings to specify constraints specially if the constraints are more than a single word, as is done in other layouts is not something that I prefer. It can always be done by saving a couple of lines of code at the cost of cryptic string commands which make their own mini-language, but I think it's not worth it.

    Posted by: varan on October 05, 2006 at 03:14 PM

  • varan, i'm looking at the PageLayout code and i see that each control is referenced twice in the code. So, if i need to move stuff around, i'll have to change it in two places. A simple example would be switching rows - compare how easy / difficult it is in the three proposed layouts (Mig / Page / Zone).

    Posted by: kirillcool on October 05, 2006 at 03:26 PM

  • No you don't have to refer to a control the second time unless you want to impose a size constraint. Many of the constraints in the code above would be unnecessary if I had used a grid instead of a column of rows.

    You can switch around any of the rows in the constructor without changing any other part of the code to get the same result.


    Column column=new Column(Cell.LEFT,Cell.CENTER,
    row1,row2,row3,row4,row5,row6,row7);

    By the way, the code shown by John above underscores my point that GroupLayout may be good as a backend for automated GUI Builders, but
    it does not lend itself to easy usage by human programmers. I am surprised that Sun is going to release it as a part of JDK 1.6. I think its a mistake.

    Posted by: varan on October 05, 2006 at 04:14 PM

  • varan - i'd assume that as the developer of the layout you'd show the best to use it for the specific case. As you have decided to go with double-referenced implementation, that's what i'm seeing. And indeed, GroupLayout is a nasty beast to maintain by hand - never said the opposite. For now, as you are trying to propose an alternative to MigLayout - i don't see how it's better, especially since MigLayout is going to have API-based layout (in addition to string-based layout).

    Posted by: kirillcool on October 05, 2006 at 04:16 PM

  • Since you insist, here is the code for 'singly referenced' components.
    Here cell is a predfined 2-d array.

    It is already API based. I don't think the other manager can handle nested layouts without introducing extraneous panels.


    cells[0]= new Component[]
    {lastName,lastNameE,firstName,firstNameE};
    cells[1]= new Component[]
    {phone,phoneE,email,emailE};
    cells[2]= new Component[]
    {address1,address1E,CellGrid.HSPANComponent,
    CellGrid.HSPANComponent};
    cells[3]= new Component[]
    {address2,address2E,CellGrid.HSPANComponent,
    CellGrid.HSPANComponent};
    cells[4]= new Component[]
    {city,cityE,null,null};
    cells[5]= new Component[]
    {state,stateE,postal,postalE};
    cells[6]= new Component[]
    {county,countyE,null,null};
    CellGrid grid=CellGrid.createCellGrid(cells);

    Column column=new Column(CENTER,CENTER,grid);


    Posted by: varan on October 05, 2006 at 05:39 PM

  • wrandelshofer,

    Finally I see someone mentioning the problem of constants in layouts! (Pardon the bold text, but it has been 10 years!)

    There is an insidious number of places where constants appear in layouts, and many instances where you cannot control things in indirected ways. I'm talking about what's in the library right now; and not about something that may appear in Swinglabs: and though I don't know everything there I have even seen some "new" approaches - using bindings and things - with constants in XML files!

    For example, borders, insets, and spacing force you to use constants. It is much more sensible to be able to return values based on the current font size so they can scale dynamically. I have subclassed some borders and struts to try doing that, but unfortunately the API is such that it's not 100% guaranteeable.

    And a related bug is one I was working on submitting a fix for, where overriding getPreferredSize on a JLabel in BoxLayout gives rise to a broken layout. The components and Layout managers become usure of what sizes to use because some code is assuming things based on set property values and some is invoking methods. It's just so poor to shove numbers into setWidth or something.

    Since layout managers have been part of the AWT from the beginning it's just not really good that components, including spacing, would be sized explicitly.

    It's completely plausible to have solid ergonomic layouts without setting values on things. But over the years it has leaned far to much in the direction of explicit constants. Do you have any tips for me?

    -Steev Coco.

    Posted by: steevcoco on October 05, 2006 at 08:01 PM

  • steevcoco.
    I totally agree with you. I am craving for a means of creating ergonomic and visually appealing layouts that work across look and feels, across screen resolution, and maybe even across platforms.

    For me, basing spacings on font size isn't sufficient. The layouts that I create often use fonts at different sizes at the same time. I am looking for a solution that allows me to create a layout based on logical and visual criteria, and then have it work seamlessly across the things I mentioned above.

    I haven't got any tips for you that work with the existing J2SE library. You may want to take a look at class LayoutStyle, which is used by GroupLayout behind the scenes to get rid of constant values. LayoutStyle is very good at this, because it takes the current state of a component and the current look and feel into account. Maybe John may talk about this in a future blog of his?.
    This doesn't address the border, insets and spacing problems you are mentioning. I personally made a go at this, by implementing a look and feel of my own, that - together with LayoutStyle - supports spacings based on the visual features of components. It allows to specify a "related" or "unrelated" space between the visually perceived borders of two components. That is, by taking their visually perceivable borders, insets, and curvings into account. I tried to convince the Swing team to implement something like this, but they couldn't, because they need to access native rendering functionality of Windows and KDE for platform fidelity. Unfortunately these user interface toolkits don't provide access to information about perceived bounds.
    Best regards, Werner

    Posted by: wrandelshofer on October 05, 2006 at 11:09 PM

  • kirillcool,

    Why would you want to change the references to Zone 'a'? Odds are you might want to change the properties of Zone 'a', and in that case you would manipulated the layout definition.

    If you wanted to slightly alter a row in the layout, you could create a new row template and insert that one instead for that particular row. Or you don't have to use templates at all. You could definte the entire layout without them.

    As for the layout definition being hard to read... you get used to it quickly. It becomes far easier to read than these other layouts. You begin to "see" the general idea of a layout when looking at the spec. These other layout managers require you to reverse engineer all of the specifications to understand what's going on. And would you rather declaratively parse strings or use regular expressions? I feel the same way about my layout code. Simple and concise. And ZoneLayout layout code is much easier to read than regular expressions (not as many features).

    Posted by: bnahas on October 06, 2006 at 09:34 AM

  • bnahas, would you venture to provide the download statistics for ZoneLayout to substantiate the claims of ease-of-use / adoption rate?

    Posted by: kirillcool on October 06, 2006 at 04:25 PM

  • kirrilcool

    Would you care to clarify your relationship, if any, with MiG Layout guys?

    Posted by: varan on October 06, 2006 at 06:03 PM

  • varan - none, except knowing Mikael's work in blogosphere and on custom Swing components. Are you implying that i'm a Mig InfoCom employee / affiliate trying to play the role of an "objective" bystander?

    Posted by: kirillcool on October 06, 2006 at 08:19 PM

  • kirillcool, have you downloaded ZoneLayout and invested the necessary 15-30 minutes to try it out? Can you definitively say that you didn't think it was easy to use after doing so?

    I get the feeling you haven't.

    No, the ZoneLayout downloads are not substantial, but that doesn't necessarily speak about its ease of use. I suspect that has to do more with lack of awareness and its unorthodox nature. There are people out there using it and a few that have taken the time to provide me feedback have been very complimentary.

    Posted by: bnahas on October 07, 2006 at 06:22 AM

  • John O'Conner

    Clearly there is a need for a neutral third party to post an unbiased review and comparison of the various Layout Managers which are being talked about here, and perhaps others, especially in light of the fact that the code for each of them for your example is far more compact than the GroupLayout code generated by Matisse.

    I will be more than happy to help anyone who wants to do it.

    Posted by: varan on October 07, 2006 at 08:58 AM

  • varan, agreed. Do we have a neutral party around here? Personally, I doubt it. I'll open up a friendly competition that utilizes our biased nature via my next blog, and I'll specify the forms, the rules, and the layout managers of interest.

    In the meantime, you could send me your list of layout managers that are interesting. I'll make sure they all get included.

    Posted by: joconner on October 07, 2006 at 11:27 AM

  • John, i was just about to propose it - thankfully you beat me to it. I'd suggest at least FormLayout (JGoodies), MigLayout, ZoneLayout, PageLayout, GroupLayout (NB), TableLayout. In addition, the following question should be considered - support for RTL, support for IDEs, support for easily adding /removing a row / column, support for resizing (growing one column, growing a subset of columns, ...), licensing issues, documentation, amount of code needed to layout simple / common examples.

    Posted by: kirillcool on October 07, 2006 at 11:56 AM

  • Thanks John.

    I think your idea is very good.

    One example that you might want to include in your challenge is
    this, with the stipulation that no nested panels be used solely for the purpose of layout.

    I think the list of layout managers given in the post above is quite exhaustive. At least it exhausts my knowledge of the various available alternatives.

    Posted by: varan on October 07, 2006 at 04:16 PM

  • I'm in, representing MiG Layout.

    The tough part is for the poor guy or gal who's going to, in words, specify how a panel should look like...

    Cheers,
    Mikael

    Posted by: mikaelgrev on October 07, 2006 at 04:27 PM

  • John - how about a few screens from Eclipse / NB / IDEA's Options / Preferences / ... They have some pretty nice and complicated stuff there. Of course no limitations should be imposed on the implementation, like varan suggests, but the ease of creating each such screen would be judged by the code complexity and maintainability.

    Posted by: kirillcool on October 07, 2006 at 06:32 PM

  • OK Kirill, others. Let me get my mind around this a little better and I'll present the idea of a contest with preliminary rules and current participants in a couple days. Send me email at john at joconner dot com if you are interested in providing the analysis for a specific layout manager. Then well take a few days of input on the rules, allow for suggestions and changes, then we'll let all the participants take a week or so to do their analysis. I'll start another blog for this soon.

    Posted by: joconner on October 08, 2006 at 02:08 AM


  • What about SwingWiki ?

    I would be excited to see each layout manager described on this wiki, with features, pros and cons, and opinions.

    One might also propose a contest page, or more simply, a manager central page, on this wiki, proposing numerous panels to implement. Then, each layout manager proponents may give their implementations of each panel within the associated manager's pages.

    Such a wiki could be an interesting neutral party
    (while opening the doors to numerous writers, and providing pages, and page relationships
    to organize content better than a blog).

    Using this wiki (or another one ?) looks useful, as beyond contest, it would ease layout manager learning curve, with gathering plenty of documentation/examples into a single place.

    What do you think about it ?

    NB : I am not part of this wiki.

    Posted by: dmdevito on October 09, 2006 at 08:16 AM

  • dmdevito


    thanks a lot for the info. I have added a section on PageLaout on SwingWiki. Hope that the site has some audience.

    Posted by: varan on October 09, 2006 at 02:05 PM


  • I have just updated few pages in the SwingWiki for my own purposes. Registration is free for updating the wiki. So, I imagine it could be the place for your layout manager contest.

    -- Dominique


    Posted by: dmdevito on October 10, 2006 at 03:29 PM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds