GWT DisclosurePanel open/close without header

April 19th, 2010 Javier Ochoa, Consultant  (email the author)

This entry is part 2 of 11 in the series Developing GWT Applications

The DisclosurePanel in GWT is a special Widget that contains a header and a body, and the header contains an anchor tag for expanding or collapsing the body. It can look like this, where clicking on the arrow next to “Advanced Criteria” will disclose the rest of the panel:

gwt_disclosure

A typical use of DisclosurePanel is something like this:

DisclosurePanel pnlDisclosure = new DisclosurePanel();
pnlDisclosure.setHeader(new Label("Title"));
pnlDisclosure.setContent(new Label("Content"));

In a recent project, however, the interface designer on my team asked whether we could disable the anchor tag (for expand/collapse) on the DisclosurePanel header and have a single button do the job instead, helping the user with a hint that this panel is actually expandable. So, for example, the DisclosurePanel would look something like this (note the arrow on the right):

Collapsed:
Collapsed disclosurepanel

Expanded:
Expanded disclosurepanel

I said “OK, let’s see the DisclosurePanel javadoc”. Suprise! All you can do is have a header that itself is surrounded by the clickable anchor… time to extend Composite!

The solution I found is quite simple, but I’m sure there are others out there, if you know a different one just drop a comment:

1. First get the nested widgets right:

FlowPanel pnlMain = new FlowPanel(); //Main panel
FlowPanel pnlHeader = new FlowPanel();
DisclosurePanel pnlDisclosure = new DisclosurePanel();

pnlMain.add(pnlHeader);
pnlMain.add(pnlDisclosure);

2. Add a Label to the header, which will act as the expand/collapse button. You can use a PushButton which gives you more possibilities to style button states (on mouse over, down, up, etc.):

Label btnCollapseExpand = new Label();
btnCollapseExpand.setText('\u25BA' + "");
btnCollapseExpand.setTitle("expand/collapse");


pnlHeader.add(btnCollapseExpand);
pnlHeader.add(new Label("Title in disclosure panel"));

3. This is the key, add only Content to the disclosure panel (no header):

// Disclosure panel with no header
pnlDisclosure.setWidth("100%");
pnlDisclosure.setContent(new Label("Disclosure panel with a specific expand/collapse button"));

4. And don’t forget to add the corresponding click handler to the button to change the disclosure panel state:

btnCollapseExpand.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
pnlDisclosure.setOpen(!pnlDisclosure.isOpen());
}
});

And that’s it! You have now a DisclosurePanel and one button which invites the user to click on it. One extra enhancement if you want to change the button text/title when the panel opens/close, add the following two handlers:

pnlDisclosure.addOpenHandler(new OpenHandler() {
@Override
public void onOpen(OpenEvent event) {
btnCollapseExpand.setText('\u25BC' + "");
btnCollapseExpand.setTitle("collapse");
}
});

pnlDisclosure.addCloseHandler(new CloseHandler() {
@Override
public void onClose(CloseEvent event) {
btnCollapseExpand.setText('\u25BA' + "");
btnCollapseExpand.setTitle("expand");
}
});

Here is the source code of the custom widget, so go ahead and take a look!

Be Sociable, Share!

Entry Filed under: Agile and Development

7 Comments Add your own

  • 1. Flo  |  March 30th, 2011 at 9:26 am

    If you stumbled across this like me, trying to customize the header of a DisclosurePanel without losing its look and feel, here’s a start. Unfortunately, the DisclosurePanel’s default header is created by an inner class which cannot be edited easily. You can wrap it, though:

    DisclosurePanel disclosurePanel = new DisclosurePanel(“Define your header text here”);
    Widget defaultHeader = disclosurePanel.getHeader();
    HorizontalPanel newHeader = new HorizontalPanel();
    newHeader.add(defaultHeader);
    Widget whatever = new Button(“Whatever”);
    newHeader.add(whatever);
    disclosurePanel.setHeader(newHeader);

  • 2. Javier Ochoa  |  April 1st, 2011 at 10:59 am

    How is this different from your code? I don’t see the advantage of getting the header widget as opposed of defining a Label with that text.

    DisclosurePanel disclosurePanel = new DisclosurePanel();
    HorizontalPanel newHeader = new HorizontalPanel();
    newHeader.add(new Label(“Define your header text here”);
    Widget whatever = new Button(“Whatever”);
    newHeader.add(whatever);
    disclosurePanel.setHeader(newHeader);

    Is the click working different?

  • 3. David  |  October 3rd, 2011 at 3:04 pm

    I think Its a subtle but important difference. Flo’s example is using a decorator design pattern approach to solving the problem. With Flo’s code you get to keep having the functionality of the orginal behaviour of a disclosure panel’s default header with your own customizations decorated around it .. (ie the open and close images (the arrows) and styling of the original widget are maintained.) If Google changes the default header – Flo’s decorated code will get the changes as well.

  • 4. Javier Ochoa  |  October 4th, 2011 at 1:38 pm

    looks pretty similar, but you might be right. Flo’s code is actually removing the generated header from its parent when doing the newHeader.add(defaultHeader) and can maintain the defined behavior.

  • 5. Michelle  |  June 8th, 2012 at 4:31 pm

    Flo’s solution was exactly what I needed; thanks!

  • 6. Wengfu Zhoudong  |  June 14th, 2012 at 8:25 am

    The example provided in this article is a hack. In comparison, Flo’s solution is applying software engineering principles.

  • 7. törzsmókus  |  November 3rd, 2012 at 3:13 am

    I think I found another subtle but important difference :)
    With Flo’s beautiful solution, we still have the clickable header*, which we (at least me nor the original author) do not want. Watch out.
    * setHeader() puts the new header _inside_ the anchor element

Leave a Comment

Required

Required, hidden


+ one = 3

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed

© 2010-2014 Summa All Rights Reserved