常见问题解答 - UI
布局
我在布局方面遇到了问题。如何查看我的面板在哪里?
当您使用复杂的布局时,有时很难理解为什么您的小部件没有显示在您认为应该显示的位置。
例如,假设您要尝试创建一个包含两个按钮的布局,一个在浏览器的左侧,另一个在浏览器的右侧。以下是一些尝试执行此操作的代码
VerticalPanel vertPanel = new VerticalPanel();
DockPanel dockPanel = new DockPanel();
dockPanel.setWidth("100%");
dockPanel.add(new Button("leftButton"), DockPanel.WEST);
dockPanel.add(new Button("rightButton"), DockPanel.EAST);
vertPanel.add(dockPanel);
RootPanel.get().add(vertPanel);
以下是屏幕最终显示的样子
出了什么问题?我们将 DockPanel 设置为填充 100% 的空间,然后将每个按钮设置在屏幕的左侧或右侧。此时,探查并查看小部件的边界可能会有所帮助,因为它们可能不在您认为应该在的位置。
第一个技巧是使用 DOM 检查工具,例如 Firebug for the Firefox 浏览器。当您将鼠标悬停在 DOM 中的元素上时,它们将在浏览器窗口中突出显示。
您还可以使用的另一个技巧是修改您的 GWT 代码以在您的面板(或其他小部件)上打开边框。
VerticalPanel vertPanel = new VerticalPanel();
DockPanel dockPanel = new DockPanel();
dockPanel.setWidth("100%");
dockPanel.add(new Button("leftButton"), DockPanel.WEST);
dockPanel.add(new Button("rightButton"), DockPanel.EAST);
dockPanel.setStylePrimaryName("dockPanel");
dockPanel.setBorderWidth(5);
vertPanel.add(dockPanel);
vertPanel.setStylePrimaryName("vertPanel");
vertPanel.setBorderWidth(5);
RootPanel.get().add(vertPanel);
您还可以使用关联的 CSS 样式表来更改边框属性。在这种情况下,样式表会更改边框的颜色以使它们更容易区分
.dockPanel {
border-color: orange;
}
.vertPanel {
border-color: blue;
}
现在您可以清楚地看到每个面板的轮廓在哪里
在这种情况下,最外层面板也需要 100% 的宽度,因此我们更改代码,然后在浏览器窗口中点击“刷新”
vertPanel.setWidth("100%");
这更接近我们想要的结果,但仍然不正确。现在我们需要更改 DockPanel 实例中的单元格对齐方式
Button rightButton = new Button("rightButton");
dockPanel.add(rightButton, DockPanel.EAST);
dockPanel.setCellHorizontalAlignment(rightButton, HasHorizontalAlignment.ALIGN_RIGHT);
(完成后不要忘记关闭这些样式!)
如何创建一个应用程序,当浏览器窗口调整大小时,该应用程序会垂直填充页面?
从 GWT 2.0 开始,使用 布局面板 就可以轻松地创建一个填充浏览器的应用程序。诸如 DockLayoutPanel 和 SplitLayoutPanel 之类的布局面板会自动调整大小以适应窗口的大小,当浏览器调整大小。
the Mail 示例应用程序 演示了 SplitLayoutPanel 的实际应用。
有关更多详细信息和代码片段,请参阅开发人员指南中的 布局面板。
为什么将小部件的高度设置为百分比不起作用?
在某些情况下,Widget.setHeight() 和 Widget.setSize() 方法似乎不适用于以百分比表示的大小。GWT 小部件不会对这些值进行任何计算。这些方法会设置小部件的 CSS 高度和/或宽度属性,并依赖于封闭小部件的行为。
在标准模式下,如果元素(如 <
div>
)位于表格单元格 <
td>
内,则无法将 <
div>
高度和宽度属性设置为百分比。它们会被忽略。例如,下面 <
div>
元素中的样式在标准模式下会被忽略
<td>
<div style="height:100%;width:100%;>test</div>
</td>
解决方法包括
- 尝试将封闭的外层小部件更改为其他类型。例如,VerticalPanel 是用 HTML
<
table>
元素实现的,其行为可能与 AbsolutePanel 不同,AbsolutePanel 是用 HTML<
div>
元素实现的。 - 如果 HTML 主页中的
<
DOCTYPE…>
声明设置为标准模式(如 HTML 4.01 Transitional),请尝试删除<
DOCTYPE …>
声明或将其更改为使浏览器渲染引擎进入怪异模式。
GWT 是否支持标准模式?
从 GWT 1.5 开始,是的。支持标准模式。为了向后兼容,怪异模式仍然受到支持。但是,对怪异模式的支持可能会在 GWT 的未来版本中被删除,建议您更新支持 GWT 的页面以使用标准模式。
事件处理和性能
如何在表格中以良好的性能显示大量项目?
以下是一些关于如何有效地通过表格小部件显示大量数据的技巧。
固定宽度表格
从性能角度来看,使用固定宽度表格比使用动态调整大小的表格更好。
RPC 和其他网络事务注意事项
大多数应用程序都在通过网络加载其表格的数据。尝试减少应用程序填充表格所需的往返次数。两个主要策略浮出水面
- 在同一个请求中获取多行。
- 将应用程序不同子系统的活动合并到一个 RPC 调用中。从组合的数据结构中,这样您就可以在同一个 RPC 调用中获取与应用程序不同部分相关的数据,并减少用户等待时间。
测试性能
如果您有一个大型表格,请确保您使用要支持的最大行数运行测试。在某些浏览器上,已经观察到表格性能随着行数的增加而呈非线性下降。
尝试使用 PagingScrollTable
如果您发现表格性能存在问题,解决问题的最佳方法可能是不要显示大部分数据。一种称为 PagingScrollTable 的表格实现可以帮助您一次显示一页数据,而不是必须等待整个数据集下载到浏览器。这种类型的表格在 Web 应用程序中非常常见,用户不会感到陌生。一般来说,如果您要显示 50 行以上的数据,请考虑使用 PagingScrollTable。
请注意,PagingScrollTable 是 GWT Incubator 项目的一部分,您需要从核心 GWT 发行版中单独下载该项目。
如果您可以使用 PagingScrollTable,那么请考虑使用 CachedTableModel(也是 GWT Incubator 的一部分),您可以使用它自动预取行,例如下一页。这可以显着提高感知速度。
尝试使用 BulkTableRenderer 和 PreloadedTable 类
BulkTableRenderer 将一次渲染表格中的所有行。BulkTableRenderer 有针对不同目的的派生类型。只要您的表格内容不是小部件,您就可以提供一个表格模型,BulkRenderer 会创建整个表格并将其渲染为单个 HTML 字符串,并使用 setInnerHtml() 设置,这比以往快 2-10 倍。
请注意,加载后,可以将小部件、单元格跨度、行跨度等添加到表格中,但这样做不会带来速度优势。
我该怎么做才能使图像和边框在第一次使用时看起来加载得更快?
第一次应用程序访问图像时,您可能会注意到它可能只加载了一部分,或者加载速度比后续调用慢。由于第一印象很重要,因此您可以尝试使用此技巧。
根本问题是,背景、边框或动画所需的图像都是按需从服务器获取的。一个解决方案是预取图像,以便它们在实际调用动画时已位于浏览器缓存中。检查您的 CSS 文件以查找在样式中使用的图像,如果这些图像运行缓慢,请使用 Image.prefetch() 方法。
Image.prefetch("images/corner-bl.png");
Image.prefetch("images/corner-br.png");
Image.prefetch("images/corner-tl.png");
Image.prefetch("images/corner-tr.png");
为什么使用 1 像素高的背景图像时会出现性能低下?
使用单像素图片作为重复背景图很常见。但是请注意,用小图片覆盖大面积可能会导致性能下降(尤其是在 Internet Explorer 上我们发现这个问题)。在使用 GWT 动画时,这种情况尤为明显。
解决这个问题的一种方法是增加图片尺寸,这样渲染图片就不需要频繁地重复图片。因此,与其使用 20 x 1 的图片,你可以尝试使用 20 x 100 的图片。这样做需要权衡的是,浏览器需要从网络上下载更大的图片。
随着应用程序的增长,事件处理程序的触发速度似乎变慢了
如果你正在创建一个包含许多需要响应事件的组件的界面(例如 `click` 事件),你可能会发现应用程序处理事件的速度越来越慢。例如,在一个表格中有一系列组件。
导致性能下降的一个因素可能是管理大量点击处理程序实例的开销。考虑一个常见的处理点击事件的方法。
Button newButton = new Button(titleText);
newButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
dialogBox.hide();
}
});
每个组件都有自己的点击处理程序实例,该实例是在创建组件时通过添加匿名内部类创建的。这种构造很方便,在大多数情况下不会导致性能问题,但当创建许多需要事件处理的组件时,考虑创建一个单一的点击处理程序并将其在多个组件之间共享。
class MyApp implements EntryPoint, ClickHandler {
/* Be careful with saving UI components in datastructures like this:
* if you remove a button from the app, make sure you also remove
* its reference from buttonMap HashMap to avoid memory leaks.
*/
Map buttonMap<Button, Integer> = new HashMap<Button,Integer>();
public void onModuleLoad() {
FlowPanel panel = new FlowPanel();
for (int i = 1; i < 100; ++i) {
Button newButton = new Button("Option " + i);
newButton.addClickHandler(this);
panel.add(newButton);
buttonmap.add(newButton, Integer.valueOf(i));
}
RootPanel.get().add(panel);
}
// The shared ClickHandler code.
public void onClick(ClickEvent event) {
Object sender = event.getSource();
if (sender instanceof Button) {
Button b = (Button) sender;
Integer context = buttonMap.get(b);
if (context != null) {
// ... Handle the button click for this button.
}
}
}
}
如何有效地处理来自许多内部组件的事件?
Quirksmode 网站有一篇关于 事件冒泡 的文章,解释了不同浏览器传递事件的方式。在使用 GWT 事件处理程序时,GWT 会将这一切隐藏起来,只为你传递你感兴趣的元素的事件。这是一个有用的编程抽象,但在系统中添加了大量处理程序时会导致性能下降。
如果你正在构建一个组件,你可能想考虑以另一种方式处理事件,称为事件冒泡。本质上,这种技术意味着你为整个组件设置一个处理程序,并且你有一个处理程序回调,它代表所有内部组件执行。
请参阅 Tree 类实现,了解在 GWT 中使用事件冒泡的示例。