样式
此时,StockWatcher 已经可以正常工作了。现在,你想给它添加一些视觉风格。
在本节中,你将
CSS 的优势
GWT 提供的与样式直接相关的 Java 方法很少。相反,我们建议您在层叠样式表中定义样式。
在为 Web 应用程序设置样式方面,CSS 是理想的选择。除了将样式从应用程序逻辑中干净地分离之外,这种职责分离还有助于应用程序更快地加载和呈现,消耗更少的内存,甚至在编辑/调试周期中更容易调整,因为不需要为了样式调整而重新编译。
将样式表与项目关联
StockWatcher 项目已经关联了两个样式表。
- 一个主题样式表,standard.css:定义了 GWT 默认样式
- 应用程序样式表,StockWatcher.css:您在这里定义 StockWatcher 的特定样式
当您使用 webAppCreator 创建 StockWatcher 时,它创建了应用程序样式表(StockWatcher.css)。它还在 GWT 模块中引用了主题。
打开 GWT 模块,StockWatcher/src/com/google/gwt/sample/stockwatcher/StockWatcher.gwt.xml。注意,默认情况下正在使用 Standard 主题。
<?xml version="1.0" encoding="UTF-8"?> <module rename-to='stockwatcher'> <!-- Inherit the core Web Toolkit stuff. --> <inherits name='com.google.gwt.user.User'/> <!-- Inherit the default GWT style sheet. You can change --> <!-- the theme of your GWT application by uncommenting --> <!-- any one of the following lines. --> <inherits name='com.google.gwt.user.theme.standard.Standard'/> <!-- <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> --> <!-- <inherits name="com.google.gwt.user.theme.dark.Dark"/> --> <!-- Other module inherits --> <!-- Specify the app entry point class. --> <entry-point class='com.google.gwt.sample.stockwatcher.client.StockWatcher'/> </module>
打开 StockWatcher/war/StockWatcher.html。注意,应用程序样式表是 StockWatcher.css。
<!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 src="stockwatcher/stockwatcher.nocache.js"></script> </head> <body> <h1>StockWatcher</h1> <div id="stockList"></div> </body> </html>
自动资源包含
与图像一样,CSS 文件是存储在公共目录中并从 HTML 主页引用的静态资源。您可以通过两种方式将样式表与应用程序关联。
- 首选:在模块 XML 文件(StockWatcher.gwt.xml)中
- 备选:在 HTML 主页(StockWatcher.html)中
无论您选择哪种方法,您都可以将一个或多个应用程序样式表与项目关联。它们的级联顺序与 HTML 文档中的顺序相同。
对于 StockWatcher,您将遵循首选策略。您将使用模块 XML 文件,而不是在 HTML 主页中添加指向样式表的链接。然后,当您编译 StockWatcher 时,GWT 编译器将捆绑运行应用程序所需的所有静态资源,包括样式表。这种机制称为自动资源包含。
在大多数情况下,这是一种更好的策略,因为样式表将跟随您的模块,无论它在新的上下文中使用,无论您将它嵌入到哪个 HTML 主页中。随着您进行更复杂的开发,您将希望重用或共享模块。共享模块不包含主机页,因此,除非您使用自动资源包含,否则您无法保证应用程序样式表的可用性。
如果您希望将模块嵌入的任何主机页都决定其 Widgets 的样式,那么不要在模块 XML 文件中包含样式表。
更改主题
GWT 附带三种主题:Standard、Chrome 和 Dark。默认情况下,创建 GWT 模块时会选择 Standard 主题。每个应用程序一次只能使用一个主题。但是,如果您已有样式或更喜欢从头开始设计,则根本不需要使用任何主题。花点时间看看其他主题的外观。
将主题从 Standard 更改为 Dark。
- 在 StockWatcher.gwt.xml 中,注释掉引用 Standard 主题的行。
- Eclipse 快捷键:Source > Toggle Comment。
取消注释引用 Dark 主题的行。
- Eclipse 快捷键:Source > Toggle Comment。
<!-- Inherit the default GWT style sheet. You can change --> <!-- the theme of your GWT application by uncommenting --> <!-- any one of the following lines. --> <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> --> <!-- <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> --> <inherits name="com.google.gwt.user.theme.dark.Dark"/>
测试更改。
- 保存对 StockWatcher.gwt.xml 文件的更改。
- 如果开发模式仍在运行,请终止它,然后重新启动 StockWatcher。
对于 StockWatcher,您将基于 Standard 主题构建。因此,在您试用过主题的运作方式后,将主题设置回 Standard。
注意:GWT 主题也有 RTL(从右到左)版本,以支持从右到左书写的语言,例如阿拉伯语。要使用从右到左的主题,请在主题名称后附加 RTL。<inherits name='com.google.gwt.user.theme.standard.StandardRTL'/>
决定实施策略
您可以通过多种方式修改 GWT 的默认样式。
- 您可以在应用程序样式表 Stockwatcher.css 中创建新的样式规则。
- 使用这种方法进行的更改将应用于所有类型的 Widgets,例如,应用于所有 Buttons。
- 您可以通过添加另一个类属性将辅助样式附加到 HTML 元素。
- 使用这种方法进行的更改将应用于单个 Widget,例如,仅应用于 StockWatcher 中的 Remove 按钮。
- 您可以覆盖 Widget 的主要样式名称。
- 如果您需要清除从主题或其他样式表继承的任何现有样式,则可以更改与 Widget 关联的默认主要类。
- 如果您将 GWT 应用程序嵌入到现有页面中,则可以编辑自己的样式表。
- 您可以从头开始。
对于 StockWatcher 应用程序,您将主要关注第二种方法:您将学习如何附加辅助样式。
将样式规则与 GWT 生成的 HTML 元素关联
元素的主要样式
您可能已经注意到,StockWatcher 的按钮具有渐变背景。按钮的样式来自哪里?
如果在编译 StockWatcher 后,您查看 Add 按钮的生成的 JavaScript,您将看到按钮具有 gwt-Button 类属性:<button class="gwt-Button" tabindex="0" type="button">Add</button>
在 GWT 中,每个 Widgets 类都具有一个关联的样式名称(如 gwt-Button),将它绑定到 CSS 样式规则。这是 Widget 的主要样式。默认值在主题样式表中定义。
元素类型 | HTML 标签 | CSS 选择器 |
---|---|---|
静态 HTML 中的按钮和 GWT 生成的按钮 | <button> |
button |
仅 GWT 生成的按钮 | <button class="gwt-Button"> |
button.gwt-Button |
仅我的特殊 GWT 生成的按钮 | <button class="gwt-Button my-button"> |
button.my-button |
提示:您可以通过访问 GWT API 参考(通过 Widget 库)来查找每个 Widget 的样式规则名称(CSS 选择器)。
GWT 利用了您可以将多个类与 HTML 元素关联的事实,因此您可以为特定的 GWT 生成的元素指定样式,而不会影响同一类型的其他元素。在本节中,您将学习如何在 GWT 生成的 HTML 元素上设置辅助类。
创建辅助样式
为 HTML 元素创建辅助样式是一个两步过程
- 在 StockWatcher.css 中指定样式规则。
- 通过在 StockWatcher.java 中以编程方式设置 HTML 类属性来应用样式。
让我们快速进行一次更改,看看机制是如何工作的。然后,您可以一次性完成其余的更改。我们将从更改存储标题信息的首页的颜色开始。
在 CSS 中定义样式
创建 StockWatcher 应用程序时,webAppCreator 生成了应用程序样式表(StockWatcher.css),并在模块 XML 文件(StockWatcher.gwt.xml)中添加了一个指向它的指针。因此,您已经可以开始定义样式规则了。
- 打开应用程序样式表。
- 打开 StockWatcher/war/StockWatcher.css。
对于任何具有 watchListHeader 类属性的 HTML 元素,设置颜色和文本属性。
- 将 StockWatcher.css 的内容替换为以下样式规则。
/* Formatting specific to the StockWatcher application */ body { padding: 10px; } /* stock list header row */ .watchListHeader { background-color: #2062B8; color: white; font-style: italic; }
将您的更改保存到 StockWatcher.css。
使用 addStyleName 方法应用样式
在具有静态元素的网页中,您现在将遍历 HTML 源代码并添加类属性到各种元素以将它们与 CSS 文件中定义的样式相关联。例如:<tr class="watchListHeader">
但是,GWT 元素是在运行时动态创建的。因此,您将使用 addStyleName 方法在 Java 源代码中设置 HTML 类属性。您将指定行(标题是第 0 行)和辅助类的名称,watchListHeader。
在 StockWatcher.java 中,在 onModuleLoad 方法中,在股票表格的标题行中添加一个辅助样式。
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"); // Add styles to elements in the stock list table. stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader");
将您的更改保存到 StockWatcher.java,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
- Flex 表格中的标题行以蓝色背景显示白色斜体标题。
实现 StockWatcher 的剩余辅助样式更改
我们将通过创建辅助样式进行的每个更改都列在下面。您可以一次应用一个更改以查看每个更改的效果,或者可以复制粘贴本节末尾总结的更改集。
- 在股票列表周围放置一个边框。
- 在股票列表中右对齐数字数据。
- 居中移除按钮并使其更宽。
- 在添加股票面板中添加空白(填充)。
在股票列表周围放置一个边框
定义样式。
- 在 StockWatcher.css 中,为类属性为 watchList 的 HTML 元素创建一个样式规则。
/* stock list header row */ .watchListHeader { background-color: #2062B8; color: white; font-style: italic; } /* stock list flex table */ .watchList { border: 1px solid silver; padding: 2px; margin-bottom:6px; }
应用样式。
- 在 StockWatcher.java 中,在股票 Flex 表格中添加一个辅助类属性。
// Add styles to elements in the stock list table. stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader"); stocksFlexTable.addStyleName("watchList");
保存您的更改,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
- 股票列表表格有一个银色边框。
在股票列表中右对齐数字数据
首先,您将格式化股票表格标题行中的文本,该文本在 StockWatcher 启动时加载。稍后,您将对包含股票数据的表格行应用相同的样式规则。
定义样式。
- 在 StockWatcher.css 中,创建一个将右对齐包含价格和变化字段的列的样式规则。
/* stock list flex table */ .watchList { border: 1px solid silver; padding: 2px; margin-bottom:6px; } /* stock list Price and Change fields */ .watchListNumericColumn { text-align: right; width:8em; }
应用样式。
- 在 StockWatcher.java 中,在价格和变化字段中添加一个辅助类属性。
// Add styles to elements in the stock list table. stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader"); stocksFlexTable.addStyleName("watchList"); stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn");
保存您的更改,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
- 价格和变化列具有固定宽度,标题行中的文本右对齐。
居中移除按钮并使其更宽
定义样式。
- 在 StockWatcher.css 中,创建一个将居中包含移除按钮的列中的文本的样式规则。
/* stock list Price and Change fields */ .watchListNumericColumn { text-align: right; width:8em; } /* stock list Remove column */ .watchListRemoveColumn { text-align: center; }
应用样式。
- 在 StockWatcher.java 中,在移除字段中添加一个辅助类属性。
// Add styles to elements in the stock list table. stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader"); stocksFlexTable.addStyleName("watchList"); stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn");
保存您的更改,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
- 标题占据了字段的整个宽度。在您在下一步格式化数据行后,您将能够看到按钮在移除列中居中。
将相同的单元格格式应用于保存股票数据的行
您已格式化 Flex 表格的标题行,该行在 StockWatcher 启动时显示。但是请记住,在 Flex 表格中,保存股票的行直到用户将股票添加到列表中才会创建。因此,您将在 addStock 方法而不是 onLoad 方法中添加格式化股票数据的代码。
- 您已经在 StockWatcher.css 中定义了样式。
应用样式。
- 在 StockWatcher.java 中,在 addStock 方法中,在价格、变化和移除列中的表格单元格中添加辅助类属性。
// Add the stock to the table. int row = stocksFlexTable.getRowCount(); stocks.add(symbol); stocksFlexTable.setText(row, 0, symbol); stocksFlexTable.getCellFormatter().addStyleName(row, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 3, "watchListRemoveColumn");
保存您的更改,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
- 将股票添加到列表中。价格和变化数据右对齐。移除按钮居中。
在添加股票面板周围添加边距
在添加股票面板中的文本框和添加按钮周围添加空白。
定义样式。
- 在 StockWatcher.css 中,创建一个样式规则以加宽添加股票面板周围的边距。
/* stock list Remove column */ .watchListRemoveColumn { text-align: center; } /* Add Stock panel */ .addPanel { margin: 10px 0px 15px 0px; }
应用样式。
- 在 StockWatcher.java 中,在 onModuleLoad 方法中,在 addPanel 中添加一个辅助类属性。
// Assemble Add Stock panel. addPanel.add(newSymbolTextBox); addPanel.add(addStockButton); addPanel.addStyleName("addPanel");
保存您的更改,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
- 股票表格和添加股票面板之间的边距已增加。
更改摘要
以下是我们到目前为止所做的更改摘要。
对 StockWatcher.css 的更改
/* Formatting specific to the StockWatcher application */
body {
padding: 10px;
}
/* stock list header row */
.watchListHeader {
background-color: #2062B8;
color: white;
font-style: italic;
}
/* stock list flex table */
.watchList {
border: 1px solid silver;
padding: 2px;
margin-bottom:6px;
}
/* stock list Price and Change fields */
.watchListNumericColumn {
text-align: right;
width:8em;
}
/* stock list Remove column */
.watchListRemoveColumn {
text-align: center;
}
/* Add Stock panel */
.addPanel {
margin: 10px 0px 15px 0px;
}
对 StockWatcher.java 的更改,onModuleLoad
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");
// Add styles to elements in the stock list table.
stocksFlexTable.getRowFormatter().addStyleName(0, "watchListHeader");
stocksFlexTable.addStyleName("watchList");
stocksFlexTable.getCellFormatter().addStyleName(0, 1, "watchListNumericColumn");
stocksFlexTable.getCellFormatter().addStyleName(0, 2, "watchListNumericColumn");
stocksFlexTable.getCellFormatter().addStyleName(0, 3, "watchListRemoveColumn");
// Assemble the Add Stock panel
addPanel.add(newSymbolTextBox);
addPanel.add(addStockButton);
addPanel.addStyleName("addPanel");
.
.
.
}
对 StockWatcher.java 的更改,addStock
// Add the stock to the table.
int row = stocksFlexTable.getRowCount();
stocks.add(symbol);
stocksFlexTable.setText(row, 0, symbol);
stocksFlexTable.getCellFormatter().addStyleName(row, 1, "watchListNumericColumn");
stocksFlexTable.getCellFormatter().addStyleName(row, 2, "watchListNumericColumn");
stocksFlexTable.getCellFormatter().addStyleName(row, 3, "watchListRemoveColumn");
创建依赖于主要样式的辅助样式
接下来,您想更改移除按钮的样式。移除按钮从 Button 小部件继承其样式。所有 GWT Button 小部件的默认样式由 GWT 在 standard.css 中定义。
<button class="gwt-Button" tabindex="0" type="button">x</button>
.gwt-Button {
background:transparent url(images/hborder.png) repeat-x scroll 0px -27px;
border:1px outset #CCCCCC;
cursor:pointer;
font-size:small;
margin:0pt;
padding:3px 5px;
text-decoration:none;
}
对于 StockWatcher,您希望样式更改仅应用于移除按钮。因此,您将按照您一直在做的事情:在移除按钮元素中添加一个辅助样式。但是这次,您将使辅助样式依赖于主要样式。依赖样式很强大,因为只要主要样式名称发生更改,它们就会自动更新。相反,当主要样式名称发生更改时,不会自动更新非依赖样式名称的辅助样式名称。
为此,您将使用 addStyleDependentName 方法而不是 addStyleName 方法。
定义样式规则。
/* Add Stock panel */ .addPanel { margin: 10px 0px 15px 0px; } /* stock list, the Remove button */ .gwt-Button-remove { width: 50px; }
应用样式。
- 在 StockWatcher.java 中,使用 addStyleDependentName 在移除按钮中添加一个辅助的依赖类属性。
// Add a button to remove this stock from the table. Button removeStockButton = new Button("x"); removeStockButton.addStyleDependentName("remove");
保存您的更改,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
- 移除按钮的高度小于宽度。添加按钮不受此更改的影响。
现在,生成的 HTML 有两个类属性。
<button class="gwt-Button gwt-Button-remove" tabindex="0" type="button">x</button>
动态更新样式
您要实现的最终样式更改是更改价格变化的颜色。如果股票价格上涨,StockWatcher 以绿色显示;下跌,以红色显示;没有变化,以黑色显示。这是 StockWatcher 运行时动态变化的一种样式。
您已经在单元格元素中应用了一个 HTML 类属性以右对齐单元格内部的数字值。为了使代码简单,如果您只对单元格内的文本应用 HTML 类属性,那就太好了。一种简单的方法是使用嵌套小部件。在这种情况下,您将在第 2 列中的每个单元格内插入一个 Label 小部件。
定义样式。
- 在 StockWatcher.css 中,添加以下样式规则。
/* stock list, the Remove button */ .gwt-Button-remove { width: 50px; } /* Dynamic color changes for the Change field */ .noChange { color: black; } .positiveChange { color: green; } .negativeChange { color: red; }
在表格单元格中插入一个 Label 小部件。
- 在 StockWatcher.java 中,在 addStock 方法中,为第 2 列中的每个单元格创建一个 Label 小部件。
// Add the stock to the table. int row = stocksFlexTable.getRowCount(); stocks.add(symbol); stocksFlexTable.setText(row, 0, symbol); stocksFlexTable.setWidget(row, 2, new Label()); stocksFlexTable.getCellFormatter().addStyleName(row, 1, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 2, "watchListNumericColumn"); stocksFlexTable.getCellFormatter().addStyleName(row, 3, "watchListRemoveColumn");
- 现在,您不必再设置表格单元格的文本,而是必须设置 Label 小部件的文本。
在 changeWidget 上设置文本。
- 在 updateTable(StockPrice) 方法中,删除对 Change 列(第 2 列)的 setText 的调用。
- 创建一个 Label 小部件实例并将其称为 changeWidget。
- 在 changeWidget 上设置文本。
// Populate the Price and Change fields with new data. stocksFlexTable.setText(row, 1, priceText); Label changeWidget = (Label)stocksFlexTable.getWidget(row, 2); changeWidget.setText(changeText + " (" + changePercentText + "%)");
根据每个 changeWidget 的值更改其颜色。
// Populate the Price and Change fields with new data. stocksFlexTable.setText(row, 1, priceText); Label changeWidget = (Label)stocksFlexTable.getWidget(row, 2); changeWidget.setText(changeText + " (" + changePercentText + "%)"); // Change the color of text in the Change field based on its value. String changeStyleName = "noChange"; if (price.getChangePercent() < -0.1f) { changeStyleName = "negativeChange"; } else if (price.getChangePercent() > 0.1f) { changeStyleName = "positiveChange"; } changeWidget.setStyleName(changeStyleName);
保存您的更改,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
- Change 字段中的值的颜色分别为红色、绿色或黑色,具体取决于变化是负数、正数还是没有变化。
设置元素的 HTML 属性
有时,您确实希望直接在 HTML 元素上设置样式属性,而不是在 CSS 中定义样式规则。例如,HTML 表格元素具有 cellpadding 属性,该属性便于设置表格中所有单元格的填充。
在 GWT 中,根据 HTML 元素,您可以在 Java 代码中设置一些属性以生成相应的 HTML。
为股票表格指定 cellpadding。
- 在 StockWatcher.java 中,在 onModuleLoad 方法中,添加 setCellPadding 方法。
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"); // Add styles to elements in the stock list table. stocksFlexTable.setCellPadding(6);
保存您的更改,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
添加图像或其他静态 HTML 元素
您的应用程序的 HTML 主页可以包含您需要的任何其他静态 HTML 元素。例如,在 StockWatcher 中,您将添加 Google Code 徽标。要包含图像,请将它们放在项目的公共目录中。GWT 编译器会将所有必要的文件复制到输出目录以进行部署。
要将静态图像包含在应用程序中。
创建一个目录来保存与该应用程序关联的图像文件。
- 在 war 目录中,创建一个 images 目录。
StockWatcher/war/images
从此页面复制徽标的图像并将其粘贴到 images 目录中。
StockWatcher/war/images/GoogleCode.png
在 StockWatcher.html 中,插入一个指向徽标文件的 img 标签。
<!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 src="stockwatcher/stockwatcher.nocache.js"></script> </head> <body> <img src="images/GoogleCode.png" /> <h1>StockWatcher</h1> <div id="stockList"></div> </body> </html>
注意:为简洁起见,已省略 HTML 注释。
保存您的更改,然后按运行开发模式的浏览器中的刷新按钮以查看它们。
深入了解:有关包含样式表、JavaScript 文件和其他 GWT 模块的更多信息,请参阅开发者指南,自动资源包含.
下一步
此时,您已完成 StockWatcher 的初始实现。客户端功能正在运行,并且用户界面具有新的视觉设计。
注意:为了简单起见,我们使用小部件以编程方式创建了此教程程序的用户界面。对于 StockWatcher,这很好,因为 UI 很简单。但是,GWT 具有一个名为 UiBinder 的强大工具,它允许您使用声明性 XML 文件创建复杂的界面,这可以减少代码大小和复杂性。查看开发者指南关于 使用 UiBinder 进行声明性布局 和 构建用户界面 的部分,以获取有关 UiBinder 和 UI 设计的更多信息。
现在您已准备好编译 StockWatcher。您将把 Java 代码编译成 JavaScript,并检查 StockWatcher 在生产模式下与在开发模式下运行的方式相同。