Redrawing container or individual, dynamic elements in GWT page?

I am developing a GWT app (I’m fairly new to GWT so this is a request for best practices; I haven’t found any relevant answer on SO or elsewhere) where a timeline is required. This timeline (with descriptions, labels, interaction handles, and plots) resides in its own container (a Panel).

          [<] [now] [>]             // Interaction (navigation)
          2007 2008 2009 2010       // Labels
          |    |    |    |
+ Group 1                           // Collapsible groups
- Group 2
  Item 2a  =====   ==               // Item with plots (plots are wrapped in container per Item)
  Item 2b    =====     ===  =
-Group 3
  Item 3a ===
  Item 3b      ===

Now, when user’s navigate the timeline (using the button to move forward or backwards), I need to recalculate some elements of the layout:

  • Labels need recalculating / repositioning
  • Plots need recalculating / repositioning. Plots are based on a set of Timeslot elements (extends Widget, attributes dateStart and dateEnd) which are already related to Items which are related to Groups.

The collapsible panels are DisclosurePanels.

As far as I can tell, I now have two options for handling navigation:

  1. I can clear() the container panel and do a complete redraw. For this, I need to preserve the state (collapsed/expanded) for all groups. (Groups and items are static for the entire period, by the way!) This will give one big redraw.
  2. I can let the plot containers (each Item has its own TimeslotContainer which is a FlowPanel) hold a reference to all its Timeslots and then let every TimeslotContainer redraw itself (i.e., filter and position relevant Timeslots) based on the current timespan. This will give several minor redraws (one per Item per expanded Group), the advantage being that the DisclosurePanels will be preserved, thus maintaining their own state.

I’m inclined to go with the second solution. But are there any best practices on this one? Am I missing some common gotchas?

Answer

I went ahead and implemented a version of the second solution under the original intention to try the first if the second did not perform sufficiently. (This was never realized, though, as the second solution performed highly satisfactorily.)

What I asked in the question was primarily references to the GWT way to do this. I still haven’t found anything written regarding this issue and so suspect that nobody has missed such guidelines before 🙂 To conclude my search, I will self-answer the question outlining the way I ended up implementing together with the (assumed) pros and cons. Thanks to @Ümit for supporting my instincts. The following is in part intended to address the last paragraph in @Ümit’s answer regarding the complexity of the draw methods.


I ended up letting TimeslotContainers (the Panels containing TimeSlots), LabelPanel (Panel with generated HTML elements), and NavigationPanel realize a simple interface:

public interface IReceivesPeriodChangedEvents {
    public void periodChanged();
}

A simple EventBus handled the notification process on these IReceivesPeriodChangedEvents instances:

public class EventBus {
    private static EventBus instance;

    private Set<IReceivesPeriodChangedEvents> receivers;

    private EventBus() {
        this.receivers = new HashSet<IReceivesPeriodChangedEvents>();
    }

    public static EventBus getInstance() {
        if (instance == null) {
            instance = new EventBus();
        }

        return instance;
    }

    public void addReceiver(IReceivesPeriodChangedEvents receiver) {
        this.receivers.add(receiver);
    }

    public void notifyPeriodChanged() {
        for (IReceivesPeriodChangedEvents receiver : this.receivers) {
            receiver.periodChanged();
        }
    }
}

Whenever one of TimeslotContainer, LabelPanel or NavigationPanel were instantiated (once per page load, these objects are reused throughout the lifetime of the page) they made sure to subscribe to the EventBus:

public class TimeslotContainer extends FlowPanel implements IReceivesPeriodChangedEvents {
    public TimeslotContainer(/* ... */) {
        // ...
        EventBus.getInstance().addReceiver(this);
    }
    // ...
}

In order to handle the “complex” draw method, I simply created a method (buildFromStore()) to add relevant Widgets (e.g., newly created Timeslot objects on the TimeslotContainers). This resulted in great reuse of the draw method:

public class NavigationPanel extends FlowPanel implements IReceivesPeriodChangedEvents {
    public NavigationPanel() {
        // ...
        buildFromStore();
        EventBus.getInstance().addReceiver(this);
    }

    private void buildFromStore() {
        // Add lots of HTML elements here
    }

    @Override
    public void periodChanged() {
        clear();
        buildFromStore();
    }
}

Simple as that!


In conclusion:
No gotchas encounted. Lots of minor redraws did not seem to be a problem (I never implemented solution one, though). The draw methods could be reused (in this case, at least). The collapsible DisclosurePanels never lost their state as they were never replaced (only their contents were).

Leave a Reply

Your email address will not be published. Required fields are marked *