【译自:https://developers.google.com/web-toolkit/doc/latest/tutorial/buildui?hl=zh-CN】
到此,我们已经创建了StockWatcher工程,也审视了功能需求和界面元素。
这一切,我们要开始使用GWT提供的控件和面板来构建用户界面。
GWT已经处理了很多跨浏览器的兼容问题。因此,如果你是基于GWT的控件和面板构建你的应用,那它可以在大多数最近版本的IE, Chrome,Firefox,Opera和Safari上工作的很好。不过DHTML用户界面还是有些问题,因此你需要自己在每个浏览器上进行测试。
首先,看一下Widget Gallery ,给每个UI元素选择对应的GWT控件。
在Widget Gallery中,每个Widget都有一个缺省的样式,因此他们现在看起来和最终的效果不太一样,这个暂时可以先不管。我们现在只需要使得它们能工作,稍后在Applying Syles一切,会通过定义CSS来改变它们的外观。
GWT提供了一个特别的叫做FlexTable的表格控件。FlexTable会按需创建表格单元。这个对于创建股票数据列表很有用,因为你不知道用户会添加多少列股票数据。实现FlexTable的表格在用户添加或删除股票时会自动进行扩展或收缩。
只要有可能,GWT就会首先选择浏览器默认的控件。例如,一个Button就是一个HTML的<button>,而不是一个长得像Button的合成物,例如来自一个<div>。这就意味着,GWT的按钮外观是由浏览器和客户OS决定的,好外就是更快,更易理解,对于用户来说也更熟悉。并且,它也可以使用CSS来定义样式。
GWT提供了几个控件可供用户输入:
StockWatcher用户将在一行中输入股票代码,因此是一个TextBox。
不同于Button,Label控件并不对应HTML中的<label>,相反,它影射到一个<div>元素。它可以包含任一的不解析为html的文本。作为一个<div>,它是一个block-level的元素,而不是一个inline的元素。
<div class="gwt-Label">Last update : Oct 1, 2008 1:31:48 PM</div>
如果你有兴趣看一下用于构建StockWatcher要用的控件的API,可以点击下面表格中的链接:
UI element | GWT implementation |
a table to hold the stock data | FlexTable widget |
two buttons, one to add stocks and one to remove them | Button widget |
an input box to enter the stock code | TextBox widget |
a timestamp to show the time and date of the last refresh | Label widget |
a logo | image file referenced from HTML host page |
a header | static HTML in HTML host page |
colors to indicate whether the change in price was positive or negative | dynamic CSS |
深入:如果你没有找到合适的控件,你也可以创建你自己的。具体的,请参考:Creating Custom Widgets.
现在你已经知道了你在使用哪些控件,下面就是选择放置他们的合适的面板了。GWT提供了一些管理布局的面板,并且面板可以嵌套其他的面板。这就像在HTML中你可以使用嵌套的div或Table一样。对于StockWatcher,我们会用到一个嵌套在vertical(竖直)面板里的horizontal(水平)面板:
两个用于添加股票的元素:输入框和添加按钮,在功能上是相关紧密,因此将以边对边的放在一起,我们将把他们放在一个水平面板上。在java代码中,创建一个HorizontalPanel 实例,命令为addPanel。
剩下的元素会被竖直放置:
这里会使用到一个Vertical panel。在java代码里,将创建一个 VerticalPanel 实例,并命名为mainPanel.
还有一个你看不见的Panel:Root Panel。Root Panel用来存放所有动态的元素,它处于用面界面的最顶层。有两种使用Root Panel的方法:生成整个Body界面或者Body中的某个元素部分。
Root Panel包装了Body或其他HTML页面中的元素。默认的(如果你没有在页面里添加占位符),Root Panel表示整个Body元素。不过你也可以使用任意已经指定了id的元素,当调用Root Panel时,只需要传入这个id值。例如在StockWatcher里,可能如下使用:
RootPanel.get() // Default. Wraps the HTML body element. RootPanel.get("stockList") // Wraps any HTML element with an id of "stockList"
一个主页里可以包含多个Root Panel。例如如果你嵌入多个GWT控件或面板在一个页面里,每个控件或面板都可以相对于其他元素独立存在,包装在他们自己的Rool Panel里。
为了在浏览器里运行StockWatcher,需要把它嵌入在一个HTML文件,也即主页里。StockWatcher的主页是StockWatcher.html,这个文件是默认生成的。StockWatcher.html有一个空的Body,因此,Root Panel表示整个Body元素。输入框、文本框和按钮都是GWT动态生成的。如果你没有静态的元素,那么就不需要编辑这个主页。
不过对于StockWatcher,还是有一些静态资源需要定义的:标题和logo。我们将使用一个占位符<div>,它的id是"stockList"来添加所有动态的元素。这种策略在将GWT应用添加到一个已经存在应用中时尤其有用。
如下代码所示,我们需要完成:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link type="text/css" rel="stylesheet" href="StockWatcher.css">
<title>StockWatcher</title>
<script type="text/javascript" language="javascript" src="stockwatcher/stockwatcher.nocache.js"></script>
</head>
<body>
<h1>StockWatcher</h1>
<div id="stockList"></div>
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
<noscript>
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
Your web browser must have JavaScript enabled
in order for this application to display correctly.
</div>
</noscript>
<h1>Web Application Starter Project</h1>
<table align="center">
<tr>
<td colspan="2" style="font-weight:bold;">Please enter your name:</td>
</tr>
<tr>
<td id="nameFieldContainer"></td>
<td id="sendButtonContainer"></td>
</tr>
</table>
</body>
</html>
下面就开始使用GWT控件和面板搭建我们的用户界面了。
如果你想尽早的显示UI,那么可以在onModuleLoad方法里实现。这一节,我们将做:
你可以跟随教程一步一步的做,也可以直接到 Summary 一节去复制整个内容。
初始化控件和面板
打开StockWatcher/src/com/google/gwt/sample/stockwatcher/client/StockWatcher.java.用以下代码替换已有内容:
package com.google.gwt.sample.stockwatcher.client; public class StockWatcher implements EntryPoint { private VerticalPanel mainPanel = new VerticalPanel(); private FlexTable stocksFlexTable = new FlexTable(); private HorizontalPanel addPanel = new HorizontalPanel(); private TextBox newSymbolTextBox = new TextBox(); private Button addStockButton = new Button("Add"); private Label lastUpdatedLabel = new Label(); /** * Entry point method. */ public void onModuleLoad() { // TODO Create table for stock data. // TODO Assemble Add Stock panel. // TODO Assemble Main panel. // TODO Associate the Main panel with the HTML host page. // TODO Move cursor focus to the input box. } }
如果有找不着类的错误,按:Ctrl+Shift+O 添加所有需要的导入语句
添加保存股票数据的表格。使用setText方法设置每一行/列的表头:Symbol,Price,Change,Remove。在onModuleLoad 方法里,用以下代码替换// TODO Create table for stock data:
// Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove");
可以看到通过调用setText()来完成一个表格。其中每一个参数表示行号,第二个参数表示列号,最后一个参数表示列名。
在布置控件,需要组装两个面板:Add Stock面板和Mail面板。首先组装Add Stock面板,这是一个水平放置的,包含有一个文本框和一个按钮的面板;然后组件Mail面板,它是一个竖直放置,包括一个表格,Add Stock面板和一个时间戳。
在代码中,用以下代码替换// TODO Assemble Add Stock panel:
// Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton);
用以下代码替换// TODO Assemble Main panel.
// Assemble Main panel. mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel);
所有需要显示在页面上的控件或面板都需要包含在一个Root Panel里。在页面里,我们定义了一个id为stocklist的<div>元素,我们要装Main面板关联到这个元素上,例如以下代码替换// TODO Associate the Main panel with the HTML host page:
// Associate the Main panel with the HTML host page. RootPanel.get("stockList").add(mainPanel);
用以下代码替换// TODO Move cursor focus to the input box.:
// Move cursor focus to the input box. newSymbolTextBox.setFocus(true);
最后代码如下:
package com.google.gwt.sample.stockwatcher.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; public class StockWatcher implements EntryPoint { private VerticalPanel mainPanel = new VerticalPanel(); private FlexTable stocksFlexTable = new FlexTable(); private HorizontalPanel addPanel = new HorizontalPanel(); private TextBox newSymbolTextBox = new TextBox(); private Button addStockButton = new Button("Add"); private Label lastUpdatedLabel = new Label(); /** * Entry point method. */ public void onModuleLoad() { // Create table for stock data. stocksFlexTable.setText(0, 0, "Symbol"); stocksFlexTable.setText(0, 1, "Price"); stocksFlexTable.setText(0, 2, "Change"); stocksFlexTable.setText(0, 3, "Remove"); // Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); // Assemble Main panel. mainPanel.add(stocksFlexTable); mainPanel.add(addPanel); mainPanel.add(lastUpdatedLabel); // Associate the Main panel with the HTML host page. RootPanel.get("stockList").add(mainPanel); // Move cursor focus to the input box. newSymbolTextBox.setFocus(true); } }
保存修改,在工程节点上运行菜单Run > Debug As > Web Application, 如果顺利,在浏览器中打开得到的URL,你将看到以下界面: