构建 UI
此时,您已经创建了 StockWatcher 项目的组件,并回顾了它的功能需求和 UI 设计。在本节中,您将使用 GWT 小部件和面板构建用户界面。
- 选择实现 UI 元素所需的 GWT 小部件。
- 选择用于布局 UI 元素所需的 GWT 面板。
- 将应用程序嵌入到主机页面 StockWatcher.html 中。
- 在 StockWatcher.java 中实现小部件和面板。
- 在开发模式下测试布局。
GWT 可以让您不必过多地担心跨浏览器兼容性问题。如果您使用 GWT 小部件和组合构建界面,您的应用程序将在 Chrome、Firefox、Internet Explorer、Opera 和 Safari 的最新版本上运行。但是,DHTML 用户界面仍然非常古怪;因此,您仍然必须在每个浏览器上彻底测试您的应用程序。
选择 GWT 小部件来实现 UI 元素
首先,查看 小部件库 并为每个 UI 元素选择 GWT 小部件。
在小部件库中,小部件具有默认样式,因此它们的外观与 StockWatcher 的最终实现中不完全相同。现在不用担心这一点。首先,您将专注于使小部件正常工作。稍后,您将在 应用样式 部分中使用 CSS 更改它们的外观。
股票数据表
GWT 提供了一个名为 FlexTable 的特殊表格小部件。FlexTable 小部件按需创建单元格。这正是您需要用于包含股票数据的表格的,因为您不知道用户将添加多少股票。使用 FlexTable 小部件实现的表格将随着用户添加或删除股票而扩展或收缩。
按钮
只要有可能,GWT 就会使用浏览器的本机用户界面元素。例如,Button 小部件将成为一个真正的 HTML <button>
,而不是一个合成按钮状小部件,例如,从 <div>
构建的。这意味着 GWT 按钮将按浏览器和客户端操作系统的设计呈现。使用本机浏览器控件的好处是它们速度快、可访问,并且大多数用户都熟悉它们。此外,它们可以使用 CSS 样式化。
输入框
GWT 提供了多个小部件来创建用户可以键入的字段
- TextBox 小部件,一个单行文本框
- PassWordTextBox 小部件,一个在视觉上屏蔽输入的文本框
- TextArea 小部件,一个多行文本框
- SuggestBox,一个显示预配置项目集的文本框
StockWatcher 用户将键入股票代码,这只是一行文本;因此,实现一个 TextBox 小部件。
标签
与 Button 小部件相反,Label 小部件不会映射到 HTML <label>
元素,该元素用于 HTML 表单。相反,它映射到一个 <div>
元素,该元素包含未解释为 HTML 的任意文本。作为 <div>
元素,它是一个块级元素,而不是一个内联元素。
<div class="gwt-Label">Last update : Oct 1, 2008 1:31:48 PM</div>
如果您有兴趣查看将用于构建 StockWatcher 界面的 GWT 小部件的 API 参考,请点击下表中的链接。
UI 元素 | GWT 实现 |
---|---|
一个用于保存股票数据的表格 | FlexTable 小部件 |
两个按钮,一个用于添加股票,另一个用于删除股票 | Button 小部件 |
一个用于输入股票代码的输入框 | TextBox 小部件 |
一个时间戳,用于显示上次刷新的时间和日期 | Label 小部件 |
一个徽标 | 从 HTML 主页引用的图像文件 |
一个标题 | HTML 主页中的静态 HTML |
颜色,用于指示价格变化是正还是负 | 动态 CSS |
深入了解: 如果您没有找到满足应用程序功能需求的小部件,可以创建自己的小部件。有关使用 Java 或 JavaScript 创建组合小部件或从头开始创建小部件的详细信息,请参阅开发者指南,创建自定义小部件.
选择 GWT 面板来布局 UI 元素
现在您已经知道将使用哪些小部件,您将决定如何使用 GWT 面板来布局它们。GWT 提供了几种类型的面板来管理布局。面板可以嵌套在其他面板中。这类似于使用嵌套的 div 元素或表格在 HTML 中布局网页。对于 StockWatcher,您将使用一个嵌套在垂直面板中的水平面板。
水平面板
用于添加股票的两个元素 - 用于键入新股票代码的输入框和 Add 按钮 - 在功能上密切相关,并且您希望在视觉上将它们放在一起。要将它们并排布局,您将把 TextBox 小部件和一个 Button 小部件放在水平面板中。在 Java 代码中,您将创建一个 HorizontalPanel 的新实例,并将其命名为 addPanel。
垂直面板
您希望将剩余元素垂直布局
- 用于股票表格的 FlexTable 小部件
- Add Stock 面板,它包含输入框和 Add 按钮
- 用于时间戳的 Label 小部件
您将使用一个垂直面板来完成此操作。在 Java 代码中,您将创建一个 VerticalPanel 的新实例,并将其命名为 mainPanel。
根面板
您还需要一个在用户界面中不可见的另一个面板:根面板。根面板是应用程序动态元素的容器。它位于任何 GWT 用户界面层次结构的顶部。有两种方法可以使用根面板,要么生成页面的整个主体,要么生成嵌入主体的特定元素。
根面板通过包装 HTML 主页中的 <body>
或其他元素来工作。默认情况下(即,如果您没有在主机页面中添加任何占位符),根面板将包装整个 <body>
元素。但是,如果您给某个元素指定了一个 id,然后在调用根面板时将该 id 作为参数传递,您就可以包装任何元素。您将在下一节中看到如何在 StockWatcher 中执行此操作。
RootPanel.get() // Default. Wraps the HTML body element.
RootPanel.get("stockList") // Wraps any HTML element with an id of "stockList"
主机页面可以包含多个根面板。例如,如果您将多个 GWT 小部件或面板嵌入到主机页面中,则每个小部件或面板都可以独立于其他小部件或面板实现,并包装在自己的根面板中。
将应用程序嵌入到主机页面中
要使 StockWatcher 应用程序在浏览器中运行,您需要将其嵌入到一个 HTML 文件中,即 HTML 主页。StockWatcher 项目的主页 StockWatcher.html 是由 webAppCreator 生成的。对于 入门应用程序,StockWatcher.html 具有一个空的主体元素。因此,根面板包装了整个主体元素。文本输入框、标签(“请输入您的姓名:”)和“发送”按钮是使用 GWT 动态构建的。如果您的应用程序没有静态元素,您根本不需要编辑 HTML 主页。
但是,对于 StockWatcher,您将使用一些静态 HTML 文本(用于标题)和一个图像(用于徽标),以及动态元素。您将使用一个占位符将 GWT 应用程序嵌入到浏览器页面中,即一个 <div>
元素,其 id 为“stockList”。这种实现策略对于将 GWT 嵌入到现有应用程序中特别有用。
如以下代码所示,执行以下操作
- 打开主机页面 StockWatcher/war/StockWatcher.html。
- 在 head 元素中,将标题文本更改为 StockWatcher。
- 在 body 元素中,添加一个
<h1>
标题,StockWatcher。 - 在 body 元素中,添加一个
<div>
元素,并为其指定 id 为 stockList。 - 删除入门项目应用程序中不需要的元素。
- 保存文件 StockWatcher.html。
<!DOCTYPE html>
<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>
</body>
</html>
注意: 为了简洁,已省略 HTML 注释。
实现小部件和面板
接下来,您将使用 GWT 小部件和面板构建用户界面。
您希望 UI 在 StockWatcher 启动时立即显示,因此您将在 onModuleLoad 方法中实现它们。在本节中,您将
- 实例化每个小部件和面板。
- 创建用于保存股票数据的表格。
- 使用 Add Stock(水平)面板和 Main(垂直)面板布局小部件。
- 将 Main 面板与根面板关联。
- 将光标焦点移动到输入框。
您可以逐步执行本教程的这一部分,也可以从文末的 摘要 中剪切粘贴整个代码块。
实例化每个小部件和面板
使用类字段初始值设定项实例化每个小部件和面板。
- 打开 **StockWatcher/src/com/google/gwt/sample/stockwatcher/client/StockWatcher.java**。
- 在 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. } }
- 在左侧边缘,Eclipse 使用红色“x”标记变量定义,因为它们的类型未定义。
**提示:**您可以利用 Eclipse 的一种方法是使用其“建议”功能添加所需的导入声明,如下所示。
通过单击第一个红色“x”显示建议的更正。
- 通过按回车键选择 `import EntryPoint (com.google.gwt.core.client.EntryPoint)"`。
通过以相同方式声明导入声明来解决所有其他错误。如果您没有使用 Eclipse,请从下面突出显示的代码中剪切并粘贴。
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.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() { // 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. } }
为股票数据创建一个表格
实现将保存股票数据的表格。设置表格的标题行。为此,请使用 setText 方法在每个列的标题中创建标签:符号、价格、变化、删除。
为股票数据创建一个表格。
在 onModuleLoad 方法中,将 TODO 注释替换为突出显示的代码。
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.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"); // 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. } }
您可以看到,可以通过调用 setText 方法向表格添加内容。第一个参数表示行,第二个参数表示列,最后一个参数是将在表格单元格中显示的文本。
布局小部件
要布局小部件,您将组装两个面板,即“添加股票”面板和“主”面板。首先组装“添加股票”面板,这是一个水平面板,包装输入框和“添加”按钮。然后组装“主”面板,这是一个垂直面板,指定股票列表表格、添加股票面板和时间戳的布局。
在“添加股票”面板和“主”面板中布局小部件。
在 onModuleLoad 方法中,将 TODO 注释替换为突出显示的代码。
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.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); // TODO Associate the Main panel with the HTML host page. // TODO Move cursor focus to the input box. } }
将“主”面板与“根”面板关联
为了将任何 GWT 小部件或面板嵌入 HTML 主页,它必须包含在“根”面板中。将“根”面板与分配给 mainPanel 的垂直面板相关联。“根”面板包装 HTML 元素(在 StockWatcher 的主机页面中),该元素具有 id 为“stocklist”。在本例中,它是一个 `<div>` 元素。
通过“根”面板将“主”面板与主机页面关联。
- 在 onModuleLoad 方法中,将 TODO 注释替换为突出显示的代码。
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.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); // TODO Move cursor focus to the input box. } }
- Eclipse 标记 RootPanel 并建议正确的导入声明。
包含导入声明。
import com.google.gwt.user.client.ui.RootPanel;
将光标焦点移至输入框
最后,将光标焦点移至输入框,以便在 StockWatcher 加载时,用户可以开始添加股票。
在 onModuleLoad 方法中,将 TODO 注释替换为突出显示的代码。
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);
}
}
总结
到目前为止,您已经通过实现 GWT 小部件和面板来构建 StockWatcher 的基本 UI 组件。这些小部件尚未响应任何输入。
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);
}
}
测试布局
在 AJAX 应用程序开发中使用 GWT 的一个好处是,您可以在刷新运行开发模式的浏览器后立即看到代码更改的效果。为了让您在开发或调试时都能看到更改,请在 Eclipse 中以调试模式运行 StockWatcher。然后,您将能够在 Java 和调试透视图之间切换,而无需重新启动 StockWatcher。
- 保存已编辑的文件
- 保存 `StockWatcher.java`
- 如果 StockWatcher 项目仍在从启动应用程序运行,请通过转到“开发模式”选项卡并单击其右上角的红色正方形(其工具提示显示为“终止所选启动”),然后单击其右边的灰色“XX”(其工具提示显示为“删除所有已终止的启动”)来停止它。它可能需要一分钟才能完成,然后才能执行下一步。
- 在开发模式下启动 StockWatcher。
- 从 Eclipse 菜单栏中,选择 `运行 > 以调试方式运行 > Web 应用程序`
- 如果您没有使用 Eclipse,请从命令行输入 `ant devmode`
- 浏览器将显示您对 StockWatcher 应用程序的第一次迭代。在您稍后实现它之前,按钮将无法使用。
- StockWatcher 显示 flex 表格的标题、输入框和“添加”按钮。您尚未设置标签的文本,因此它没有显示。在您实现股票刷新机制之后,您将执行此操作。
- 使 StockWatcher 在开发模式下保持运行。
- 在本教程的其余部分中,您将经常在开发模式下测试更改。
刷新开发模式
在修改源代码后,您并不总是需要重新启动应用程序以进行开发模式。相反,只需在保存更改后单击浏览器的刷新按钮,代码服务器就会自动重新编译您的应用程序并打开新版本。
**最佳实践:**您可能会注意到,即使您没有刷新开发模式,您的更改有时也会生效。这种行为是开发模式与编译代码交互方式的结果,但并非总是可靠的。具体来说,它仅在您对现有函数进行细微更改时才会发生。为了确保您的更改包含在内,请养成在进行更改后始终刷新浏览器的习惯。
下一步
到目前为止,您已经通过实现 GWT 小部件和面板构建了 StockWatcher 的基本 UI 组件。这些小部件尚未响应任何输入。
现在您已准备好对客户端进行事件处理编码。您将连接小部件以侦听事件并编写响应这些事件的代码。