Locked History Actions

Diff for "GWT/DevGuideUiPanels"

Differences between revisions 3 and 4
Deletions are marked like this. Additions are marked like this.
Line 56: Line 56:

The bulk of the layout system is embodied in a series of panel widgets. Each of these widgets uses the underlying layout system to position its children in a dependable manner.
RootLayoutPanel

This panel is a singleton that serves as a root container to which all other layout panels should be attached (see RequiresResize and ProvidesResize below for details). It extends LayoutPanel, and thus you can position any number of children with arbitrary constraints.

You most commonly use RootLayoutPanel as a container for another panel, as in the following snippet, which causes a DockLayoutPanel to fill the browser's client area:
レイアウトシステムの大部分は一連のパネルウィジェットで実現される。
これらのウィジェットは下層のレイアウトシステムを用いて、子ウィジェットを信頼できるやり方でポジショニングする。


=== RootLayoutPanel ===

このパネルは他のすべてのレイアウトパネルがアタッチされるルートコンテナの役割をするシングルトンである
(詳細は後述するRequiresResizeとProvidesResizeを参照のこと)。
このパネルはLayoutPanelを継承しており、任意の制約をつけた複数の子をポジショニングすることができる。

多くの場合、以下のスニペットに示すように、他のパネルのコンテナとしてRootLayoutPanelを使うことになる。
ここでは、ブラウザのクライアントエリアをDockLayoutPanelで覆っている。
Line 71: Line 76:
Think of LayoutPanel as the most general layout mechanism, and often one upon which other layouts are built. Its closest analog is AbsolutePanel, but it is significantly more general in that it allows its children to be positioned using arbitrary constraints, as in the following example: LayoutPanelは最も一般的なレイアウトメカニズムであり、他のレイアウトは多くの場合これを元にしている。
Its closest analog is AbsolutePanel, but it is significantly more general in that it allows its children to be positioned using arbitrary constraints, as in the following example:
Line 85: Line 92:
DockLayoutPanel

===
DockLayoutPanel ===

Developer's Guide - Layout Using Panels

http://code.google.com/intl/ja/webtoolkit/doc/latest/DevGuideUiPanels.htmlの訳(予定)

GWTにおけるパネルは他のUIにおけるlayoutに相当する。 最も大きな違いとしては、GWTのパネルはその子ウィジェットをレイアウトするのにHTML要素を使用する点である。

パネルはウィジェットや他のパネルを格納し、ブラウザ中でのUIインターフェースのレイアウト定義に用いられる。

基本的なパネル

RootPanel

RootPanelは他のウィジェットすべてが最終的にアタッチされるト最上位のパネルである。 RootPanel.get()は、HTMLドキュメント中の<body>要素をラップする単一のパネルを取得する。

RootPanel.get(String id)を使うことによって、ページ中のいかなる他要素をも取得することができる。

FlowPanel

FlowPanelは最も単純なパネルである。単一の<div>要素を作成し、そこに子を何の変更も無しに直接アタッチする。 子ウィジェットのレイアウトに自然なHTMLの流れを使いたい場合に、このクラスを使うこと。

HTMLPanel

このクラスはHTML構造を定義するのに単純な方法を提供する。 within which widgets will be embedded at defined points. 直接使うこともできるが、UiBinderテンプレートで使用するのが普通だ。

FormPanel

HTMLフォームの振る舞いを再現する必要のあるときにFormPanelを使うことができる(つまり、POSTリクエストを期待するサーバとの作用や、ブラウザにおけるデフォルトのキーボードの振る舞いを取得したい場合:訳注:?)。 このパネルに含まれるウィジェットは、<form>要素に含まれることになる。

ScrollPanel

他のパネル中にスクロール可能領域を作成したいときにScrollPanelを使う。 このパネルは、適切なスクロールが必要になる明示的なサイズを供給するレイアウトパネルとうまく協調する(後述する)。

PopupPanelとDialogBox

これれは、単純なポップアップとモーダルなダイアログを作る。 これらはブラウザ中の既存のコンテンツにオーバラップし、互いにスタックすることが可能である。

GridとFlexTable

これら二つのウィジェットは伝統的な<table>要素を作成する。 それに加えて、パネルとしても使用可能であるが、この場合はセル中に任意のウィジェットを格納することができる。

レイアウトパネル

GWT 2.0では多くの新パネルが道入されたが、これらは高速で予測可能なアプリケーションレベルのレイアウトの安定したベースとなるものである。 背景と詳細については、後述する"Design of the GWT 2.0 layout system"を参照してほしい。

レイアウトシステムの大部分は一連のパネルウィジェットで実現される。 これらのウィジェットは下層のレイアウトシステムを用いて、子ウィジェットを信頼できるやり方でポジショニングする。

RootLayoutPanel

このパネルは他のすべてのレイアウトパネルがアタッチされるルートコンテナの役割をするシングルトンである (詳細は後述するRequiresResizeProvidesResizeを参照のこと)。 このパネルはLayoutPanelを継承しており、任意の制約をつけた複数の子をポジショニングすることができる。

多くの場合、以下のスニペットに示すように、他のパネルのコンテナとしてRootLayoutPanelを使うことになる。 ここでは、ブラウザのクライアントエリアをDockLayoutPanelで覆っている。

DockLayoutPanel appPanel = new DockLayoutPanel(Unit.EM);
RootLayoutPanel.get().add(appPanel);

LayoutPanel

LayoutPanelは最も一般的なレイアウトメカニズムであり、他のレイアウトは多くの場合これを元にしている。

  • Its closest analog is AbsolutePanel, but it is significantly more general in that it allows its children to be positioned using arbitrary constraints, as in the following example:

Widget child0, child1, child2;
LayoutPanel p = new LayoutPanel();
p.add(child0); p.add(child1); p.add(child2);

p.setWidgetLeftWidth(child0, 0, PCT, 50, PCT);  // Left panel
p.setWidgetRightWidth(child1, 0, PCT, 50, PCT); // Right panel

p.setWidgetLeftRight(child2, 5, EM, 5, EM);     // Center panel
p.setWidgetTopBottom(child2, 5, EM, 5, EM);

LayoutPanel example

DockLayoutPanel

DockLayoutPanel serves the same purpose as the existing DockPanel widget, except that it uses the layout system to achieve this structure without using tables, and in a predictable manner. You would often use to build application-level structure, as in the following example:

DockLayoutPanel p = new DockLayoutPanel(Unit.EM); p.addNorth(new HTML("header"), 2); p.addSouth(new HTML("footer"), 2); p.addWest(new HTML("navigation"), 10); p.add(new HTML(content));

DockLayoutPanel example

Note that DockLayoutPanel requires the use of consistent units for all children, specified in the constructor. It also requires that the size of each child widget (except the last, which consumes all remaining space) be specified explicitly along its primary axis. SplitLayoutPanel

The SplitLayoutPanel is identical to the DockLayoutPanel (and indeed extends it), except that it automatically creates a user-draggable splitter between each pair of child widgets. It also supports only the use of pixel units. Use this instead of HorizontalSplitPanel and VerticalSplitPanel.

SplitLayoutPanel p = new SplitLayoutPanel(); p.addWest(new HTML("navigation"), 128); p.addNorth(new HTML("list"), 384); p.add(new HTML("details"));

SplitLayoutPanel example StackLayoutPanel

StackLayoutPanel replaces the existing StackPanel (which does not work very well in standards mode). It displays one child widget at a time, each of which is associated with a single "header" widget. Clicking on a header widget shows its associated child widget.

StackLayoutPanel p = new StackLayoutPanel(Unit.EM); p.add(new HTML("this content"), new HTML("this"), 4); p.add(new HTML("that content"), new HTML("that"), 4); p.add(new HTML("the other content"), new HTML("the other"), 4);

StackLayoutPanel example

Note that, as with DockLayoutPanel, only a single unit type may be used on a given panel. The length value provided to the add() method specifies the size of the header widget, which must be of a fixed size. TabLayoutPanel

As with the existing TabPanel, TabLayoutPanel displays a row of clickable tabs. Each tab is associated with another child widget, which is shown when a user clicks on the tab.

TabLayoutPanel p = new TabLayoutPanel(1.5, Unit.EM); p.add(new HTML("this content"), "this"); p.add(new HTML("that content"), "that"); p.add(new HTML("the other content"), "the other");

TabLayoutPanel example

The length value provided to the TabLayoutPanel constructor specifies the height of the tab bar, which you must explicitly provide. When should I not use layout panels?

The panels described above are best used for defining your application's outer structure — that is, the parts that are the least "document-like". You should continue to use basic widgets and HTML structure for those parts for which the HTML/CSS layout algorithm works well. In particular, consider using UiBinder templates to directly use HTML wherever that makes sense. Animation

The GWT 2.0 layout system has direct, built-in support for animation. This is necessary to support a number of use-cases, because the layout system must properly handle animation among sets of layout constraints.

Panels that implement AnimatedLayout, such as LayoutPanel, DockLayoutPanel, and SplitLayoutPanel, can animate their child widgets from one set of constraints to another. Typically this is done by setting up the state towards which you wish to animate, then calling animate(). See "Recipes" below for specific examples. RequiresResize and ProvidesResize

Two new characteristic interfaces were introduced in GWT 2.0: RequiresResize and ProvidesResize. These are used to propagate notification of resize events throughout the widget hierarchy.

RequiresResize provides a single method, onResize(), which is called by the widget's parent whenever the child's size has changed. ProvidesResize is simply a tag interface indicating that a parent widget will honor this contract. The purpose of these two interfaces is to form an unbroken hierarchy between all widgets that implement RequiresResize and the RootLayoutPanel, which listens for any changes (such as the browser window resizing) that could affect the size of widgets in the hierarchy. When to use onResize()

Most widgets should not need to know when they've been resized, as the browser's layout engine should be doing most of the work. However, there are times when a widget does need to know. This comes up, for example, when a widget contains a dynamic list of items depending upon how much room is available to display them. Because it's almost always faster to let the layout engine do its work than to run code, you should not lean upon onResize() unless you have no alternative. When and how to implement ProvidesResize

A panel that implements ProvidesResize is expected to propagate resize events to any of its child widgets that implement RequiresResize. For a canonical example of this, see the implementation of LayoutPanel.onResize(). Most custom widgets will want to composite an existing layout panel using ResizeComposite, however, as described next. ResizeComposite

When creating a custom Composite widget that wrap a widget that implements RequiresResize, you should use ResizeComposite as its base class. This subclass of Composite automatically propagates resize events to its wrapped widget. Moving to Standards Mode

The GWT 2.0 layout system is intended to work only in "standards mode". This means that you should always place the following declaration at the top of your HTML pages: <!DOCTYPE html> What won't work in standards mode?

As mentioned above, some of the existing GWT panels do not behave entirely as expected in standards mode. This stems primarily from differences between the way standards and quirks modes render tables. CellPanel (HorizontalPanel, VerticalPanel, DockPanel)

These panels all use table cells as their basic structural units. While they still work in standards mode, they will lay out their children somewhat differently. The main difference is that their children will not respect width and height properties (it is common to set children of CellPanels explicitly to 100% width and height). There are also differences in the way that the browser allocates space to individual table rows and columns that can lead to unexpected behavior in standards mode.

You should use DockLayoutPanel in place of DockPanel. VerticalPanel can usually be replaced by a simple FlowPanel (since block-level elements will naturally stack up vertically).

HorizontalPanel is a bit trickier. In some cases, you can simply replace it with a DockLayoutPanel, but that requires that you specify its childrens' widths explicitly. The most common alternative is to use FlowPanel, and to use the float: left; CSS property on its children. And of course, you can continue to use HorizontalPanel itself, as long as you take the caveats above into account. StackPanel

StackPanels do not work very well in standards mode. Because of the differences in table rendering mentioned above, StackPanel will almost certainly not do what you expect in standards mode, and you should replace them with StackLayoutPanel. SplitPanel (HorizontalSplitPanel and VerticalSplitPanel)

SplitPanels are very unpredictable in standards mode, and you should almost invariably replace them with SplitLayoutPanel. Design of the GWT 2.0 layout system

Prior to 2.0, GWT's mechanisms for handling application-level layout have a number of significant problems:

  • They're unpredictable. They often require extra code to fix up their deficiencies:
    • For example, causing an application to fill the browser's client area with interior scrolling is nearly impossible without extra code.
    They don't all work well in standards mode.

Their underlying motivation was sound — the intention was to let the browser's native layout engine do almost all of the work. But the above deficiencies can be crippling. Goals

  • Perfectly predictable layout behavior. Precision layout should be possible.
    • It should also work in the presence of CSS decorations (border, margin, and padding) with arbitrary units.
    Work correctly in standards-mode. Get the browser to do almost all of the work in its layout engine.
    • Manual adjustments should occur only when strictly necessary.
    Smooth, automatic animation.

Non-Goals

  • Work in quirks-mode. Swing-style layout based on "preferred size". This is effectively intractable in the browser. Take over all layout. This design is intended to handle coarse-grained "desktop-like" layout. The individual bits and pieces, such as form elements, buttons, tables, and text should still be laid out naturally.

The Layout class

The Layout class contains all the underlying logic used by the layout system, along with all the implementation details used to normalize layout behavior on various browsers.

It is actually widget-agnostic, operating directly on DOM elements. Most applications will have no reason to work directly with this class, but it should prove useful to alternate widget library writers. Constraint-based Layout

The GWT 2.0 layout system is built upon the simple constraint system that exists natively in CSS. This uses the properties left, top, width, height, right, and bottom. While most developers are familiar with these properties, it is less well-known that they can be combined in various ways to form a simple constraint system. Take the following CSS example:

.parent {

  • position: relative;

}

.child {

  • position: absolute; left:1em; top:1em; right:1em; bottom:1em;

}

In this example, the child will automatically consume the parent's entire space, minus 1em of space around the edge. Any two of these properties (on each axis) forms a valid constraint pair (three would be degenerate), producing lots of interesting possibilities. This is especially true when you consider various mixtures of relative units, such as "em" and "%". Recipes

The following are a series of simple "recipes" for creating various structures and dealing with different scenarios. Where possible, we'll describe the layout in terms of UiBinder templates. Basic application layout

The following sample shows a simple application-style layout with a header, a navigation area on the left edge, and a scrollable content area.

<g:DockLayoutPanel unit='EM'>

  • <g:north size='4'>

    • <g:Label>Header</g:Label>

    </g:north>

    <g:west size='16'>

    • <g:Label>Navigation</g:Label>

    </g:west>

    <g:center>

    </g:center>

</g:DockLayoutPanel>

You must place this structure in a container that implements ProvidesResize, which is most commonly RootLayoutPanel. The following code demonstrates how to do this:

interface Binder extends UiBinder<Widget, BasicApp> { } private static final Binder binder = GWT.create(Binder.class);

public void onModuleLoad() {

}

Splitters

SplitLayoutPanel works much like DockLayoutPanel, except that it only supports pixel units. The basic application structure above can be given a splitter between the navigation and content areas like so:

<g:DockLayoutPanel unit='EM'>

  • <g:north size='4'>

    • <g:Label>Header</g:Label>

    </g:north>

    <g:center>

    </g:center>

</g:DockLayoutPanel>

Note how we mix the dock and split panels, so that the header's size can be specified in EM units. Layout animation

To use animation with a LayoutPanel, you must first create an initial set of constraints, then animate to a target set of constraints. In the following example, we start with a child widget positioned at the top, but with no height so that it is effectively hidden. Calling LayoutPanel.forceLayout() "fixes" the initial constraints.

panel.setWidgetTopHeight(child, 0, PX, 0, PX); panel.forceLayout();

Now we give the widget a height of 2em and explicitly call LayoutPanel.animate(int) to cause it to resize over 500 ms.

panel.setWidgetTopHeight(child, 0, PX, 2, EM); panel.animate(500);

This will work with any constraints and any number of children. Implementing a Composite that RequiresResize

Widgets that implement RequiresResize expect RequiresResize.onResize() to be called whenever the widget's size changes. If you are wrapping such a widget in a Composite, you'll need to use ResizeComposite instead to ensure that this call is propagated correctly, like so:

class MyWidget extends ResizeComposite {

}

Child widget visibility

The Layout class has to wrap each of its child elements in a "container" element in order to work properly. One implication of this is that, when you call UIObject.setVisible(boolean) on a widget within a LayoutPanel, it won't behave quite as expected: the widget will indeed be made invisible, but it will tend to consume mouse events (actually, it's the container element that is doing so).

To work around this, you can get the container element directly using LayoutPanel.getWidgetContainerElement(Widget), and set its visibility directly:

LayoutPanel panel = ...; Widget child; panel.add(child); UIObject.setVisible(panel.getWidgetContainerElement(child), false);

Using a LayoutPanel without RootLayoutPanel

In most cases you should use layout panels by attaching them to a RootLayoutPanel, either directly or via other panels that implement ProvidesResize.

There are, however, instances where you need to use a layout panel within a normal widget (e.g., FlowPanel or RootPanel). In these cases, you will need to set the panel's size explicitly, as in the following example:

LayoutPanel panel = new LayoutPanel(); RootPanel.get("someId").add(panel); panel.setSize("20em", "10em");

Note that RootLayoutPanel provides no mechanism for wrapping an arbitrary element like RootPanel does. This is because it is impossible to know when an arbitrary element has been resized by the browser. If you want to resize a layout panel in an arbitrary element, you must do so manually.

This also applies to layout panels used in PopupPanel and DialogBox. The following example shows the use of a SplitLayoutPanel in a DialogBox:

SplitLayoutPanel split = new SplitLayoutPanel(); split.addWest(new HTML("west"), 128); split.add(new HTML("center")); split.setSize("20em", "10em");

DialogBox dialog = new DialogBox(); dialog.setText("caption"); dialog.add(split); dialog.show();

Tables and Frames

Widgets that are implemented using <table> or <frame> elements do not automatically fill the space provided by the layout. In order to fix this, you will need to explicitly set these widgets width and height to 100%. The following example shows this with a RichTextArea, which is implemented using an <iframe> element.

<g:DockLayoutPanel unit='EM'>

  • <g:north size='2'>

    • <g:HTML>Header</g:HTML>

    </g:north>

    <g:south size='2'>

    • <g:HTML>Footer</g:HTML>

    </g:south>

    <g:center>

    </g:center>

</g:DockLayoutPanel>