在GWT页面中重绘容器或个人,动态元素?

时间:2011-11-07 08:16:46

标签: java gwt

我正在开发一个GWT应用程序(我对GWT很新,所以这是对最佳实践的请求;我没有在SO或其他地方找到任何相关答案)需要时间表。此时间轴(包含描述,标签,交互句柄和图表)位于其自己的容器中(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      ===

现在,当用户导航时间线时(使用按钮向前或向后移动),我需要重新计算布局的一些元素:

  • 标签需要重新计算/重新定位
  • 情节需要重新计算/重新定位。图表基于一组Timeslot元素(扩展Widget,属性dateStartdateEnd),这些元素已经与Item相关,与{ {1}}秒。

可折叠面板为DisclosurePanel s。

据我所知,我现在有两个处理导航的选项:

  1. 我可以clear()容器面板并完成重绘。为此,我需要保留所有组的状态(折叠/扩展)。 (顺便说一句,组和项目在整个时期都是静态的!)这将给出一个大的重绘
  2. 我可以让情节容器(每个Group都有自己的Item,这是FlowPanel)持有对其所有TimeslotContainer的引用,然后让每个{ {1}}根据当前时间跨度重绘自身(即过滤和定位相关的Timeslot)。这将提供几次小重绘(每个展开TimeslotContainerTimeslot一个),优势是Item将被保留,从而保持自己的状态
  3. 我倾向于采用第二种解决方案。但是这方面有什么最佳做法吗?我错过了一些常见的陷阱吗?

2 个答案:

答案 0 :(得分:1)

如果团体和物品是静止的,我也会推荐第二种方法 DOM操作(构造等)是GWT应用程序中最昂贵的功能(性能明智),因此这些DOM操作应保持在最低限度。 但是我不认为性能可能是一个大问题,因为DOM元素的数量相对较低。

尽管如此,我仍然认为第二种方法更好。您不必为组和项目存储状态,因为它们是静态的,重绘它们并没有多大意义。

我只能想到第一种方法的一个优点: 只有一个相对容易的绘制功能。在第二种方法中,所有TimesSlotContainer都必须实现一个函数才能重绘自己,并且还要考虑Timespan的位置和上下文。该功能可能比一个大的重绘功能更复杂。

答案 1 :(得分:0)

我继续在初衷下实施了第二个解决方案的版本,如果第二个解决方案没有充分执行,则尝试第一个。 (但这一点从未实现过,因为第二种解决方案表现得非常令人满意。)

我在问题中提到的主要是 GWT方式这样做。我仍然没有找到关于这个问题的任何书面内容,所以怀疑没有人错过这样的指导方针:)为了结束我的搜索,我将自我回答问题,概述我最终与(假设的)专业人员一起实施的方式利弊。感谢@Ümit支持我的直觉。以下部分旨在解决@Ümit's answer中有关绘制方法复杂性的最后一段。


我最终让TimeslotContainer s(包含TimeSlot s的面板),LabelPanel(包含生成的HTML元素的面板)和NavigationPanel实现了简单的界面:

public interface IReceivesPeriodChangedEvents {
    public void periodChanged();
}

一个简单的EventBus处理了这些IReceivesPeriodChangedEvents个实例的通知流程:

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();
        }
    }
}

每当TimeslotContainerLabelPanelNavigationPanel中的一个被实例化时(每页加载一次,这些对象在页面的整个生命周期中都会被重用),他们确保订阅{ {1}}:

EventBus

为了处理“复杂”的绘制方法,我只是创建了一个方法(public class TimeslotContainer extends FlowPanel implements IReceivesPeriodChangedEvents { public TimeslotContainer(/* ... */) { // ... EventBus.getInstance().addReceiver(this); } // ... } )来添加相关的buildFromStore() s(例如,Widget新对象Timeslot 1}}为s)。这导致了绘制方法的重复使用:

TimeslotContainer

这很简单!


总结:
没有陷入困境。很多小的重绘似乎不是一个问题(我从来没有实现过解决方案)。绘制方法可以重复使用(至少在这种情况下)。可折叠的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(); } } 永远不会丢失他们的状态,因为他们从未被替换过(只有他们的内容)。