我正在学习GWT,并试图把我的注意力集中在所有的UI选项上。我试图弄清楚什么时候/哪里/如何使用小部件、UIBinder、和自定义小部件。具体地说:
com.google.gwt.user.client.ui.*
和com.google.gwt.user.client.ui.Composite
有什么区别?对我来说,我觉得所有这些事情都是一样的,也许这只是GWT为您提供多种方式来完成演示的方式?如果没有,请在这些项目上纠正我。
发布于 2012-09-07 06:19:29
Panel
中添加两个小部件。如果涉及到任何CSS,我总是使用UiBinder,因为使用样式要容易得多。Composite
,因为我要么使用UiBinder,要么向Panel
添加东西。即使我只有一个小部件,我也发现扩展Composite
并将我的一个小部件添加到SimplePanel
中更容易。我很少扩展Widget
,因为您必须调用Document.get().createFooElement()
来创建DOM Element
,但是我通常会发现Widget
s (可以添加到Panel
s )比Element
的更容易使用。我如何构造小部件
每个小部件实现一个扩展IsWidget
的接口。每个想要使用Widget
的人都应该依赖于接口,而不是底层类。这提供了一个单独的、不含JSNI的抽象。
如果小部件非常简单,我将有一个扩展Composite
并实现接口的类。小部件将非常简单,并将一些项添加到Panel
中,或者它将使用UiBinder。
如果小部件具有我想要测试的非平凡逻辑,我使用MVP模式。将有一个演示类实现小部件的“公共”接口,一个视图接口扩展了演示者所依赖的IsWidget
,以及一个实现视图接口的视图小部件。
为小部件拥有一个“公共”接口的好处是,如果逻辑变得复杂,您可以从使用单个Composite
类实现接口改为使用MVP,而且使用小部件的人根本不需要更改。
我使用Gin将所有接口和实现连接在一起。
示例
这最好用一些代码来解释。假设我有一个图表,我想在几个页面上使用,所以我决定为它制作一个可重用的小部件。在显示RPC响应之前,有一些重要的逻辑需要处理,所以我想彻底地对它进行单元测试。我会做这样的事情:
public interface FinancialChart extends IsWidget {
void setTickerSymbol(String tickerSymbol);
}
class FinancialChartPresenter extends Composite implements FinancialChart {
private final FinancialChartView view;
private final DataServiceAsync service;
@Inject(FinancialChartView view, DataServiceAsync service) {
this.view = view;
this.service = service;
}
@Override public Widget asWidget() {
return view.asWidget();
}
@Override public void setTickerSymbol(String tickerSymbol) {
service.getData(tickerSymbol, new AsyncCallback<FinancialData>() {
@Override public void onFailure(Throwable t) {
// handle error
}
@Override public void onSuccess(FinancialData data) {
SimpleData simpleData = // do some parsing with presentation-specific
// logic, e.g. make dramatic increases or decreases in price have a
// a different color so they stand out. End up with something simple
// that's essentially some (x, y) points that the dumb view can plot
// along with a label and color for each point.
view.drawGraph(simpleData);
}
}
}
interface FinancialChartView extends IsWidget {
void drawGraph(SimpleData simpleData);
}
class FinancialChartWidget extends Composite implements FinancialChartView {
@Override public void drawGraph(SimpleData simpleData) {
// plot the points on a chart. set labels. etc.
}
}
class SomethingWithFinancialChartWidget extends Composite
implements SomethingWithFinancialChart {
interface Binder extends UiBinder<Widget, SomethingWithFinancialChartWidget> {}
@UiField(provided = true) final FinancialChart chart;
@Inject SomethingWithFinancialChartWidget(Binder binder, FinancialChart chart) {
this.chart = chart;
initWidget(binder.createAndBindUi(this));
}
}
// In SomethingWithFinancialChartWidget.ui.xml
<ui:HTMLPanel>
<!-- lots of stuff -->
<mynamespace:FinancialChart ui:field="chart" />
<!-- lots more stuff -->
</ui:HTMLPanel>
class MyPackagesGinModule extends AbstractGinModule {
@Override protected void configure() {
bind(FinancialChart.class).to(FinancialChartPresenter.class);
bind(FinancialChartView.class).to(FinancialChartWidget.class);
}
}
这允许我为JUnit编写非常简单、彻底和快速的FinancialViewPresenter
测试,因为它没有GWT依赖项,需要JSNI,它必须在浏览器中运行,作为GWT测试用例的一部分。您可以创建一个模拟FinancialChartView
。
这里需要注意的一点是,由于SomethingWithFinancialChartWidget
依赖于接口FinancialChart
,所以它不能实例化该对象,因为它只是一个接口。这就是为什么在chart
的SomethingWithFinancialChartWidget
代码中将SomethingWithFinancialChartWidget
设置为@UiField(provided = true)
的原因。Gin将从FinancialChart
接口绑定到一个具体的类,这样它就可以向SomethingWithFinancialChartWidget
的@Inject
构造函数提供一个实现,然后设置this.chart
就可以为UiBinder提供它需要的对象。
有许多文件是为MVP中的所有接口和实现创建的,但是抽象是绝对值得的,因为它们支持对演示者进行简单的单元测试,并允许您更改顶层接口FinancialChart
在本例中的实现方式,例如从单个Composite
类更改为MVP,而不需要更改客户端。
我确信有些实现细节可能不太清楚,或者我忽略了一些事情,例如GWT测试,所以请发表评论,我可以编辑我的答案来更新和澄清。
发布于 2012-09-07 07:48:27
让我们与你的问题保持距离,并立即回答整体关心的问题。但首先,我最喜欢的口号是:
没有魔法!
UiBinder是一种获取XML定义并从中生成Java代码的工具。也就是说(通过调用GWT.create()
构建的一切都是这样的:没有魔法!)你可以用Java代码手工写同样的东西。换句话说,UiBinder只是一个工具,可以通过减少代码来实现相同的目标,从而使更有效率。但是,当它生成您可以手工编写的代码时,它不会在运行时提供更好的性能(也不会更糟);然而,它使使用能够提高性能的模式变得更容易,即HTMLPanel
:在纯Java中维护HTMLPanel
-based代码是一场噩梦,与UiBinder完全相反。
UiBinder将:
ClientBundle
,为每个<ui:style>
生成隐式CssResource
,为每个<ui:image>
生成隐式ImageResource
,为每个<ui:data>
生成隐式DataResource
<ui:msg>
接口,<ui:ph>
等。ui:field
属性和ui:field
代码中的@UiField
注释,将对象注入合作伙伴对象的字段(称为所有者,并作为参数传递给provided=true
方法);如果注释具有provided=true
,则可能从合作伙伴对象中检索对象。@UiConstructor
-annotated构造函数或合作伙伴对象的@UiFactory
-annotated方法创建对象,或者使用GWT.create()
调用作为最后手段。@UiHandler
-annotated方法绑定为XML模板中的小部件的事件处理程序(基于ui:field
属性)UiBinder最常见的用法是我上面提到的对象都是小部件。然后组装它们意味着将小部件添加到其他容器小部件中。
这就是为什么您通常看到UiBinder在Composite
中被用于为initWidget()
方法提供值: UiBinder将创建并组合所需的所有小部件,并返回最顶部的小部件,作为复合小部件的根。
您已经理解了:您不会在小部件上使用UiBinder,也不会将小部件转换为UiBinder XML (实际上正好相反)。
现在让我们来问一些更具体的问题:
您是编写了大量的UIBinder XML“片段”,还是只将它们打包到一个大的完整的XML文件中?
UiBinder是一种实现细节。大多数情况下,您将使用UiBinder构建(可重用的)小部件(复合);它不会扩展到外部世界,它只会看到一个小部件,而不是“用UiBinder构建的东西”。
这意味着您将拥有大量的中小型UiBinder模板(通常在应用程序中每个屏幕上都有一个模板,或者更一般的规则是,每个复杂UI组件一个)。
对于我自己的定制组件,扩展com.google.gwt.user.client.ui.*与扩展com.google.gwt.user.client.ui.Composite有什么区别?
麻省理工学院回答了这个问题,同时也回答了文档:https://developers.google.com/web-toolkit/doc/latest/DevGuideUiCustomWidgets
分工:Widget/UIBinder与布局与CSS文件:谁在做什么?
不幸的是,这个问题没有简单的答案。那得看情况。
这取决于您正在构建的应用程序类型,以及您想要的UI类型。对于应用程序的“全局布局”,您将使用多个RootPanel
或一个大HTMLPanel
,并使用HTML和CSS进行布局(或者在HTML主页中,或者在UiBinder模板中充当应用程序的外壳),或者使用所谓的版面板。
对于更多的本地化布局(在复合小部件中),我建议使用HTMLPanel
或FlowPanel
;或者可能使用布局面板。如果需要处理滚动事件,或者需要在容器小部件内滚动,则使用ScrollPanel
,否则只需在CSS中使用overflow: scroll
。
是有权衡的。你得做实验。最后,使用您认为对您有好处的。没有一刀切的东西。
最后,尽管它是最常见的用例,但是请注意,UiBinder可以不使用小部件,例如用于创建非复合小部件 (或UiObject
s,但它们的用例很少;例如,您将看到它们用于MenuItem
s和TreeItem
s ),使用setElement()
而不是initWidget()
或创建自定义单元格。
实际上,Composite
的用例也不多:您可以简单地实现IsWidget
(返回createAndBindUi
的结果,调用一次并缓存在私有字段中),并且它应该在任何需要/接受小部件的地方工作。
发布于 2012-09-07 06:36:56
UIBinder
XML代码。java代码只是一种声明性语法,它可以转换成实际的UIBinder
代码(就像您要在Java
类中创建元素一样)。UiBinder
只是使它更具可读性,因为它是声明性的,并且您最终不会实例化许多UI元素(即TextBox textbox = new TextBox();
和container.add(textBox)
)。UiBinder
片段,并将它们放到父UIBinder文件(即Presenter
)中。但是,将每一个微小的组件(即表单的标签+ TextBox )放入单独的UIBinder片段可能是没有意义的。您必须找到一个很好的平衡(尽管在本例中,如果您广泛使用TextBox,可以创建Label +UiBinder组件)。Composite
。如果您创建了一个唯一的新小部件或组件,不能使用现有的小部件或组件,请使用Widget
或IsWidget
。。
LayoutPanels
。ClientBundle
和CSSResource
。<ui:style>
声明放入相应的UiBinder文件中。最后,Michael提出了一些关于MVP
和测试的优点。我强烈建议跟随他们。
https://stackoverflow.com/questions/12318266
复制相似问题