posts - 14, comments - 0, trackbacks - 0, articles - 0

Using CSS with GWT

Posted on 2007-01-10 17:08 忆了又忆 阅读(21719) 评论(0)  编辑  收藏 所属分类: Java

This is an attempt to put together a comprehensive reference for using Cascading Style Sheets with the Google Web Toolkit. I’ve assembled this document by first starting with the official documentation and then reviewing the source code. Where the source disagreed with the documentation I’ve sided with the source. I then did a runtime analysis of the sample applications that ship with the SDK to verify the results.

I feel there is a need for this because the documentation that comes with the SDK is rather unhelpful. The SDK says, basically, that widget styles are conventionally named [project]-[widget], e.g., gwt-Button, and style names correspond to CSS class names, so in order to style your button you would include something like

.gwt-Button { font-size: 150%; }
				

in your stylesheet. And that’s all it says. Really.

I believe this documentation to be inadequate for a number of reasons.

  1. The style is almost never as simple as the button example. Many GWT widgets correspond to messy nested tables, divs, and spans so it can be hard to know what it is you’re actually styling and what options are available to you in that context.
  2. The naming rule is not applied consistently within the SDK. The DialogBox class, for one, does not follow the rule.
  3. In some situations similarly named styles (*-selected*) are used in different or even contradictory manners making it hard to generalize your experience from one widget to another.
  4. In many cases the documentation is incorrect; the documented style simply is not implemented. The ListBox class should, according to both the general rule above and the specific class documentation, implement a style named gwt-ListBox. Nope, not there. Grep the source directory if you don’t believe me.

If I’ve left out a class below, it’s probably because it doesn’t participate in styling in any way. (I hope.) If you’re trying to read this straight through instead of just jumping to an item of interest, more power to you. If you find yourself yawning you might want to skip around a bit.

With that said…

AbsolutePanel

Implemented as a DIV and by default sets overflow to hidden. Contents are positioned absolutely according to given x, y values unless x == -1 and y == -1 in which case the widget is positioned statically.

<div style="overflow: hidden;"></div>
				

Button

Implemented as HTML BUTTON. Default style name is gwt-Button and is used. No default attributes. Can contain text or HTML.

<button class="gwt-Button" />
				

CellPanel

Implemented as a TABLE. No default styles. Can set border and cell-spacing attributes.

<table>
</table>
				

CheckBox

Implemented as HTML CHECKBOX. Default style name is gwt-CheckBox and is used. Automatically generates unique id of the form checkN where N is an integer. Uses checked, defaultChecked, and disabled attributes. No default styles.

<checkbox class="gwt-CheckBox" />
				

DeckPanel

Implemented using a DIV containing any number of children. The visibility of the individual children are controlled using the display attribute. The DeckPanel sets display to 'none' or '' as appropriate.

<div style="width: 100%; height: 100%"></div>
				

DialogBox

Default style names are gwt-DialogBox and Caption and are both used. Implemented as a DIV and the caption is also a DIV. (Technically, the caption is an HTML, which is a Label, which is implemented using a DIV.)

<div class="gwt-DialogBox">
  <table cell-spacing="0" cell-padding="0">
    <tbody>
      <tr>
      <td><div class="Caption">caption</div></td> </tr> <tr> <td> content </td> </tr> </tbody> </table> </div>

DockPanel

Implemented using TABLE. cell-spacing and cell-padding attributes both default to 0. Nesting of TR and TD elements can get quite complicated in order to achieve desired layout.

<table cell-spacing="0" cell-padding="0">
  <tbody>
  </tbody>
</table>
				

FlexTable

Just a TABLE, there’s nothing funky going on here.

<table>
  <tbody>
  </tbody>
</table>
				

FlowPanel

Implemented as a DIV with display set to inline.

<div style="display: inline;">content</div>
				

FocusPanel

A DIV. FocusPanel is only important in that it publishes a number of events (FOCUSEVENTS, KEYEVENTS, ONCLICK, and MOUSEEVENTS) and is very useful for containing widgets that don’t publish their own events. See Drag-and-Drop with the Google Web Toolkit.

<div>
  content
</div>
				

FocusWidget

Can be anything because it is implemented using whatever element is passed to it in the constructor. Interesting because it generates FOCUSEVENTS and KEYEVENTS.

Frame

Implemented as an IFRAME. Documented style name of gwt-Frame is not implemented.

<iframe>
</iframe>
				

Grid

Is just a table.

<table>
  <tbody>
  </tbody>
</table>
				

HTML

Implemented as a DIV with default style name of gwt-HTML. Can also set attribute white-space to normal or nowrap.

<div class="gwt-HTML">html</div>
				

HTMLPanel

Is a DIV that can either contain HTML exactly as HTMLor a collection of widgets. Does not use the gwt-HTML style. The most useful attribute of an HTMLPanel is that it contains the method createUniqueId that returns an id of the form HTMLPanel_N that can be used to apply styles to specific elements, as opposed to classes.

Contrast this with CheckBox which generates ids of the form checkN without either the capitalization or the underscore. Not a bug, just another minor inconsistency.

<div>
  content
</div>
				

HTMLTable

Unsurprisingly this class is implemented as a TABLE. The most important things to know about HTMLTable are (a) that it is the superclass for both FlexTable and Grid and (b) that it provides methods for setting the styles of individual rows or cells.

It is also worth noting that HTMLTable does not include a THEAD. The 0th row therefore must be used as something of a pseudo-header by applying any necessary styles.

<table>
  <tbody>
    <tr>Row 0 -- if you want a header you have to fake it here.</tr>
  </tbody>
</table>
				
// Style the first row to fake a header.
table.getRowFormatter(0).setStyleName("something-interesting");
				

HorizontalPanel

Implemented using a TABLE with all elements laid out as TDs in a single TR.

<table cell-spacing="0" cell-padding="0">
  <tbody>
    <tr>
      <td style="display: static; vertical-align: top;" align="left">Item 1</td>
      <td style="display: static; vertical-align: top;" align="left">Item 2</td>
    </tr>
  </tbody>
</table>
				

HyperLink

A DIV containing an anchor. Documented style name gwt-HyperLink is not implemented.

<div></div>
				

Image

Implemented as IMG. Documented style of gwt-Image is not implemented.

<img src="..." />
				

Label

Label is implemented as a DIV with a default style name of gwt-Label. Labels do not interpret their content as HTML and by default allow word-wrap. If you want to use HTML content in your label then you should use an instance of HTML. Both classes provide MOUSEEVENTS.

You can change the default word-wrap by calling the setWordWrap method.

<div class="gwt-Label">your text here</div>
				

ListBox

Implemented using SELECT with OPTION for elements. Documented style name gwt-ListBox is not implemented. Uses attributes selected, size, and multiple as part of implementation.

MenuBar

Implemented as a DIV containing a TABLE with menu items contained in TD elements. A horizontal MenuBar contains all menu items as children of a single TR and a vertical MenuBar uses a separate TR for each item. Simple enough. The documented style name of gwt-MenuBar is used and applied to the outer DIV.

<div class="gwt-MenuBar">
  <table>
    <tbody>
      
      <tr>
        <td class="gwt-MenuItem">text or html</td>
        <td class="gwt-MenuItem">text or html</td>
      </tr>
      <!-- example of a vertical menu
        <tr><td class="gwt-MenuItem">text or html</td></tr>
        <tr><td class="gwt-MenuItem">text or html</td></tr>
      -->
    </tbody>
  </table>
</div>
				

MenuItem

A MenuItem is a TD that can be inserted into a MenuBar. The default style name is gwt-MenuItem. A selected MenuItem has the additional style name of gwt-MenuItem-selected. I want to emphasize that the selected style is added to the default style, so that class="gwt-MenuItem" becomes class="gwt-MenuItem gwt-MenuItem-selected". This is not the case with all widgets and is another minor inconsistency in the GWT style design. See StackPanel for an example of the opposite behavior.

PasswordTextBox

Implemented as PASSWORD. Uses gwt-PasswordTextBox.

PopupPanel

Just a DIV.

RadioButton

Implemented as an instance of INPUT. Uses gwt-RadioButton.

RootPanel

A RootPanel can be attached to any element, but it will discard all children previously belonging to that element. If you stop to think about it, this can be useful in contexts outside of your application init.

ScrollPanel

A DIV with overflow set to scroll or auto. Defaults to auto.

<div style="overflow: auto;">
  content
</div>
				

SimplePanel

Just a DIV.

StackPanel

Implemented as a TABLE with 2 rows per item. In each pair of rows the first contains the caption and the second contains the corresponding widget. By default the TABLE is styled with gwt-StackPanel. The captions are styled with gwt-StackPanelItem and gwt-StackPanelItem-selected. When an item is selected the caption’s unselected style gwt-StackPanelItem is replaced with gwt-StackPanelItem-selected. Not all widgets behave this way. See MenuItem for an example of the opposite behavior.

<table class="gwt-StackPanel" cell-spacing="0" cell-padding="0">
  <tbody>
    
    <tr>
      <td class="gwt-StackPanelItem" height="1px">text/html</td>
    </tr>
    <tr>
      <td height="100%" valign="top">
        content -- a widget
      </td>
    </tr>
  </tbody>
</table>
				

TabBar

A TabBar is implemented using a HorizontalPanel so it is effectively a TABLE. The style name gwt-TabBar applies to the TABLE — that is, to the actual tabs. The style gwt-TabBarFirst applies to the first (effectively empty) HTML widget and is only useful for creating some sort of left border effect. The style gwt-TabBarRest applies to that part of the TabBar following the tabs.

When a tab is selected the style gwt-TabBarItem-selected gets added to the existing style. This behavior is like that of MenuItem but opposite that of StackPanel.

<table class="gwt-TabBar" cell-spacing="0" cell-padding="0">
  <tbody>
    <tr>
      <td class="gwt-TabBarFirst" style="height: 100%;"><div class="gwt-HTML" style="height: 100%;">&amp;nbsp;</div></td>
      <td>Tab #1</td>
      <td>Tab #2</td>
      <td class="gwt-TabBarRest" style="width: 100%;"><div class="gwt-HTML" style="height: 100%;">&amp;nbsp;</div></td>
    </tr>
  </tbody>
</table>
				

TabPanel

Implemented as a VerticalPanel containing a TabBar and a DeckPanel. In other words, it’s a bunch of nested tables. The style gwt-TabPanel applies to the top-level TABLE, gwt-TabBar still applies to the contained TABLE implementing the TabBar, and gwt-TabPanelBottom styles the DIV containing the actual content.

Note that the TabBar gets the added default style of width: 100%. This ensures that the TabBar is as wide as the content panel and is the reason the gwt-TabBarRest style is important. It’s all about how you want that empty space to look.

<table class="gwt-TabPanel" cell-spacing="0" cell-padding="0">
  <tbody>
    <tr>
      <td>
        
        <table class="gwt-TabBar" style="width: 100%;" cell-spacing="0" cell-padding="0">
          <tbody>
            <tr>
              <td class="gwt-TabBarFirst" style="height: 100%;"><div class="gwt-HTML" style="height: 100%;">&amp;nbsp;</div></td>
	      
              <td class="gwt-TabBarRest" style="width: 100%;"><div class="gwt-HTML" style="height: 100%;">&amp;nbsp;</div></td>
            </tr>
          </tbody>
        </table>
      </td>
    </tr>
    <tr>
      <td>
        <div class="gwt-TabPanelBottom">
	  
	</div>
      </td>
    </tr>
  </tbody>
</table>
				

TextArea

Implemented as a TEXTAREA with a default style of gwt-TextArea.

TextBox

<input type="text" class="gwt-TextBox" />
				

Tree

Implemented as a DIV containing nested TreeItems. The style name gwt-Tree applies to the DIV and the style overflow defaults to auto.

<div class="gwt-Tree" style="overflow: auto;">
  
  <div style="position: relative; margin-left: 16;" (handle)>
    <table>
      <tr>
        <td></td>
        <td></td>
      </tr>
    </table>
    
  </div>
</div>
				

TreeItem

Implemented as a TABLE nested within a DIV. The styles gwt-TreeItem and gwt-TreeItem-selected apply to the nested content element, a SPAN. The selected state gwt-TreeItem-selectedreplaces the unselected state gwt-TreeItem, like StackPanel but unlike MenuItem or TabBar.

<div style="position: relative; margin-left: 16; white-space: nowrap" (handle)>
  <table style="white-space: nowrap;">
    <tr>
      <td style="vertical-align: middle;"><img src="tree_white.gif" /></td>
      <td style="vertical-align: middle;">content</td>
    </tr>
  </table>
  children
</div>
				

VerticalPanel

Implemented using a TABLE with all elements laid out as TRs.

<table cell-spacing="0" cell-padding="0">
  <tbody>
    <tr><td style="display: static; vertical-align: top;" align="left">Item 1</td></tr>
    <tr><td style="display: static; vertical-align: top;" align="left">Item 2</td></tr>
  </tbody>
</table>