61阅读

NAS群晖DSM进阶教程-photoshop进阶教程:打造超酷的3D网页

发布时间:2018-01-15 所属栏目:使用评测

一 : photoshop进阶教程:打造超酷的3D网页

Hi~在这辑Step by Step中,我将教大家使用几个简单的渐变和图层样式制作超酷的3D网页,如果你想让你的网页脱颖而出,那你绝对不能错过这辑,开始吧

素材图片:

最终效果:

Sample.jpg

Step 1

创建一个 1000x750像素大小的文件,双击背景图层将其变为可编辑的图层,并打开图层样式>颜色叠加,用#47382e叠加。

webt_s1.jpg

Step 2

打开标尺(视图>标尺),按下图添加一些参考线

webt_s2.jpg

Step 3

用矩形工具创建一个矩形,将该图层命名为header.

webt_s3.jpg

Step 4

将前景色设为黑色,选择椭圆工具创建一个阴影区域,大小要高于白色的矩形。将椭圆形图层命名为shadow,并将其置于header图层下面。然后打开滤镜>转换智能滤镜,之后滤镜>模糊>高斯模糊,半径为10像素,并把不透明度设为60%,得到下图效果:

2.jpg

3.jpg

Step 5

选中header图层,双击打开图层样式,选择渐变叠加,按照下图参数设置。

webt_s5.jpg

Step 6

使用直线工具画一条亮红色直线,然后再用黑色画另外一条直线(1像素),之后将红线和黑线图层编组,组命名为 vDivider。打开图层>图层蒙版> 现实全部。使用径向渐变工具,从黑色到白色,自上而下拉去,在组上添加渐变效果。

webt_s6.jpg

Step 7

使用文字工具创建导航栏(字体白色)。然后将所有标签编组,命名为White Links。复制这个组,将其置于white links组下面,将字体颜色设为黑色,然后将其向上和向左移动1像素大小的位置。这样是为了制作3D效果。

webt_s7.jpg

Step 8

按照 Step 6的方法制作分栏线。

webt_s8.jpg

Step 9

选择所有分栏线图层将其编组,并命名为hDividers,然后打开图层>图层蒙版>显示全部。使用线性渐变(黑-白)在蒙版做渐变效果

webt_s9.jpg

Step 10

保存下面的纹理图片,然后用ps打开,选择编辑>定义图案,将其命名为 webPattern。复制header图层,命名为pattern。然后双击打开图层样式,取消渐变叠加,打开图案叠加,选择之前我们创建的webpattern图案叠加,然在pattern图层上添加图层蒙版,在图层蒙版创建径向渐变效果。

a.jpg

5.jpg

7.jpg

8.jpg

Step 11

现在来添加LOGO和勺子。敲入Chinavisual.com,其中Chinavisual使用粗一些的字体。然后添加图层样式:

11.jpg

22.jpg

33.jpg

66.jpg

Step 11

下载勺子图片,然后添加图层样式

44.jpg

77.jpg

完工~

文:视觉中国

二 : gxt初学进阶教程

第一章:初识ExtGWT

在本章中,我要介绍一下什么是ExtGWT, 并且解释说明她是如何和GWT(google)协同工作的。(www.61k.com]然后会告诉大家如何搭建第一个Ext GWT项目。

概要: ?

?

?

? 在Eclipse上搭建Ext GWT环境 创建一个GWT项目 在GWT项目里使用Ext GWT 用Ext GWT的组件改写GWT实例程序 到底GWT还缺少啥?

做为java程序员,去开发富客户端的web程序是很头疼的一件事。我们需要掌握深厚的web前端技术,诸如“Javascript,AJAX, css”此类,更别说还需要处理不同浏览器之间的差异了。Google公司早就发现这一问题,就这样Google WebToolkit(GWT)就孕育而生了。她致力于让java程序员用java面向对象开发习惯,去开发web界面应用(类似与java Applet)。尽管如此,GWT工具包有些异于通常的项目开发架构的需要,就大多数项目而言,使用GWT只能作为一个局部的解决方案,而不是整个的。

解开GWT的神秘面纱,她只是一组比较基本的控件集。这远远不能够满足开发人员的需要,去搭建一个企业级的应用。所幸,GWT是一个开源的并且扩展性强的项目。为了弥补她的不足,有不少与之相关的项目孕育而生,ExtGWT就是她们其中之一。 ExtGWT给我们提供什么?

借助于GWT优势,使用ExtGWT开发出来的项目,可以让开发商给他们的用户近类似于桌面应用程序的体验。

ExtGWT提供了类似于桌面开环境的扩展组件包,GWT的程序员可以轻松的使用他们就像使用GWT组件一样。除此之外,ExtGWT还具有强大的本地操作和远程调用的特性,同时满足开发企业级应用程序的MVC架构需求。

在GWT项目里面加入ExtGWT(GXT)

对于任何一个GWT项目来说,加入GXT只需要简单的附加类库既可。如果我们现在现有一个GWT项目,那么我仅仅需要做的就是如下三步:

?

?

? 从Sencha官网上,下载GXT SDK。 在GWT项目里配置引用相关GXT类库。 拷贝GXT自带的resource目录到现有的项目中

gxt gxt初学进阶教程

如果我们没有现成的GWT项目,也不要紧。(www.61k.com)现在我们就从头开始GXT。

准备工作

在开始我的GXT之旅之前,我首先要下载GWT,搭建GWT开发环境。下面是我们主要的所需列表: ?

? Eclipse IDE for JavaEE Developers 3.6(http://www.eclipse.org/downloads/) Ext GWT 2.2.0 SDKfor GWT 2.0 SDK

(http://www.sencha.com/products/extgwt/)

? GWT的建立过程参见

() Google提供

了非常有用的开发GWT的EclipsePlugin,具体插件安装过程就不赘述了。

GXT准备工作

下载好GXTSDK包之后,我们解压缩后,开始配置Eclipse:

?

?

?

? 打开Eclipse,点击Window |Preferences 在左边的列表中,点击Java |Build Path | User Libraries 新建一个User Libraries,命名为GXT_2_2_5 加入GXT的jar包,选择适合自己当前GWT版本的jar包

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

创建第一个GWT项目

项目环境已经搭建好了,接下来我们先创建一个GWT项目,然后在此基础上进入GXT应用。[www.61k.com)

? ? 首先,点击File | New| Project 在弹出的向导里面,选择Google目录里面的Web Application Project

gxt gxt初学进阶教程

输入项目名称和package基目录(我没有用那么高的版本),按照截图勾选相关的选项。 ?

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 点击Finish,就会成功创建一个默认的GWT项目。[www.61k.com]按照截图运行程序

gxt gxt初学进阶教程

? 双击生成的url,就会在浏览器上显示出来默认功能页面

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 最好安装Chrome浏览器,使用Firefox的话不要太高的版本。(www.61k.com)因为第一次运

行GWT程序的时候浏览器会下载插件,GWT的插件在高版本的Firefox会

上安装失效。大家会注意到url后面跟的另外一个端口地址,那个是用来调用

插件功能的。它会和jetty服务器通讯,帮你调试degug,编译GWT程序自

动发布js,方便开发。jetty是google自带的一个服务器,也可以使用tomcat来跑。

gxt gxt初学进阶教程

在tomcat上跑起来

jetty是google自带的一个服务器,不用安装,Eclipse插件安装好后,就可以运行。我不知道她是否有容器可以支撑spring,hibernate等,也不知道随着项目不断壮大能否负载的了。 经过反复测试,小妹我自己总结出来如何让GWT的项目既可以在jetty上跑,也可以在tomcat上跑。(但是当运行在tomcat时,client端的代码没办法跟断点debug)

? 新建一个Dynamic Web Project

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 项目创建完毕后,右键项目,点击properties。[www.61k.com)给项目引入GWT,如截图

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 此时的项目还不是一个GWT

gxt gxt初学进阶教程

项目,因为还没有相关的GWT配置文件,要配

置GWT的Entry Point Modules(类似于flex的程序入口文件指定)项目才可以运行,我们可以把先前生成项目里面的package和java code都拷贝过来先。(www.61k.com]如下截图

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 注意0:编辑FirstApp项目的web.xml文件,删除FirstApp1项目。[www.61k.com)然后把

FirstApp项目中凡是“FirstApp1”字样的“1”都给去掉。下面是几个主要文件修改后的结果

gxt gxt初学进阶教程

FirstApp.gwt.xml文件,Eclipse的GWT项目,主要通过这个文件进行编译,来规定程序的入口文件

[html] view plaincopyprint? 1. <?xml version="1.0" encoding="UTF-8"?>

2. <module rename-to='firstapp'>

3. <!-- Inherit the core Web Toolkit stuff. -->

4. <inherits name='com.google.gwt.user.User'/>

5.

6. <!-- Inherit the default GWT style sheet. You can change -->

7. <!-- the theme of your GWT application by uncommenting -->

8. <!-- any one of the following lines. -->

9. <inherits name='com.google.gwt.user.theme.standard.Standard'/>

10. <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->

11. <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->

12.

13. <!-- Other module inherits -->

14.

15. <!-- Specify the app entry point class. -->

16. <entry-point class='com.danielvaughan.firstapp.client.FirstApp'/>

17.

18. <!-- Specify the paths for translatable code -->

19. <source path='client'/>

20. <source path='shared'/>

21.

22. </module>

web.xml文件修改后的内容如下

[html] view plaincopyprint?

1. <?xml version="1.0" encoding="UTF-8"?>

2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

3. xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

gxt gxt初学进阶教程

5. id="WebApp_ID" version="2.5">

6. <display-name>FirstApp</display-name>

7. <!-- Servlets -->

8. <servlet>

9. <servlet-name>greetServlet</servlet-name>

10. <servlet-class>com.danielvaughan.firstapp.server.GreetingServiceImpl</

servlet-class>

11. </servlet>

12.

13. <servlet-mapping>

14. <servlet-name>greetServlet</servlet-name>

15. <url-pattern>/firstapp/greet</url-pattern>

16. </servlet-mapping>

17.

18. <!-- Default page to serve -->

19. <welcome-file-list>

20. <welcome-file>FirstApp.html</welcome-file>

21. </welcome-file-list>

22. </web-app>

? 注意1:Java build Path里面的tomcat类库一定要在最下面,否则项目无法

运行。[www.61k.com]我分析是tomcat的类库的jar包和引入的GWT:gwt-servlet.jar冲突。所以从项目在加载jar的顺序上做处理,让项目先加载gwt-servlet.jar,然后再加载tomcat相关的jar包,这样就可以避免冲突。

gxt gxt初学进阶教程

? 注意2:用jetty

gxt gxt初学进阶教程

运行时,她会自动帮你编译。(www.61k.com]用tomcat运行时,则需要你手

动的编译GWT。编译成功后,会在WebContent目录下生成firstapp目录,里面存放一些编译后的js等文件

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 注意3:启动tomcat前要配置勾选“Public module contexts to separate XML

files”,否则项目发布不成功。[www.61k.com)

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 注意4:tomcat成功启动程序后,断点debug只能跟踪server包下的类,而

client包下是没办法跟踪断点的。[www.61k.com)没办法只能同时启动jetty。我测试的url是(?gwt.codesvr=127.0.0.1:999

7)这样任何目录下都可以跟踪断点了:)。运行效果如下

gxt gxt初学进阶教程

gxt gxt初学进阶教程

GWT项目开始真正的GXT的之旅

之前我们都是开始搭建一个GWT项目,如何编译,运行她,在jetty和tomcat上。[www.61k.com)以及一些需要注意的问题。现在我们需要把这个项目用GXT做一下修改。

步骤如下:

? 导入GXT类库:

找到FirstApp项目,右键,进入Java Build Path,引入GXT-2.2.5类库。

并且把gxt-.2.25-gwt22.jar拷贝到FirstApp\WebContent\WEB-INF\lib里面以保证项目运行环境。

gxt gxt初学进阶教程

? 在GWT module 配置里,加入GXT的entry: GWT module 文件(FirstApp.gwt.xml),她配置了GWT程序的入口配置,以及所引用的一些额外的使用类库。(www.61k.com]她始终以“gwt.xml”文件名结尾,并且放在项目的基包

(com.danielvaughan.firstapp/FirstApp.gwt.xml)里面。为了使用GXT,我们需要修改里面的内容。

默认情况下,GWT项目引用她自带的样式包(<inherits

name='com.google.gwt.user.theme.standard.Standard'/>)。现在我们要使用GXT的样式包(<inherits name='com.extjs.gxt.ui.GXT' />),修改后的FirstApp.gwt.xml文件如下:

[html] view plaincopyprint? 1. <?xml version

gxt gxt初学进阶教程

="1.0" encoding="UTF-8"?>

2. <module rename-to='firstapp'>

3. <!-- Inherit the core Web Toolkit stuff. -->

4. <inherits name='com.google.gwt.user.User' />

5.

gxt gxt初学进阶教程

6. <!-- Inherit the default GWT style sheet. You can change -->

7. <!-- the theme of your GWT application by uncommenting -->

8. <!-- any one of the following lines. -->

9. <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/>-->

10. <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->

11. <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> --> 12.

13. <!-- Other module inherits -->

14. <inherits name='com.extjs.gxt.ui.GXT' />

15. <!-- Specify the app entry point class. -->

16. <entry-point class='com.danielvaughan.firstapp.client.FirstApp' /> 17.

18. <!-- Specify the paths for translatable code -->

19. <source path='client' />

20. <source path='shared' />

21.

22. </module>

? 拷贝GXT SDK目录里面的resources文件夹到项目WebContent下,然后

重命名为gxt,然后整个项目的结构目录如下:

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 修改FirstApp.html文件,引用GXT的css

[html] view plaincopyprint?

1. <link type="text/css" rel="stylesheet" href="gxt/css/gxt-all.css">

gxt gxt初学进阶教程

? 注意此时还不能运行项目,因为默认项目是使用GWT的控件来完成页面渲

染,我们目前仅仅引入了GXT的css,并没有使用GXT的控件

? 下一节我们会FirstApp项目里面的GWT控件替换为GXT控件,到那时大家

就会看到同一个功能页面,展示的不用页面渲染效果哦~~~~

旧貌换新颜 现在,我们FirstApp项目已经引入了GXT库,但是我们还没有具体使用他们。(www.61k.com]现在我们从FirstApp.java拷贝出一份文件,重命名为FirstGxtApp.java。在整个文件里,我们将使用GXT的控件去替换GWT的控件。通过之间的比较,我们会发现他们之间很相似,但是也有不同,下面跟我小妹的脚步吧:

?

? 找到FirstApp.java,拷贝出一份文件,重命名为FirstGxtApp.java 删除一些import

[html] view plaincopyprint? 1. import com.google.gwt.event.dom.client.ClickEvent;

2. import com.google.gwt.event.dom.client.ClickHandler;

3. import com.google.gwt.event.dom.client.KeyUpEvent;

4. import com.google.gwt.event.dom.client.KeyUpHandler;

5. import com.google.gwt.user.client.ui.Button;

6. import com.google.gwt.user.client.ui.DialogBox;

7. import com.google.gwt.user.client.ui.Label;

8. import com.google.gwt.user.client.ui.TextBox;

9. import com.google.gwt.user.client.ui.VerticalPanel;

? 导入一些相应的GXT

[java] view plaincopyprint?

1. import com.extjs.gxt.ui.client.event.ButtonEvent;

2. import com.extjs.gxt.ui.client.event.SelectionListener;

3. import com.extjs.gxt.ui.client.event.KeyListener;

4. import com.extjs.gxt.ui.client.event.ComponentEvent;

5. import com.extjs.gxt.ui.client.widget.Dialog;

6. import com.extjs.gxt.ui.client.widget.Label;

7. import com.extjs.gxt.ui.client.widget.VerticalPanel;

gxt gxt初学进阶教程

8. import com.extjs.gxt.ui.client.widget.button.Button;

9. import com.extjs.gxt.ui.client.widget.form.TextField;

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 接下来,我们要做的,就是在FirstGXTApp.java中,重新用GXT类库,来

定义控件。[www.61k.com]在GWT例子(FirstApp.java)里面,所有的控件代码集都是定义在

onModuleLoad()方法里面,然后使用的内部类去实现Handler(interface),来

处理不同的事件。但是GXT使用listeners(class)去处理事件的,因此在处理

方式上,我们需要把GXT的控件提出到onModuleLoad()方法之外,变成属

性去处理。

[java] view plaincopyprint?

1. private final Button sendButton = new Button("Send");

2. private final TextField<String> nameField = new

3. TextField<String>();

4. private final Dialog dialogBox = new Dialog();

5. private final Label textToServerLabel = new Label();

6. private final HTML serverResponseLabel = new HTML();

? GXT和GWT的控件之间,在functions上,存在这一些不同。在开始修改之

前,先看看我总结的一些不同点。

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 另外一个不同点,就正如我上面提到的,就是事件处理机制不同。[www.61k.com)GWT使用

event handlers,GXT 是使用event listeners(类似于早期版本的GWT)。但

是不管怎么样,代码风格上也非常类似。下面我把整个两个文件贴出来,大

家看看不同之处

FirstApp.java

[java] view plaincopyprint?

1. package com.danielvaughan.firstapp.client;

2.

3. import com.danielvaughan.firstapp.shared.FieldVerifier;

4. import com.google.gwt.core.client.EntryPoint;

5. import com.google.gwt.core.client.GWT;

6. import com.google.gwt.event.dom.client.ClickEvent;

7. import com.google.gwt.event.dom.client.ClickHandler;

8. import com.google.gwt.event.dom.client.KeyCodes;

9. import com.google.gwt.event.dom.client.KeyUpEvent;

10. import com.google.gwt.event.dom.client.KeyUpHandler;

11. import com.google.gwt.user.client.rpc.AsyncCallback;

12. import com.google.gwt.user.client.ui.Button;

13. import com.google.gwt.user.client.ui.DialogBox;

14. import com.google.gwt.user.client.ui.HTML;

15. import com.google.gwt.user.client.ui.Label;

16. import com.google.gwt.user.client.ui.RootPanel;

17. import com.google.gwt.user.client.ui.TextBox;

18. import com.google.gwt.user.client.ui.VerticalPanel;

19.

20. /**

21. * Entry point classes define <code>onModuleLoad()</code>.

22. */

gxt gxt初学进阶教程

23. public class FirstApp implements EntryPoint {

24. /**

25. * The message displayed to the user when the server cannot be reached or

26. * returns an error.

27. */

28. private static final String SERVER_ERROR = "An error occurred while "

29. + "attempting to contact the server. Please check your network "

30. + "connection and try again.";

31.

32. /**

33. * Create a remote service proxy to talk to the server-side Greeting service.

34. */

35. private final GreetingServiceAsync greetingService = GWT

36. .create(GreetingService.class);

37.

38. /**

39. * This is the entry point method.

40. */

41. public void onModuleLoad() {

42. final Button sendButton = new Button("Send");

43. final TextBox nameField = new TextBox();

44. nameField.setText("GWT User");

45. final Label errorLabel = new Label();

46.

47. // We can add style names to widgets

48. sendButton.addStyleName("sendButton");

49.

50. // Add the nameField and sendButton to the RootPanel

51. // Use RootPanel.get() to get the entire body element

52. RootPanel.get("nameFieldContainer").add(nameField);

53. RootPanel.get("sendButtonContainer").add(sendButton);

54. RootPanel.get("errorLabelContainer").add(errorLabel);

55.

56. // Focus the cursor on the name field when the app loads

57. nameField.setFocus(true);

gxt gxt初学进阶教程

58. nameField.selectAll();

59.

60. // Create the popup dialog box

61. final DialogBox dialogBox = new DialogBox();

62. dialogBox.setText("Remote Procedure Call");

63. dialogBox.setAnimationEnabled(true);

64. final Button closeButton = new Button("Close");

65. // We can set the id of a widget by accessing its Element

66. closeButton.getElement().setId("closeButton");

67. final Label textToServerLabel = new Label();

68. final HTML serverResponseLabel = new HTML();

69. VerticalPanel dialogVPanel = new VerticalPanel();

70. dialogVPanel.addStyleName("dialogVPanel");

71. dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));

72. dialogVPanel.add(textToServerLabel);

73. dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));

74. dialogVPanel.add(serverResponseLabel);

75. dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);

76. dialogVPanel.add(closeButton);

77. dialogBox.setWidget(dialogVPanel);

78.

79. // Add a handler to close the DialogBox

80. closeButton.addClickHandler(new ClickHandler() {

81. public void onClick(ClickEvent event) {

82. dialogBox.hide();

83. sendButton.setEnabled(true);

84. sendButton.setFocus(true);

85. }

86. });

87.

88. // Create a handler for the sendButton and nameField

89. class MyHandler implements ClickHandler, KeyUpHandler {

90. /**

91. * Fired when the user clicks on the sendButton.

92. */

gxt gxt初学进阶教程

93. public void onClick(ClickEvent event) {

94. sendNameToServer();

95. }

96.

97. /**

98. * Fired when the user types in the nameField.

99. */

100.

101.

102.

103.

104.

105.

106.

107.

108.

109.

110.

111.

112.

113.

114.

115.

116.

117.

118.

119.

120.

121.

122.

123.

124.

125.

126.

127. public void onKeyUp(KeyUpEvent event) { if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { sendNameToServer(); } } /** * Send the name from the nameField to the server and wait for a response. */ private void sendNameToServer() { // First, we validate the input. errorLabel.setText(""); String textToServer = nameField.getText(); if (!FieldVerifier.isValidName(textToServer)) { errorLabel.setText("Please enter at least four characters"); return; } // Then, we send the input to the server. sendButton.setEnabled(false); textToServerLabel.setText(textToServer); serverResponseLabel.setText(""); greetingService.greetServer(textToServer, new AsyncCallback<String>() { public void onFailure(Throwable caught) { // Show the RPC error message to the user dialogBox .setText("Remote Procedure Call - Failure");

gxt gxt初学进阶教程

128.

129.

130.

131.

132.

133.

134.

135.

136.

137.

138.

139.

140.

141.

142.

143.

144.

145.

146.

147.

148.

149.

150.

151.

152. serverResponseLabel .addStyleName("serverResponseLabelError"); serverResponseLabel.setHTML(SERVER_ERROR); dialogBox.center(); closeButton.setFocus(true); } public void onSuccess(String result) { dialogBox.setText("Remote Procedure Call"); serverResponseLabel .removeStyleName("serverResponseLabelError"); serverResponseLabel.setHTML(result); dialogBox.center(); closeButton.setFocus(true); } }); } } // Add a handler to send the name to the server MyHandler handler = new MyHandler(); sendButton.addClickHandler(handler); nameField.addKeyUpHandler(handler); } }

FirstGXTApp.java

[java] view plaincopyprint?

1. package com.danielvaughan.firstapp.client;

2.

3. import com.extjs.gxt.ui.client.Style.HorizontalAlignment;

4. import com.extjs.gxt.ui.client.event.ButtonEvent;

5. import com.extjs.gxt.ui.client.event.ComponentEvent;

6. import com.extjs.gxt.ui.client.event.KeyListener;

gxt gxt初学进阶教程

7. import com.extjs.gxt.ui.client.event.SelectionListener;

8. import com.extjs.gxt.ui.client.widget.Dialog;

9. import com.extjs.gxt.ui.client.widget.Label;

10. import com.extjs.gxt.ui.client.widget.VerticalPanel;

11. import com.extjs.gxt.ui.client.widget.button.Button;

12. import com.extjs.gxt.ui.client.widget.form.TextField;

13. import com.google.gwt.core.client.EntryPoint;

14. import com.google.gwt.core.client.GWT;

15. import com.google.gwt.event.dom.client.KeyCodes;

16. import com.google.gwt.user.client.rpc.AsyncCallback;

17. import com.google.gwt.user.client.ui.HTML;

18. import com.google.gwt.user.client.ui.RootPanel;

19.

20. /**

21. * Entry point classes define <code>onModuleLoad()</code>.

22. */

23. public class FirstGXTApp implements EntryPoint {

24. /**

25. * The message displayed to the user when the server cannot be reached or

26. * returns an error.

27. */

28. private static final String SERVER_ERROR = "An error occurred while "

29. + "attempting to contact the server. Please check your network "

30. + "connection and try again.";

31.

32.

33. /**

34. * Create a remote service proxy to talk to the server-side Greeting

35. * service.

36. */

37. private final GreetingServiceAsync greetingService = GWT

38. .create(GreetingService.class);

39.

40. private final Dialog dialogBox = new Dialog();

41. private final VerticalPanel dialogVPanel = new VerticalPanel();

gxt gxt初学进阶教程

42. private final TextField<String> nameField = new TextField<String>();

43. private final Button sendButton = new Button("Send");

44. private final HTML serverResponseLabel = new HTML();

45. private final Label textToServerLabel = new Label();

46.

47. /**

48. * This is the entry point method.

49. */

50. public void onModuleLoad() {

51.

52. nameField.setValue("GWT User");

53.

54. // We can add style names to widgets

55. sendButton.addStyleName("sendButton");

56.

57. // Add the nameField and sendButton to the RootPanel

58. // Use RootPanel.get() to get the entire body element

59. RootPanel.get("nameFieldContainer").add(nameField);

60. RootPanel.get("sendButtonContainer").add(sendButton);

61.

62. // Focus the cursor on the name field when the app loads

63. nameField.focus();

64. nameField.selectAll();

65.

66. // Create the popup dialog box

67.

68. dialogBox.setHeading("Remote Procedure Call");

69. dialogBox.setAnimCollapse(true);

70.

71. dialogVPanel.addStyleName("dialogVPanel");

72. dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));

73. dialogVPanel.add(textToServerLabel);

74. dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));

75. dialogVPanel.add(serverResponseLabel);

76. dialogVPanel.setHorizontalAlign(HorizontalAlignment.RIGHT);

gxt gxt初学进阶教程

77. dialogBox.setButtons(Dialog.CLOSE);

78. dialogBox.add(dialogVPanel);

79.

80. Button closeButton = dialogBox.getButtonById(Dialog.CLOSE);

81. // Add a handler to close the DialogBox

82. closeButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

83. @Override

84. public void componentSelected(ButtonEvent ce) {

85. dialogBox.hide();

86. sendButton.setEnabled(true);

87. sendButton.focus();

88. }

89. });

90.

91. sendButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

92. /**

93. * Fired when the user clicks on the sendButton.

94. */

95. @Override

96. public void componentSelected(ButtonEvent ce) {

97. sendNameToServer();

98. }

99. });

100.

101.

102.

103.

104.

105.

106.

107.

108.

109.

110.

111. // Add a handler to send the name to the server nameField.addKeyListener(new KeyListener() { /** * Fired when the user types in the nameField. */ @Override public void componentKeyUp(ComponentEvent event) { if (event.isSpecialKey(KeyCodes.KEY_ENTER)) { sendNameToServer(); } }

gxt gxt初学进阶教程

112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123.

{ 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144.

145. }); } /** * Send the name from the nameField to the server and wait for a response. */ private void sendNameToServer() { sendButton.setEnabled(false); String textToServer = nameField.getValue(); textToServerLabel.setText(textToServer); serverResponseLabel.setText(""); greetingService.greetServer(textToServer, new AsyncCallback<String>() public void onFailure(Throwable caught) { // Show the RPC error message to the user dialogBox.setHeading("Remote Procedure Call - Failure"); serverResponseLabel.addStyleName("serverResponseLabelError"); serverResponseLabel.setHTML(SERVER_ERROR); dialogBox.show(); dialogBox.center(); Button closeButton = dialogBox.getButtonById(Dialog.CLOSE); closeButton.focus(); } public void onSuccess(String result) { dialogBox.setHeading("Remote Procedure Call"); serverResponseLabel.removeStyleName("serverResponseLabelError"); serverResponseLabel.setHTML(result); dialogBox.show(); dialogBox.center(); Button closeButton = dialogBox.getButtonById(Dialog.CLOSE); closeButton.focus(); } }); }

gxt gxt初学进阶教程

146. }

? 两个文件修改好了之后,我们要修改GWT的module文件。[www.61k.com)打开

FirstApp.gxt.xml,修改entry-point为新的FirstGXTApp。然后我们运行一下吧

[html] view plaincopyprint?

1. <!--entry-point class='com.danielvaughan.firstapp.client.FirstApp' /-->

2. <entry-point class='com.danielvaughan.firstapp.client.FirstGXTApp' />

gxt gxt初学进阶教程

第二章:GXT组件

现在我们已经有了开发环境,在本章中,我要详细介绍ExtGWT组件用法,并且通过开发一个demo程序来展示一系列的GXT组件。一开始会介绍一些关键的概念,然后就会着眼于demo项目的实战开发。

本章,我们会涉及到如下GXt功能集:

gxt gxt初学进阶教程

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Component Container BoxComponent ScrollContainer LayoutContainer FlowLayout ContentPanel Viewport BorderLayout Loading messages Custom Components Buttons Tooltip Popup SelectionListener TextField KeyListener

下图,是我们本章所涉及的控件集的层次结构。[www.61k.com]

gxt gxt初学进阶教程

gxt gxt初学进阶教程

ExtGwt Demo 库

在Sencha官网上,我们可以看到所有的GXT的Demo

()。(www.61k.com]如果大家还没有预览,请先通览一下,然后再开始我们的demo项目。

GXT基础1:Component

GWT中,Widget(com.google.gwt.user.client.ui.Widget)是所有显式组件的基类,正如我们可以在浏览器中看见的:buttons, textboxes, tree views

gxt gxt初学进阶教程

GXT中,Component(com.extjs.gxt.ui.client.widget.Component)则是所有显式组件的基类。(www.61k.com]因为GXT是建立在GWT之上的,所以我们也不会奇怪,所有GXT的componests是建立在GWT的Widget之上的。具体说来,GXT components的父类是GXT的Widget,并扩展了一些新的功能而已。

gxt gxt初学进阶教程

所有的GXT的components都引入了生命周期的概念,他们是:创建,附加,自动分离,异步渲染。Components 继承了基本的hide and show, enable and disable 功能。 BoxComponent

所有的GXt显式组件,都继承了Component,同时也直接或间接的使用了BoxComponent。

异步渲染

GWT的工作原理,就是操作DOM元素——Document Object Model来渲染浏览器中的html页面。GWT widget 其实就是由html标记集合组成的,可以在DOM中添加和删除。 例如,一个GWT的button widget的html标记会被表述成,如下:

[html] view plaincopyprint?

1. <button type="button" class="gwt-Button" style="position: absolute;

2. left: 80px; top: 45px; ">Click Me!</button>

在GWT中,当一个widget被初始化后,html标记会被同时的渲染在DOM中。当一个widget被添加到另一个GWT panel 的widget上时,也是同时的html标记被渲染。

GXT的components(就相对于GWT的widgets)则被渲染的方式是不同的——异步渲染(懒渲染)。当一个GXT component被初始化后,html标记不会马上被渲染。只有当component的渲染方法被调用之后,html标记才会被渲染。这种方法被看作是更有效的去节省html所占用的内存空间。

虽然GWT的component是异步渲染的,但是components的相关属性是可以在渲染之前就被设置的。例如,一个TextField在被html渲染之前,我们就可以给它设置一个value属性。

如果另外一种情况,就是GXT的componment被添加到另外一个GWT的panel上时,component的渲染方法则会马上被调用,也就是说会被同时的渲染该component。如果换成是一个GXT的panel里,添加了也是GXt的component 的时候,那么他还是被异步渲染的。

gxt gxt初学进阶教程

GXT基础2:Container

Container是Boxcomponent的一个子类,它可以包含其他的components。[www.61k.com)类路径是:com.extjs.gxt.ui.client.widget.Container<T>。他们只是负责附加,分离和管理他们的子components,就Container自身而言,他不负责去处理components的布局摆放和渲染。下面是从左到右的类继承关系。

gxt gxt初学进阶教程

LayoutContainer

Layoutcontainer继承了ScrollContainer, ScrollContainer的父类就是Container。顾名思义,ScrollContainer可以使其内容在Container里是可折叠的。LayoutContainer则多具备一项功能,可以让子components的布局摆放效果交给一个具体的Layout类来处理。 让我通过如下一个简单例子,来了解异步渲染是如果工作的。

? 首先我们创建一个LayoutContainer

[java] view plaincopyprint?

1. LayoutContainer layoutContainer = new LayoutContainer();

? 此时,还没有任何html的渲染,当前的layoutcontainer也没有被添加到GXT容器和GWT的Panel中。下面我们添加一个Button

[java] view plaincopyprint?

1. LayoutContainer layoutContainer = new LayoutContainer();

2. Button button = new Button("Click me");

? 同样,我们虽然创建了两个对象layoutContainer和button,仍然还是没有任何的html标记被渲染。下面将button添加到layoutContainer中

[java] view plaincopyprint?

1. LayoutContainer layoutContainer = new LayoutContainer();

2. Button button = new Button("Click me");

gxt gxt初学进阶教程

3. layoutContainer.add(button);

? 同样的,此时此刻仍然没有任何的html被渲染出来,这是因为

layoutContainer他本身没有被渲染。[www.61k.com)如果我们将layoutContainer添加到GWT的Panel中(RootPanel),让我们拭目以待

[java] view plaincopyprint? 1. LayoutContainer layoutContainer = new LayoutContainer();

2. Button button = new Button("Click me");

3. layoutContainer.add(button);

4. RootPanel.get().add(layoutContainer);

? 添加layoutContainer到RootPanel中,会触发layoutContainer的渲染方法

被调用。Container中的所有控件会有一种级联效应,被层级的渲染出来。因此,当layoutContainer被渲染之后,他的children们的渲染方法也会被调用,在这里就是刚刚创建的那个button的渲染方法会随之被调用。当我们通过工具查看DOM的时候,我们会找到到layoutContainer和button对应的html标记

? 如果我们像再添加一个button,如下代码:

[java] view plaincopyprint?

1. LayoutContainer layoutContainer = new LayoutContainer();

2. Button button = new Button("Click me");

3. layoutContainer.add(button);

4. RootPanel.get().add(layoutContainer);

5.

6. Button anotherButton = new Button("Click me too");

7. layoutContainer.add(anotherButton);

? 如果你认为anotherButton也会显式出来,那么你就想错了!当

layoutContainer已经被渲染之后,再在layoutContainer身上添加的

anotherButton不会被渲染了。对于这种情况,我们还有别的解决办法,就是调用layoutContainer的layout()方法,那么系统会自动的去调用两个button的渲染方法。

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. LayoutContainer layoutContainer = new LayoutContainer();

2. Button button = new Button("Click me");

3. layoutContainer.add(button);

4. RootPanel.get().add(layoutContainer);

5. Button anotherButton = new Button("Click me too");

6. layoutContainer.add(anotherButton);

7. layoutContainer.layout();

? 此时,anotherButton的html标记已经被添加到DOM中了。(www.61k.com)

FlowLayout

FlowLayout是LayoutContainer的默认布局排列(layout)方式。这种layout方式下,所添加的components,都不能够被设置其摆放位置,大小等功能。只是每个component会伴随着前一个component的渲染,而从左到右,从上到下的排列。之后我们会了解到更多的layout方式。

ContentPanel

ContentPanel是LayoutContainer的一个子类。这是个非常有用的,利于用户交互的控件。稍后我们会使用到它。他由页眉,页脚和内容区三部分组成,在顶端和底端都可以显式工具栏。它就有内建的折叠按钮和用来自定义功能的按钮。 GXT基础3:Events

Events 概念是指:当有事件发生时,通知应用程序作出响应的这一过程。点击button或者控件的状态改变,都可以当作一个事件,然后通过应用程序,使用户和程序之间产生某种互动的效果。用户在控件上的每一个行为,每一个操作,都会导致某些事件的触发,如果这个控件自身监听到了某些事件的发生,那么就会跳转到对应的处理流程中,以此作为事件的响应。

从专业的角度来说,就像总所周知的observer模式那样。在GXT里,使用listeners来处理事件的。如果一个listener已经被添加到某个component上,当某个event被触发后,那么与之对应的listener就会被唤醒,然后处理该event。

gxt gxt初学进阶教程

gxt gxt初学进阶教程

所有Events的基类是:com.extjs.gxt.ui.client.event.BaseEvent。[www.61k.com)并且GXT提供了广泛的事件类型。稍后我们会在demo应用程序中逐渐的使用他们。

事件的sink和swallow

作为GWT设计的一部分,widgets只能响应浏览器中部分的事件,GXT也是如此。原因是降低内存使用量,避免内存使用溢出。如果让一个widget可以响应一个浏览器里的事件,要调用sinkEvents()方法把该事件注册。例如,默认的一个component可以响应onClick event, 但是不支持响应onDoubleClick。为此,我们需要通过sinkEvents()方法在此控件上组册此双击事件。

类似的方法,我们也可以销毁某些事件,来避免一个事件被多次触发。例如,如果像让一个button component的onClick event失效,我们可以注销调他。

Demo应用程序-RSSReader

下面我们就开始一步一步的搭建一个demo程序,此demo会贯穿全文,我们会不断的优化她,通过此过程深入了解GXT的各种应用。首先呢,我需要先新建一个最基本的项目。

gxt gxt初学进阶教程

需求:假如我们的客户有这样一个简单的需求。[www.61k.com)创建一个RSS 新闻订阅读器,可以管理用户指定的各式各样的RSS;此程序必须要可以通过web访问,显式效果必须类似于桌面的应用程序。不需要强制用户安装某一特定的浏览器,不需要用户设置显示器分辨率,要尽可能的让我们的程序灵活起来。 解决方案:GWT提供最优话的跨浏览器JavaScript解决方案,这正好满足了综上需求。在此基础上,我们再使用GXT,可以让程序展现的更像桌面程序。

项目背景:我们现在需要创建一个新的GXT项目,按照第一章所讲的步骤,此次项目命名为RSSReader。同时我们不需要GWT的默认生成的代码,要清楚干净他们。

?

? 创建项目基包:com.danielvaughan.rssreader 在此包下创建GWT modal文件

(com.danielvaughan.rssreader.RSSReader.gwt.xml)

[java] view plaincopyprint? 1. <?xml version="1.0" encoding="UTF-8"?>

2. <module rename-to='rssreader'>

3. <!-- Inherit the core Web Toolkit stuff. -->

4. <inherits name='com.google.gwt.user.User'/>

5.

6. <!-- Inherit the default GWT style sheet. You can change -->

7. <!-- the theme of your GWT application by uncommenting -->

8. <!-- any one of the following lines. -->

9. <inherits name='com.google.gwt.user.theme.standard.Standard'/>

10. <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->

11. <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->

12.

13. <!-- Other module inherits -->

14. <inherits name='com.extjs.gxt.ui.GXT'/>

15.

16. <!-- Specify the app entry point class. -->

17. <entry-point class='com.danielvaughan.rssreader.client.RSSReader'/>

18.

19. <!-- Specify the paths for translatable code -->

20. <source path='client'/>

21. <source path='shared'/>

gxt gxt初学进阶教程

22.

23. </module>

? 创建新包(client),并在此包下创建类

(com.danielvaughan.rssreader.client.RSSReader),实现onModuleLoad()方法。[www.61k.com)

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client;

2.

3. import com.google.gwt.core.client.EntryPoint;

4.

5. /**

6. * Entry point classes define <code>onModuleLoad()</code>.

7. */

8. public class RSSReader implements EntryPoint {

9.

10. /**

11. * This is the entry point method.

12. */

13. @Override 14. public void onModuleLoad() {

15.

16. }

17. }

? 编辑web.xml文件,设置欢迎页面

[html] view plaincopyprint?

1. <?xml version="1.0" encoding="UTF-8"?>

2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

3. xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

gxt gxt初学进阶教程

5. id="WebApp_ID" version="2.5">

6. <display-name>RSSReader</display-name>

7. <!-- Default page to serve -->

8. <welcome-file-list>

9. <welcome-file>RSSReader.html</welcome-file>

10. </welcome-file-list>

11. </web-app>

?

? WebContent/目录下创建RSSReader.css空文件。[www.61k.com] 创建欢迎页面(RSSReader.html);引入GXT resources目录里面的css

文件和刚才建立的RSSReader.css;引入rssreader.nocache.js(GWT编译后会自动生成在WebContent/目录下,注意大小写);把<body>标签里内容清空。

[html] view plaincopyprint? 1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

2. <html>

3. <head>

4. <meta http-equiv="content-type" content="text/html; charset=UTF-8">

5. <link type="text/css" rel="stylesheet" href="RSSReader.css">

6. <link type="text/css" rel="stylesheet" href="gxt/css/gxt-all.css">

7. <title>RSSReader</title>

8. <pre class="html" name="code"><script type="text/javascript"

language="javascript"

9. src="rssreader/rssreader.nocache.js"></script>

10. </pre></head><body></div></body></html>

11. <pre></pre>

12. <p></p>

13. <pre></pre>

14. <p></p>

15. <ul>

16. <li>搭建后的空项目,我们启动后访问应该是一个空白页面。整个目录结构如下

</li></ul>

17. <p><img alt=""

src="http://hi.csdn.net/attachment/201201/3/0_1325584108i4Ff.gif"></p>

gxt gxt初学进阶教程

18. <ul>

19. <li>下一节,会在这个RSSReader项目上开始GXT之旅。[www.61k.com)请大家拭目以待哦~~~<br>

20. </li></ul> Viewport

Viewport的父类是LayoutContainer,它会自动的填充整个浏览器的窗口,并且会监听窗口的大小变化,随之变化。于此同时,也会负责处理其里面的子components在新改变窗口后的大小。对于去展现一个类似于桌面应用程序来说,Viewport是一个非常有用的component。 我们会使用Viewport,作为整个项目的基础面板。因此,它会被直接的添加到GWT的root panel上。不需要我们调用其layout()方法,viewport就会自动的伴随着root panel 的渲染而被渲染出来。

? 找到RSSReader.java类中的onModuleLoad()方法,这是程序的入口方法。

我们创建一个Viewport,然后添加到GWT的RootPanel里: [java] view plaincopyprint?

1. public void onModuleLoad() {

2. Viewport viewport = new Viewport();

3. RootPanel.get().add(viewport);

4. }

? 此时我们运行浏览器,会仍然看到空白页面。那是因为Viewport目前没有应

用任何css样式。所以在RSSReader.css文件中加入如下css样式,Viewport

会自动的应用此样式。

[css] view plaincopyprint?

1. .x-viewport

2. {

3. background-color: #070;

4. }

? .x-viewport 样式会自动的应用到GXT Viewport控件中,我们定义的是绿色

背景,所以当我们启动程序时,浏览器会随着javaScript的执行,Viewport

的渲染,而从白色变成绿色。

gxt gxt初学进阶教程

Layout

Layout类定义了Layoutcontainer

gxt gxt初学进阶教程

里面components是如何布局和显式的。(www.61k.com]类路径是:com.extjs.gxt.ui.client.widget.Layout。稍后的章节会逐步使用到他们,这一章呢,我们先从BorderLayout开始学习。

BorderLayout

如果我们想展示一个全屏的应用程序,就一定要使用BorderLayout。对于一个应用程序来说,会被各种components充斥起来,但是他们也不会被胡乱的摆放。通常一个完整屏幕会被划分为中心区域,其周围由东,南,西,北包围着。BorderLayout就是为此布局设计的,用户可以随意的改变每个区域的大小,伸缩和隐藏。

gxt gxt初学进阶教程

gxt gxt初学进阶教程

这种布局对于开发应用系统来说非常常见。[www.61k.com]North区域用来作为页眉,South区域作为页脚,Center区域最为具体显式的内容,West或East最为导航区。

BorderLayoutData

在使用BorderLayout 添加子component到父component之前,我们要首先使用BorderLayoutData 对象来定义component是如何展现的。

具体来说,就是我们需要通过创建BorderLayoutData 对象,才可以设置其布局的区域(North,South,West,East,Center),初始化面积,用户是否可以折叠他,以及最大和最小面积等选项。

当我们定义好了一个具体的BorderLayoutData对象之后,我们才可以使用他去添加一个component,应用到一个BorderLayout中去。通过下面的步骤,一看便知:

? 找到RSSReader.java类中的onModuleLoad()方法,新建一个BorderLayout

布局对象,然后让Viewport应用此布局。(大家一定要有个概念,就是控件

和布局效果是分开的,需要创建各自的对象,然后再让一个控件去应用一个

布局)

[java] view plaincopyprint?

1. public void onModuleLoad() {

gxt gxt初学进阶教程

2. Viewport viewport = new Viewport();

3. final BorderLayout borderLayout = new BorderLayout();

4. viewport.setLayout(borderLayout);

5. RootPanel.get().add(viewport);

6. }

? 然后,创建一个BorderLayoutData对象,并设置他的布局位置,高度,以及

是否可以折叠功能。(www.61k.com]

[java] view plaincopyprint? 1. BorderLayoutData northData = new

BorderLayoutData(LayoutRegion.NORTH,20);

2. northData.setCollapsible(false);

3. northData.setSplit(false);

? 新建一个HTML widget(一提到widget就是GWT的东东,一提到component

就是GXT的东东),最为整个页面的页眉(就是放在North区域)。

[java] view plaincopyprint?

1. HTML headerHtml = new HTML(); 2. headerHtml.setHTML("<h1>RSS Reader</h1>");

3. viewport.add(headerHtml, northData);

? 再分别创建两个BorderLayoutData,分别负责Center和west区域的布局效

果。West区最为导航菜单来说,当然是可以折叠的。同时对其宽度做具体的设置。

[java] view plaincopyprint?

1. BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);

2. centerData.setCollapsible(false);

3. BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST, 200,

150, 300);

4. westData.setCollapsible(true);

gxt gxt初学进阶教程

5. westData.setSplit(true);

? 最后要创建两个components(ContentPanel),分别对应,上面创建的两个

BorderLayoutData。(www.61k.com]

[java] view plaincopyprint? 1. ContentPanel mainPanel = new ContentPanel(); 2. ContentPanel navPanel = new ContentPanel();

3. viewport.add(mainPanel, centerData); 4. viewport.add(navPanel, westData); ? 运行后的效果如下(怎么样,是不是看到有点像模像样啦):

gxt gxt初学进阶教程

? 把完整的代码贴出来,给大家分享一下:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client; 2.

3. import com.extjs.gxt.ui.client.Style.LayoutRegion;

4. import com.extjs.gxt.ui.client.widget.ContentPanel;

5. import com.extjs.gxt.ui.client.widget.Viewport;

6. import com.extjs.gxt.ui.client.widget.layout.BorderLayout;

gxt gxt初学进阶教程

7. import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;

8. import com.google.gwt.core.client.EntryPoint;

9. import com.google.gwt.user.client.ui.HTML;

10. import com.google.gwt.user.client.ui.RootPanel;

11.

12. /**

13. * Entry point classes define <code>onModuleLoad()</code>.

14. */

15. public class RSSReader implements EntryPoint {

16.

17. /**

18. * This is the entry point method.

19. */

20. @Override

21. public void onModuleLoad() {

22. Viewport viewport = new Viewport();

23. final BorderLayout borderLayout = new BorderLayout();

24.

25. BorderLayoutData northData = new BorderLayoutData(LayoutRegion.NORTH,

26. 20);

27. northData.setCollapsible(false);

28. northData.setSplit(false);

29.

30. HTML headerHtml = new HTML();

31. headerHtml.setHTML("<h1>RSS Reader</h1>");

32. viewport.add(headerHtml, northData);

33.

34. BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);

35. centerData.setCollapsible(false);

36.

37. BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST,

38. 200, 150, 300);

39. westData.setCollapsible(true);

40. westData.setSplit(true);

41.

gxt gxt初学进阶教程

42. ContentPanel mainPanel = new ContentPanel();

43. ContentPanel navPanel = new ContentPanel();

44. viewport.add(mainPanel, centerData);

45. viewport.add(navPanel, westData);

46.

47. viewport.setLayout(borderLayout);

48. RootPanel.get().add(viewport);

49. }

50. } 加载消息

构建任何一种GUI(graphic user interface图形用户界面),最重要的一点就是一定要让用户知道此时此刻应用程序正在做什么。[www.61k.com]GWT,尤其是GXT应用程序,会在javaScript和图片加载时候,占用几秒钟。因此,在这一期间,就需要显示一个等待加载的一个消息界面。 大致思路:当浏览器通过url找到此应用程序的时候,也就是JavaScript还没有被加载的时候,我们要在应用程序的html页面一直显式一个等待的消息。当浏览器加载完毕JavaScript和UI被渲染完毕的时候,再把这个等待的消息给隐藏。

? 打开应用的欢迎HTML页面,RSSReader.html。在<body>标记之间,加入

如下的代码:

[html] view plaincopyprint? 1. <div id="loading">

2. <div class="loading-indicator">

3. <img src="gxt/images/default/shared/large-loading.gif" width="32"

height="32"/>RSS Reader<br />

4. <span id="loading-msg">Loading...</span></div>

5. </div>

? <div>标记的id必须命名为loading,当应用加载完毕的时候,就会马上的,

自动的,去隐藏loading标记。large-loading.gif 图片,正好是使用GXT SDK

包里面的resources目录里现成的。

? 接下来,我们要给loading标记,指定一个css样式。所以我们应该编辑

RSSReader.css文件,清空里面的内容,然后添加如下的css定义:

gxt gxt初学进阶教程

[css] view plaincopyprint? 1. #loading {

2. position: absolute;

3. left: 45%;

4. top: 40%;

5. margin-left: -45px;

6. padding: 2px;

7. z-index: 20001;

8. height: auto;

9. border: 1px solid #ccc;

10. }

11.

12. #loading a {

13. color: #225588;

14. }

15.

16. #loading .loading-indicator {

17. background: white;

18. color: #444;

19. font: bold 13px tahoma, arial, helvetica;

20. padding: 10px;

21. margin: 0;

22. height: auto;

23. }

24.

25. #loading .loading-indicator img {

26. margin-right: 8px;

27. float: left;

28. vertical-align: top;

29. }

30.

31. #loading-msg {

32. font: normal 10px arial, tahoma, sans-serif;

33. }

gxt gxt初学进阶教程

? 此时呢,让我们好好通读一下RSSReader.html。(www.61k.com)在JavaScript加载区域,

毫无疑问的,必须的,要加载GWT生成rssreader/rssreader.nocache.js。但是通常都是把此类的JavaScripte加载的标记片段,放在<head>标记里,可是这样就意味着他们会早与<body>标记被浏览器先加载进来。换句话说,就是当js文件加载后,找不到<body>标签里面的任何内容。这就无法实现:在js加载后替换loading的<div>标签的想法。因此解决这个问题的好方法就是,把js文件的加载片段,写在<body>标签的最后面。经过修改后的RSSReader.html如下:

[html] view plaincopyprint? 1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

2. <html>

3. <head>

4. <meta http-equiv="content-type" content="text/html; charset=UTF-8">

5. <link type="text/css" rel="stylesheet" href="RSSReader.css">

6. <link type="text/css" rel="stylesheet" href="gxt/css/gxt-all.css">

7. <title>RSSReader</title>

8. </head>

9. <body>

10. <div id="loading">

11. <div class="loading-indicator"><img

12. src="gxt/images/default/shared/large-loading.gif" width="32"

13. height="32" />RSS Reader<br />

14. <span id="loading-msg">Loading...</span></div>

15. </div>

16. <script type="text/javascript" language="javascript"

17. src="rssreader/rssreader.nocache.js"></script>

18. </body>

19. </html>

? 如果对于GWT的程序而言,想实现js加载后隐藏loading标记之一功能。

我们要在onModuleLoad()方法里加入相关的隐藏功能的代码。但是现在我们是使用GXT,当我们使用了Viewport,她就会自动的去寻找ID为loading

gxt gxt初学进阶教程

的标签,并将他隐藏,不需要我们做任何的操作。[www.61k.com]事实上,隐藏的过程不是

突然的,而是一个逐渐的过程,这样一来界面就会很友好的显示。如果一个

加载消息的标签,ID别命名为别的字符串了,我们可以使用Viewport的

setLoadingPanelId(java.lang.String loadingPanelId)方法设置一下,照样会达

到效果。

? 下面运行一下应用,我们会发现,当UI被渲染好之后,loading标记会消失

的。

定制组件

在GXT

gxt gxt初学进阶教程

,乃至GWT中,定制组件是非常普遍并且有用的。定制组件大致可以分为两种:第一种,修改一个现有组件的功能;第二种,封装一个或多个组件并且加入新的功能,使其成为一个新的组件。相对于GXT而言,GWT有一个复合组件的概念——通过把一个组件包装到另外一个组件之上,从而达到定制组件的效果。但是GXT如果想实现这种复合组件会发生很多问题!

比如前面所用到的ContentPanel,用于RSSReader项目的west导航区。当把ContentPanel生成的对象放入west区显示的时候,同时也设置了其可折叠功能。但是如果基于ContentPanel创建一个复合组件的话,那个折叠功能的按钮就再也不会出现了。

gxt gxt初学进阶教程

原因是,当你要创建一个复合组件的话,那些public API方法就会不可见。(www.61k.com)GXT的设计理念是,如果要把几个组件复合成一个新的组件的话,就视为你怀疑GXT components自带的功能,既然如此那么这些功能就做废掉了,你将无法使用它们。

综上所述,GXT制定组件的最佳方法就是继承某个Component,然后直接或间接的使用其他的components。

onRender()

在开始定制组件之前,要再介绍一个非常重要的方法onRender()。当你继承某个component的时候,可选择是否覆盖(override)onRender()方法。这一机制得追溯于先前提到的GXT的“懒渲染”概念。当一个component在初始化的时候,他的构造函数内的所有代码都会被执行;类似的,当一个component被渲染的时候,onRender()方法内的代码也会被执行。 根据此理论,我们可以很灵活的把需要立即执行的代码写在当前component的构造函数理,把需要在当前component被渲染之后,再执行的代码写在onRender()方法里。按照如此的编程思想,可以很好的提高GXT应用程序的性能和效率。

现在,我们就开始在RSSReader项目上,开始第一个定制组件——把原先应用在west导航区和center内容区的两个ContentPanels,替换为自定义的components。(随着RSSReader项目开发,我们将加入更多的定制组件)

? 在RSSReader项目里,新建package:

com.danielvaughan.rssreader.client.components;再在此包下,新建

RssNavigationPanel类,继承ContentPanel。作为west导航区域显示的内

容。

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.components;

2.

3. import com.extjs.gxt.ui.client.widget.ContentPanel;

4. public class RssNavigationPanel extends ContentPanel

5. {

6. public RssNavigationPanel()

7. {

8. setHeading("Navigation");

9. }

10. }

gxt gxt初学进阶教程

? 同样的,新建RssMainPanel类,作为center内容区显示的内容。(www.61k.com]仅仅设置

一下题头而已。

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.components; 2.

3. import com.extjs.gxt.ui.client.widget.ContentPanel;

4.

5. public class RssMainPanel extends ContentPanel

6. {

7. public RssMainPanel()

8. {

9. setHeading("Main");

10. }

11. }

? 接下来,在RSSReader类的onModuleLoad()方法中,用新建的两个定制

components替换原来的ContentPanels

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client;

2.

3. import com.danielvaughan.rssreader.client.components.RssMainPanel;

4. import

com.danielvaughan.rssreader.client.components.RssNavigationPanel;

5. import com.extjs.gxt.ui.client.Style.LayoutRegion;

6. import com.extjs.gxt.ui.client.widget.Viewport;

7. import com.extjs.gxt.ui.client.widget.layout.BorderLayout;

8. import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;

9. import com.google.gwt.core.client.EntryPoint;

10. import com.google.gwt.user.client.ui.HTML;

11. import com.google.gwt.user.client.ui.RootPanel;

12.

gxt gxt初学进阶教程

13. /**

14. * Entry point classes define <code>onModuleLoad()</code>.

15. */

16. public class RSSReader implements EntryPoint {

17.

18. /**

19. * This is the entry point method.

20. */

21. @Override

22. public void onModuleLoad() {

23. Viewport viewport = new Viewport();

24. final BorderLayout borderLayout = new BorderLayout();

25.

26. BorderLayoutData northData = new BorderLayoutData(LayoutRegion.NORTH,

27. 20);

28. northData.setCollapsible(false);

29. northData.setSplit(false);

30.

31. HTML headerHtml = new HTML();

32. headerHtml.setHTML("<h1>RSS Reader</h1>");

33. viewport.add(headerHtml, northData);

34.

35. BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);

36. centerData.setCollapsible(false);

37.

38. BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST,

39. 200, 150, 300);

40. westData.setCollapsible(true);

41. westData.setSplit(true);

42.

43. RssMainPanel mainPanel = new RssMainPanel();

44. RssNavigationPanel navPanel = new RssNavigationPanel();

45. viewport.add(mainPanel, centerData);

46. viewport.add(navPanel, westData);

47.

gxt gxt初学进阶教程

48. viewport.setLayout(borderLayout);

49. RootPanel.get().add(viewport);

50. }

51. } ? 最后运行应用程序,会看到导航区和内容区的题头。[www.61k.com)

gxt gxt初学进阶教程

gxt gxt初学进阶教程

ToggleButton

Button控件对于大家来说并不陌生,也就不专门介绍了。下面要特殊的介绍一下

ToggleButton。他是Button的子类,他就像一个开关,有“按下”和“未按下”两种状态。同时呢,我们可以给ToggleButton进行分组,使用setToggleGroup(String toggleGroup)就可以实现。分组后的ToggleButton不管如何点击其中某个按钮,都会只有一个按钮显示被“按下”的状态。

添加一个Link feed button

gxt gxt初学进阶教程

我们要在RssNavigationPanel组件上,添加一个“Link feed” button。[www.61k.com]其作用是,通过点击此按钮,显示一个表单,用户可以通过此表单录入一个RSS的URl。当然如果像取消对表单的录入,通常我们得加入一个cancel button来关闭此表单。但是我们现在要使用

ToggleButton来实现“Link feed” button的功能——通过两种开关状态,控制表单的显示与否。

接下来,我们进一步定制RssNavigationPanel component——添加ToggleButton

? 在RssNavigationPanel 类的构造函数里,新建一个ToggleButton

[java] view plaincopyprint?

1. final ToggleButton btnLinkFeed = new ToggleButton("Link feed");

? 在RSSReader.css文件里,加入合适的css样式来设置此button的图标。

[css] view plaincopyprint?

1. .link-feed {

2. background: url("gxt/images/icons/feed_link.png") no-repeat center left

3. !important;

4. }

? 让btnLinkFeed 应用此css样式

[java] view plaincopyprint?

1. btnLinkFeed.setIconStyle("link-feed");

? 设置btnLinkFeed在RssNavigationPanel容器里水平居左

[java] view plaincopyprint?

1. setButtonAlign(HorizontalAlignment.LEFT);

gxt gxt初学进阶教程

? 最后,要把btnLinkFeed添加到RssNavigationPanel容器显示出来。(www.61k.com]

[java] view plaincopyprint?

1. addButton(btnLinkFeed);

? 运行程序,预期效果如下:

gxt gxt初学进阶教程

Tooltip

自然情况下,我们会让一个button的label的内容很简洁。一般的用户就会通过label明白此button是做什么的。但是还是有些用户无法通过图片和label来明白此button 是用来做什么的,那么我们就需要使用Tooltip。

Tooltip可以被添加在一个button或其他的components上。当鼠标经过此component上时,Tooltip就会显示出来,给用户更多的信息。

接下来,给刚刚添加的Link feed button添加一个Tooltip。

? 同样还是在RssNavigationPanel类的构造函数里,添加如下的代码。

[java] view plaincopyprint?

1. ToolTipConfig linkFeedToolTipConfig = new ToolTipConfig();

2. linkFeedToolTipConfig.setTitle("Link to existing RSS feed");

3. linkFeedToolTipConfig

4. .setText("Allows you to enter the URL of an existing RSS feed you would

like to link to");

?

? 要注意的是ToolTipConfig 是另外之用ToolTip——可以支持标题和内容。 设置btnLinkFeed的ToolTip,除了使用ToolTipConfig 之外,当然还支持

String类型

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. btnLinkFeed.setToolTip(linkFeedToolTipConfig);

? 预期效果如下:

ToggleButton

Button控件对于大家来说并不陌生,也就不专门介绍了。[www.61k.com)下面要特殊的介绍一下

ToggleButton。他是Button的子类,他就像一个开关,有“按下”和“未按下”两种状态。同时呢,我们可以给ToggleButton进行分组,使用setToggleGroup(String toggleGroup)

gxt gxt初学进阶教程

就可以实现。

gxt gxt初学进阶教程

分组后的ToggleButton不管如何点击其中某个按钮,都会只有一个按钮显示被“按下”的状态?/P>

添加一个Link feed button

我们要在RssNavigationPanel组件上,添加一个“Link feed?button。其作用是,通过点击此按钮,显示一个表单,用户可以通过此表单录入一个RSS的URl。当然如果像取消对表单的录入,通常我们得加入一个cancel button来关闭此表单。但是我们现在要使用

ToggleButton来实现“Link feed?button的功能——通过两种开关状态,控制表单的显示与否?BR>

接下来,我们进一步定制RssNavigationPanel component——添加ToggleButton

? 在RssNavigationPanel 类的构造函数里,新建一个ToggleButton

[java] view plaincopyprint?

1. final ToggleButton btnLinkFeed = new ToggleButton("Link feed");

gxt gxt初学进阶教程

? 在RSSReader.css文件里,加入合适的css样式来设置此button的图标?

/LI>

[css] view plaincopyprint? 1. .link-feed { 2. background: url("gxt/images/icons/feed_link.png") no-repeat center left

3. !important;

4. }

? 让btnLinkFeed 应用此css样式

[java] view plaincopyprint? 1. btnLinkFeed.setIconStyle("link-feed");

? 设置btnLinkFeed在RssNavigationPanel容器里水平居巿/LI>

[java] view plaincopyprint?

1. setButtonAlign(HorizontalAlignment.LEFT);

? 最后,要把btnLinkFeed添加到RssNavigationPanel容器显示出来?/LI>

[java] view plaincopyprint? 1.

gxt gxt初学进阶教程

addButton(btnLinkFeed);

? 运行程序,预期效果如下:

gxt gxt初学进阶教程

Tooltip

自然情况下,我们会让一个button的label的内容很简洁。(www.61k.com)一般的用户就会通过label明白此button是做什么的。但是还是有些用户无法通过图片和label来明白此button 是用来做什么的,那么我们就需要使用Tooltip?P>

Tooltip可以被添加在一个button或其他的components上。当鼠标经过此component上时,Tooltip就会显示出来,给用户更多的信息?/P>

接下来,给刚刚添加的Link feed button添加一个Tooltip?/P>

? 同样还是在RssNavigationPanel类的构造函数里,添加如下的代码?BR>

[java] view plaincopyprint?

1. ToolTipConfig linkFeedToolTipConfig = new ToolTipConfig();

2. linkFeedToolTipConfig.setTitle("Link to existing RSS feed");

3. linkFeedToolTipConfig

4. .setText("Allows you to enter the URL of an existing RSS feed you would like to link to");

? 要注意的是ToolTipConfig 是另外之用ToolTip——可以支持标题和内容?

/LI>

? 设置btnLinkFeed的ToolTip,除了使用ToolTipConfig 之外,当然还支持

String类型

[java] view plaincopyprint?

1. btnLinkFeed.setToolTip(linkFeedToolTipConfig);

? 预期效果如下_/LI>

gxt gxt初学进阶教程

Popup

Popup继承自LayoutContainer,可以使其弹出的窗口,始终至于其他的components之上。(www.61k.com)现在,我想要在用户点击Link feed按钮的时候可以显示一个Popup表单窗口,可以让用户输入一个URL。

? 创建新package:com.danielvaughan.rssreader.client.components。在此包

下创建LinkFeedPopup类,继承自Popup。

? 然后在构造函数里,加入相关设置,代码如下:

[java] view plaincopyprint? 1. public LinkFeedPopup() {

2. setSize(300, 55);

3. setBorders(true);

4. setShadow(true);

5. setAutoHide(false);

6. }

? 我们设置了其大小,是否有边框,和阴影效果。

SelectionListener

现在我们有button和popup。如果想通过点击button可以控制popup,那么就需要Listener(正如先前提到的,GXT对事件的处理是使用的Listener),首先要把一个Listener

gxt gxt初学进阶教程

注册到某一个component上,当有对应的事件发生的时候,就会通知Listener。因此要在Listener里编写相关的代码,以作为此次事件的响应时来执行。在我们的RSSReader项目里,Link feed button的点击Listener,应该是SelectionListener(而不是click之类的)。具体操作步骤如下:

? 因为Link feed button被添加到RssNavigationPanel里,自然的我们要在

RssNavigationPanel类,新建一个LinkFeedPopup。

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. final LinkFeedPopup linkFeedPopup = new LinkFeedPopup();

? 要保证popup的弹出始终在整个面板Viewport内:

[java] view plaincopyprint?

1. linkFeedPopup.setConstrainViewport(true);

? 注册SelectionListener

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.components; 2.

3. import com.extjs.gxt.ui.client.Style.HorizontalAlignment;

4. import com.extjs.gxt.ui.client.event.ButtonEvent;

5. import com.extjs.gxt.ui.client.event.SelectionListener;

6. import com.extjs.gxt.ui.client.widget.ContentPanel;

7. import com.extjs.gxt.ui.client.widget.button.ToggleButton;

8. import com.extjs.gxt.ui.client.widget.tips.ToolTipConfig; 9.

10. public class RssNavigationPanel extends ContentPanel

11. {

12. public RssNavigationPanel()

13. {

14. setHeading("Navigation");

15. final ToggleButton btnLinkFeed = new ToggleButton("Link feed");

16. btnLinkFeed.setIconStyle("link-feed");

17. setButtonAlign(HorizontalAlignment.LEFT);

18.

19. ToolTipConfig linkFeedToolTipConfig = new ToolTipConfig();

20. linkFeedToolTipConfig.setTitle("Link to existing RSS feed");

21. linkFeedToolTipConfig

gxt gxt初学进阶教程

22. .setText("Allows you to enter the URL of an existing RSS feed you would like to link to");

23. btnLinkFeed.setToolTip(linkFeedToolTipConfig);

24.

25. final LinkFeedPopup linkFeedPopup = new LinkFeedPopup(); 26. linkFeedPopup.setConstrainViewport(true);

27. btnLinkFeed.addSelectionListener(new SelectionListener<ButtonEvent>() {

28. @Override

29. public void componentSelected(ButtonEvent ce) {

30. if (btnLinkFeed.isPressed()) {

31. linkFeedPopup.show();

32. } else {

33. linkFeedPopup.hide();

34. }

35. }

36. });

37.

38.

39. addButton(btnLinkFeed);

40. }

41. }

? 给btnLinkFeed注册了一个SelectionListener, 当btnLinkFeed被按下的时

候,显示linkFeedPopup;当btnLinkFeed被按起的时候,隐藏linkFeedPopup

gxt gxt初学进阶教程

TextField

TestField继承自Field,Field继承自BoxComponent。(www.61k.com)Field作为表单数据项的基类。这些具体的Field,例如textboxes,checkboxes,listboxes等,都会被渲染成标准的HTML标签。TextField则是他们其中之一。一个GXT的TextField的定义代码如下:

[java] view plaincopyprint?

1. TextField<String> text = new TextField<String>();

其中泛型String

gxt gxt初学进阶教程

类型,表示其保存的值的类型。GXT的Field同样具有内建的功能来设置验证条件。对于我们RSSReader项目目前的需求来说,我们需要使用TextField来限制用户只可以输入URL的字符串。

? 因为要在弹出的popup窗口构建一个表单,自然我们要在LinkFeedPopup

类里面编辑。创建一个TextField的属性

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. private final TextField<String> tfUrl = new TextField<String>(); ? Override LinkFeedPopup类的onRender()方法,一个重新的,空的onRender()

方法如下:

[java] view plaincopyprint? 1. @Override

2. protected void onRender(Element parent, int pos) {

3. super.onRender(parent, pos);

4. }

? 在onRender()方法里加入一个Text component,来告诉用户应该录入URL:

[java] view plaincopyprint?

1. final Text txtExplaination = new Text("Enter a feed url");

? 创建一个button,当用户录入URL后,可以点击他来提交。(www.61k.com]

[java] view plaincopyprint? 1. final Button btnAdd = new Button("add");

2. btnAdd.addSelectionListener(new SelectionListener<ButtonEvent>() {

3. @Override

4. public void componentSelected(ButtonEvent ce) {

5. addFeed(tfUrl.getValue());

6. }

7. });

? 在响应点击事件处理的过程里,我们调用的addFeed方法,其用来处理具体

的提交之后的操作。目前呢,只是先把用户录入的URL弹出一个Alert而已。

[java] view plaincopyprint?

1. public void addFeed(String url) {

2. Window.alert("We would now attempt to add " + url + " at this point");

3. }

gxt gxt初学进阶教程

? 之前的操作,大家会发现创建了两个对象,并注册了Listener。(www.61k.com)但是并没有

添加到LinkFeedPopup类里面设置具体的显示效果。因此我们要对popup设置其布局显示效果。

[java] view plaincopyprint?

1. final BorderLayout layout = new BorderLayout();

2. setLayout(layout);

? 让txtExplaination 放在north区

[java] view plaincopyprint? 1. final BorderLayoutData northData = new 2. BorderLayoutData(LayoutRegion.NORTH, 20);

3. northData.setMargins(new Margins(2));

4. add(txtExplaination, northData);

? 让textbox放在center区

[java] view plaincopyprint? 1. final BorderLayoutData centerData = new

2. BorderLayoutData(LayoutRegion.CENTER);

3. centerData.setMargins(new Margins(2));

4. add(tfUrl, centerData);

? 让提交button放在east区

[java] view plaincopyprint?

1. final BorderLayoutData eastData = new

2. BorderLayoutData(LayoutRegion.EAST, 50);

3. eastData.setMargins(new Margins(2));

4. add(btnAdd, eastData);

gxt gxt初学进阶教程

? 最后运行一下程序,当点击Link feed button

? 录入一个URL之后,点击add button

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? 完整的LinkFeedPopup类代码如下 :

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.components; 2.

3. import com.extjs.gxt.ui.client.Style.LayoutRegion;

gxt gxt初学进阶教程

4. import com.extjs.gxt.ui.client.event.ButtonEvent;

5. import com.extjs.gxt.ui.client.event.ComponentEvent;

6. import com.extjs.gxt.ui.client.event.KeyListener;

7. import com.extjs.gxt.ui.client.event.SelectionListener;

8. import com.extjs.gxt.ui.client.util.Margins;

9. import com.extjs.gxt.ui.client.widget.Popup;

10. import com.extjs.gxt.ui.client.widget.Text;

11. import com.extjs.gxt.ui.client.widget.button.Button;

12. import com.extjs.gxt.ui.client.widget.form.TextField;

13. import com.extjs.gxt.ui.client.widget.layout.BorderLayout;

14. import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;

15. import com.google.gwt.event.dom.client.KeyCodes;

16. import com.google.gwt.user.client.Element;

17. import com.google.gwt.user.client.Window;

18.

19. public class LinkFeedPopup extends Popup

20. {

21. private final TextField<String> tfUrl = new TextField<String>(); 22.

23. public LinkFeedPopup() {

24. setSize(300, 55);

25. setBorders(true);

26. setShadow(true);

27. setAutoHide(false);

28. }

29.

30. @Override

31. protected void onRender(Element parent, int pos) {

32. super.onRender(parent, pos);

33. final Text txtExplaination = new Text("Enter a feed url");

34. final Button btnAdd = new Button("add");

35. btnAdd.addSelectionListener(new SelectionListener<ButtonEvent>() {

36. @Override

37. public void componentSelected(ButtonEvent ce) {

38. addFeed(tfUrl.getValue());

gxt gxt初学进阶教程

39. }

40. });

41.

42.

43. final BorderLayout layout = new BorderLayout();

44. setLayout(layout);

45.

46. final BorderLayoutData northData = new

BorderLayoutData(LayoutRegion.NORTH, 20); 47. northData.setMargins(new Margins(2));

48. add(txtExplaination, northData);

49.

50. final BorderLayoutData centerData = new

BorderLayoutData(LayoutRegion.CENTER);

51. centerData.setMargins(new Margins(2));

52. add(tfUrl, centerData);

53.

54. final BorderLayoutData eastData = new BorderLayoutData(LayoutRegion.EAST,

50);

55. eastData.setMargins(new Margins(2));

56. add(btnAdd, eastData);

57. }

58.

59. public void addFeed(String url) {

60. Window.alert("We would now attempt to add " + url + " at this point");

61. }

62.

63. }

Popup的位置

先前的程序,运行后,会发现popup会在整个屏幕的中央显示。(www.61k.com)这样一来就有些显示的不友好,最好可以让Popup可以在Link feed button的上面直接的显示出来。之前用的是show()方法,未加入任何的设置,直接显示popup。为了让让Popup可以在Link feed button的上面直接的显示出来,我们就需要在show()方法上做文章了。在作此之前,先了解一些新的概念。

gxt gxt初学进阶教程

1. 一个button,从根本上说,就是个元素(element)。(www.61k.com]获得一个button的元

素,需要使用Button.getElement()方法。

2. Popup类中public void show(Element elem, String pos)方法的pos参数,就

是来规定Popup的显示位置的。Popup.show(Button.getElement(), “bl-tl?”)的意思是说——Popup的显示位置是以Button为基准,Popup的左下角(bl)对准Button的左上角(tl),来显示的。那么如果pos字符串以“?”号为结尾,就是在“bl-tl”位置定义的基础上,保证Popup的显示不会超出整个Viewport的范围之外。“-”之前的是Popup的基准锚点,“-”之后是Button.getElement()的基准锚点。

3. 其他的的pos位置定义字符串表格如下:

gxt gxt初学进阶教程

? 找到RssNavigationPanel类,修改Link feed button的点击监听事件处理方

法。

[java] view plaincopyprint?

1. btnLinkFeed.addSelectionListener(new SelectionListener<ButtonEvent>() {

2. @Override

3. public void componentSelected(ButtonEvent ce) {

4. if (btnLinkFeed.isPressed()) {

5. linkFeedPopup.show(btnLinkFeed.getElement(), "bl-tl?");

6. } else {

7. linkFeedPopup.hide();

gxt gxt初学进阶教程

8. } 9. }

10. });

? 运行之后,参照“bl-tl?” 字符串的位置设置,理解一下

linkFeedPopup.show(btnLinkFeed.getElement(), "bl-tl?");到底是说明了什么

意思。(www.61k.com]

gxt gxt初学进阶教程

KeyListener

接下来进一步完善我们的RSSReader项目:参看上面的截图,当用户输入URL之后,通过点击add button完成整个操作。但是习惯上来说,用户输入URL之后会直接敲击一下回车键,来表明完成了整个操作。这样的操作过程也很快捷方便,不需要用户就动鼠标去点击button。

TextField component支持监听(KeyListener)键盘操作的事件。回车键的key code早已经在GWT里有了定义——KeyCodes.KEY_ENTER。因此我们要在TextField 注册一个KeyListener,当TextField里有回车键传入的时候,表明URL已经录入完毕。

如下是加入KeyListener的完整代码:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.components;

2.

3. import com.extjs.gxt.ui.client.Style.LayoutRegion;

4. import com.extjs.gxt.ui.client.event.ButtonEvent;

5. import com.extjs.gxt.ui.client.event.ComponentEvent;

6. import com.extjs.gxt.ui.client.event.KeyListener;

7. import com.extjs.gxt.ui.client.event.SelectionListener;

8. import com.extjs.gxt.ui.client.util.Margins;

9. import com.extjs.gxt.ui.client.widget.Popup;

gxt gxt初学进阶教程

10. import com.extjs.gxt.ui.client.widget.Text;

11. import com.extjs.gxt.ui.client.widget.button.Button;

12. import com.extjs.gxt.ui.client.widget.form.TextField;

13. import com.extjs.gxt.ui.client.widget.layout.BorderLayout;

14. import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;

15. import com.google.gwt.event.dom.client.KeyCodes;

16. import com.google.gwt.user.client.Element;

17. import com.google.gwt.user.client.Window;

18.

19. public class LinkFeedPopup extends Popup {

20. private final TextField<String> tfUrl = new TextField<String>(); 21.

22. public LinkFeedPopup() {

23. setSize(300, 55);

24. setBorders(true);

25. setShadow(true);

26. setAutoHide(false);

27. }

28.

29. @Override

30. protected void onRender(Element parent, int pos) {

31. super.onRender(parent, pos);

32. final Text txtExplaination = new Text("Enter a feed url");

33. final Button btnAdd = new Button("add");

34. btnAdd.addSelectionListener(new SelectionListener<ButtonEvent>() {

35. @Override

36. public void componentSelected(ButtonEvent ce) {

37. addFeed(tfUrl.getValue());

38. }

39. });

40.

41. tfUrl.addKeyListener(new KeyListener() {

42. @Override

43. public void componentKeyDown(ComponentEvent event) {

44. if (event.getKeyCode() == KeyCodes.KEY_ENTER) {

gxt gxt初学进阶教程

45. addFeed(tfUrl.getValue());

46. }

47. }

48. });

49.

50. final BorderLayout layout = new BorderLayout();

51. setLayout(layout);

52.

53. final BorderLayoutData northData = new BorderLayoutData(

54. LayoutRegion.NORTH, 20);

55. northData.setMargins(new Margins(2));

56. add(txtExplaination, northData);

57.

58. final BorderLayoutData centerData = new BorderLayoutData(

59. LayoutRegion.CENTER);

60. centerData.setMargins(new Margins(2));

61. add(tfUrl, centerData);

62.

63. final BorderLayoutData eastData = new BorderLayoutData(

64. LayoutRegion.EAST, 50);

65. eastData.setMargins(new Margins(2));

66. add(btnAdd, eastData);

67. }

68.

69. public void addFeed(String url) {

70. Window.alert("We would now attempt to add " + url + " at this point");

71. }

72.

73. }

第三章:表单和窗口

本章我们要学习GXT的表单功能。(www.61k.com]了解相关的表单components和如何使用他们。也会涉及到GXT Registry,来学习如何跨越各个components来传递对象的。

本章,我们会涉及到如下GXt功能集

gxt gxt初学进阶教程

?

?

?

?

?

?

?

?

? The full range of fields available in GXT FormPanel FormLayout Window FitLayout FieldMessages Form submission Working with GWT RPC Using the registry RSSReader项目新增需求

目前为止, 我们的RSSReader虚拟项目已经有一个大致的雏形了。[www.61k.com)但对于经常发散思维的用户来说,如此的一个小RSSReader项目,功能上是无法满足用户需求的。

比如用户就说了:现在不仅仅可以通过URL获得RSS信息,还可以自己创建他们。这就意味着我们需要创建一个表单,给用户提供录入的页面。对于GXT来说,这点需求不在话下。

RSS2.0规范

RSSReader项目可以按照RSS2.0的规范读取RSS的URL,来获得数据。一个简单的RSS feed其实就是个XML格式的标签包裹着指定的内容。因此如果想创建一个RSS feed就得按照其规范创建。

RSS2.0的详细说明:。例子:

http://cyber.law.harvard.edu/rss/examples/rss2sample.xml

简单来说,一个RSS的xml有channel和多个RSS feed的item组成的。RSS feed的item大致是由:title,link,description三个元素组成,所以就要创建与之对应的两个表单(Form),一个用来接收channel信息,一个用来接收item信息。

FormPanel

FormPanel继承自ContentPanel,他可以管理有关表单的components。默认情况下,FormPanel的布局效果是设置成FormLayout。FormPanel只允许其添加Field的

components,例如:TextField,LabelField等。如果添加了其他的components是不会被渲染的,会被自动忽略。

FormPanel的最大用户在于,可以作为其添加的Fields的总管。可以通过设置FormPanel来影响其包含的所有的Fields components。比如设置只读属性,验证表单,Fields的显示状态,最后还包括表单的提交功能——HTTP POST提交和GWT RPC(稍后提到)。

gxt gxt初学进阶教程

Fields

对于具体的Fields的介绍,说实话GXT我也是探索中曲折前进。[www.61k.com)大家可以参看:#forms

创建一个feed button

既然用户提出需求了,我们就要开始开发新的功能了。我们需要在RssNavigationPanel类中,添加一个button,来允许用户添加一个具体的feed信息。此次是实用的的Button,而不是ToggleButton。

? 编辑RSSReader.css:加入如下的css样式,为了给“Create feed”button应

用此样式。

[css] view plaincopyprint?

1. .create-feed {

2. background: url(gxt/images/icons/feed_create.png) no-repeat center left

3. !important;

4. }

? RssNavigationPanel类构造函数中,继续加入“Create feed”button的定义。

[java] view plaincopyprint? 1. <pre class="java" name="code"> final Button btnCreateFeed = new

Button("Create feed");

2. btnCreateFeed.setIconStyle("create-feed");

3. ToolTipConfig createNewToolTipConfig = new ToolTipConfig();

4. createNewToolTipConfig.setTitle("Create a new RSS feed");

5. createNewToolTipConfig.setText("Creates a new RSS feed");

6. btnCreateFeed.setToolTip(createNewToolTipConfig);

7. addButton(btnCreateFeed);

8.

9. addButton(btnLinkFeed);</pre>

10. <pre></pre>

11. <ul>

12. <li>运行程序,观看“Create feed”button的显示效果</li></ul>

gxt gxt初学进阶教程

13. <img alt=""

src="http://hi.csdn.net/attachment/201201/9/0_13261054526IiI.gif">

14. <p></p>

15. <p></p>

16. <h2>创建一个Feed 类</h2>

17. 创建一个用来存储feed信息的POJO类。[www.61k.com)之后他会通过Google RPC发送,所以要保证

Feed类implements Serializable接口,并且有无参数的构造函数。

18. <p></p>

19. <p>Feed类既被client端使用,又会被Server端使用。因此,相对于client和server

包,最好把他放在shared 包下更合适。那么shared包里的类,就会被client和server类共同调用。</p>

20. <p>在这里要重点说明一下,GWT不是会把项目里面所有的package都作为编译成

javaScript的source 代码,而是通过module xml文件配置的(RSSReader.gwt.xml)。因此需要把shared包加入GWT的编译路径中去。</p>

21. <ul>

22. <li>创建新包:com.danielvaughan.rssreader.shared.model</li><li>修改

RSSReader.gwt.xml,加入另外一个GWT编译入口——shared package:</li></ul>

23. <pre class="html" name="code"> <!-- Specify the paths for translatable code

-->

24. <source path='client'/>

25. <source path='shared'/></pre>

26. <ul>

27. <li>如上配置,client就是指:com.danielvaughan.rssreader.client,shared就

是指:com.danielvaughan.rssreader.shared,为什么GWT就就此翻译成此路径,我个人认为是RSSReader.gwt.xml配置文件存放在com.danielvaughan.rssreader包下的原因。<br>

28. </li></ul>

29. <ul>

30. <li>创建Feed类,放在com.danielvaughan.rssreader.shared.model下:

</li></ul>

31. <pre class="java" name="code">package

com.danielvaughan.rssreader.shared.model;

32.

33. import java.io.Serializable;

34.

gxt gxt初学进阶教程

35. @SuppressWarnings("serial")

36. public class Feed implements Serializable { 37.

38. private String description;

39. private String link;

40. private String title;

41. private String uuid;

42.

43. public Feed() {

44.

45. }

46.

47. public Feed(String uuid) {

48. this.uuid = uuid;

49. }

50.

51. public String getDescription() {

52. return description;

53. }

54.

55. public String getLink() {

56. return link;

57. }

58.

59. public String getTitle() {

60. return title;

61. }

62.

63. public String getUuid() {

64. return uuid;

65. }

66.

67. public void setDescription(String description) {

68. this.description = description;

69. }

gxt gxt初学进阶教程

70.

71. public void setLink(String link) {

72. this.link = link;

73. }

74.

75. public void setTitle(String title) {

76. this.title = title;

gxt gxt初学进阶教程

77. }

78. }

79. </pre>

80. <ul>

81. <li>目前为止,整个项目RSSReader的项目结构如下:</li></ul>

82. <img alt=""

src="http://hi.csdn.net/attachment/201201/10/0_1326165011JrRU.gif"><br

>

83. <br>

84. <p><br>

85. </p>

86. <p><br>

87. </p>

88. <pre></pre>

Window

Window的父类的ContentPanel,他是在程序中用来显示窗口的component。[www.61k.com)有些类似与Popup,但是Window的窗口有已经定义好的布局效果,比如拖拽,关闭按钮,用户拖拉其大小等。

FitLayout

gxt gxt初学进阶教程

如果我们要在Window里加入一个表单,我们希望整个表单可以填满整个Widnow窗口,所以就要使用FitLayout布局。(www.61k.com)任何一个包裹着一个子集的容器,都可以应用此布局。 创建FeedWindow component

接下来,我们要创建一个新的Widnow,来作为feed表单的容器。通过Create feet button来显示此Window。

? 创建新包:com.danielvaughan.rssreader.client.windows,在此包下,创建

新FeedWindow类

[java] view plaincopyprint?

1. public class FeedWindow extends Window {}

? 同样要在构造函数里,设置题头。但是此次的构造函数,有一个参数是Feed

[java] view plaincopyprint?

1. public FeedWindow(final Feed feed) {

2. setHeading("Feed");

3. }

? 再加入一些其他的设置

[java] view plaincopyprint? 1. public FeedWindow(final Feed feed) {

2. setHeading("Feed");

3. setWidth(350);

4. setHeight(200);

5. setResizable(false);

6. setLayout(new FitLayout());

7. }

? Create feed Button先前被添加到RssNavigationPanel类中。现在,我们需

要给Create feed button,添加SelectionListener,来新建FeedWindow窗

口。

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. btnCreateFeed

2. .addSelectionListener(new SelectionListener<ButtonEvent>() {

3. @Override

4. public void componentSelected(ButtonEvent ce) {

5. createNewFeedWindow();

6. }

7. });

? 在RssNavigationPanel类中,加入createNewFeedWindow()方法的实现。[www.61k.com]

[java] view plaincopyprint? 1.

gxt gxt初学进阶教程

private void createNewFeedWindow() {

2. final Window newFeedWindow = new FeedWindow(new Feed());

3. newFeedWindow.show();

4. }

? 运行程序,当我们点击Create feed button的时候,就会弹出FeedWindow。

gxt gxt初学进阶教程

? 最后,完整的RssNavigationPanel类如下:

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.components;

2.

3. import com.danielvaughan.rssreader.client.windows.FeedWindow;

4. import com.danielvaughan.rssreader.shared.model.Feed;

5. import com.extjs.gxt.ui.client.Style.HorizontalAlignment;

6. import com.extjs.gxt.ui.client.event.ButtonEvent;

7. import com.extjs.gxt.ui.client.event.SelectionListener;

8. import com.extjs.gxt.ui.client.widget.ContentPanel;

9. import com.extjs.gxt.ui.client.widget.Window;

10. import com.extjs.gxt.ui.client.widget.button.Button;

11. import com.extjs.gxt.ui.client.widget.button.ToggleButton;

12. import com.extjs.gxt.ui.client.widget.tips.ToolTipConfig;

13.

14. public class RssNavigationPanel extends ContentPanel {

15. public RssNavigationPanel() {

16. setHeading("Navigation");

17. final ToggleButton btnLinkFeed = new ToggleButton("Link feed");

18. btnLinkFeed.setIconStyle("link-feed");

19. setButtonAlign(HorizontalAlignment.LEFT);

20.

21. ToolTipConfig linkFeedToolTipConfig = new ToolTipConfig();

22. linkFeedToolTipConfig.setTitle("Link to existing RSS feed");

23. linkFeedToolTipConfig

24. .setText("Allows you to enter the URL of an existing RSS feed you would

like to link to");

25. btnLinkFeed.setToolTip(linkFeedToolTipConfig);

26.

27. final LinkFeedPopup linkFeedPopup = new LinkFeedPopup();

28. linkFeedPopup.setConstrainViewport(true);

gxt gxt初学进阶教程

29. btnLinkFeed.addSelectionListener(new SelectionListener<ButtonEvent>() {

30. @Override

31. public void componentSelected(ButtonEvent ce) {

32. if (btnLinkFeed.isPressed()) {

33. linkFeedPopup.show(btnLinkFeed.getElement(), "bl-tl?");

34. } else {

35. linkFeedPopup.hide();

36. }

37. }

38. });

39.

40. final Button btnCreateFeed = new Button("Create feed");

41. btnCreateFeed.setIconStyle("create-feed");

42. ToolTipConfig createNewToolTipConfig = new ToolTipConfig();

43. createNewToolTipConfig.setTitle("Create a new RSS feed");

44. createNewToolTipConfig.setText("Creates a new RSS feed");

45. btnCreateFeed.setToolTip(createNewToolTipConfig);

46.

47. btnCreateFeed

48. .addSelectionListener(new SelectionListener<ButtonEvent>() {

49. @Override

50. public void componentSelected(ButtonEvent ce) {

51. createNewFeedWindow();

52. }

53. });

54.

55. addButton(btnCreateFeed);

56.

57. addButton(btnLinkFeed);

58. }

59.

60. private void createNewFeedWindow() {

61. final Window newFeedWindow = new FeedWindow(new Feed());

62. newFeedWindow.show();

63. }

gxt gxt初学进阶教程

64. } 新建FeedForm

先前窗口的工作已经完成了,下面要在窗口里加入表单。(www.61k.com] ? 新建包:com.danielvaughan.rssreader.client.forms,在此包下新建

FeedForm类,继承FormPanel。

? 通过构造函数,设置隐藏题头

[java] view plaincopyprint? 1. public FeedForm()

2. {

3. setHeaderVisible(false);

4. }

? 定义表单中的Fields,就是先前提到的title,link,description

[java] view plaincopyprint?

1. private final TextField<String> tfTitle = new TextField<String>();

2. private final TextArea taDescription = new TextArea();

3. private final TextField<String> tfLink = new TextField<String>();

? 我们希望这三个Fields,在当前的FeedForm被渲染之后,才被渲染。因此

override onRender()方法

[java] view plaincopyprint? 1. @Override

2. protected void onRender(Element parent, int pos) {

3. super.onRender(parent, pos);

4. tfTitle.setFieldLabel("Title");

5. taDescription.setFieldLabel("Description");

6. tfLink.setFieldLabel("Link");

7. add(tfTitle);

gxt gxt初学进阶教程

8. add(taDescription);

9. add(tfLink);

10. }

? FeedForm类编写完毕之后,要把它添加到先前的FeedWindow类中。(www.61k.com]因此

打开FeedWindow类,加入属性FeedForm

[java] view plaincopyprint?

1. private final FeedForm feedForm = new FeedForm(); ? 同样,在onRender()方法中渲染feedForm

[java] view plaincopyprint?

1. @Override

2. protected void onRender(Element parent, int pos) {

3. super.onRender(parent, pos);

4. add(feedForm);

5. }

? 此时运行程序,再次点击Create feed button的时候,弹出的FeedWindow

里就会显示FeedForm

gxt gxt初学进阶教程

Validation Fields

GXT Fields提供内建的校验功能。[www.61k.com)通过isValid()方法,可以验证任何的Field是否包含有效值。当Fields被包含在FormPanel中,那么就可以调用FormPanel.isValid()来验证其所有的子Fields是否都有效。 默认情况下,Fields的校验时间是在用户编辑完毕(on blur)。当然我们可以通过setAutoValidate(true),让用户的每次录入都会校验(key press)。

? 接下来,对FeedForm的表单Fields进行校验。打开FeedForm class,编辑

onRender(),加入校验的设置代码:

[java] view plaincopyprint? 1.

gxt gxt初学进阶教程

@Override

2. protected void onRender(Element parent, int pos) {

3. super.onRender(parent, pos);

4. tfTitle.setFieldLabel("Title");

5. tfTitle.setAllowBlank(false);

6. taDescription.setFieldLabel("Description");

7. taDescription.setAllowBlank(false);

gxt gxt初学进阶教程

8. tfLink.setFieldLabel("Link"); 9. tfLink.setAllowBlank(false);

10. tfLink.setRegex("^http\\://[a-zA-Z0-9\\-\\.]+\\.[a-zAZ]{

11. 2,3}(/\\S*)?{1}quot;);

12. }

? 运行效果如下:

设置验证提示消息

就像设置校验策略一样,同样可以设置不同验证策略下的提示内容——FieldMessages Fields已经使用内部类实现了FieldMessages

gxt gxt初学进阶教程

。[www.61k.com)所以设置消息的最好方式是使用Field里的getMessages()获得FieldMessages之后,在设置合适的消息内容。

? 具体代码如下。

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. @Override

2. protected void onRender(Element parent, int pos) {

3. super.onRender(parent, pos);

4.

5. tfTitle.setFieldLabel("Title");

6. tfTitle.setAllowBlank(false);

7. tfTitle.getMessages().setBlankText("Title is required");

8.

9. taDescription.setFieldLabel("Description");

10. taDescription.setAllowBlank(false);

11. taDescription.getMessages().setBlankText("Description is required"); 12.

13. tfLink.setFieldLabel("Link");

14. tfLink.setAllowBlank(false);

15. tfLink.setRegex("^http\\://[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,3}(/\\S*)?{

1}quot;);

16. tfLink.getMessages().setBlankText("Link is required");

17. tfLink.getMessages()

18. .setRegexText(

19. "The link field must be a URL e.g. http://www.example.com/rss.xml"); 20.

21. add(tfTitle);

22. add(taDescription);

23. add(tfLink);

24. }

? 显示效果:

gxt gxt初学进阶教程

? 完整的FeedForm类如下:

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.forms; 2.

gxt gxt初学进阶教程

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

4. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

5. import com.danielvaughan.rssreader.shared.model.Feed;

6. import com.extjs.gxt.ui.client.Registry;

7. import com.extjs.gxt.ui.client.widget.Info;

8. import com.extjs.gxt.ui.client.widget.form.FormPanel;

9. import com.extjs.gxt.ui.client.widget.form.TextArea;

10. import com.extjs.gxt.ui.client.widget.form.TextField;

11. import com.google.gwt.user.client.Element;

gxt gxt初学进阶教程

12. import com.google.gwt.user.client.rpc.AsyncCallback;

13.

14. public class FeedForm extends FormPanel {

15.

16. private final TextField<String> tfTitle = new TextField<String>();

17. private final TextArea taDescription = new TextArea();

18. private final TextField<String> tfLink = new TextField<String>(); 19.

20. public FeedForm() {

21. setHeaderVisible(false);

22. }

23.

24. @Override

25. protected void onRender(Element parent, int pos) {

26. super.onRender(parent, pos);

27.

28. tfTitle.setFieldLabel("Title");

29. tfTitle.setAllowBlank(false);

30. tfTitle.getMessages().setBlankText("Title is required");

31.

32. taDescription.setFieldLabel("Description");

33. taDescription.setAllowBlank(false);

34. taDescription.getMessages().setBlankText("Description is required"); 35.

36. tfLink.setFieldLabel("Link");

37. tfLink.setAllowBlank(false);

38. tfLink.setRegex("^http\\://[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,3}(/\\S*)?{

1}quot;);

39. tfLink.getMessages().setBlankText("Link is required");

40. tfLink.getMessages()

41. .setRegexText(

42. "The link field must be a URL e.g. http://www.example.com/rss.xml"); 43.

44. add(tfTitle);

45. add(taDescription);

gxt gxt初学进阶教程

46. add(tfLink);

47. }

48. } 表单使用HTTP提交

表单有两种提交方式,第一种就是传统的HTTP提交。[www.61k.com]

最直接的步骤就是: ?

?

? 使用FormPanel的setAction()方法,去定义submit的URL 使用FormPanel的isValid()方法,去验证所有的fields是否有正确 如果正确,使用FormPanel的submit()方法提交表单。

[java] view plaincopyprint? 1. setAction("http://www.example.com/submit.php");

2. final Button btnSave = new Button("Save");

3. btnSave.setIconStyle("save");

4. btnSave.addSelectionListener(new SelectionListener<ButtonEvent>()

5. {

6. public void componentSelected(ButtonEvent ce) {

7. if (isValid())

8. {

9. submit();

10. } }

11. });

12. addButton(btnSave);

GWT RPC

表单就拥有了另外一种提交方式——RPC。对于GWT和GXT来说,他不像传统的web应用,在client端我们可以选择存储和操作java类型的数据——不管这些数据是在web前端还是通过GWT RPC或者JSON别的什么方法提交到后端,我们都可以操作他们。 在RSSReader项目里,我们就会使用GWT RPC。

创建一个Feed service

gxt gxt初学进阶教程

为了能够检索到Feed对象,就必须有唯一的ID。[www.61k.com]java里有专门用来生成的主键的类——UUID。接下来我们要实现一个功能,就是当在client端所使用Feed的实例对象,是通过RPC从server端返回的,并且已经赋值ID的。因为先前,我们所创建的Feed类,就是为了在client和server两端都可以使用。那么接下来就要创建一个GWT RPC的service去处理Feed实例对象。

? 创建新包:com.danielvaughan.rssreader.client.services,在此包下,新建一

个接口FeedService,继承GWT RemoteService。定义一个方法

createNewFeed():

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.services;

2.

3. import com.danielvaughan.rssreader.shared.model.Feed;

4. import com.google.gwt.user.client.rpc.RemoteService;

5. import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

6.

7. @RemoteServiceRelativePath("feed-service")

8. public interface FeedService extends RemoteService {

9. Feed createNewFeed();

10. }

? 注意1:@RemoteServiceRelativePath("feed-service") 注解了当前这个

service,在web.xml应该配置的url映射地址。也就是说不管哪个类实现了

FeedService接口,那么他在web.xml的servlet url映射就应该设置成

"feed-service"。

? 注意2:FeedService接口创建完毕之后,GWT就会自动的提示你去创建与

之对应的另外一个接口FeedServiceAsync

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.services;

2. 3.

gxt gxt初学进阶教程

import com.danielvaughan.rssreader.shared.model.Feed;

4. import com.google.gwt.user.client.rpc.AsyncCallback;

5.

6. public interface FeedServiceAsync {

7.

8. void createNewFeed(AsyncCallback<Feed> callback);

9.

10. }

? FeedServiceAsync接口中生成了FeedService接口中的,异步回调的抽象方

法。(www.61k.com]其目的是在createNewFeed()方法执行之后的返回期间会调用FeedServiceAsync接口中的与之对应的

createNewFeed(AsyncCallback<Feed> callback)方法,来作为

createNewFeed()方法执行情况的反馈。

? 之前的两个接口都是属于client端的services,具体的实现类就应该属于的

server端的services。所以新建包:

com.danielvaughan.rssreader.server.services,在此包下创建

FeedServiceImpl类实现FeedService,继承RemoteServiceServlet。具体的实现如下代码:

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. package com.danielvaughan.rssreader.server.services; 2.

3. import java.io.IOException;

4. import java.util.UUID;

5.

6. import com.danielvaughan.rssreader.client.services.FeedService;

7. import com.danielvaughan.rssreader.shared.model.Feed;

8. import com.google.gwt.user.server.rpc.RemoteServiceServlet; 9.

10. @SuppressWarnings("serial")

11. public class FeedServiceImpl extends RemoteServiceServlet implements

12. FeedService {

13. @Override

14. public Feed createNewFeed() {

15. UUID uuid = UUID.randomUUID();

16. return new Feed(uuid.toString());

17. } 18.

19. }

? 配置FeedServiceImpl的servlet映射。[www.61k.com)编辑web.xml

[html] view plaincopyprint?

1. <servlet>

2. <servlet-name>feedServlet</servlet-name>

3. <servlet-class>

4. com.danielvaughan.rssreader.server.services.FeedServiceImpl

5. </servlet-class>

6. </servlet>

7. <servlet-mapping>

8. <servlet-name>feedServlet</servlet-name>

9. <url-pattern>/rssreader/feed-service</url-pattern>

10. </servlet-mapping>

gxt gxt初学进阶教程

? 注意:<url-pattern>/rssreader/feed-service</url-pattern>其中的rssreader

是小写,这与<script type="text/javascript" language="javascript"

src="rssreader/rssreader.nocache.js"></script>是一直的。[www.61k.com)

? RPC的services已经创建完毕了。只要记住他包括client端和server端代码。

client端是接口的定义,server端是具体的实现。web.xml里配置的server

gxt gxt初学进阶教程

端的servlet。

Registry

GXT提供一个Registry类。他就像HashMap,可以在应用程序的client端内随意使用它。他就像一个载体,穿梭在client端的任何类之间,用于传递数据。

Registry存储services

gxt gxt初学进阶教程

Registry就是用来存储数据的。[www.61k.com]数据可以是多种多样的,除了基本的list之外,他可以存储services——当services被创建的时候,就被放入Registry内,然后可以在client端的任何位置,调用registry,取出services,通过services调用server端的代码,大致套路就是这样了。对于RSSReader项目目前而言,registry要存放的service是FeedServiceAsync,当从registry中取出FeedServiceAsync(services) ,去调用FeedServiceAsync里的方法,那么就会调用server端的FeedServiceImpl类中对应的具体实现方法。

? 首先,要创建一个const类,用来定义放入Registry中的

keys——RSSReaderConstants

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client;

2.

3. public class RSSReaderConstants {

4. public static final String FEED_SERVICE = "feedService";

5. }

? 要在程序最开始的时候,就把services注册到Registry内。所以编辑

RSSReader类的onModuleLoad()方法,加入如下代码:

[java] view plaincopyprint?

1. Registry.register(RSSReaderConstants.FEED_SERVICE,

2. GWT.create(FeedService.class));

? 注意:GWT.create(FeedService.class)的含义是,通过FeedService.class,

得到了FeedServiceAsync.class。

? 修改RssNavigationPanel类的createNewFeedWindow(),加入从Registry

内获得FeedServiceAsync类的代码:

[java] view plaincopyprint?

1. private void createNewFeedWindow()

2. {

3. final FeedServiceAsync feedService =

4. Registry.get(RSSReaderConstants.FEED_SERVICE);

gxt gxt初学进阶教程

5. }

? 得到了FeedServiceAsync,下面就要通过GWT的RPC去调用server端了

(FeedServiceImpl)。(www.61k.com]完整的在createNewFeedWindow()方法内,调用RPC的代码如下:

[java] view plaincopyprint? 1. private void createNewFeedWindow() { 2. final FeedServiceAsync feedService = Registry

3. .get(RSSReaderConstants.FEED_SERVICE);

4. feedService.createNewFeed(new AsyncCallback<Feed>() {

5. @Override

6. public void onFailure(Throwable caught) {

7. Info.display("RSSReader", "Unable to create a new feed");

8. }

9.

10. @Override

11. public void onSuccess(Feed feed) {

12. final Window newFeedWindow = new FeedWindow(feed);

13. newFeedWindow.show();

14. }

15. });

16. }

? 注意,上面代码的执行流程是:首先调用FeedServiceImpl.createNewFeed()

方法。当执行完毕之后,成功了就会回调onSuccess(),反之失败了,就会回调onFailure()方法。注意此过程是异步的(asynchronous)。

? 因此整个过程实现了,当点击create feed button 的时候,会调用

createNewFeedWindow()方法,去请求一个有ID主键的Feed 对象。如果Feed对象成功返回之后,新建一个FeedWindow窗口,同时传入刚刚成功返回的feed,然后显示FeedWindow窗口。Registry在此过程中,提供了调用RPC的feedService。

gxt gxt初学进阶教程

保存Feed

接下来,在FeedForm类中要新建save()方法,用来接收用户录入的信息,存储到先前通过RPC成功返回的feed中去。(www.61k.com)当然还得添加一个button用来验证表单,当验证通过之后,调用save()方法。

? 在FeedForm类中要新建save(),用来接收用户录入的信息:

[java] view plaincopyprint? 1. public void save(final Feed feed) {

2. feed.setTitle(tfTitle.getValue());

3. feed.setDescription(taDescription.getValue());

4. feed.setLink(tfLink.getValue());

5.

6. }

? 在FeedWindow类中加入Save button。当form验证通过之后,调用

FeedForm类中save()方法。

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.windows;

2.

3. import com.danielvaughan.rssreader.client.forms.FeedForm;

4. import com.danielvaughan.rssreader.shared.model.Feed;

5. import com.extjs.gxt.ui.client.event.ButtonEvent;

6. import com.extjs.gxt.ui.client.event.SelectionListener;

7. import com.extjs.gxt.ui.client.widget.Window;

8. import com.extjs.gxt.ui.client.widget.button.Button;

9. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

10. import com.google.gwt.user.client.Element;

11.

12. public class FeedWindow extends Window {

13.

14. private final FeedForm feedForm = new FeedForm();

gxt gxt初学进阶教程

15. 16. public FeedWindow(final Feed feed) {

17. setHeading("Feed");

18. setWidth(350);

19. setHeight(200);

20. setResizable(false);

21. setLayout(new FitLayout());

22.

23. final Button btnSave = new Button("Save");

24. btnSave.setIconStyle("save");

25. btnSave.addSelectionListener(new SelectionListener<ButtonEvent>() {

26. public void componentSelected(ButtonEvent ce) {

27. btnSave.setEnabled(false);

28. if (feedForm.isValid()) {

29. hide(btnSave);

30. feedForm.save(feed);

31. } else {

32. btnSave.setEnabled(true);

33. }

34. }

35. });

36. addButton(btnSave);

37. }

38.

39. @Override

40. protected void onRender(Element parent, int pos) {

41. super.onRender(parent, pos);

42. add(feedForm);

43. }

44.

45. }

? 当然要给Save button美化一下。[www.61k.com]

gxt gxt初学进阶教程

[css] view plaincopyprint? 1. .save { 2. background: url(gxt/images/icons/disk.png) no-repeat center

3. left

4. !important;

5. }

? 运行之后的效果:

gxt gxt初学进阶教程

? 当点击save button 之后,用户录入的信息,就会存入到feed对象中。[www.61k.com]填充

好feed之后的持久化操作,下一节会提到。

创建RSS XML

接下来,要把用户录入的feed内容保存起来。最合适的方式是,保存为RSS XML格式的文档。所以要在FeedService接口中新增一个方法saveFeed()方法。

我们需要使用JDOM 1.1库,操作feed对象,将其转换成XML格式。

下载jdom-1.1.2.jar包,放入工作空间里。

? 编辑FeedService接口,加入:

[java] view plaincopyprint?

1. void saveFeed(Feed feed);

gxt gxt初学进阶教程

? GWT在Eclipse中会提示并自动在FeedServiceAsync接口里生成:

[java] view plaincopyprint?

1. void saveFeed(Feed feed, AsyncCallback<Void> callback);

? 在FeedServiceImpl类中,实现saveFeed方法。[www.61k.com)

[java] view plaincopyprint? 1. @Override

2. public void saveFeed(Feed feed) {

3. Element eleRoot = new Element("rss");

4. eleRoot.setAttribute(new Attribute("version", "2.0")); 5.

6. // Create a document from the feed object

7. Document document = new Document(eleRoot);

8.

9. Element eleChannel = new Element("channel");

10. Element eleTitle = new Element("title");

11. Element eleDescription = new Element("description");

12. Element eleLink = new Element("link");

13.

14. eleTitle.setText(feed.getTitle());

15. eleDescription.setText(feed.getDescription());

16. eleLink.setText(feed.getLink());

17.

18. eleChannel.addContent(eleTitle);

19. eleChannel.addContent(eleDescription);

20. eleChannel.addContent(eleLink);

21.

22. eleRoot.addContent(eleChannel);

23.

gxt gxt初学进阶教程

24. try {

25. XMLOutputter serializer = new XMLOutputter();

26. Format prettyFormat = Format.getPrettyFormat();

27. serializer.setFormat(prettyFormat);

28. System.out

29. .println("At this point we would serialize the feed "

30. + feed.getTitle()

31. + " to a file. For now we are just going to write it to the console.");

32. serializer.output(document, System.out);

33. } catch (IOException e) {

34. System.out.println("Error saving feed");

35. }

36. }

? 上面的代码,只是把feed数据,转换成document 。[www.61k.com)然后将document输出

到控制台。

? 编辑FeedForm类的save方法。加入RPC的调用代码。

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.forms;

2.

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

4. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

5. import com.danielvaughan.rssreader.shared.model.Feed;

6. import com.extjs.gxt.ui.client.Registry;

7. import com.extjs.gxt.ui.client.widget.Info;

8. import com.extjs.gxt.ui.client.widget.form.FormPanel;

9. import com.extjs.gxt.ui.client.widget.form.TextArea;

10. import com.extjs.gxt.ui.client.widget.form.TextField;

11. import com.google.gwt.user.client.Element;

12. import com.google.gwt.user.client.rpc.AsyncCallback;

13.

14. public class FeedForm extends FormPanel {

15.

gxt gxt初学进阶教程

16. private final TextField<String> tfTitle = new TextField<String>();

17. private final TextArea taDescription = new TextArea();

18. private final TextField<String> tfLink = new TextField<String>(); 19.

20. public FeedForm() {

21. setHeaderVisible(false);

22. }

23.

24. @Override

25. protected void onRender(Element parent, int pos) {

26. super.onRender(parent, pos);

27.

28. tfTitle.setFieldLabel("Title");

29. tfTitle.setAllowBlank(false);

30. tfTitle.getMessages().setBlankText("Title is required");

31.

32. taDescription.setFieldLabel("Description");

33. taDescription.setAllowBlank(false);

34. taDescription.getMessages().setBlankText("Description is required"); 35.

36. tfLink.setFieldLabel("Link");

37. tfLink.setAllowBlank(false);

38. tfLink.setRegex("^http\\://[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,3}(/\\S*)?{

1}quot;);

39. tfLink.getMessages().setBlankText("Link is required");

40. tfLink.getMessages()

41. .setRegexText(

42. "The link field must be a URL e.g. http://www.example.com/rss.xml"); 43.

44. add(tfTitle);

45. add(taDescription);

46. add(tfLink);

47. }

48.

49. public void save(final Feed feed) {

gxt gxt初学进阶教程

50. feed.setTitle(tfTitle.getValue());

51. feed.setDescription(taDescription.getValue());

52. feed.setLink(tfLink.getValue());

53.

54. final FeedServiceAsync feedService = Registry

55. .get(RSSReaderConstants.FEED_SERVICE);

56. feedService.saveFeed(feed, new AsyncCallback<Void>() {

57. @Override

58. public void onFailure(Throwable caught) {

59. Info.display("RSS Reader",

60. "Failed to save feed: " + feed.getTitle());

61. }

62.

63. @Override

64. public void onSuccess(Void result) {

65. Info.display("RSS Reader", "Feed " + feed.getTitle()

66. + " saved sucessfully");

67. }

68. });

69.

70. }

71.

72. }

? 最后当用户录入数据后,提交到server端处理。(www.61k.com)就会在控制台显示如下格式

的xml内容:

[html] view plaincopyprint?

1. <rss version="2.0">

2. <channel>

3. <title>Example Feed</title>

4. <description>This is an example feed</description>

5. <link>http://www.example.com/</link>

6. </channel>

7. </rss>

gxt gxt初学进阶教程

优化LinkFeedPopup

还记得LinkFeedPopup窗口,用来提供用户输入URL的页面吗?现在要给他优化一下,加入validation的代码。(www.61k.com]

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.components;

2.

3. import com.extjs.gxt.ui.client.Style.LayoutRegion;

4. import com.extjs.gxt.ui.client.event.ButtonEvent;

5. import com.extjs.gxt.ui.client.event.ComponentEvent;

6. import com.extjs.gxt.ui.client.event.KeyListener;

7. import com.extjs.gxt.ui.client.event.SelectionListener;

8. import com.extjs.gxt.ui.client.util.Margins;

9. import com.extjs.gxt.ui.client.widget.Popup;

10. import com.extjs.gxt.ui.client.widget.Text;

11. import com.extjs.gxt.ui.client.widget.button.Button;

12. import com.extjs.gxt.ui.client.widget.form.TextField;

13. import com.extjs.gxt.ui.client.widget.layout.BorderLayout;

14. import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;

15. import com.google.gwt.event.dom.client.KeyCodes;

16. import com.google.gwt.user.client.Element;

17. import com.google.gwt.user.client.Window;

18.

19. public class LinkFeedPopup extends Popup {

20. private final TextField<String> tfUrl = new TextField<String>();

21.

22. public LinkFeedPopup() {

23. setSize(300, 55);

24. setBorders(true);

25. setShadow(true);

26. setAutoHide(false);

27. }

28.

29. public void addFeed(String url) {

gxt gxt初学进阶教程

30. Window.alert("We would now attempt to add " + url + " at this point");

31. }

32.

33. @Override

34. protected void onRender(Element parent, int pos) {

35. super.onRender(parent, pos);

36. final Text txtExplaination = new Text("Enter a feed url");

37. final Button btnAdd = new Button("add");

38. btnAdd.addSelectionListener(new SelectionListener<ButtonEvent>() { 39.

40. public void componentSelected(ButtonEvent ce) {

41. if (tfUrl.isValid())

42. addFeed(tfUrl.getValue());

43. }

44. });

45.

46. tfUrl.addKeyListener(new KeyListener() {

47. public void componentKeyDown(ComponentEvent event) {

48. if (event.getKeyCode() == KeyCodes.KEY_ENTER) {

49. addFeed(tfUrl.getValue());

50. }

51. }

52. });

53. tfUrl.setAllowBlank(false);

54. tfUrl.setRegex("^http\\://[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,3}(/\\S*)?$"

);

55. tfUrl.setAllowBlank(false);

56. tfUrl.getMessages().setBlankText(

57. "Please enter the URL of an existing feed");

58. tfUrl.setAutoValidate(true);

59. tfUrl

60. .getMessages()

61. .setRegexText(

62. "The link field must be a URL e.g. http://www.example.com/rss.xml"); 63.

gxt gxt初学进阶教程

64. final BorderLayout layout = new BorderLayout();

65. setLayout(layout); 66.

gxt gxt初学进阶教程

67. final BorderLayoutData northData = new BorderLayoutData(

68. LayoutRegion.NORTH, 20);

69. northData.setMargins(new Margins(2));

70. add(txtExplaination, northData);

71.

72. final BorderLayoutData centerData = new BorderLayoutData(

73. LayoutRegion.CENTER);

74. centerData.setMargins(new Margins(2));

75. add(tfUrl, centerData);

76.

77. final BorderLayoutData eastData = new BorderLayoutData(

78. LayoutRegion.EAST, 50);

79. eastData.setMargins(new Margins(2, 2, 2, 20));

80. add(btnAdd, eastData);

81. }

82.

83. }

gxt gxt初学进阶教程

第四章:Data与Components 本章我们要学习,GXT是如何允许我们和Data协同工作的。(www.61k.com)我们会着眼与components的检索,操作,加工data的能力。并且学习具有操作数据能力的components。

本章,我们会涉及到如下GXt功能集

Data

?

?

?

?

? ? ModelData BeanModel BeanModelTag BeanModelMarker BeanModelFactory Stores

Remote Data

?

?

?

?

? ? DataProxies DataReaders ListLoadResults ModelType Loaders LoadConfigs

Data-backed components

?

?

? ListField ComboBox Grid

o ColumnModel

o ColumnConfig

o GridCellRenderer

操作数据(Data)

AJAX应用,包括用GXT搭建的应用程序,其中一个最大的优势在于——在浏览器中可以直接操作数据。GXT提供了非常有用的可以操作数据的components(Data-backed components),可以允许用户直接通过他们操作数据。比如ListField,ComboBox,Grid

gxt gxt初学进阶教程

等components。[www.61k.com]通过使用这些components,可以方便快捷的对数据进行过滤,排序,编辑内容等操作。 当然还有另一组非可视化的控件集合:负责获得远程数据,缓存客户端数据,传递数据给可视化components。

我们这章都会涉及到他们。但是,首先我们要创建一组data,作为可视化components(Data-backed components)的数据源。

ModelData接口

GXT提供了ModelData接口。data-backed components使用的任何data objects必须实现此接口。比如查看一下GXT中ListField的类定义,就明白此话的含义了:

[java] view plaincopyprint?

1. public class ListField<D extends ModelData> extends Field<D> implements

SelectionProvider<D> ModelData接口提供了执行期间检索names和values的能力。GWT不支持反射,而GXT则使用反射机制。摘自ModelData接口里的注释

[java] view plaincopyprint? :

1. /**

2. * Primary interface for GXT model objects without support events. Models

3. * support a form of "introspection" as property names and values can be

4. * retrieved at runtime.

5. */

在我们RSSReader项目里,目前我们使用的Feed JavaBean去存储feed 数据。但是Feed类还没有实现ModelData接口,所以Feed类还不能够作为data-backed components的数据源!

想要让一个JaveBean可以作为data-backed components的数据源,有下面三种方法:

1.修改Feed JaveBean,让其extends com.extjs.gxt.ui.client.data.BaseModel。这种方法不可取,因为改动量大,而且keys容易出错,看代码便知晓:

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. public class Feed extends BaseModel {

2. public Feed () {

3. }

4. public Feed (String uuid) { 5. set("uuid", uuid);

6. }

7. public String getDescription() {

8. return get("description");

9. }

10. public String getLink() {

11. return get("link");

12. }

13. public String getTitle() {

14. return get("title");

15. }

16. public String getUuid() {

17. return get("uuid");

18. }

19. public void setDescription(String description) {

20. set("description", description);

21. }

22. public void setLink(String link) {

23. set("link", link);

24. }

25. public void setTitle(String title) {

26. set("title", title);

27. }

28. }

2.修改Feed JaveBean,让其implements com.extjs.gxt.ui.client.data.BeanModelTag。(www.61k.com)具体代码如下:

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. public class Feed implements Serializable, BeanModelTag { 2. private String description;

3. private String link;

4. private String title;

5. private String uuid;

6. public Feed() {

7. }

8. public Feed(String uuid) {

9. this.uuid = uuid;

10. }

11. public String getDescription() {

12. return description;

13. }

14. public String getLink() {

15. return link;

16. }

17. public String getTitle() {

18. return title;

19. }

20. public String getUuid() {

21. return uuid;

22. }

23. public void setDescription(String description) {

24. this.description = description;

25. }

26. public void setLink(String link) {

27. this.link = link;

28. }

29. public void setTitle(String title) {

30. this.title = title;

31. }

32. }

gxt gxt初学进阶教程

3.新建一个类FeedBeanModel,实现BeanModelMarker 接口,通过在FeedBeanModel类中的注解@BEAN,指定此类包装了Feed JavaBean。[www.61k.com]此方法可以避免直接修改Feed JaveBean。我们推荐使用此方法。

? Feed JavaBean在shared包下,但是BeanModel相关的类,属于client端

的代码。所以新建包:com.danielvaughan.rssreader.client.model:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.model;

2.

3. import com.extjs.gxt.ui.client.data.BeanModelMarker;

4. import com.extjs.gxt.ui.client.data.BeanModelMarker.BEAN;

5.

6. @BEAN(com.danielvaughan.rssreader.shared.model.Feed.class)

7. public class FeedBeanModel implements BeanModelMarker {

8. }

? @BEAN(com.danielvaughan.rssreader.shared.model.Feed.class)就指定了

FeedBeanModel是Feed的包装BeanModel类。

总结

简单明了的说,本章就是讲了如下意思:

? 如果想让Data-backed components的组件能够显示出来数据,其数据必须

是ModelData。

?

?

? 想让一个普通的JavaBean成为ModelData,有三种方法。 我们推荐第三种方法实现ModelData——因为不需要修改原先的JavaBean。 That's all

Stroes

在GXT中,Stroe,一个抽象类,用于穿梭于client端,提供ModelData objects。Stroe其实就是为data-backed components存储数据的。

gxt gxt初学进阶教程

Stroe有两种:TreeStore——为了使用于Tree components;ListStore——为了存储list数据的(被ListField, ComboBox, Grid components使用)。[www.61k.com)

创建一个ListStore对象用来存储我们上一节创建的Feed BeanModel,代码如下:

[java] view plaincopyprint?

1. ListStore<BeanModel> feedStore = new ListStore<BeanModel>();

通过其泛型的定义,就可以显而易见,Store就是用来存储BeanModel的。但是如果想往Store中放入BeanModel,不能直接添加,需要借助BeanModelFactory。BeanModelFactory会把一个Feed javaBean转换成BeanModel的表现形式,之后才可以被添加到Store中。 我们要修改RSSReader项目,新建一个Feed JavaBean 对象,将其转换成BeanModel的表现形式,添加到ListStore中。

? 在RSSReaderConstants类,加入一个FEED_STORE,用来最为Registry

注册的key。

[java] view plaincopyprint?

1. public static final String FEED_STORE = "feedStore";

? 在RSSReader.onModuleLoad方法,加入Registry

[java] view plaincopyprint? 1. public void onModuleLoad() {

2. Registry.register(RSSReaderConstants.FEED_SERVICE,

3. GWT.create(FeedService.class));

4. Registry.register(RSSReaderConstants.FEED_STORE, new

5. ListStore<BeanModel>());

6. …

7. }

? 修改FeedForm.save方法中的,onSuccess回调方法,加入从registry获得

feed store的相关代码:

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. public void save(final Feed feed) { 2. @Override

3. public void onSuccess(Void result) { 4. Info.display("RSS Reader", "Feed " + feed.getTitle()

5. + " saved successfully");

6. final ListStore<BeanModel> feedStore = Registry

7. .get(RSSReaderConstants.FEED_STORE);

8. }

9. …

10. }

? 通过Feed生成BeanModelFactory

[java] view plaincopyprint?

1. public void onSuccess(Void result) {

2. Info.display("RSS Reader", "Feed " + feed.getTitle() + " saved

3. successfully");

4. final ListStore<BeanModel> feedStore =

5. Registry.get(RSSReaderConstants.FEED_STORE);

6. BeanModelFactory beanModelFactory =

7. BeanModelLookup.get().getFactory(feed.getClass());

8. }

? 最后,在通过BeanModelFactory去生成Feed的BeanModel,添加到feed

store

[java] view plaincopyprint?

1. public void onSuccess(Void result) {

2. Info.display("RSS Reader", "Feed " + feed.getTitle() + " saved

3. successfully");

gxt gxt初学进阶教程

4. final ListStore<BeanModel> feedStore =

5. Registry.get(RSSReaderConstants.FEED_STORE);

6. BeanModelFactory beanModelFactory =

7. BeanModelLookup.get().getFactory(feed.getClass()); 8. feedStore.add(beanModelFactory.createModel(feed));

9. }

Data-backed ListField

只要一个data-backed component和一个Store绑定到一起,Store的任何变化,都会自动的展现在data-backed component。(www.61k.com)对于影响Store数据的事件如下: ?

?

?

?

?

? ? Add Clear Data Changed Filter Remove Sort Update

在RSSReader例子中,要新建一个ListField的Data-backed component。然后让feed store绑定到ListField身上,这样feed store的内容就会通过ListField 可视化的组件展现出来。当feed store有变化就会自动的影响ListField的显示效果。

? 新建包:com.danielvaughan.rssreader.client.lists,在此包下,新建FeedList

extends LayoutContainer

[java] view plaincopyprint?

1. public class FeedList extends LayoutContainer {}

? 在构造函数里,设置FitLayout

[java] view plaincopyprint?

1. public FeedList() {

gxt gxt初学进阶教程

2. setLayout(new FitLayout()); 3. }

? Override onRender方法,新建一个ListField

[java] view plaincopyprint? 1. @Override

2. protected void onRender(Element parent, int index) { 3. super.onRender(parent, index);

4. final ListField<BeanModel> feedList = new

5. ListField<BeanModel>();

6. }

? 在onRender方法,通过Registry获得feed store

[java] view plaincopyprint?

1. final ListStore<BeanModel> feedStore =

Registry.get(RSSReaderConstants.FEED_STORE);

? 让feedList和feedStore绑定在一起

[java] view plaincopyprint? 1. feedList.setStore(feedStore);

? 设置feedList显示的列——feedList这个Data-backed component,会自动

的找到feedStore里所有的BeanModel(Feed JavaBean),然后通过title字符串,按照反射原理在Feed里查找以title为key的value,将value按照ListField的形式展示出来,有多少条Feed(BeanModel)在store中,就会显示出来。[www.61k.com]

[java] view plaincopyprint?

1. feedList.setDisplayField("title");

gxt gxt初学进阶教程

? 将feedList 可视化组件,加入到容器中。(www.61k.com)

[java] view plaincopyprint? 1. add(feedList)

? 在RssNavigationPanel构造函数里,加入如下代码,添加刚才新建FeedList

类,加入到west导航区。 [java] view plaincopyprint?

1. setLayout(new FitLayout());

2. add(new FeedList());

gxt gxt初学进阶教程

? 最后运行程序,效果如下:

gxt gxt初学进阶教程

gxt gxt初学进阶教程

总结:ModelData,Data-backed components,Stroe之间的关系

?

?

?

? Data-backed components的数据源是Store Store中存储的数据必须是ModelData 但是ModelData必须是通过BeanModelFactory生成的。[www.61k.com] 并不是任何一个普通的JavaBean就可以被BeanModelFactory生成为

ModelData的。前提是JavaBean必须具有成为ModelData的能力,如何实

现,就得看前一节的内容。

http://blog.csdn.net/miqi770/article/details/7193740

Server端的持久化

到目前为止,在RSSReader项目里,还没有任何持久化的操作。为了让我们项目更具有真实性,现在我们要添加持久化的代码。但是为了让我们更专注于client-side,持久化的逻辑仅仅是最基本的操作——实现真实的持久化逻辑之前先加入持久化的接口,这样就可以为了需要,可以在不改变接口调用的基础上,改用另外一种持久化操作的内容既可(比如hibernate)。

目前,实现最初的持久化版本,步骤如下:

?

? 当添加新的feed实体时候,在server-side使用xml文件来存储。 xml文件只有一个,我们会在这个文件里维护feed的列表。

gxt gxt初学进阶教程

持久化的代码不属于GXT的犯愁,因此我们可以把他以一个黑盒对待。[www.61k.com]在我们RSSReader项目里,要加入Persistence接口和实现此接口的FilePersistence类,他们的功能就是负责存储和获得RSS feed信息的。

持久化一个存在的Feed

在第二章,我们新建一个Link feed button,目的是用来从internet里导入一个已经存在的RSS feed网络地址。接下来我们要在FeedService接口里,定义addExistingFeed方法,用作持久层存储RSS feed的URL地址。此功能要被绑定到LinkFeedPopup的add button上。

? 在FeedService接口里,定义addExistingFeed方法,当然要传入一个URL 参数 [java] view plaincopyprint?

1. void addExistingFeed(String feedUrl);

? 同样的会在FeedServiceAsync接口里,定义与之相关的异步回调方法

[java] view plaincopyprint?

1. void addExistingFeed(String feedUrl, AsyncCallback<Void>

2. callback);

? 修改LinkFeedPopup的addFeed方法,加入addExistingFeed回调方法的

调用,具体逻辑一看便知

[java] view plaincopyprint?

1. public void addFeed(final String feedUrl) {

2. final FeedServiceAsync feedService = Registry

3. .get(RSSReaderConstants.FEED_SERVICE);

4. feedService.addExistingFeed(feedUrl, new AsyncCallback<Void>() {

5. @Override

gxt gxt初学进阶教程

6. public void onFailure(Throwable caught) { 7. Info.display("RSS Reader", "Failed to add feed at: " + feedUrl);

8. }

9.

10. @Override

11. public void onSuccess(Void result) {

12. tfUrl.clear();

13. Info.display("RSS Reader", "Feed at " + feedUrl

14. + " added successfully");

15. hide();

16. }

17. });

18. }

? FeedServiceImpl类里,我们要加入日志,这里用简单的

java.util.logging.Logger

[java] view plaincopyprint?

1. private final static Logger LOGGER =

Logger.getLogger(FeedServiceImpl.class

2. .getName());

? 在FeedServiceImpl类里,加入private的方法loadFeed,用来根据feed的

URL,在JDOM规范下,从internet里获得RSS的XML内容,返回Feed实体bean

[java] view plaincopyprint?

1. private Feed loadFeed(String feedUrl) {

2. Feed feed = new Feed(feedUrl);

3. try {

4. SAXBuilder parser = new SAXBuilder();

5. Document document = parser.build(new URL(feedUrl));

gxt gxt初学进阶教程

6. Element eleRoot = document.getRootElement(); 7. Element eleChannel = eleRoot.getChild("channel");

8. feed.setTitle(eleChannel.getChildText("title"));

9. feed.setDescription(eleChannel.getChildText("description"));

10. feed.setLink(eleChannel.getChildText("link"));

11. return feed;

12. } catch (IOException e) {

13. LOGGER.log(Level.SEVERE, "IO Error loading feed", e);

14. return feed; 15. } catch (JDOMException e) {

16. LOGGER.log(Level.SEVERE, "Error parsing feed", e);

17. return feed;

18. }

19. }

? 在FeedServiceImpl类里,加入HashMap的属性,用来存储Feed对象

[java] view plaincopyprint?

1. private Map<String, Feed> feeds = new HashMap<String, Feed>(); ? 我们目前的持久化功能是依赖与jdom-1.1.2.jar包功能的实现,具体的持久化

代码如下,全部贴出来

[html] view plaincopyprint?

1. 持久化的配置文件:rssreader.properties(放在src\下)

2. feed.file=feeds.txt

3. data.folder=data

4. base.url=http://127.0.0.1:8888

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.server.utils;

gxt gxt初学进阶教程

2.

3. import java.util.Set;

4.

5. import org.jdom.Document;

6.

7. public interface Persistence {

8.

9. public Set<String> loadFeedList();

10.

11. public void saveFeedList(Set<String> feedUrls); 12.

13. public void saveFeedXml(String uuid, Document document); 14.

15. public String getUrl(String uuid);

16. }

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.server.utils; 2.

3. import java.io.BufferedReader;

4. import java.io.BufferedWriter;

5. import java.io.DataInputStream;

6. import java.io.File;

7. import java.io.FileInputStream;

8. import java.io.FileWriter;

9. import java.io.IOException;

10. import java.io.InputStream;

11. import java.io.InputStreamReader;

12. import java.util.HashSet;

13. import java.util.Properties;

14. import java.util.Set;

15. import java.util.logging.Logger;

16.

17. import org.jdom.Document;

gxt gxt初学进阶教程

18. import org.jdom.output.Format;

19. import org.jdom.output.XMLOutputter;

20.

21. public class FilePersistence implements Persistence {

22.

23. private final static Logger LOGGER =

Logger.getLogger(FilePersistence.class

24. .getName());

25.

26. private String dataFolder;

27. private String feedFilePath;

28. private String baseUrl;

29.

30. private final Properties properties = new Properties();

31.

32. public FilePersistence() {

33. // Read properties file.

34. try {

35. ClassLoader loader = ClassLoader.getSystemClassLoader();

36. InputStream in = loader.getResourceAsStream("rssreader.properties");

37. properties.load(in);

38.

39. dataFolder = (String) properties.get("data.folder");

40. String feedFile = (String) properties.get("feed.file");

41. feedFilePath = dataFolder + "\\" + feedFile;

42. baseUrl = (String) properties.get("base.url");

43.

44. initDataFolder();

45. } catch (IOException e) {

46. LOGGER.severe("Unable to load properties file");

47. }

48. }

49.

50. private void initDataFolder() {

51. try {

gxt gxt初学进阶教程

52. File dataFolderFile = new File(dataFolder);

53. if (!dataFolderFile.exists()) {

54. dataFolderFile.mkdir();

55. }

56. File feedFile = new File(feedFilePath);

57. if (!feedFile.exists()) {

58. feedFile.createNewFile();

59. }

60. } catch (IOException e) {

61. LOGGER.severe("Error initialising data folder");

62. }

63. }

64.

65. @Override

66. public void saveFeedList(Set<String> feedUrls) {

67. try {

68. FileWriter fileWriter = new FileWriter(feedFilePath);

69. BufferedWriter out = new BufferedWriter(fileWriter);

70. for (String feedUrl : feedUrls) {

71. String line = feedUrl.concat("\n");

72. out.write(line);

73. }

74. out.close();

75. } catch (Exception e) {

76. LOGGER.severe("Error: " + e.getMessage());

77. }

78. }

79.

80. @Override

81. public Set<String> loadFeedList() {

82. Set<String> feedUrls = new HashSet<String>();

83. try {

84. FileInputStream fstream = new FileInputStream(feedFilePath);

85. DataInputStream in = new DataInputStream(fstream);

86. BufferedReader br = new BufferedReader(new InputStreamReader(in));

gxt gxt初学进阶教程

87. String strLine;

88. while ((strLine = br.readLine()) != null) {

89. feedUrls.add(strLine);

90. }

91. in.close();

92. return feedUrls;

93. } catch (Exception e) {

94. LOGGER.severe("Error: " + e.getMessage());

95. return feedUrls;

96. }

97. }

98.

99. @Override

100.

101.

102.

103.

104.

105.

106.

107.

108.

109.

110.

111.

112.

113.

114.

115.

116.

117.

118.

119.

120.

121. public void saveFeedXml(String feedId, Document document) { try { File file = new File(generateFilePath(feedId)); XMLOutputter serializer = new XMLOutputter(); Format prettyFormat = Format.getPrettyFormat(); serializer.setFormat(prettyFormat); FileWriter writer = new FileWriter(file); serializer.output(document, writer); writer.close(); } catch (IOException e) { LOGGER.severe("Error: " + e.getMessage()); } } private String generateFilePath(String feedId) { return dataFolder + "/" + feedId + ".xml"; } @Override public String getUrl(String feedId) { String fileName = generateFilePath(feedId); return baseUrl + "/" + fileName;

gxt gxt初学进阶教程

122.

123. } }

? 最后在FeedServiceImpl类里,实现addExistingFeed方法,调用刚才创建

的loadFeed方法,根据feedUrl返回Feed对象,再调用上面持久化类的saveFeedList方法,完成持久化操作

[java] view plaincopyprint? 1. @Override

2. public void addExistingFeed(String feedUrl) {

3. Feed loadResult = loadFeed(feedUrl);

4. if (loadResult.getTitle() != null) {

5. feeds.put(feedUrl, loadFeed(feedUrl)); 6. persistence.saveFeedList(feeds.keySet());

7. }

8. }

? 创建本地的RSS xml文件用来读取:http://127.0.0.1:8888/rss2sample.xml。(www.61k.com]

在WebContent\下创建rss2sample.xml,内容如下:

[html] view plaincopyprint? 1. <?xml version="1.0"?>

2. <rss version="2.0">

3. <channel>

4. <title>Liftoff News</title>

5. <link>http://liftoff.msfc.nasa.gov/</link>

6. <description>Liftoff to Space Exploration.</description>

7. <language>en-us</language>

8. <pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate>

9.

10. <lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate>

11. <docs>http://blogs.law.harvard.edu/tech/rss</docs>

gxt gxt初学进阶教程

12. <generator>Weblog Editor 2.0</generator>

13. <managingEditor>editor@example.com</managingEditor>

14. <webMaster>webmaster@example.com</webMaster>

15. <item>

16.

17. <title>Star City</title>

18. <link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp</link>

19. <description>How do Americans get ready to work with Russians aboard the

International Space Station? They take a crash course in culture, language and protocol at Russia's <a

href="">Star

City</a>.</description>

20. <pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate>

21. <guid>#item573</guid> 22.

23. </item>

24. <item>

25. <description>Sky watchers in Europe, Asia, and parts of Alaska and Canada

will experience a <a

href="">partial eclipse of the Sun</a> on Saturday, May 31st.</description>

26. <pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate>

27. <guid>#item572</guid> 28.

29. </item>

30. <item>

31. <title>The Engine That Does More</title>

32. <link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link>

33. <description>Before man travels to Mars, NASA hopes to design new engines

that will let us fly through the Solar System more quickly. The proposed VASIMR engine would do that.</description>

34. <pubDate>Tue, 27 May 2003 08:37:32 GMT</pubDate>

35. <guid>#item571</guid> 36.

37. </item>

gxt gxt初学进阶教程

38. <item>

39. <title>Astronauts' Dirty Laundry</title>

40. <link>http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp</link>

41. <description>Compared to earlier spacecraft, the International Space

Station has many luxuries, but laundry facilities are not one of them. Instead, astronauts have other options.</description>

42.

gxt gxt初学进阶教程

<pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate>

43. <guid>#item570</guid> 44.

45. </item>

46. </channel>

47. </rss>

? 运行程序,会读取rssreader.properties配置文件初始化持久化的配置。(www.61k.com)当你

通过Link feed button 成功添加一个真实的URL link

(http://127.0.0.1:8888/rss2sample.xml)的时候,会在项目

WebContent\data\feeds.txt文件里存储一行内容

http://127.0.0.1:8888/rss2sample.xml

gxt gxt初学进阶教程

gxt gxt初学进阶教程

GXT之旅:第四章:Data与Components(4)——远程数据(remote data)

分类: ExtGWT2012-01-27 14:29815人阅读评论(0)收藏举报

使用remote data

stores的数据来源不单单可以从client-side获得(就是从Registry里获得),也可以通过调用远程数据来获得。[www.61k.com)对于远程数据的加载和处理工作,GXT已经提供了轻巧方便的手段。她支持通过HTTP协议来检索XML或者JSON格式的数据,或者直接通过GWT RPC来

gxt gxt初学进阶教程

检索到objects对象。(www.61k.com)对于不同的数据源,GXT提供了相应的机制。如果有必要的话,会把原始的数据转换成ModelData并且自动的放入store里。

对于远程数据的处理过程,会涉及到几个components(非可视化组件)。他们各尽其责,协同工作完成远程数据的检索和加工等操作。 ?

?

? DataProxy—负责从数据源检索出原始的数据 DataReader—将检索出的原始数据转换成client-side可用的ModelData Loader—将转换好的ModelData自动的加载到store里,给data-backed

components使用

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

?

? ModelData类型的对象集合 一个实现了ListLoadResult接口的object——在ListLoadResult接口里有个

一getData()方法用来返回ModelData object的

? 一个PagingLoadResult object——PagingLoadResult 扩展了

ListLoadResult接口,加入了分页的功能,因此返回一组数据的子集。[www.61k.com]

gxt gxt初学进阶教程

gxt gxt初学进阶教程

上面的列表大家会注意到“ModelType定义”这句话。[www.61k.com]ModelType是在Reader在进行转换的时候会用到的类。

ModelType的使用

ModelType是用来定义原始数据的结构类型的。定要其原始数据的结构之后,reader就会根据此结构进行读取转换。

拿XML类型的数据来说,其结构比如:

[html] view plaincopyprint? 1. <books>

2. <book>

3. <title>The best book in the world</title>

4. </book>

5. <book>

6. <title>The worst book in the world</title>

7. </book>

8. </books>

那么就上面的结构,ModelType应该有如下定义:

[java] view plaincopyprint?

1. final ModelType modelType = new ModelType(); 2. modelType.setRoot("books");

3. modelType.setRecordName("book");

4. modelType.addField("title");

跟节点是books,book是记录集,title是具体的一个field属性。

ModelType当然也支持定义Json数据类型的结构。如下的Json数据,ModelType的定义同上

[html] view plaincopyprint?

1. {

gxt gxt初学进阶教程

2. "books": [

3. {

4. "book": {

5. "title": "The best book in the world"

6. },

7. "book": { 8. "title": "The worst book in the world"

9. }

10. }

11. ]

12. }

Loader接口

1. 当DataProxy将原始数据获得,

2. 数据被DataReader转换成ModelData之后

3. 就需要使用Loaders,将ModelData装入

gxt gxt初学进阶教程

Store

Loader是所有接口根接口,与之对应的BaseLoader是所有抽象类的根抽象类。[www.61k.com]当然BaseLoader实现了Loader接口。请看下图:

Loader一共就分两类:一个是List一个是Tree。打开源码一看便知之前的关系。

Loaders可以在数据加载的时候,将其排序,可以功过setSortField,setSortDir方法进行设置,当然也可以通过LoadConfig对象来设置。

LoadConfig

gxt gxt初学进阶教程

LoadConfig配置了数据是如何被Loader到store的。[www.61k.com)Loadconfig接口有一系列的实现类(BaseGroupingLoadConfigBasePagingLoadConfig),看名称就猜到大概意思这里就不详细介绍了。我自己也没怎么研究。。。

重新屡屡思路

1. GXT所能使用的classes必须要直接或间接的实现了ModelData接口,才可

以放入Store里

2. Store里面存储的ModelData,其实是充当的client-side的缓存层,

Data-backed components直接使用的是Store

3. 用DataProxy将远程的原始数据获得

4. ModelType定义了远程数据的结构体

5. DataReader根据ModelType的描述,把原始的数据转换成ModelData

6. Loader按照DataProxy和DataReader的定义,一气呵成,执行之后将数据

装入Store。

7. Loadconfig的定义告诉Loader对ModelData数据如何排序,分组,分页等

配置。

将上面提到的所有内容应用到RSSReader项目里

? 编辑com.danielvaughan.rssreader.client.listsFeedList类的onRender方法

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.lists;

2.

3. import java.util.List;

4.

5. import com.danielvaughan.rssreader.client.RSSReaderConstants;

6. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

7. import com.danielvaughan.rssreader.shared.model.Feed;

8. import com.extjs.gxt.ui.client.Registry;

9. import com.extjs.gxt.ui.client.data.BaseListLoader;

10. import com.extjs.gxt.ui.client.data.BeanModel;

gxt gxt初学进阶教程

11. import com.extjs.gxt.ui.client.data.BeanModelReader;

12. import com.extjs.gxt.ui.client.data.ListLoadResult;

13. import com.extjs.gxt.ui.client.data.ListLoader;

14. import com.extjs.gxt.ui.client.data.RpcProxy;

15. import com.extjs.gxt.ui.client.store.ListStore;

16. import com.extjs.gxt.ui.client.widget.LayoutContainer;

17. import com.extjs.gxt.ui.client.widget.form.ListField;

18. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

19. import com.google.gwt.user.client.Element;

20. import com.google.gwt.user.client.rpc.AsyncCallback;

21.

22. public class FeedList extends LayoutContainer {

23.

24. public FeedList() {

25. setLayout(new FitLayout());

26. }

27.

28. @Override

29. protected void onRender(Element parent, int index) {

30. super.onRender(parent, index);

31. final ListField<BeanModel> feedList = new ListField<BeanModel>();

32. //0:从Registry里获得Service

33. final FeedServiceAsync feedService = (FeedServiceAsync) Registry

34. .get(RSSReaderConstants.FEED_SERVICE);

35. //1:定义proxy在load方法里嗲用Serivce里的方法

36. RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {

37. @Override

38. protected void load(Object loadConfig,

39. AsyncCallback<List<Feed>> callback) {

40. feedService.loadFeedList(callback);

41.

42. }

43. };

44. //2:定义Reader

45. BeanModelReader reader = new BeanModelReader();

gxt gxt初学进阶教程

46. //3:将proxy和reader传入,定义loader

47. ListLoader<ListLoadResult<BeanModel>> loader = new

BaseListLoader<ListLoadResult<BeanModel>>(

48. proxy, reader);

49. //4:传入loader,生成store,此时还没有load数据

50. ListStore<BeanModel> feedStore = new ListStore<BeanModel>(loader);

51. //5:将stroe绑定到data-backed component身上

52. feedList.setStore(feedStore);

53. feedList.setDisplayField("title"); 54. //6:真正的load数据,load成功之后,data-backed component会自动的显示出来。(www.61k.com]

55. loader.load();

56.

57. add(feedList);

58. }

59. }

GXT之旅:第四章:Data与Components(5)——Grid

分类: ExtGWT2012-01-30 15:24806人阅读评论(2)收藏举报

准备工作——Item

正如我们所知,一个feed的信息,里面会包含多组Item的信息,也就是一对多的概念。如果想将这些items都显示出来,我们需要有另外的model bean class来存储他们。整个处理过程如下:

? 新建Item modalData类,其属性用来存储对应的信息(在这里为了简单起见,

直接使用之前提到的第一种方法,让Item成为ModalData类。):

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.shared.model;

2.

3. import com.extjs.gxt.ui.client.data.BaseModel;

4.

5. @SuppressWarnings("serial")

gxt gxt初学进阶教程

6. public class Item extends BaseModel {

7.

8. public Item() {

9.

10. }

11.

12. public String getCategory() {

13. return get("category");

14. }

15.

16. public String getDescription() {

17. return get("description");

18. }

19.

20. public String getLink() {

21. return get("link");

22. }

23.

24. public String getTitle() {

25. return get("title");

26. }

27.

28. public void setCategory(String category) {

29. set("category", category);

30. }

31.

32. public void setDescription(String description) {

33. set("description", description);

34. }

35.

36. public void setLink(String link) {

37. set("link", link);

38. }

39.

40. public void setTitle(String title) {

gxt gxt初学进阶教程

41. set("title", title);

42. }

43. } ? 在FeedService接口里,定义loadItems方法,根据url,返回Item List

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.services; 2.

3. import java.util.List;

4.

5. import com.danielvaughan.rssreader.shared.model.Feed;

6. import com.danielvaughan.rssreader.shared.model.Item;

7. import com.google.gwt.user.client.rpc.RemoteService;

8. import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; 9.

10. @RemoteServiceRelativePath("feed-service")

11. public interface FeedService extends RemoteService {

12. void addExistingFeed(String feedUrl);

13.

14. Feed createNewFeed();

15.

16. List<Feed> loadFeedList();

17.

18. List<Item> loadItems(String feedUrl);

19.

20. void saveFeed(Feed feed);

21. }

? 同样的FeedServiceAsync 异步回调类,添加对应的回调方法

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.services;

gxt gxt初学进阶教程

2. 3. import java.util.List;

4.

5. import com.danielvaughan.rssreader.shared.model.Feed;

6. import com.danielvaughan.rssreader.shared.model.Item;

7. import com.google.gwt.user.client.rpc.AsyncCallback;

8.

9. public interface FeedServiceAsync {

10. void addExistingFeed(String feedUrl, AsyncCallback<Void> callback); 11.

12. void createNewFeed(AsyncCallback<Feed> callback);

13.

14. void loadFeedList(AsyncCallback<List<Feed>> asyncCallback); 15.

16. void loadItems(String feedUrl, AsyncCallback<List<Item>> callback); 17.

18. void saveFeed(Feed feed, AsyncCallback<Void> callback);

19. }

? 在FeedServiceImpl实现类,实现抽象方法loadItems

[java] view plaincopyprint?

1. @SuppressWarnings("unchecked")

2. public List<Item> loadItems(String feedUrl) {

3. List<Item> items = new ArrayList<Item>();

4. try {

5. SAXBuilder parser = new SAXBuilder();

6. Document document = parser.build(new URL(feedUrl));

7. Element eleRoot = document.getRootElement();

8. Element eleChannel = eleRoot.getChild("channel");

9. List<Element> itemElements = eleChannel.getChildren("item");

10. for (Element eleItem : itemElements) {

11. Item item = new Item();

gxt gxt初学进阶教程

12. item.setTitle(eleItem.getChildText("title"));

13. item.setDescription(eleItem.getChildText("description"));

14. item.setLink(eleItem.getChildText("link"));

15. item.setCategory(eleItem.getChildText("category"));

16. items.add(item);

17. }

18. return items;

19. } catch (IOException e) {

20. e.printStackTrace(); 21. return items;

22.

23. } catch (JDOMException e) {

24. e.printStackTrace();

25. return items;

26. }

27. }

Grid

Grid很类似与flex的datagrid。[www.61k.com]GXT的Grid component 拥有这许多不同的功能。现在,我们就从最基本的功能——如何的让Grid显示数据开始。当通过Grid的构造函数创建实例的之后,需要指定两方面的内容:ListStore和ColumnModel

[java] view plaincopyprint?

1. Grid<ModelData> grid = new Grid<ModelData>(itemStore, columnModel);

ColumnConfig

Columnconfig定义了Grid在显示的时候每一列。具体点说就是指明了:1.使用了列数据;

2.数据是如何被渲染出来的。

Conlumnconfig和ColumnModel之间的关系,查看源码的构造函数一看便知:

[java] view plaincopyprint?

1. public ColumnModel(List<ColumnConfig> columns) {

2. this.configs = new ArrayList<ColumnConfig>(columns);

3. }

gxt gxt初学进阶教程

Columnconfig可以有很多组,存入list里,然后传入到ColumnModel的构造函数中去,生成ColumnModel的实例。(www.61k.com)

那么将上面提到所有内容加入到我们的RSSReader项目里——让应用程序在启动的时候,自动的读取一个RSS url 将读取的items信息显示到Grid中: ? 创建新package:com.danielvaughan.rssreader.client.grids,在新包内加入

ItemGrid内的自定义组件。我们将在这个ItemGrid 内加入Grid的代码

? 为了让Grid能够自适应浏览器窗口的大小,ItemGrid类要继承

LayoutContainer

? 习惯上,构造函数里,设置其LayOut

[java] view plaincopyprint?

1. public ItemGrid() {

2. setLayout(new FitLayout());

3. }

? 当然了,必须要override onRender方法。首先,定义ColumnConfigs 他是

一个List<ColumnConfig>

[java] view plaincopyprint?

1. final List<ColumnConfig> columns = new ArrayList<ColumnConfig>(); 2. columns.add(new ColumnConfig("title", "Title", 200)); 3. columns.add(new ColumnConfig("description", "Description", 200));

? 将定义好的columns传入ColumnModel的构造函数

[java] view plaincopyprint?

1. final ColumnModel columnModel = new ColumnModel(columns);

? 定义测试的RSS url,为了保证定义的url一定好用:

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. final String TEST_DATA_FILE = "http://127.0.0.1:8888/rss2sample.xml";

? 从Registry里拿feedService

[java] view plaincopyprint? 1. final FeedServiceAsync feedService =

Registry.get(RSSReaderConstants.FEED_SERVICE);

? 还是按照之前的远程调用,RpcProxy去调用FeedService的loadItems方法。[www.61k.com)

通过

[java] view plaincopyprint? 1. final FeedServiceAsync feedService = Registry.get(RSSReaderConstants.FEED_SERVICE);

2. RpcProxy<List<Item>> proxy = new RpcProxy<List<Item>>() {

3. @Override

4. protected void load(Object loadConfig,

5. AsyncCallback<List<Item>> callback) {

6. feedService.loadItems(TEST_DATA_FILE, callback);

7. }

8. };

? 因为Item是使用的一种方法实现的modelData——直接继承了BaseModel

(其属性都是用get/set写的),因此不需要reader进行转换。loader可以直接通过proxy获得

[java] view plaincopyprint?

1. ListLoader<ListLoadResult<Item>> loader = new

BaseListLoader<ListLoadResult<Item>>(proxy);

? 通过loader,获得store数据

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. ListStore<ModelData> itemStore = new ListStore<ModelData>(loader);

? ListStore和ColumnModel都准备完毕之后,开始创建Grid,将两个对象传

入Grid的构造函数当中。[www.61k.com)设置description列可以自动伸展,填充空白区域。

[java] view plaincopyprint? 1. Grid<ModelData> grid = new Grid<ModelData>(itemStore,

2. columnModel);

3. grid.setBorders(true);

4. grid.setAutoExpandColumn("description");

? 调用load方法,让Grid装载store

[java] view plaincopyprint?

1. loader.load();

? 将Grid添加到LayoutContainer内显示

[java] view plaincopyprint?

1. add(grid);

? 最后编辑com.danielvaughan.rssreader.client.components.RssMainPanel,

添加ItemGrid

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.components;

2.

3. import com.danielvaughan.rssreader.client.grids.ItemGrid;

4. import com.extjs.gxt.ui.client.widget.ContentPanel;

5. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

6.

7. public class RssMainPanel extends ContentPanel {

8. public RssMainPanel() {

gxt gxt初学进阶教程

9. setHeading("Main");

10. setLayout(new FitLayout());

11. add(new ItemGrid());

12. }

13. }

gxt gxt初学进阶教程

GXT之旅:第四章:Data与Components(6)——

GridCellRenderer

分类: ExtGWT2012-01-31 10:34605人阅读评论(1)收藏举报

GridCellRenderer(渲染器)

目前看来,RSSReader项目的grid已经简单的显示出来了——每一列都是显示简单的一个field数据。[www.61k.com]如果想要让几个fields联合起来,更丰富的显示的话,我们就需要使用GridCellRenderer。它允许我们使用HTML去渲染表格里面的内容。

GridCellRenderer定义好之后,需要通过ColumnConfig.setRenderer方法设置,应用于一个列上。

接下来我们要使用GridCellRenderer在我们RSSReader项目的自定义component

ItemGrid。用来替换先前定义的title和description两个列,使用GridCellRenderer来显示上下结构的(title在上,description在下)一列。

? ItemGrid的onRender方法里,定义一个GridCellRenderer

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. GridCellRenderer<ModelData> itemsRenderer = new GridCellRenderer<ModelData>() {

2. @Override

3. public Object render(ModelData model, String property,

4. ColumnData config, int rowIndex, int colIndex,

5. ListStore<ModelData> store, Grid<ModelData> grid) {

6. String title = model.get("title");

7. String description = model.get("description");

8. return "<b>" + title + "</b><br/>" + description;

9. } 10. };

? 实现了render方法,通过model获得title和description,联合形成一个html的String

? 新建一个ColumnConfig,将定义好的itemsRenderer设置进去,同时定义了

一列名为Items,删除之前的ColumnConfig [java] view plaincopyprint?

1. ColumnConfig column = new ColumnConfig();

2. column.setId("items");

3. column.setRenderer(itemsRenderer);

4. column.setHeader("Items");

? 将column加入到配置列表中,将配置列表放入ColumnModel里。[www.61k.com]

[java] view plaincopyprint?

1. columns.add(column);

2. final ColumnModel columnModel = new ColumnModel(columns); ? 因为只有一列,所以让items这一列伸展出来

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. grid.setAutoExpandColumn("items");

? 运行程序之后的效果如下:

? 当我们再把先前的title和description列定义加入之后就会更清楚

ColumnConfig意义,整个代码如下:

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.grids; 2.

gxt gxt初学进阶教程

3. import java.util.ArrayList;

4. import java.util.List;

5.

6. import com.danielvaughan.rssreader.client.RSSReaderConstants;

7. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

8. import com.danielvaughan.rssreader.shared.model.Item;

9. import com.extjs.gxt.ui.client.Registry;

10. import com.extjs.gxt.ui.client.data.BaseListLoader;

11. import com.extjs.gxt.ui.client.data.ListLoadResult;

gxt gxt初学进阶教程

12. import com.extjs.gxt.ui.client.data.ListLoader;

13. import com.extjs.gxt.ui.client.data.ModelData;

14. import com.extjs.gxt.ui.client.data.RpcProxy;

15. import com.extjs.gxt.ui.client.store.ListStore;

16. import com.extjs.gxt.ui.client.widget.LayoutContainer;

17. import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;

18. import com.extjs.gxt.ui.client.widget.grid.ColumnData;

19. import com.extjs.gxt.ui.client.widget.grid.ColumnModel;

20. import com.extjs.gxt.ui.client.widget.grid.Grid;

21. import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;

22. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

23. import com.google.gwt.user.client.Element;

24. import com.google.gwt.user.client.rpc.AsyncCallback;

25.

26. public class ItemGrid extends LayoutContainer {

27.

28. public ItemGrid() {

29. setLayout(new FitLayout());

30. }

31.

32. @Override

33. protected void onRender(Element parent, int index) {

34. super.onRender(parent, index);

35.

36. final List<ColumnConfig> columns = new ArrayList<ColumnConfig>(); 37.

38. columns.add(new ColumnConfig("title", "Title", 200));

39. columns.add(new ColumnConfig("description", "Description", 200)); 40.

41. GridCellRenderer<ModelData> itemsRenderer = new

GridCellRenderer<ModelData>() {

42. @Override

43. public Object render(ModelData model, String property,

44. ColumnData config, int rowIndex, int colIndex,

45. ListStore<ModelData> store, Grid<ModelData> grid) {

gxt gxt初学进阶教程

46. String title = model.get("title");

47. String description = model.get("description");

48. return "<b>" + title + "</b><br/>" + description;

49. }

50. };

51. ColumnConfig column = new ColumnConfig();

52. column.setId("items");

53. column.setRenderer(itemsRenderer);

54. column.setHeader("Items");

55. columns.add(column);

56. final ColumnModel columnModel = new ColumnModel(columns);

57. final String TEST_DATA_FILE = "http://127.0.0.1:8888/rss2sample.xml"; 58.

59. final FeedServiceAsync feedService = Registry

60. .get(RSSReaderConstants.FEED_SERVICE);

61. RpcProxy<List<Item>> proxy = new RpcProxy<List<Item>>() {

62. @Override

63. protected void load(Object loadConfig,

64. AsyncCallback<List<Item>> callback) {

65. feedService.loadItems(TEST_DATA_FILE, callback);

66. }

67. };

68. ListLoader<ListLoadResult<Item>> loader = new

BaseListLoader<ListLoadResult<Item>>(

69. proxy);

70. ListStore<ModelData> itemStore = new ListStore<ModelData>(loader); 71.

72. Grid<ModelData> grid = new Grid<ModelData>(itemStore, columnModel);

73. grid.setBorders(true);

74. grid.setAutoExpandColumn("items");

75. loader.load();

76. add(grid);

77. }

78. }

gxt gxt初学进阶教程

gxt gxt初学进阶教程

? ColumnConfig其实就是定义一列。[www.61k.com]如果其不使用渲染其,则默认的简单文本

显示,如果使用渲染器,可以自定义显示效果支持html标签。显示的列的顺序根add的顺序有关!

GXT之旅:第五章:高级Components(1)——Trees和TreeGrid(1)

分类: ExtGWT2012-01-31 17:27752人阅读评论(0)收藏举报

第五章:高级Components

本章我们要基于前几章内容,更深入的学习data-backed components。我们会学习Tree以及如何优化和改进数据的加载和显示等内容。学习如何将Tree的概念应用与Grid。会涉及到Grid的一些高级功能。最后我们要学习menus和toolbars

本章,我们会涉及到如下GXt功能集

?

? Trees BaseTreeModel

o TreeStore

o TreePanel

o TreeGrid

o TreeGridCellRenderer

? Advanced grid features

o Column grouping

gxt gxt初学进阶教程

? HeaderGroupConfig

o Aggregation rows

?

?

o Paging

?

? AggregationRowConfig SummaryType PagingListResult PagingLoadConfig

?

?

? PagingModelMemoryProxy PagingLoader PagingToolBar

?

? ImageBundle Toolbars and menus

o Menu

o MenuItem

o CheckMenuItem

o MenuBar

o MenuBarItem

o MenuEvent

o ToolBar

o Status Trees

上一章,我们所涉及的components只是使用ListData。(www.61k.com)现在我们要学习那些使用TreesData的components。

GXT所提供的有关tree的components和list的components是很类似的。不同的是,对于tree来说,要使用其专门的ModelData—Store, DataReader, 和Loader。

BaseTreeModel

BaseTreeModel 继承 BaseModel 实现了TreeModel接口,自然添加了关于tree的功能方法——有关于管理父子关系的功能方法。为了让ModelData可以被TreePanel或者TreeGrid使用,javaBean就需要继承BaseTreeModel而不是BaseModel。

在RSSReader项目里,我们准备让一个feed的url的items集合存在一个树的分类上。为了实现此功能,我们需要创建一个Category class继承BaseTreeModel

? 在com.danielvaughan.rssreader.shared.model包下,新建类Category,继

承BaseTreeModel。

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. public class Category extends BaseTreeModel {} ? 新建一个静态的ID属性,用来做自增序列。(www.61k.com)新建一个构造函数,其参数是

String类型的title,并且让ID自增

[java] view plaincopyprint? 1. private static int ID = 0;

2.

3. public Category(String title) {

4. set("id", ID++);

5. set("title", title);

6. }

? 再添加一个无参数的构造函数,只是让ID自增 [java] view plaincopyprint?

1. public Category() {

2. set("id", ID++);

3. }

? 在加入get方法,整个Category类的定义如下:

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.shared.model; 2.

3. import com.extjs.gxt.ui.client.data.BaseTreeModel; 4.

5. @SuppressWarnings("serial")

6. public class Category extends BaseTreeModel {

7. private static int ID = 0;

8.

9. public Category() {

10. set("id", ID++);

gxt gxt初学进阶教程

11. }

12.

13. public Category(String title) { 14. set("id", ID++);

15. set("title", title);

16. }

17.

18. public Integer getId() { 19. return (Integer) get("id");

20. } 21.

22. public String getTitle() {

23. return (String) get("title");

24. }

25. }

接下来,需要在FeedService接口里,定义新的方法,用来根据给定的category获得属于该category内的items集合。(www.61k.com]

? FeedService接口内定义loadCategorisedItems方法

[java] view plaincopyprint?

1. List<ModelData> loadCategorisedItems(String feedUrl, Category category);

? 同样的,异步回调方法

[java] view plaincopyprint?

1. void loadCategorisedItems(String feedUrl, Category category,

2. AsyncCallback<List<ModelData>> callback);

? 在FeedServiceImpl类里,实现其抽象方法

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. @Override

2. public List<ModelData> loadCategorisedItems(String feedUrl,

3. Category category) {

4. List<Item> items = loadItems(feedUrl);

5. Map<String, List<Item>> categorisedItems = new HashMap<String,

List<Item>>();

6. for (Item item : items) {

7. // 0:get each item 's category

8. String itemCategoryStr = item.getCategory();

9. if (itemCategoryStr == null) {

10. itemCategoryStr = "Uncategorised";

11. }

12. // 1: get categoryItems by itemCategoryStr

13. List<Item> categoryItems = categorisedItems.get(itemCategoryStr);

14. if (categoryItems == null) {

15. categoryItems = new ArrayList<Item>();

16. }

17. // 2: add current item into categoryItems

18. categoryItems.add(item);

19.

20. // 3: put categoryItems into categorisedItems(hashMap) named as

21. // itemCategoryStr

22. categorisedItems.put(itemCategoryStr, categoryItems);

23. }

24. // 4: if category is null, return the whole categoryList

25. if (category == null) {

26. List<ModelData> categoryList = new ArrayList<ModelData>();

27. for (String key : categorisedItems.keySet()) {

28. categoryList.add(new Category(key));

29. }

30. return categoryList;

31. } else {

32. return new ArrayList<ModelData>(categorisedItems.get(category

33. .getTitle()));

34. }

gxt gxt初学进阶教程

35. }

TreeStore

TreeStore 是另外一个Store的实现类。[www.61k.com)其不同点在于,使用TreeStore来存储ListStore,用来表示层级的数据,而不是普通的数据集合。 我们可以将TreeModel添加到TreeStore里面,不需要使用TreeModel去管理父子层级关系,不需要复杂的编码,系统内部会自动的管理其关系。对于如何通过

gxt gxt初学进阶教程

add方法,将TreeModel添加到TreeStore中并同时设置之间的层级关系,之后会介绍。

TreePanel

TreePanel是一个真正的可视化树控件。使用起来也很简单,掌握起来也很容易。

当通过构造函数创建TreePanel的时候,其必须传入TreeStore的参数。通过

setDisplayProperty方法,来设置显示TreeStore里面的哪一列内容。

默认情况下,当一个节点有子节点的时候,显示的图标是文件夹;如果是叶子节点的时候(就是该节点没有子节点),显示的图标是白色文件图片。当然可以通过setLeafIcon来设置叶子节点的图标(需要以GWT的AbstractImagePrototype类作为参数)。

ImageBundle

Tree components 使用 GWT提供的ImageBundle 功能,用来作为tree节点的图标的初始化加载过程。如果想要在我们RSSReader项目里,让tree components使用自定义的图标的话,就需要我们定义一个ImageBundle。尽管ImageBundle是GWT的内容并未GXT的内容,但是我们要注意的是:虽然ImageBundle的出现是用来替换ClientBundle,但是他还是不推荐被直接使用的(deprecation)。我们需要自加工一个Icons。

? 新建包:com.danielvaughan.rssreader.client.resources,在其包下新建Icons

接口,继承ImageBundle

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. @SuppressWarnings("deprecation")

2. public interface Icons extends ImageBundle {}

? 每个被添加到ImageBundle的图片,都需要一个无参的方法返回

AbstractImagePrototype。(www.61k.com)使用@Resource注解图片的位置,相对于当前package的路径

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.resources; 2.

3. import com.google.gwt.user.client.ui.AbstractImagePrototype;

4. import com.google.gwt.user.client.ui.ImageBundle;

5.

6. @SuppressWarnings("deprecation")

7. public interface Icons extends ImageBundle {

8. @Resource("rss.png")

9. AbstractImagePrototype rss();

10. }

? 在同样的package下,新建Resources类,用来静态引用刚才生成的Icons。

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.resources;

2.

3. import com.google.gwt.core.client.GWT;

4.

5. public class Resources {

6. public static final Icons ICONS = GWT.create(Icons.class);

7. }

? 最后,我们RSSReader项目的package层级关系如下:

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

GXT之旅:第五章:高级Components(1)——Trees和TreeGrid(2)

分类: ExtGWT2012-02-01 10:34628人阅读评论(1)收藏举报

TreeGrid

TreeGrid将Trees和Grids的功能结合在一起。(www.61k.com]整体上看是由多个columns组成的Grid,但是内容上看,支持显示树目录结构的数据。

他和TreePanel一样,使用的Store也是TreeStore,ModelDate也是BaseTreeModel。

TreeGridCellRenderer

TreeGridCellRenderer实现了GridCellRenderer,其功能顾名思义,用来渲染TreeGrid的column的。接下来我们要在RSSReader项目里使用TreeGridCellRenderer,对于一个renderer来说可以被设置在任何一个column上。

? 在package:com.danielvaughan.rssreader.client.grids里,新建

ItemCategoryGrid,继承LayoutContainer

[java] view plaincopyprint?

1. public class ItemCategoryGrid extends LayoutContainer {

2. public ItemCategoryGrid() {

3. setLayout(new FitLayout());

4. }

gxt gxt初学进阶教程

5. }

? Override onRender方法,在其方法内从Registry内获得FeedService

[java] view plaincopyprint? 1. protected void onRender(Element parent, int index) {

2. super.onRender(parent, index);

3. final FeedServiceAsync feedService = (FeedServiceAsync) Registry

4. .get(RSSReaderConstants.FEED_SERVICE);

5. }

? 通过RpcProxy,调用FeedService.loadCategorisedItems方法。[www.61k.com)因为对于

Trees或者TreeGrid的数据,每次数据加载都只加载当前node节点的

children,不是一股脑的将所有数据都加载到client。所以每次的请求调用过程,就都需要传入参数——loadConfig,那么对于当前的例子来说,loadConfig就是Category(BaseTreeModel)。

[java] view plaincopyprint?

1. final String TEST_DATA_FILE = "http://127.0.0.1:8888/rss2sample.xml";

2. RpcProxy<List<ModelData>> proxy = new RpcProxy<List<ModelData>>() {

3. @Override

4. protected void load(Object loadConfig,

5. AsyncCallback<List<ModelData>> callback) {

6. feedService.loadCategorisedItems(TEST_DATA_FILE,

7. (Category) loadConfig, callback);

8. }

9. };

? 新建BaseTreeLoader对象,override hasChildren方法。

[java] view plaincopyprint?

1. final TreeLoader<ModelData> loader = new BaseTreeLoader<ModelData>(

2. proxy) {

3. @Override

4. public boolean hasChildren(ModelData parent) {

gxt gxt初学进阶教程

5. if (parent instanceof Category) {

6. return true; 7. } else {

8. return false;

9. }

10. } 11. };

? 这里不需要使用reader,因为RpcProxy所调用的远程方法,已经返回的是

ModelData。(www.61k.com)通过刚刚生成的loader,传入TreeStore的构造函数。

[java] view plaincopyprint?

1. final TreeStore<ModelData> feedStore = new TreeStore<ModelData>(loader);

? 创建ColumnConfig,使用TreeGridCellRenderer作为Tree的渲染器

[java] view plaincopyprint?

1. ColumnConfig title = new ColumnConfig("title", "Title", 200);

2. title.setRenderer(new TreeGridCellRenderer<ModelData>());

? 新建另外一个ColumnConfig description,然后将ColumnConfig title和

description以list的形式传入ColumnModel

[java] view plaincopyprint?

1. ColumnConfig description = new ColumnConfig("description","Description",

200);

2. ColumnModel columnModel = new ColumnModel(Arrays.asList(title,

description));

? 定义TreeGrid,传入刚刚生成feedStore和columnModel。让title列自动伸

展,再设置上一节定义的ICONs

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. TreeGrid<ModelData> treeGrid = new

TreeGrid<ModelData>(feedStore,columnModel);

2. treeGrid.setBorders(true);

3. treeGrid.setAutoExpandColumn("title");

4. treeGrid.getStyle().setLeafIcon(Resources.ICONS.rss()); ? 通过loader的load方法,开始启动整个执行过程,将treeGrid加入LayoutContainer

[java] view plaincopyprint?

1. loader.load();

2. add(treeGrid);

? 在RssMainPanel类的构造函数里,去掉先前add的ItemGrid,替换为add

ItemCategoryGrid.

[java] view plaincopyprint?

1. public RssMainPanel() {

2. setHeading("Main"); 3.

gxt gxt初学进阶教程

setLayout(new FitLayout());

4. add(new ItemCategoryGrid());

5. }

? 最后运行程序如下:

? 整个代码如下:

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. package com.danielvaughan.rssreader.client.grids;

2.

3. import java.util.Arrays;

4. import java.util.List;

5.

6. import com.danielvaughan.rssreader.client.RSSReaderConstants;

7. import com.danielvaughan.rssreader.client.resources.Resources;

8. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

9. import com.danielvaughan.rssreader.shared.model.Category;

10. import com.extjs.gxt.ui.client.Registry;

11. import com.extjs.gxt.ui.client.data.BaseTreeLoader;

12. import com.extjs.gxt.ui.client.data.ModelData;

13. import com.extjs.gxt.ui.client.data.RpcProxy;

14. import com.extjs.gxt.ui.client.data.TreeLoader;

15. import com.extjs.gxt.ui.client.store.TreeStore;

16. import com.extjs.gxt.ui.client.widget.LayoutContainer;

17. import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;

18. import com.extjs.gxt.ui.client.widget.grid.ColumnModel;

19. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

20. import com.extjs.gxt.ui.client.widget.treegrid.TreeGrid;

21. import com.extjs.gxt.ui.client.widget.treegrid.TreeGridCellRenderer;

22. import com.google.gwt.user.client.Element;

23. import com.google.gwt.user.client.rpc.AsyncCallback;

24.

25. public class ItemCategoryGrid extends LayoutContainer {

26. public ItemCategoryGrid() {

27. setLayout(new FitLayout());

28. }

29.

30. @Override

31. protected void onRender(Element parent, int index) {

32. super.onRender(parent, index);

33. final FeedServiceAsync feedService = (FeedServiceAsync) Registry

34. .get(RSSReaderConstants.FEED_SERVICE);

35. final String TEST_DATA_FILE = "http://127.0.0.1:8888/rss2sample.xml";

gxt gxt初学进阶教程

36. RpcProxy<List<ModelData>> proxy = new RpcProxy<List<ModelData>>() {

37. @Override

38. protected void load(Object loadConfig,

39. AsyncCallback<List<ModelData>> callback) {

40. feedService.loadCategorisedItems(TEST_DATA_FILE,

41. (Category) loadConfig, callback);

42. }

43. };

44.

45. final TreeLoader<ModelData> loader = new BaseTreeLoader<ModelData>(

46. proxy) {

47. @Override

48. public boolean hasChildren(ModelData parent) {

49. if (parent instanceof Category) {

50. return true;

51. } else {

52. return false;

53. }

54. }

55. };

56.

57. final TreeStore<ModelData> feedStore = new TreeStore<ModelData>(loader); 58.

59. ColumnConfig title = new ColumnConfig("title", "Title", 200);

60. ColumnConfig description = new ColumnConfig("description","Description",

200);

61.

62. title.setRenderer(new TreeGridCellRenderer<ModelData>());

63.

64. ColumnModel columnModel = new

ColumnModel(Arrays.asList(title,description));

65.

66. TreeGrid<ModelData> treeGrid = new TreeGrid<ModelData>(feedStore,

67. columnModel);

68. treeGrid.setBorders(true);

gxt gxt初学进阶教程

69. treeGrid.setAutoExpandColumn("title");

70. treeGrid.getStyle().setLeafIcon(Resources.ICONS.rss());

71. //loader.load();//不需要load

72. add(treeGrid);//当treeGrid添加之后,GXT内部会自动的loader.load();,如果

我们再手动的load的话,就会call service 两次

73. }

74. }

注意:通过断点跟踪FeedServiceImpl.loadCategorisedItems方法。(www.61k.com]我们会发现,此方法会被多次调用。整个现象如下: ? TreeGrid在初始化的时候(也就是load的时候),会调用一次

FeedServiceImpl.loadCategorisedItems方法。数据显示的时候,文件夹图标

都是闭合的。

? 当闭合的图标第一次被打开的时候,会在调用一次

FeedServiceImpl.loadCategorisedItems方法。此时,代码内部会自动的将当

前节点的Category,传入到proxy的load方法中去,作为参数,让

FeedServiceImpl.loadCategorisedItems方法去根据Category,获得items

数据。 ? 当闭合的图标关闭后再打开的时候,就不会调用了。也就是说,第一次将内

容加载到client之后,就不会再发出请求了。

大家再看看源代码——TreeGridCellRenderer.render方法。

? 当我们在新建TreeGridCellRenderer的时候,不需要override render方法,

GXT已经给写好了。直接new出对象既可。

? TreeGrid在初始化的时候(也就是load的时候),有多少条数据,就会调用

多少遍TreeGridCellRenderer.render方法。

? 当点击文件夹图标的节点的时候,也就会自动的调用

TreeGridCellRenderer.render方法。

GXT之旅:第五章:高级Components(2)——Grid的高级应用

分类: ExtGWT2012-02-02 11:18625人阅读评论(0)收藏举报

gxt gxt初学进阶教程

Grid的高级应用

之前,我们学习的都是Grid的基本功能。(www.61k.com)事实上,Grids提供了丰富的功能,下面就让我们了解一下。

HeaderGroupConfig

假设我们想比较欧洲东部在1950和2000年之间的人口数,通常的显示效果如下:

gxt gxt初学进阶教程

但是我们想让表格更直观的显示,如下:

gxt gxt初学进阶教程

这时我们就需要对GXT Grid有如下步骤的加工:

?

?

? 针对每一列,新建ColumnConfig 将所有的ColumnConfigs放入一个list 通过list生成ColumnModel

[java] view plaincopyprint?

1. final List<ColumnConfig> columns = new ArrayList<ColumnConfig>();

2. ColumnConfig column = new ColumnConfig("countryName",

3. "Country",100);

4. columns.add(column);

5. column = new ColumnConfig("population1950", "1950",130);

gxt gxt初学进阶教程

6. columns.add(column);

7. column = new ColumnConfig("population2000", "2000",130);

8. columns.add(column); 9. final ColumnModel columnModel = new ColumnModel(columns);

? 上述的代码,所呈现出的Grid如下:

gxt gxt初学进阶教程

?

gxt gxt初学进阶教程

如果希望将后面两列分组一组,我们就需要使用到HeaderGroupConfig

[java] view plaincopyprint?

1. HeaderGroupConfig headerGroupConfig = new HeaderGroupConfig(

2. "Population (000's)", 1, 2);

?

? 第一个参数是title,第二和第三个参数分别是合并后的行数和合并后的列数。(www.61k.com] 将headerGroupConfig add在ColumnModel里。并指明行号和起始的列号

[java] view plaincopyprint?

1. columnModel.addHeaderGroup(0, 1, headerGroupConfig););

? 执行后的效果如下:

AggregationRowConfig

使用AggregationRowConfig,可以创建统计行,用来针对某些列的统计数据。 SummaryType是用来设置其统计数据的算法:

? SummaryType.SUM

gxt gxt初学进阶教程

?

? ? ? SummaryType.AVG SummaryType.MIN SummaryType.MAX SummaryType.COUNT

gxt gxt初学进阶教程

如果我们想实现上图的效果,我们应该实现的代码如下:

? 新建AggregationRowConfig,

[java] view plaincopyprint?

1. AggregationRowConfig<Statistic>> totals = new AggregationRowConfig

2. <Statistic>();

? 通过setHtml方法,设置该行的题头

[java] view plaincopyprint?

1. totals.setHtml("countryName", "Total");

? 针对与要统计的列,我们需要设置其统计算法。[www.61k.com]

[java] view plaincopyprint?

1. totals.setSummaryType("population1950", SummaryType.SUM);

2. totals.setSummaryType("population2000", SummaryType.SUM);

gxt gxt初学进阶教程

? 对于要统计的列,为了显示的需要,要设置NumberFormat

(com.google.gwt.i18n.client.NumberFormat)。[www.61k.com]当然也可以通过

AggregationRenderer.实现,但是不管怎样,都需要使用其中一种方法,否

则,会空白显示

[java] view plaincopyprint? 1. totals.setSummaryFormat("population1950", NumberFormat.

2. getDecimalFormat());

3. totals.setSummaryFormat("population2000", NumberFormat.

4. getDecimalFormat());

? 同样的,AggregationRowConfig实例需要被添加到columnModel里

[java] view plaincopyprint?

1. columnModel.addAggregationRow(totals); GXT之旅:第五章:高级Components(3)

gxt gxt初学进阶教程

——Paging

gxt gxt初学进阶教程

2012-02-02 16:22853人阅读评论(3)收藏举报

Paging

Paging是GXT提供的非常有用的功能。顾名思义,就是分页显示数据,而不是一页显示所有的数据。GXT支持远程和本地的分页:远程分页就是真分页,每次server端返回数据都是数据库里分页后的数据;本地的分页就是假分页,数据库一次性load全部数据后,前端再分页内存里面的数据。为了方便起见,仅仅使用假分页,给大家展示一下Paging的功能。

介绍一下分页工作的相关类

PagingLoadResult

gxt gxt初学进阶教程

分页的数据,其必须被填充到PagingLoadResult。(www.61k.com]PagingLoadResult是ListLoadResult的扩展接口,提供了额外的功能(TotalLength和Offset),

PagingLoadConfig

PagingLoadConfig封装了请求分页数据的参数,指定了offset,数据返回起始点等。 接下来,我们要在RSSReader项目里,新建一个方法,返回PagingLoadResult<Item>

? FeedService接口里,定义第二个loadItems方法,

[java] view plaincopyprint?

1. PagingLoadResult<Item> loadItems(String feedUrl, final

2. PagingLoadConfig config);

? FeedServiceAsync接口里,定义其回调方法

[java] view plaincopyprint?

1. void loadItems(String feedUrl, PagingLoadConfig config,

2. AsyncCallback<PagingLoadResult<Item>> callback);

? FeedServiceImpl里,实现这个抽象方法。

[java] view plaincopyprint? 1. @Override

2. public PagingLoadResult<Item> loadItems(String feedUrl,

3. PagingLoadConfig config) {

4. List<Item> items = loadItems(feedUrl);

5. return getPagingLoadResult(items, config);

6. }

? getPagingLoadResult的方法实现如下:

[java] view plaincopyprint?

1. private PagingLoadResult<Item> getPagingLoadResult(List<Item> items,

2. PagingLoadConfig config) {

3. //定义pageItems,存储Item,作为返回的数据源

gxt gxt初学进阶教程

4. List<Item> pageItems = new ArrayList<Item>();

5. //通过PagingLoadConfig,获得相关参数(offset)

6. int offset = config.getOffset();

7. //获得全部数据大小

8. int limit = items.size();

9. //根据offset获得limit

10. if (config.getLimit() > 0) {

11. limit = Math.min(offset + config.getLimit(), limit); 12. }

13. //定义好边界之后,开始读取数据

14. for (int i = offset; i < limit; i++) { 15. pageItems.add(items.get(i));

16. }

17. //通过pageItems,转化成BasePagingLoadResult,同时赋值上offset和

totalLength

18. return new BasePagingLoadResult<Item>(pageItems, offset, items.size()); 19.

20. }

PagingModelMemoryProxy

对于返回分页的数据的方法的代理proxy需要使用PagingModelMemoryProxy,针对于PagingModelMemoryProxy的loader是PagingLoader

PagingLoader

PagingLoader的构造函数里,参数指明了类型是PagingModelMemoryProxy,

PagingLoader会通过PagingModelMemoryProxy,load分页的数据集到store里。[www.61k.com)

[java] view plaincopyprint?

1. PagingLoader<PagingLoadResult<ModelData>> loader = new

BasePagingLoader<PagingLoadResult<ModelData>>(proxy);

对于load数据的时候,需要指定offset和pageSize

[java] view plaincopyprint?

1. loader.load(0, 4);//public void load(int offset, int pageSize);

gxt gxt初学进阶教程

对于其过程使用的store是ListStore,因为数据本身来说,就是一般的list数据集,分页的操作只是从大的list数据集里面获取部分数据集。(www.61k.com) PagingToolBar PagingToolBar extends ToolBar

gxt gxt初学进阶教程

,预定义了相关的分页功能。

对于PagingToolBar来说,他数据源所绑定的是PagingLoader,大致代码如下:

[java] view plaincopyprint?

1. toolBar.bind(loader);

2. add(toolBar);

接下来,我们要在RSSReader项目里实现上面提到的所有概念。

? 新建ItemPagingGrid类,整个代码内容如下:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.grids;

2.

3. import java.util.ArrayList;

4. import java.util.List;

5.

6. import com.danielvaughan.rssreader.client.RSSReaderConstants;

7. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

8. import com.danielvaughan.rssreader.shared.model.Item;

9. import com.extjs.gxt.ui.client.Registry;

10. import com.extjs.gxt.ui.client.data.BasePagingLoader;

11. import com.extjs.gxt.ui.client.data.ModelData;

12. import com.extjs.gxt.ui.client.data.PagingLoadConfig;

13. import com.extjs.gxt.ui.client.data.PagingLoadResult;

14. import com.extjs.gxt.ui.client.data.PagingLoader;

15. import com.extjs.gxt.ui.client.data.RpcProxy;

16. import com.extjs.gxt.ui.client.store.ListStore;

17. import com.extjs.gxt.ui.client.widget.ContentPanel;

18. import com.extjs.gxt.ui.client.widget.LayoutContainer;

19. import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;

gxt gxt初学进阶教程

20. import com.extjs.gxt.ui.client.widget.grid.ColumnData;

21. import com.extjs.gxt.ui.client.widget.grid.ColumnModel;

22. import com.extjs.gxt.ui.client.widget.grid.Grid;

23. import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;

24. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

25. import com.extjs.gxt.ui.client.widget.toolbar.PagingToolBar;

26. import com.google.gwt.user.client.Element;

27. import com.google.gwt.user.client.rpc.AsyncCallback;

28.

29. public class ItemPagingGrid extends LayoutContainer {

30.

31. private static final int PAGE_SIZE = 2;

32.

33. public ItemPagingGrid() {

34. setLayout(new FitLayout());

35. }

36.

37. @Override

38. protected void onRender(Element parent, int index) {

39. super.onRender(parent, index);

40. // ColumnModel

41. final List<ColumnConfig> columns = new ArrayList<ColumnConfig>();

42. GridCellRenderer<ModelData> itemsRenderer = new

GridCellRenderer<ModelData>() {

43. @Override

44. public Object render(ModelData model, String property,

45. ColumnData config, int rowIndex, int colIndex,

46. ListStore<ModelData> store, Grid<ModelData> grid) {

47. String title = model.get("title");

48. String description = model.get("description");

49. return "<b>" + title + "</b><br/>" + description;

50. }

51. };

52. ColumnConfig column = new ColumnConfig();

53. column.setId("items");

gxt gxt初学进阶教程

54. column.setRenderer(itemsRenderer);

55. column.setHeader("Items");

56. columns.add(column);

57. final ColumnModel columnModel = new ColumnModel(columns);

58.

59. // Proxy:

60. final String TEST_DATA_FILE = "http://127.0.0.1:8888/rss2sample.xml";

61. final FeedServiceAsync feedService = Registry

62. .get(RSSReaderConstants.FEED_SERVICE);

63. RpcProxy<PagingLoadResult<Item>> proxy = new

RpcProxy<PagingLoadResult<Item>>() {

64. @Override

65. protected void load(Object loadConfig,// loadConfig是GXT内部自动传入的

66. AsyncCallback<PagingLoadResult<Item>> callback) {

67. feedService.loadItems(TEST_DATA_FILE,

68. (PagingLoadConfig) loadConfig, callback);

69. }

70. };

71. // Loader:根据proxy,生成loader,因为返回的类型正好是PagingLoadResult,

不需要数据转换

72. PagingLoader<PagingLoadResult<Item>> loader = new

BasePagingLoader<PagingLoadResult<Item>>(

73. proxy);

74. // Store:

75. ListStore<ModelData> itemStore = new ListStore<ModelData>(loader);

76. // PagingToolBar:定义的时候需要传入分页大小

77. final PagingToolBar toolBar = new PagingToolBar(PAGE_SIZE);

78. toolBar.bind(loader);

79. // Grid:定义的时候,需要传入store和columnModel

80. Grid<ModelData> grid = new Grid<ModelData>(itemStore, columnModel);

81. grid.setBorders(true);

82. grid.setAutoExpandColumn("items");

83. loader.load();//此时的load应用了默认的PagingLoadConfig

84. // Grid不直接加入到LayoutContainer,而是Grid添加到ContentPanel,

ContentPanel添加到LayoutContainer

gxt gxt初学进阶教程

85. ContentPanel panel = new ContentPanel();

86. panel.setLayout(new FitLayout());

87. panel.add(grid);

88. panel.setHeaderVisible(false);

89. panel.setBottomComponent(toolBar);

90. add(panel);

91. }

92. }

? 最后把ItemPagingGrid添加到RssMainPanel里,显示出来。[www.61k.com]注释掉之前的

components

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.components; 2.

3. import com.danielvaughan.rssreader.client.grids.ItemPagingGrid;

4. import com.extjs.gxt.ui.client.widget.ContentPanel;

5. import com.extjs.gxt.ui.client.widget.layout.FitLayout; 6.

7. public class RssMainPanel extends ContentPanel {

8. public RssMainPanel() {

9. setHeading("Main");

10. setLayout(new FitLayout());

11. // add(new ItemGrid());

12. // add(new ItemCategoryGrid());

13. add(new ItemPagingGrid());

14. }

15. }

? 运行结果如下

gxt gxt初学进阶教程

? 如果想让Grid在加载数据的时候直接到第二页。(www.61k.com]可以使用:loader.load(2,

PAGE_SIZE);

? 只要绑定了(toolBar.bind(loader);)loader之后,其翻页操作不需要我们实

现,PagingToolBar内部已经实现好了。

GXT之旅:第五章:高级Components(4)——Menus

2012-02-07 11:48401人阅读评论(2)收藏举报

Menu component

? Menu是一个非常灵活的component,他可以显示一组菜单,创建的大致代

码如下:

[java] view plaincopyprint? 1. Menu contextMenu = new Menu(); 2.

gxt gxt初学进阶教程

contextMenu.add(new MenuItem("Option 1")); 3.

gxt gxt初学进阶教程

contextMenu.add(new MenuItem("Option 2"));

4. contextMenu.add(new MenuItem("Option 3"));

5. Label label = new Label("Menu appears here");

6. contextMenu.show(label);

gxt gxt初学进阶教程

? 当然一个Menu可以被添加到一个Button上,来作为该Button的额外选项:

[java] view plaincopyprint? 1. Menu contextMenu = new Menu(); 2. contextMenu.add(new MenuItem("Option 1"));

3. contextMenu.add(new MenuItem("Option 2"));

4. contextMenu.add(new MenuItem("Option 3")); 5. Button button = new Button("Menu");

6. button.setMenu(contextMenu);

gxt gxt初学进阶教程

? 当一个Menu有很多的Item,可以设置允许最大的高度(setMaxHeight),

让其超出的部分是可卷动的

[java] view plaincopyprint?

1. Menu contextMenu = new Menu();

2. for (int i = 1; i < 100; i++) {

3. contextMenu.add(new MenuItem("Option " + i));

4. }

5. contextMenu.setMaxHeight(200);

6. Button button = new Button("Menu");

7. button.setMenu(contextMenu);

gxt gxt初学进阶教程

gxt gxt初学进阶教程

MenuBar component

gxt gxt初学进阶教程

? 创建的Menu不单单可以添加到Button上,也可以添加到MenuBar 上。(www.61k.com)多

组Menu添加到MenuBar上,就很像左面程序的菜单。但是Menu创建之后,不能直接添加到MenuBar上,需要包装成MenuBarItem

[java] view plaincopyprint?

1. Menu menu1 = new Menu();

2. menu1.add(new MenuItem("Option 1"));

3. menu1.add(new MenuItem("Option 2"));

4. menu1.add(new MenuItem("Option 3"));

5. Menu menu2 = new Menu();

6. menu2.add(new MenuItem("Option 4"));

7. menu2.add(new MenuItem("Option 5"));

8. menu2.add(new MenuItem("Option 6"));

9. MenuBar menuBar = new MenuBar();

10. menuBar.add(new MenuBarItem("Menu 1", menu1));

11. menuBar.add(new MenuBarItem("Menu 2", menu2));

12. viewport.add(menuBar);

MenuItem component

gxt gxt初学进阶教程

? 下面详细介绍一个MenuItem:Menu就可以看成一个容器,用来包装

MenuItem,具体的显示效果还是通过MenuItem来设置的——text,icon等

[java] view plaincopyprint? 1. Menu menu1 = new Menu(); 2. menu1.add(new MenuItem("Option 1",Resources.ICONS.page()));

3. menu1.add(new MenuItem("Option 2",Resources.ICONS.page()));

4. menu1.add(new MenuItem("Option 3",Resources.ICONS.page()));

gxt gxt初学进阶教程

一个Menu可以被设置成另外一个Menu的子集,通过MenuItem的setSubMenu方法

[java] view plaincopyprint? ?

1. Menu menu1 = new Menu();

2. menu1.add(new MenuItem("Option 1",Resources.ICONS.page()));

3. menu1.add(new MenuItem("Option 2",Resources.ICONS.page()));

4. Menu menu2 = new Menu();

5. menu2.add(new MenuItem("Option 4"));

6. menu2.add(new MenuItem("Option 5"));

7. menu2.add(new MenuItem("Option 6"));

8. MenuItem miOption3 = new MenuItem("Option 3");

9. miOption3.setSubMenu(menu2);

10. menu1.add(miOption3);

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

CheckMenuItem component

CheckMenuItem继承了MenuItem,其功能是可以让menu的items被选中。(www.61k.com)

? 通过CheckMenuItem生成的Menu,代码如下:

[java] view plaincopyprint?

1. Menu menu = new Menu();

2. menu.add(new CheckMenuItem("Option 1"));

3. menu.add(new CheckMenuItem("Option 2"));

4. menu.add(new CheckMenuItem("Option 3"));

5. MenuBar menuBar = new MenuBar();

6. menuBar.add(new MenuBarItem("Menu", menu));

? 当然对于多选组件来说,当然支持分组。CheckMenuItem可以通过setGroup

方法进行分组,但是分组后的CheckMenuItem,则编程单选组件了。

gxt gxt初学进阶教程

MenuEvent

某个MenuItem被选中时,就会触发MenuEvent事件。[www.61k.com]就像一个Button被选中的时候,会触发ButtonEvent。

MenuItem可以添加SelectionListener监听选中事件。

[java] view plaincopyprint? 1. MenuItem menuItem = new MenuItem("Option1");

2. menuItem.addSelectionListener(new SelectionListener<MenuEvent>(){

3. @Override

4. public void componentSelected(MenuEvent ce) {

5. //Action goes here 6. }

7. });

目前为止,在我们RSSReader项目里面,RssNavigationPanel组件里添加了两个

buttons——Create feed 和Link feed。接下来我们要使用MenuBar替换他们,让这两个buttons呈现在一组菜单里面。因此我们期待的页面效果如下:

gxt gxt初学进阶教程

? 修改后的RssNavigationPanel类构造函数如下:

[java] view plaincopyprint? 1. public RssNavigationPanel() { 2.

gxt gxt初学进阶教程

setHeading("Navigation");

3. setLayout(new FitLayout());

4.

5. Menu menu = new Menu();

6. //Create feed

7. final MenuItem miCreateFeed = new MenuItem("Create feed");

8. miCreateFeed.setIconStyle("create-feed");

9. ToolTipConfig createNewToolTipConfig = new ToolTipConfig();

10. createNewToolTipConfig.setTitle("Create a new RSS feed");

gxt gxt初学进阶教程

11. createNewToolTipConfig

12. .setText("Creates a new RSS feed");

13. miCreateFeed.setToolTip(createNewToolTipConfig);

14. miCreateFeed.addSelectionListener(new

15. SelectionListener<MenuEvent>() {

16. @Override

17. public void componentSelected(MenuEvent me) {

18. createNewFeedWindow();

19. }

20. });

21. menu.add(miCreateFeed);

22.

23. //Link feed

24. final MenuItem miLinkFeed = new MenuItem("Link feed");

25. miLinkFeed.setIconStyle("link-feed");

26. ToolTipConfig linkFeedToolTipConfig = new ToolTipConfig();

27. linkFeedToolTipConfig.setTitle("Link to existing RSS feed");

28. linkFeedToolTipConfig

29. .setText("Allows you to enter the URL of an existing RSS feed you would

like to link to");

30. miLinkFeed.setToolTip(linkFeedToolTipConfig);

31. final LinkFeedPopup addFeedPopup = new LinkFeedPopup();

32. addFeedPopup.setConstrainViewport(true);

33. miLinkFeed.addSelectionListener(new SelectionListener<MenuEvent>()

34. {

35. @Override

36. public void componentSelected(MenuEvent me) {

37. addFeedPopup.show(miLinkFeed.getElement(), "tl-bl?");

38. }

39. });

40. menu.add(miLinkFeed);

41.

42. //menuBar

43. MenuBar menuBar = new MenuBar();

44. MenuBarItem menuBarItem = new MenuBarItem("Add feed", menu);

gxt gxt初学进阶教程

45. menuBar.add(menuBarItem);

46. setTopComponent(menuBar);

47.

48. add(new FeedList());

49. }

GXT之旅:第五章:高级Components(5)——ToolBar

分类: ExtGWT2012-02-07 14:48378人阅读评论(0)收藏举报 ToolBar component

ToolBar component不是我们传统意义上的buttons 或 menus。(www.61k.com)

先前我们RSSReader项目,RssNavigationPanel里面的buttons已经被替换成menus,接下来我们要是ToolBar展示更丰富的功能。ToolBar里不单单可以添加butons,而且甚至ComboBox或者Label都可以添加进来。

一个ContentPanel为toolbar提供了顶部或者底部的占位符。为了继续整理RSSReader项目里Create feed 和Link feed两个buttons,我们准备添加一个ToolBar,将他们整合起来。

? 在RssNavigatorPanel类里,新建一个方法initToolbar

[java] view plaincopyprint?

1. private void initToolbar() {

? 在方法的内,首先加入ToolBar的定义

[java] view plaincopyprint?

1. final ToolBar toolbar = new ToolBar();

? 新建一个button——Add feed,用于被添加到toolbar里。

[java] view plaincopyprint?

1. final Button btnAddFeed = new Button("Add feed");

2. btnAddFeed.setIconStyle("create-feed");

3. ToolTipConfig addFeedToolTipConfig = new ToolTipConfig();

gxt gxt初学进阶教程

4. addFeedToolTipConfig.setTitle("Add a new RSS feed");

5. addFeedToolTipConfig.setText("Adds a new RSS feed");

6. btnAddFeed.setToolTip(addFeedToolTipConfig);

? 新建一个Menu

[java] view plaincopyprint?

1. Menu menu = new Menu();

? 将Create feed button定义之后,添加到menu里

[java] view plaincopyprint? 1. final MenuItem miCreateFeed = new MenuItem("Create feed");

2. miCreateFeed.setIconStyle("create-feed");

3. ToolTipConfig createNewToolTipConfig = new ToolTipConfig();

4. createNewToolTipConfig.setTitle("Create a new RSS feed");

5. createNewToolTipConfig.setText("Creates a new RSS feed");

6. miCreateFeed.setToolTip(createNewToolTipConfig);

7. miCreateFeed.addSelectionListener(new SelectionListener<MenuEvent>() {

8. @Override

9. public void componentSelected(MenuEvent me) {

10. createNewFeedWindow();

11. }

12. });

13. menu.add(miCreateFeed);

? 同样的将Link feed button定义之后,添加到menu里

[java] view plaincopyprint?

1. final MenuItem miLinkFeed = new MenuItem("Link feed");

2. miLinkFeed.setIconStyle("link-feed");

3. ToolTipConfig linkFeedToolTipConfig = new ToolTipConfig();

4. linkFeedToolTipConfig.setTitle("Link to existing RSS feed");

5. linkFeedToolTipConfig

gxt gxt初学进阶教程

6. .setText("Allows you to enter the URL of an existing RSS feed you would like to link to");

7. miLinkFeed.setToolTip(linkFeedToolTipConfig);

8. final LinkFeedPopup addFeedPopup = new LinkFeedPopup();

9. addFeedPopup.setConstrainViewport(true);

10. miLinkFeed.addSelectionListener(new SelectionListener<MenuEvent>() {

11. @Override

12. public void componentSelected(MenuEvent me) {

13. addFeedPopup.show(miLinkFeed.getElement(), "tl-bl?");

14. }

15. });

16. menu.add(miLinkFeed);

? 层层添加,最后使之能显示出来。(www.61k.com]

[java] view plaincopyprint?

1. //set menu into button

2. btnAddFeed.setMenu(menu);

3. //set button into tollbar

4. toolbar.add(btnAddFeed);

5. //set toolbar into ContentPanel

6. setTopComponent(toolbar);

? 完整的RssNavigationPanel类,如下:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.components;

2.

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

4. import com.danielvaughan.rssreader.client.lists.FeedList;

5. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

6. import com.danielvaughan.rssreader.client.windows.FeedWindow;

7. import com.danielvaughan.rssreader.shared.model.Feed;

8. import com.extjs.gxt.ui.client.Registry;

9. import com.extjs.gxt.ui.client.event.MenuEvent;

gxt gxt初学进阶教程

10. import com.extjs.gxt.ui.client.event.SelectionListener;

11. import com.extjs.gxt.ui.client.widget.ContentPanel;

12. import com.extjs.gxt.ui.client.widget.Info;

13. import com.extjs.gxt.ui.client.widget.Window;

14. import com.extjs.gxt.ui.client.widget.button.Button;

15. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

16. import com.extjs.gxt.ui.client.widget.menu.Menu;

17. import com.extjs.gxt.ui.client.widget.menu.MenuItem;

18. import com.extjs.gxt.ui.client.widget.tips.ToolTipConfig;

19. import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;

20. import com.google.gwt.user.client.Element;

21. import com.google.gwt.user.client.rpc.AsyncCallback; 22.

23. public class RssNavigationPanel extends ContentPanel {

24. public RssNavigationPanel() {

25. setHeading("Navigation");

26. setLayout(new FitLayout());

27. initToolbar();

28. add(new FeedList());

29. }

30.

31. @Override

32. protected void onRender(Element parent, int pos) {

33. super.onRender(parent, pos);

34.

35.

36. }

37.

38. private void createNewFeedWindow() {

39. final FeedServiceAsync feedService = Registry

40. .get(RSSReaderConstants.FEED_SERVICE);

41. feedService.createNewFeed(new AsyncCallback<Feed>() {

42. @Override

43. public void onFailure(Throwable caught) {

44. Info.display("RSSReader", "Unable to create a new feed");

gxt gxt初学进阶教程

45. }

46.

47. @Override

48. public void onSuccess(Feed feed) {

49. final Window newFeedWindow = new FeedWindow(feed);

50. newFeedWindow.show();

51. }

52. });

53. }

54.

55. private void initToolbar() {

56. final ToolBar toolbar = new ToolBar();

57.

58. //btnAddFeed

59. final Button btnAddFeed = new Button("Add feed");

60. btnAddFeed.setIconStyle("create-feed");

61. ToolTipConfig addFeedToolTipConfig = new ToolTipConfig();

62. addFeedToolTipConfig.setTitle("Add a new RSS feed");

63. addFeedToolTipConfig.setText("Adds a new RSS feed");

64. btnAddFeed.setToolTip(addFeedToolTipConfig);

65. //miCreateFeed

66. Menu menu = new Menu();

67. final MenuItem miCreateFeed = new MenuItem("Create feed");

68. miCreateFeed.setIconStyle("create-feed");

69. ToolTipConfig createNewToolTipConfig = new ToolTipConfig();

70. createNewToolTipConfig.setTitle("Create a new RSS feed");

71. createNewToolTipConfig.setText("Creates a new RSS feed");

72. miCreateFeed.setToolTip(createNewToolTipConfig);

73. miCreateFeed.addSelectionListener(new SelectionListener<MenuEvent>() {

74. @Override

75. public void componentSelected(MenuEvent me) {

76. createNewFeedWindow();

77. }

78. });

79. menu.add(miCreateFeed);

gxt gxt初学进阶教程

80. //miLinkFeed

81. final MenuItem miLinkFeed = new MenuItem("Link feed");

82. miLinkFeed.setIconStyle("link-feed");

83. ToolTipConfig linkFeedToolTipConfig = new ToolTipConfig();

84. linkFeedToolTipConfig.setTitle("Link to existing RSS feed");

85. linkFeedToolTipConfig

86. .setText("Allows you to enter the URL of an existing RSS feed you would

like to link to");

87. miLinkFeed.setToolTip(linkFeedToolTipConfig);

88. final LinkFeedPopup addFeedPopup = new LinkFeedPopup();

89. addFeedPopup.setConstrainViewport(true);

90. miLinkFeed.addSelectionListener(new SelectionListener<MenuEvent>() {

91. @Override

92. public void componentSelected(MenuEvent me) {

93. addFeedPopup.show(miLinkFeed.getElement(), "tl-bl?");

94. }

95. });

96. menu.add(miLinkFeed);

97. //set menu into button

98. btnAddFeed.setMenu(menu);

99. //set button into tollbar

100.

101.

102.

103.

104. toolbar.add(btnAddFeed); //set toolbar into ContentPanel setTopComponent(toolbar); } }

? 运行效果入下:

gxt gxt初学进阶教程

gxt gxt初学进阶教程

GXT之旅:第五章:高级

gxt gxt初学进阶教程

Components(6)——TabPanel,Status大概介绍

分类: ExtGWT2012-02-07 15:48444人阅读评论(0)收藏举报

TabPanel

TabPanel 继承 Container,作为可以容器,可以负责显示和管理TabItem 对象集。(www.61k.com)TabItem 对象集可以方法被add或remove。每一个TabItem都有一个id,用来通过findItem方法来获得其对象。通过setSelectedItem方法可是设置一个TabItem呈现被选中状态。通过getSelectedItem方法可以获得当前没选中的TabItem。

TabItem

TabItem 继承 LayoutContainer。当一个TabItem被添加到一个TabPanel时,可以被closed,disabled,同时在头部支持显示一个icon。

Status component

Status一般和ToolBar结合使用,用来作为一个状态栏,这种功能很类似一些桌面程序。 接下来,会在RSSReader项目里,初步的加入涉及到的功能,但是后面的章节会详细介绍。

gxt gxt初学进阶教程

? 在RssMainPanel在构造函数里面,回滚到添加ItemGrid的时候。(www.61k.com]

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.components; 2.

3. import com.danielvaughan.rssreader.client.grids.ItemGrid; 4. import com.extjs.gxt.ui.client.widget.ContentPanel; 5. import com.extjs.gxt.ui.client.widget.layout.FitLayout; 6.

7. public class RssMainPanel extends ContentPanel {

8. public RssMainPanel() {

9. setHeading("Main");

10. setLayout(new FitLayout());

11. add(new ItemGrid());

12. // add(new ItemCategoryGrid());

13. // add(new ItemPagingGrid());

14. }

15. }

? 在RssMainPanel构造函数的尾端,新建一个ToolBar

[java] view plaincopyprint?

1. ToolBar toolBar = new ToolBar();

? 紧接着,新建一个Status

[java] view plaincopyprint?

1. Status status = new Status();

2. status.setWidth(150);

? 使用Status.setBox方法设置其显示的边框状态,然后初始化其状态的内容是

OK

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. status.setBox(true);

2. status.setText("OK"); ? 将status放入到toolBar里面,将toolBar放入到ContentPanel底部

[java] view plaincopyprint?

1. toolBar.add(status);

2. setBottomComponent(toolBar);

gxt gxt初学进阶教程

GXT之旅:第六章:Templates(1)——Template(1)

gxt gxt初学进阶教程

分类: ExtGWT2012-02-07 17:39469人阅读评论(0)收藏举报

第六章:Templates

本章我们要了解Templates,以及学习他们是如何方便我们去自定义数据的格式化和显示。[www.61k.com]我们也会详细了解XTemplates的丰富功能

本章,我们会涉及到如下GXt功能集

?

?

?

?

?

? Template XTemplate RowExpander ListView ModelProcessor CheckBoxListView 之前的章节,我们学习了data-backed components 使用ModelData objects 如何自动的加载数据的。我们是通过指定其使用ModelData里面的某一列,作为显示内容。但是如果我们希望显示的内容不仅仅是一列,我们要怎么办?比如,如果我们有一个ModelData对象,里面有两列内容——first name和last name,但是我们希望显示的时候是full name(first name+last name)。

当然GXT会想到这样的问题,并且提供了连个解决方案。第一:ModelProcessor可以预加工ModelData,定义出一个新的列(以后会讲到)。第二种就是使用Template。

首先,我们要做一些准备工作,在Feed和Item类里面加入更多的fields,并在后端的server方法里面灌入数据——以供给Template使用。

? Feed类中,加入两个新的fields:imageUrl,存储图片的url;items用来存

储Item集合。当然别忘了setter和getter方法

[java] view plaincopyprint?

1. private String imageUrl;

2. private List<Item> items = new ArrayList<Item>();

? Item类加入publication和thumbnailUrl。因为是直接继承的BaseModel,所

以注意getter和setter方法的书写:

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. package com.danielvaughan.rssreader.shared.model; 2.

3. import java.util.Date;

4.

5. import com.extjs.gxt.ui.client.data.BaseModel; 6.

7. @SuppressWarnings("serial")

8. public class Item extends BaseModel {

9.

10. public Item() {

11.

12. }

13.

14. public String getCategory() {

15. return get("category");

16. }

17.

18. public String getDescription() {

19. return get("description");

20. }

21.

22. public String getLink() {

23. return get("link");

24. }

25.

26. public Date getPubDate() {

27. return get("pubDate");

28. }

29.

30. public String getThumbnailUrl() {

31. return get("thumbnailUrl");

32. }

33.

34. public String getTitle() {

35. return get("title");

gxt gxt初学进阶教程

36. }

37. 38. public void setCategory(String category) {

39. set("category", category);

40. }

41. 42. public void setDescription(String description) {

43. set("description", description);

44. }

45.

46. public void setLink(String link) {

47. set("link", link);

48. }

49.

50. public void setPubDate(Date pubDate) {

51. set("pubDate", pubDate);

52. }

53.

54. public void setThumbnailUrl(String thumbnailUrl) {

55. set("thumbnailUrl", thumbnailUrl);

56. }

57.

58. public void setTitle(String title) {

59. set("title", title);

60. }

61. }

? FeedService接口里修改原来无参数的loadFeedList()方法,为

[java] view plaincopyprint?

1. List<Feed> loadFeedList(boolean loadItems); ? 别忘了在FeedServiceAsync修改对应的回调方法

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. void loadFeedList(boolean loadItems, AsyncCallback<List<Feed>> 2. callback);

? FeedServiceImpl类里,通过修改loadFeedList()为loadFeedList(boolean

loadItems),实现其抽象方法。[www.61k.com)

[java] view plaincopyprint? 1. @Override

2. public List<Feed> loadFeedList(boolean loadItems)) {

3. feeds.clear();

4. Set<String> feedUrls = persistence.loadFeedList();

5. for (String feedUrl : feedUrls) {

6. feeds.put(feedUrl, loadFeed(feedUrl,loadItems)));

7. }

8. return new ArrayList<Feed>(feeds.values());

9. }

? 修改FeedServiceImpl.loadFeed方法,加入新的loadItems参数。具体实现

如下:

[java] view plaincopyprint? 1. private Feed loadFeed(String feedUrl, boolean loadItems) {

2. Feed feed = new Feed(feedUrl);

3. try {

4. SAXBuilder parser = new SAXBuilder();

5. Document document = parser.build(new URL(feedUrl));

6. Element eleRoot = document.getRootElement();

7. Element eleChannel = eleRoot.getChild("channel");

8. feed.setTitle(eleChannel.getChildText("title"));

9. feed.setDescription(eleChannel.getChildText("description"));

10. feed.setLink(eleChannel.getChildText("link"));

11. Element eleImage = eleChannel.getChild("image");

12. feed.setImageUrl("");

13. if (eleImage != null) {

14. Element eleUrl = eleImage.getChild("url");

gxt gxt初学进阶教程

15. if (eleUrl != null) {

16. feed.setImageUrl(eleUrl.getText());

17. }

18. }

19. if (loadItems) {

20. feed.setItems(loadItems(feedUrl));

21. }

22. return feed;

23. } catch (IOException e) {

24. LOGGER.log(Level.SEVERE, "IO Error loading feed", e);

25. return feed;

26. } catch (JDOMException e) {

27. LOGGER.log(Level.SEVERE, "Error parsing feed", e); 28. return feed;

29. }

30. }

? 牵扯到引用loadFeed方法的相关方法修改。[www.61k.com)

[java] view plaincopyprint?

1. @Override

2. public void addExistingFeed(String feedUrl) {

3. Feed loadResult = loadFeed(feedUrl, false);

4. if (loadResult.getTitle() != null) {

5. feeds.put(feedUrl, loadResult);

6. persistence.saveFeedList(feeds.keySet());

7. }

8. }

? 相应的loadItems方法也要修改,

[java] view plaincopyprint?

1. @Override

2. @SuppressWarnings("unchecked")

3. public List<Item> loadItems(String feedUrl) {

gxt gxt初学进阶教程

4. List<Item> items = new ArrayList<Item>();

5. try {

6. SAXBuilder parser = new SAXBuilder();

7. Document document = parser.build(new URL(feedUrl));

8. Element eleRoot = document.getRootElement();

9. Element eleChannel = eleRoot.getChild("channel");

10. List<Element> itemElements = eleChannel.getChildren("item");

11. for (Element eleItem : itemElements) {

12. Item item = new Item();

13. item.setTitle(eleItem.getChildText("title"));

14. item.setDescription(eleItem.getChildText("description"));

15. item.setLink(eleItem.getChildText("link"));

16. item.setCategory(eleItem.getChildText("category"));

17. Namespace ns = Namespace.getNamespace("media",

18. "http://search.yahoo.com/mrss/");

19. Element eleThumbnail = eleItem.getChild("thumbnail", ns);

20. if (eleThumbnail != null) {

21. item.setThumbnailUrl(eleThumbnail.getAttributeValue("url"));

22. }

23. String pubDateStr = eleItem.getChildText("pubDate");

24. if (pubDateStr != null) {

25. try {

26. DateFormat df = new SimpleDateFormat(

27. "EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z");

28. item.setPubDate(df.parse(pubDateStr));

29. } catch (ParseException e) {

30. item.setPubDate(null);

31. }

32. }

33. items.add(item);

34. }

35. return items;

36. } catch (IOException e) {

37. e.printStackTrace();

38. return items;

gxt gxt初学进阶教程

39.

40. } catch (JDOMException e) {

41. e.printStackTrace();

42. return items;

43. }

44. }

? 最后,在FeedList的onRender方法里,修改为新的service方调用

[java] view plaincopyprint?

1. protected void load(Object loadConfig, AsyncCallback<List<Feed>>

2. callback) {

3. feedService.loadFeedList(false, callback);

4. }

? 目前为止,准备工作已经完成,下一章会在此数据结构的基础之上使用

Template

? 修改后完整的FeedServiceImpl类如下:

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.server.services;

2.

3. import java.io.IOException;

4. import java.net.URL;

5. import java.text.DateFormat;

6. import java.text.ParseException;

7. import java.text.SimpleDateFormat;

8. import java.util.ArrayList;

9. import java.util.List;

10. import java.util.Map;

11. import java.util.Set;

12. import java.util.UUID;

13. import java.util.logging.Level;

14. import java.util.logging.Logger;

gxt gxt初学进阶教程

15.

16. import org.jdom.Attribute;

17. import org.jdom.Document;

18. import org.jdom.Element;

19. import org.jdom.JDOMException;

20. import org.jdom.Namespace;

21. import org.jdom.input.SAXBuilder;

22.

23. import com.danielvaughan.rssreader.client.services.FeedService;

24. import com.danielvaughan.rssreader.server.utils.FilePersistence;

25. import com.danielvaughan.rssreader.server.utils.Persistence;

26. import com.danielvaughan.rssreader.shared.model.Category;

27. import com.danielvaughan.rssreader.shared.model.Feed;

28. import com.danielvaughan.rssreader.shared.model.Item;

29. import com.extjs.gxt.ui.client.data.BasePagingLoadResult;

30. import com.extjs.gxt.ui.client.data.ModelData;

31. import com.extjs.gxt.ui.client.data.PagingLoadConfig;

32. import com.extjs.gxt.ui.client.data.PagingLoadResult;

33. import com.google.gwt.dev.util.collect.HashMap;

34. import com.google.gwt.user.server.rpc.RemoteServiceServlet; 35.

36. @SuppressWarnings("serial")

37. public class FeedServiceImpl extends RemoteServiceServlet implements

38. FeedService {

39.

40. private final static Logger LOGGER =

Logger.getLogger(FeedServiceImpl.class

41. .getName());

42.

43. private Map<String, Feed> feeds = new HashMap<String, Feed>(); 44.

45. private final Persistence persistence = new FilePersistence(); 46.

47. @Override

48. public void addExistingFeed(String feedUrl) {

gxt gxt初学进阶教程

49. Feed loadResult = loadFeed(feedUrl, false);

50. if (loadResult.getTitle() != null) {

51. feeds.put(feedUrl, loadResult);

52. persistence.saveFeedList(feeds.keySet());

53. }

54. }

55.

56. @Override

57. public Feed createNewFeed() {

58. UUID uuid = UUID.randomUUID();

59. return new Feed(uuid.toString());

60. }

61.

62. private PagingLoadResult<Item> getPagingLoadResult(List<Item> items,

63. PagingLoadConfig config) {

64. List<Item> pageItems = new ArrayList<Item>();

65. int offset = config.getOffset();

66. int limit = items.size();

67. if (config.getLimit() > 0) {

68. limit = Math.min(offset + config.getLimit(), limit);

69. }

70. for (int i = config.getOffset(); i < limit; i++) {

71. pageItems.add(items.get(i));

72. }

73. return new BasePagingLoadResult<Item>(pageItems, offset, items.size()); 74.

75. }

76.

77. @Override

78. public List<ModelData> loadCategorisedItems(String feedUrl,

79. Category category) {

80. List<Item> items = loadItems(feedUrl);

81. Map<String, List<Item>> categorisedItems = new HashMap<String,

List<Item>>();

82. for (Item item : items) {

gxt gxt初学进阶教程

83. String itemCategoryStr = item.getCategory();

84. if (itemCategoryStr == null) {

85. itemCategoryStr = "Uncategorised";

86. }

87. List<Item> categoryItems = categorisedItems.get(itemCategoryStr);

88. if (categoryItems == null) {

89. categoryItems = new ArrayList<Item>();

90. }

91. categoryItems.add(item);

92. categorisedItems.put(itemCategoryStr, categoryItems);

93. }

94. if (category == null) {

95. List<ModelData> categoryList = new ArrayList<ModelData>();

96. for (String key : categorisedItems.keySet()) {

97. categoryList.add(new Category(key));

98. }

99. return categoryList;

100.

101.

102.

103.

104.

105.

106.

107.

108.

109.

110.

111.

112.

113.

114.

115.

116.

117. } else { return new ArrayList<ModelData>(categorisedItems.get(category .getTitle())); } } private Feed loadFeed(String feedUrl, boolean loadItems) { Feed feed = new Feed(feedUrl); try { SAXBuilder parser = new SAXBuilder(); Document document = parser.build(new URL(feedUrl)); Element eleRoot = document.getRootElement(); Element eleChannel = eleRoot.getChild("channel"); feed.setTitle(eleChannel.getChildText("title")); feed.setDescription(eleChannel.getChildText("description")); feed.setLink(eleChannel.getChildText("link")); Element eleImage = eleChannel.getChild("image"); feed.setImageUrl("");

gxt gxt初学进阶教程

118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151.

152. if (eleImage != null) { Element eleUrl = eleImage.getChild("url"); if (eleUrl != null) { feed.setImageUrl(eleUrl.getText()); } } if (loadItems) { feed.setItems(loadItems(feedUrl)); } return feed; } catch (IOException e) { LOGGER.log(Level.SEVERE, "IO Error loading feed", e); return feed; } catch (JDOMException e) { LOGGER.log(Level.SEVERE, "Error parsing feed", e); return feed; } } @Override public List<Feed> loadFeedList(boolean loadItems) { feeds.clear(); Set<String> feedUrls = persistence.loadFeedList(); for (String feedUrl : feedUrls) { feeds.put(feedUrl, loadFeed(feedUrl, loadItems)); } return new ArrayList<Feed>(feeds.values()); } @Override @SuppressWarnings("unchecked") public List<Item> loadItems(String feedUrl) { List<Item> items = new ArrayList<Item>(); try { SAXBuilder parser = new SAXBuilder();

gxt gxt初学进阶教程

153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186.

187. Document document = parser.build(new URL(feedUrl)); Element eleRoot = document.getRootElement(); Element eleChannel = eleRoot.getChild("channel"); List<Element> itemElements = eleChannel.getChildren("item"); for (Element eleItem : itemElements) { Item item = new Item(); item.setTitle(eleItem.getChildText("title")); item.setDescription(eleItem.getChildText("description")); item.setLink(eleItem.getChildText("link")); item.setCategory(eleItem.getChildText("category")); Namespace ns = Namespace.getNamespace("media", "http://search.yahoo.com/mrss/"); Element eleThumbnail = eleItem.getChild("thumbnail", ns); if (eleThumbnail != null) { item.setThumbnailUrl(eleThumbnail.getAttributeValue("url")); } String pubDateStr = eleItem.getChildText("pubDate"); if (pubDateStr != null) { try { DateFormat df = new SimpleDateFormat( "EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z"); item.setPubDate(df.parse(pubDateStr)); } catch (ParseException e) { item.setPubDate(null); } } items.add(item); } return items; } catch (IOException e) { e.printStackTrace(); return items; } catch (JDOMException e) { e.printStackTrace();

gxt gxt初学进阶教程

188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221.

222. return items; } } @Override public PagingLoadResult<Item> loadItems(String feedUrl, PagingLoadConfig config) { List<Item> items = loadItems(feedUrl); return getPagingLoadResult(items, config); } @Override public void saveFeed(Feed feed) { Element eleRoot = new Element("rss"); eleRoot.setAttribute(new Attribute("version", "2.0")); // Create a document from the feed object Document document = new Document(eleRoot); Element eleChannel = new Element("channel"); Element eleTitle = new Element("title"); Element eleDescription = new Element("description"); Element eleLink = new Element("link"); eleTitle.setText(feed.getTitle()); eleDescription.setText(feed.getDescription()); eleLink.setText(feed.getLink()); eleChannel.addContent(eleTitle); eleChannel.addContent(eleDescription); eleChannel.addContent(eleLink); eleRoot.addContent(eleChannel); persistence.saveFeedXml(feed.getUuid(), document);

gxt gxt初学进阶教程

223.

224.

225. addExistingFeed(persistence.getUrl(feed.getUuid())); } } GXT之旅:第六章:Templates(1)——Template(2)

分类: ExtGWT2012-02-09 16:29484人阅读评论(0)收藏举报

Template

通过使用Template类,可以定义一组html的字符串去渲染ModelData或者Params。[www.61k.com]其生成的html 字符串里面可以设置占位符,要来作为变量可以设置参数。

一个占位符参数的定义,需要通过{}给包裹起来。一个使用firstName和lastName定义的Template如下:

[java] view plaincopyprint?

1. Template template = new Template("My full name is {firstName}

{lastName}.");

接下来,我们需要Params给占位符参数设值

[java] view plaincopyprint?

1. Params data = new Params();

2. data.set("firstName", "Daniel");

3. data.set("lastName", "Vaughan");

最后,让template应用data(Params)的值域,需要通过applyTemplate方法

[java] view plaincopyprint?

1. template.applyTemplate(data);

Template可以被预编译,这样就可以节约头期使用正规表达式的时间。实现此功能需要调用Template.compile方法。

在RSSReader项目里,我们要自定义组件——ItemPanel 用来使用Template将一个对象渲染成html。

? 在com.danielvaughan.rssreader.client.components包下,新建ItemPanel

extends ContentPanel

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.components;

2. 3. import com.extjs.gxt.ui.client.widget.ContentPanel;

4.

5. public class ItemPanel extends ContentPanel {

6.

7. }

? 新建一个属性——GWT的HTML widget

[java] view plaincopyprint?

1. private final HTML html = new HTML();

? 当然要override onRender方法——设置标题,并将HTMl加入到

ContentPanel里

[java] view plaincopyprint? 1. @Override 2. protected void onRender(Element parent, int index) {

3. super.onRender(parent, index);

4. setHeading("Item");

5. add(html);

6. }

? 继续在onRender方法里——因为我们希望让ContentPanel能够自适应

HTML widget的大小,所以要设置成FitLayout布局方式。(www.61k.com]当然我们同样的希望设置HTML widget应用一个CSS style,这样我们就可以编辑其样式,来设置HTML的显示方式:

[java] view plaincopyprint?

1. @Override

2. protected void onRender(Element parent, int index) {

3. super.onRender(parent, index);

gxt gxt初学进阶教程

4. setHeading("Item");

5. setLayout(new FitLayout());

6. html.setStylePrimaryName("item");

7. add(html);

8. }

? 接下来,我们构造template的字符串——Template接收的是一个String类

型的字符串,我们可以使用java标准的StringBuilder类来生成String。[www.61k.com)我们将占位符参数通过大括号包裹起来。

[java] view plaincopyprint? 1. private String getTemplate() {

2. StringBuilder sb = new StringBuilder();

3. sb.append("<h1>{title}</h1>");

4. sb.append("<p><i>{pubDate}</i></p>");

5. sb.append("<hr/>");

6. sb.append("<img src=\"{thumbnailUrl}\"/>");

7. sb.append("<p>{description}</p>");

8. return sb.toString();

9. }

? 新建一个方法displayItem——它会有一个参数为Item。将Item对象里面属

性存储的值,赋值给template的占位符,根据item的属性名称和template里占位符的属性名称一一对应。此操作GXT已经给我们提供了Util类,具体实现如下:

[java] view plaincopyprint?

1. public void displayItem(Item item) {

2.

3. setHeading(item.getTitle());

4. Template template = new Template(getTemplate());

5. html.setHTML(template.applyTemplate(Util.getJsObject(item, 1)));

6. }

gxt gxt初学进阶教程

? 下面在程序的入口html文件里(RSSReader.html),引用新建的css文件

(css/item.css)

[java] view plaincopyprint?

1. <link type="text/css" rel="stylesheet" href="css/item.css"> ? 在item.css样式文件里,定义相关其template设置的html标记的样式。(www.61k.com]

[css] view plaincopyprint? 1. .item h1 {

2. font-size: 1.5em;

3. }

4.

5. .item img {

6. border: 1px solid #000;

7. float: left;

8. margin-right: 10px; 9. }

10.

11. .item hr {

12. border-bottom: 1px solid #000;

13. }

? 我们现在需要新建一个测试类去实验,让ItemPanel显示item对象的

template。在com.danielvaughan.rssreader.client包下,新建TestObjects类,具体实现如下:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client;

2.

3. import java.util.Date;

4.

5. import com.danielvaughan.rssreader.shared.model.Item;

6.

7. public class TestObjects {

gxt gxt初学进阶教程

8. public static Item getTestItem() {

9. Item testItem = new Item();

10. testItem.setTitle("Computers get more powerful");

11. testItem

12. .setDescription("New computers are more powerful "

13. + "than the computers that were around a year ago. "

14. + "They are also much more powerful than the computers from five years ago.

"

15. + "If you were to compare current computers with the computers of twenty

"

16. + "years ago you would fine they are far more powerful.");

17. testItem.setLink("");

18. testItem.setPubDate(new Date());

19. testItem.setCategory("Category");

20. testItem

21. .setThumbnailUrl("http://localhost:8888/computers.jpg");

22. return testItem;

23. }

24. }

? 在RSSReader类里,将ItemPanel替换RssMainPanel

[java] view plaincopyprint?

1. //RssMainPanel mainPanel = new RssMainPanel();

2. ItemPanel mainPanel = new ItemPanel();

3. mainPanel.displayItem(TestObjects.getTestItem());

? 显示效果如下:

gxt gxt初学进阶教程

在其他components里使用Templates

不单单HTML widget可以使用Template,其他的components也可以使用Template去定义HTML。(www.61k.com)具体来说,ListField,ComboBox,ToolTipConfig都可以使用Template。 当我们使用ListField或ComboBox的时候,

gxt gxt初学进阶教程

Template的使用是去定义其里面的列表item。例如,使用Template定义多个fields的组合显示,去替换ListField里面的单一的field显示。但是要注意,因为ListField或ComboBox里面都是使用ModelData的结果集,因此需要针对每一个item设置其Template。

Template有一个专门的标签<tpl>,此标记提供一个方法去迭代list组件里面每一个item的,并赋予其template。在了解XTemplate之前,我们会详细了解<tpl>标记的使用。

随着时间的推移,我们会不断的修改RSSReader项目里面FeedList类,让其显示Feed对象里name和部分description内容,取代之前仅仅是显示name字段。虽然我们使用ListField举例,但是其操作过程同样应用与ComboBox component。

? 我们在FeedList类里面,定义一个getTemplate方法,用来返回Template形式的字符串

? 在此方法里,我们需要使用<tpl>用于加工store里面的每个ModelData。

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. private String getTemplate() {

2. StringBuilder sb = new StringBuilder();

3. sb.append("<tpl for=\".\">");

4. sb.append("</tpl>");

5. return sb.toString();

6. }

? 在<tpl>标记之间,我们使用<div>标签来包裹这每一行的显示效果,其css

style设置成“x-combo-list-item”

[java] view plaincopyprint?

1. private String getTemplate() {

2. StringBuilder sb = new StringBuilder();

3. sb.append("<tpl for=\".\">"); 4. sb.append("<div class='x-combo-list-item'><b>{title}</b> -{description}</div>");

5. sb.append("</tpl>");

6. return sb.toString();

7. }

? ListField同样提供setTemplate方法——在FeedList类中,onRender方法

内,替换setDisplayField方法。(www.61k.com)

[java] view plaincopyprint?

1. //feedList.setDisplayField("title");

2. feedList.setTemplate(getTemplate());

? 修改后的整个FeedList类如下:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.lists;

gxt gxt初学进阶教程

2.

3. import java.util.List;

4.

5. import com.danielvaughan.rssreader.client.RSSReaderConstants;

6. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

7. import com.danielvaughan.rssreader.shared.model.Feed;

8. import com.extjs.gxt.ui.client.Registry;

9. import com.extjs.gxt.ui.client.data.BaseListLoader;

10. import com.extjs.gxt.ui.client.data.BeanModel;

11. import com.extjs.gxt.ui.client.data.BeanModelReader;

12. import com.extjs.gxt.ui.client.data.ListLoadResult;

13. import com.extjs.gxt.ui.client.data.ListLoader;

14. import com.extjs.gxt.ui.client.data.LoadEvent;

15. import com.extjs.gxt.ui.client.data.RpcProxy;

16. import com.extjs.gxt.ui.client.event.LoadListener;

17. import com.extjs.gxt.ui.client.store.ListStore;

18. import com.extjs.gxt.ui.client.widget.LayoutContainer;

19. import com.extjs.gxt.ui.client.widget.form.ListField;

20. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

21. import com.google.gwt.user.client.Element;

22. import com.google.gwt.user.client.rpc.AsyncCallback;

23.

24. public class FeedList extends LayoutContainer {

25. private final ListStore<BeanModel> feedStoreR = Registry

26. .get(RSSReaderConstants.FEED_STORE);

27.

28. public FeedList() {

29. setLayout(new FitLayout());

30. }

31.

32. private String getTemplate() {

33. StringBuilder sb = new StringBuilder();

34. sb.append("<tpl for=\".\">");

35. sb.append("<div class='x-combo-list-item'><b>{title}</b>

-{description}</div>");

gxt gxt初学进阶教程

36. sb.append("</tpl>");

37. return sb.toString();

38. }

39.

40. @Override

41. protected void onRender(Element parent, int index) {

42. super.onRender(parent, index);

43. final ListField<BeanModel> feedList = new ListField<BeanModel>();

44. // 0:从Registry里获得Service

45. final FeedServiceAsync feedService = (FeedServiceAsync) Registry

46. .get(RSSReaderConstants.FEED_SERVICE);

47. // 1:定义proxy在load方法里掉用Serivce里的方法

48. RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {

49. @Override

50. protected void load(Object loadConfig,

51. AsyncCallback<List<Feed>> callback) {

52. feedService.loadFeedList(false, callback);

53.

54. }

55. };

56. // 2:定义Reader

57. BeanModelReader reader = new BeanModelReader();

58. // 3:将proxy和reader传入,定义loader

59. ListLoader<ListLoadResult<BeanModel>> loader = new

BaseListLoader<ListLoadResult<BeanModel>>(

60. proxy, reader);

61. // 4:传入loader,生成store,此时还没有load数据

62. final ListStore<BeanModel> feedStore = new ListStore<BeanModel>(loader);

63. // 5:将stroe绑定到data-backed component身上

64. feedList.setStore(feedStoreR);

65. //feedList.setDisplayField("title");

66. feedList.setTemplate(getTemplate());

67. // 6:真正的load数据,load成功之后,data-backed component会自动的显示出来。(www.61k.com]

68. loader.load();

69.

gxt gxt初学进阶教程

70. loader.addLoadListener(new LoadListener() {

71. @Override

72. public void loaderLoad(LoadEvent le) {

73. feedStoreR.add(feedStore.getModels());

74.

75. }

76. });

77.

78. add(feedList);

79. }

80. }

? 运行效果如下:

gxt gxt初学进阶教程

GXT之旅:第六章:Templates(2)——XTemplate(1)

分类:ExtGWT2012-02-23 09:57447人阅读评论(0)收藏举报

XTemplate

XTemplate比Template更为有用,除了拥有Template相同的功能之外,还具有更多有用的功能——提供使用更多的<tpl>标记来满足自己需要的html显示效果。(www.61k.com]

为了下面例子的引用,首先,定义一个Person的ModalData

[java] view plaincopyprint?

1. public class Person extends BaseModel {

2. public Person(String firstName,String lastName) {

3. set("firstName", firstName);

4. set("lastName", lastName);

gxt gxt初学进阶教程

5. }

6. }

For 功能 ? 首先,让我们深入了解一下上一个例子中我们所使用的for。(www.61k.com)首先我们先第一

个friends的list

[java] view plaincopyprint? 1. List<Person> friends = Arrays.asList(new Person("Fred", "Bloggs"),

2. new Person("John", "Smith"));

? <tpl>标签的for操作符,可以迭代friends里面的每一个item,并赋予template。

字符“.”说明了,template会加工处理friends里面的每一个item

[html] view plaincopyprint? 1. <tpl for="."> 2. <p>{firstName} {lastName}</p>

3. </tpl>

? 将friends应用了如上的template的时候,template会自动的根据占位符变

量名去寻找friends的每一个对象里面的值。运行的结果大致如下:

Fred Bloggs

John Smith

? 在friends的基础之上,我们再新建一个person对象,用来存储friends

[java] view plaincopyprint?

1. Person person = new Person("Daniel", "Vaughan");

2. person.set("friends", friends);

? 现在我们要加工person的内容,并且加工person里面存储的friends内容的

话,我们的template的定义应该如下(此时在看看for操作符后面的变化)

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. <p>{firstName} {lastName}'s friends:</p>

2. <ul>

3. <tpl for="friends">

4. <li>{firstName} {lastName}</li>

5. </tpl>

6. </ul>

Daniel Vaughan's friends:

?

? Fred Bloggs John Smith

?

? 运行结果如上。[www.61k.com) 习惯上来说,我们一般自定义一个方法,来设置template的string,自然的

getTemplate()方法命名跟直观易懂一些。

[java] view plaincopyprint? 1. private String getTemplate() {

2. StringBuilder sb = new StringBuilder();

3. sb.append("<p>{firstName} {lastName}'s friends</p>");

4. sb.append("<ul>");

5. sb.append("<tpl for=\"friends\">");

6. sb.append("<li>{firstName} {lastName}</li>");

7. sb.append("</tpl>");

8. sb.append("</ul>");

9. return sb.toString();

10. }

? template的创建和数据应用如下

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. XTemplate xTemplate = XTemplate.create(getTemplate());

2. String html = template.applyTemplate(Util.getJsObject(person, 2));

? 注意Util.getJsObject方法参数的含义,person是指应用template的属于;2

是指person数据挖掘的深度

if 功能

<tpl>标记,同样有if功能的操作符,使用于按条件处理的情况。(www.61k.com)

? 让我们在Person ModelData里加入age字段

[java] view plaincopyprint? 1. public class Person extends BaseModel {

2. public Person(String firstName,String lastName, int age) {

3. set("firstName", firstName);

4. set("lastName", lastName);

5. set("age", age);

6. }

7. }

? 在此Person的结构下,定义一个新的friends list

[java] view plaincopyprint? 1. List<Person> friends = Arrays.asList(new Person("Fred", "Bloggs",

2. 20), new Person("John", "Smith", 40));

3. Person person = new Person("Daniel", "Vaughan", 30);

4. person.set("friends", friends);

? 我们在定义template string的时候,使用if操作符,限定age大于30的friends

数据才会被html渲染出来

[html] view plaincopyprint?

gxt gxt初学进阶教程

1. <p>{firstName} {lastName}'s friends over 30:</p>

2. <ul> 3. <tpl for="friends">

4. <tpl if="age > 30">

5. <li>{firstName} {lastName}</li>

6. </tpl>

7. </tpl>

8. </ul>

? 将上面的friends和template应用在一起之后,显示的内容如下

Daniel Vaughan's friends over 30:

? John Smith

? 注意,if操作符后面的大于符号使用的是> 下面是一个列表介绍不同的操

作符的

gxt gxt初学进阶教程

? 注意:在<tpl>标记里没有else操作符,如果想实现else的语句跳转,我们

可以使用if的相反条件判断。(www.61k.com]

? if比较表达式,支持使用ModelData的field。比如之前的比较表达式是年龄

大于30,我们可以替换为年龄大于person对象里面age属性的值。我们可以这样定义template

[html] view plaincopyprint?

1. <p>{firstName} {lastName}'s friends over {age}:</p>

2. <ul>

3. <tpl for="friends">

gxt gxt初学进阶教程

4. <tpl if="age > parent.age">

5. <li>{firstName} {lastName}</li>

6. </tpl>

7. </tpl>

8. </ul>

? 注意,firstName不可以命名成first-name。(www.61k.com]不要使用连字号。

支持简单的数学运算

在Template中,支持简单的数学运算。

比如我们希望age的属性加1,那么可以写成{age+1}。

如果我们希望显示的friends的age要大于person的age的话,我们可以如下定义template

[java] view plaincopyprint?

1. <p>{firstName} {lastName}'s friends over {age}:</p>

2. <ul>

3. <tpl for="friends">

4. <tpl if="age > parent.age">

5. <li>{firstName} {lastName} ({age}-{parent.age} years older)</li>

6. </tpl>

7. </tpl>

GXT之旅:第六章:Templates(2)——XTemplate(2)

分类: ExtGWT2012-03-06 14:33482人阅读评论(0)收藏举报

XTemplate应用于其他的components

除了ComboBox和ListField之外,还有其他的一些components可以使用XTemplate

?

?

?

? RowExpander ListView CheckBoxListView ColorPalette

RowExpander

gxt gxt初学进阶教程

如果希望让Grid的某一列的展示具有一定的显示效果的话,我们就得使用RowExpander。[www.61k.com]RowExpander继承自ColumnConfig,因此RowExpander的使用过程和ColumnConfig一样,定义好之后直接添加到ColumnModel里。

当RowExpander被添加到Grid之后,其显示效果会在列的右上角有一个+的button。点击之后内容就会伸展开来,并且变为

gxt gxt初学进阶教程

-的

gxt gxt初学进阶教程

button

为了让RowExpander生效,我们一定要记住——使用Grid的addPlugin()方法。

和ListField不同的是,当Grid通过RowExpander应用XTemplate的时候,不需要我们定义tpl for标记,Grid就会自动的把效果应用到每一行里。

现在,在RSSReader项目里,我们就创建一个新版本的ItemGrid,来使用RowExpander显示数据。

? 打开:com.danielvaughan.rssreader.client.grids.ItemGrid,在onRender方

法里,在Grid的最后一个列的定义之后,新建一个XTemplate。这个真实的

template内容是一个img的html图片标签,然后src属性是Item对象里面

的thumbnailUrl字段,加上html标记p,显示item对象的description字段

[javascript] view plaincopyprint?

gxt gxt初学进阶教程

1. XTemplate xTemplate = XTemplate

2. .create("<img class=\"left\"

src=\"{thumbnailUrl}\"height=\"49px\"/><p>{description}</p>"); ? 然后新建一个RowExpander对象,并设置xTemplate

[java] view plaincopyprint? 1. RowExpander rowExpander = new RowExpander();

2. rowExpander.setTemplate(xTemplate);

? 将新建好的RowExpander加入到columns里——ColumnConfig的配置结果

[java] view plaincopyprint?

1. columns.add(rowExpander);

? 我们还需要将RowExpander通过Grid的addPlugin方法注册到Grid中去

[java] view plaincopyprint?

1. grid.addPlugin(rowExpander);

? 在com.danielvaughan.rssreader.client.RSSReader里,删除掉先前章节使

用的ItemPanel创建代码,取消掉RssMainPanel穿件代码的注释 [java] view plaincopyprint?

1. RssMainPanel mainPanel = new RssMainPanel();

2. //remove ItemPanel mainPanel = new ItemPanel();

3. //remove mainPanel.displayItem(TestObjects.getTestItem());

? 运行之后,效果如下:

gxt gxt初学进阶教程

ListView

ListView 支持通过XTemplate自定制数据集合的显示。[www.61k.com)这是一个很灵活的component,来让我们可以具体的控制数据的显示效果。比如,icons,grid,list或者其他的components都可以通过XTemplate和CSS联合起来定制其显示效果。

gxt gxt初学进阶教程

为了证明ListView是如何工作的,在RSSReader项目里,我们准备新建一个ListView去展示Feed objects对象集合。

? 新建类:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.lists;

2.

gxt gxt初学进阶教程

3. import com.extjs.gxt.ui.client.widget.LayoutContainer;

4.

5. public class FeedOverviewView extends LayoutContainer {

6.

7. }

? 定义一个listView的component [java] view plaincopyprint?

1. private ListView<BeanModel> listView = new ListView<BeanModel>(); ? Override onRender方法,添加DataProxy,DataReader和Loader去获得

数据

[java] view plaincopyprint? 1. @Override

2. protected void onRender(Element parent, int index) {

3. super.onRender(parent, index);

4. final FeedServiceAsync feedService = (FeedServiceAsync) Registry

5. .get(RSSReaderConstants.FEED_SERVICE);

6. RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {

7. @Override

8. protected void load(Object loadConfig,

9. AsyncCallback<List<Feed>> callback) {

10. feedService.loadFeedList(false, callback);

11. }

12. };

13. BeanModelReader reader = new BeanModelReader();

14. ListLoader<ListLoadResult<BeanModel>> loader = new

BaseListLoader<ListLoadResult<BeanModel>>(

15. proxy, reader);

16. ListStore<BeanModel> feedStore = new ListStore<BeanModel>(loader);

17. loader.load();

18. }

gxt gxt初学进阶教程

? 定义一个getTemplate方法,返回XTemplate的字符串。(www.61k.com]我们将用此XTemplate应用到feed objects中imageUrl不为空的数据上。

[java] view plaincopyprint? 1. private String getTemplate() { 2. StringBuilder sb = new StringBuilder();

3. sb.append("<tpl for=\".\">");

4. sb.append("<div class=\"feed-box\">");

5. sb.append("<h1>{title}</h1>"); 6. sb.append("<tpl if=\"imageUrl!=''\">");

7. sb.append("<img class=\"feed-thumbnail\" src=\"{imageUrl}\"

title=\"{title}\">");

8. sb.append("</tpl>");

9. sb.append("<p>{description}</p>"); 10. sb.append("</div>"); 11. sb.append("</tpl>");

12. return sb.toString();

13. }

? 回到onRender方法上,将feedStore绑定到listView组件上,并设定Template。

之后将listView加入到LayoutContainer

[java] view plaincopyprint?

1. listView.setStore(feedStore);

2. listView.setTemplate(getTemplate());

3. add(listView);

? 接下来,编写war\items.css

[css] view plaincopyprint?

1. div.feed-box {

gxt gxt初学进阶教程

2. float: left; 3. margin: 5px;

4. padding: 5px;

5. border: 1px solid black; 6. width: 200px;

7. height: 120px;

8. text-align: center;

9. }

10.

11. img.feed-thumbnail {

12. width: 100px;

13. height: 100px;

14. }

? 在主显示区,RssMainPanel。[www.61k.com]替换掉先前的ItemGrid,加入

FeedOverviewView

[java] view plaincopyprint?

1. add(new FeedOverviewView());

? 运行效果如下,内容显示区可以通过css进一步设定,让其超出部分隐藏起

来。

gxt gxt初学进阶教程

? 整个代码如下:

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.lists; 2.

gxt gxt初学进阶教程

3. import java.util.List;

4.

5. import com.danielvaughan.rssreader.client.RSSReaderConstants;

6. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

7. import com.danielvaughan.rssreader.shared.model.Feed;

8. import com.extjs.gxt.ui.client.Registry;

9. import com.extjs.gxt.ui.client.data.BaseListLoader;

10. import com.extjs.gxt.ui.client.data.BeanModel;

11. import com.extjs.gxt.ui.client.data.BeanModelReader;

12. import com.extjs.gxt.ui.client.data.ListLoadResult;

13. import com.extjs.gxt.ui.client.data.ListLoader;

gxt gxt初学进阶教程

14. import com.extjs.gxt.ui.client.data.RpcProxy;

15. import com.extjs.gxt.ui.client.store.ListStore;

16. import com.extjs.gxt.ui.client.widget.LayoutContainer;

17. import com.extjs.gxt.ui.client.widget.ListView;

18. import com.google.gwt.user.client.Element;

19. import com.google.gwt.user.client.rpc.AsyncCallback;

20.

21. public class FeedOverviewView extends LayoutContainer {

22. private ListView<BeanModel> listView = new ListView<BeanModel>(); 23.

24. private String getTemplate() {

25. StringBuilder sb = new StringBuilder();

26. sb.append("<tpl for=\".\">");

27. sb.append("<div class=\"feed-box\">");

28. sb.append("<h1>{title}</h1>");

29. sb.append("<tpl if=\"imageUrl!=''\">");

30. sb.append("<img class=\"feed-thumbnail\" src=\"{imageUrl}\"

title=\"{title}\">");

31. sb.append("</tpl>");

32. sb.append("<p>{description}</p>");

33. sb.append("</div>");

34. sb.append("</tpl>");

35. return sb.toString();

36. }

37.

38. @Override

39. protected void onRender(Element parent, int index) {

40. super.onRender(parent, index);

41. final FeedServiceAsync feedService = (FeedServiceAsync) Registry

42. .get(RSSReaderConstants.FEED_SERVICE);

43. RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {

44. @Override

45. protected void load(Object loadConfig,

46. AsyncCallback<List<Feed>> callback) {

47. feedService.loadFeedList(false, callback);

gxt gxt初学进阶教程

48. }

49. };

50. BeanModelReader reader = new BeanModelReader();

51. ListLoader<ListLoadResult<BeanModel>> loader = new

BaseListLoader<ListLoadResult<BeanModel>>(

52. proxy, reader);

53. ListStore<BeanModel> feedStore = new ListStore<BeanModel>(loader);

54. loader.load();

55.

56. listView.setStore(feedStore);

57. listView.setTemplate(getTemplate());

58. add(listView);

59. }

60. }

ModelProcesser

在这些数据并没有被真正的展示到component上之前,ModelProcesser提供了通过

template将数据预处理的功能。(www.61k.com]他不是真正的去修改object里field的值,而是会新建fields去包含和格式化结果集里面fields,其使用过程和普通的fields一样。

举个例子,就像上一个ListView例子中,其中的一个ListView所显示的feed,其description内容很长,会溢出于整个矩形。我们要做的就是使用GXT提供的Format.ellipse方法去缩短其description的内容。这个缩短后的字符串,包含一少部分的字符,其末端用省略号连接。

因此我们继续在RSSReader项目里加入ModelProcessor的代码。想要初始化数据,就要overriding prepareData方法。接下来我们就创建title和description的缩写fields。

? 在onRender方法里,在ListView定义的时候,override ListView的

prepareData方法

[java] view plaincopyprint?

1. listView = new ListView<BeanModel>() {

2. @Override

3. protected BeanModel prepareData(BeanModel feed) {

gxt gxt初学进阶教程

4. return feed; 5. }

6. };

? 上面的修改,只是返回一个原先的feed对象。[www.61k.com)接下来我们要给feed对象里加入一个shortTitle的field,其value是title字段的前50个字符。shortDescription是descripton的前100个字符

[java] view plaincopyprint? 1. listView = new ListView<BeanModel>() {

2. @Override

3. protected BeanModel prepareData(BeanModel feed) {

4. feed.set("shortTitle", Format.ellipse((String) feed

5. .get("title"), 50));

6. feed.set("shortDescription", Format.ellipse((String) feed

7. .get("description"), 100));

8. return feed;

9. }

10. };

? 接下来,修改getTemplate方法的template

[java] view plaincopyprint?

1. private String getTemplate() {

2. StringBuilder sb = new StringBuilder();

3. sb.append("<tpl for=\".\">");

4. sb.append("<div class=\"feed-box\">");

5. sb.append("<h1>{title}</h1>");

6. sb.append("<tpl if=\"imageUrl!=''\">");

7. sb

8. .append("<img class=\"feed-thumbnail\" src=\"{imageUrl}\"

title=\"{shortTitle}\">");

9. sb.append("</tpl>");

gxt gxt初学进阶教程

10. sb.append("<p>{shortDescription}</p>");

11. sb.append("</div>");

12. sb.append("</tpl>");

13. return sb.toString();

14. }

? 运行之后,那些讨厌的长字符就不会再次出现了。(www.61k.com)

Item selectors

现在的显示效果,或许大家会发现,在FeedOverviewView的items都不可以被选中。这是因为我们没有设置其选中的功能。当然这些选中的效果是块选中。接下来,我们就使用

feed-box div样式,让整个FeedOverviewView的items可以被选中,并且触发相应的event

? 首先,在onRender方法里,设置ListView的ItemSelector

[java] view plaincopyprint?

1.

gxt gxt初学进阶教程

listView.setItemSelector("div.feed-box");

? 接下来是处理选中事件。在ListView里添加一个Listener去监听

SelectionChange event。当用户选中某个item的时候,我们使用Info 去显

示其name field

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. listView.getSelectionModel().addListener(Events.SelectionChange, 2. new Listener<SelectionChangedEvent<BeanModel>>() {

3. public void handleEvent(SelectionChangedEvent<BeanModel> be) { 4.

gxt gxt初学进阶教程

BeanModel feed = (BeanModel) be.getSelection().get(0);

5. Info.display("Feed selected", (String) feed

6. .get("title"));

7. }

8. });

? 来看看运行效果

gxt gxt初学进阶教程

接下来,我们要跟进一步的操作ListView里item的显示内容。[www.61k.com)修改FeedOverviewView里的

gxt gxt初学进阶教程

XTemplate,让一个item可以显示其里面的children内容。

? 要显示item里面的children,就在load的时候,有children的数据。修改

RpcProxy,将false修改为true。

[java] view plaincopyprint?

1. RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {

2. @Override

3. protected void load(Object loadConfig,

4. AsyncCallback<List<Feed>> callback) {

5. feedService.loadFeedList(true, callback);

6. }

7. };

? 修改getTemplate方法

[java] view plaincopyprint?

1. private String getTemplate() {

2. StringBuilder sb = new StringBuilder();

3. sb.append("<tpl for=\".\">");

4. sb.append("<div class=\"feed-box\">");

5. sb.append("<h1>{title}</h1>");

gxt gxt初学进阶教程

6. sb.append("<tpl if=\"imageUrl!=''\">");

7. sb

8. .append("<img class=\"feed-thumbnail\" src=\"{imageUrl}\"

title=\"{shortTitle}\">");

9. sb.append("</tpl>"); 10. sb.append("<p>{shortDescription}</p>");

11. sb.append("<ul>");

12. sb.append("<tpl for=\"items\">");

13. sb.append("<tpl if=\"xindex < 3\">");

14. sb.append("<li>{title}</li>");

15. sb.append("</tpl>");

16. sb.append("</tpl>");

17. sb.append("</ul>");

18. sb.append("</div>");

19. sb.append("</tpl>"); 20. return sb.toString(); 21. }

第七章:Model View Controller

本章我们要了解GXT的MVC架构,以及学习他们在一个大型的应用系统里是如何系统工作的

我们会涉及到如下GXt功能集

?

?

?

?

? AppEvent EventType Controller View Dispatcher

一个好应用的需要

当我们在使用GXT搭建一个应用的时候,我认为最重要的是要如何去搭建他。(www.61k.com]当我们项目在构建的时候,会很容易的发现各种各样的问题。比如组件越来越多,耦合度越来越大,这会变得很难去跟踪和管理。这些情况会导致噩梦般的维护成本(当然了,也给我们程序员创造了更多的就业机会)。

gxt gxt初学进阶教程

对于桌面还是web可视化应用程序来说,目前最流行的就是Model View Controller模式的架构方案。(www.61k.com)所幸,GXT提供了基于的MVC模式实现方案,在此方案上架构的应用可以避免不少麻烦!

经典的MVC模式

gxt gxt初学进阶教程

MVC

gxt gxt初学进阶教程

是一个非常流行的设计模式,虽然有几个不同的变化,但是基本上是由各尽其责,互相协同工作的三部分组成的:

? Model:他负责管理,状态,数据和应用逻辑。他提供接口,允许其管理的内

容被检索和修改。支持Observer设计模式,可以通过注册与唤醒的方式,作

为状态改变的响应。

? View:是用户的操作接口。通过用户对数据的请求,View作为响应则从Model

里获得状态改变的内容,并展示给用户。当用户与view所提供的接口互相作

用,互相影响到时候,view层提供了event,会通过controller被触发事件。

view层不需要考虑任何controller的工作原理。

? Controller:controller会作为一个observer的角色,监听view层所触发的

events。也可以修改model或者view的结果集。

这种模式的好处就是,可以让model层不需要去了解controller和view层是如何工作的,从而让model与controller和view之间的没有彼此的依赖性。

GXT MVC

GXT的MVC模式有一点不同的传统的MVC模式,但是非常有用的!

gxt gxt初学进阶教程

? Model:他是存储ModelData的Store的一种表现形式。(www.61k.com)专门负责:通过get

方法,从Store里获得ModelData,通过set方法,修改ModelData。

? View:他负责组织所有的UI components。就像传统的MVC模式一样,

data-backed components 检测Model的状态,当有变化的时候,会作出响

应。跟传统MVC不同的是,一旦view管理的components被灌入了Model

里的数据,随着用户的操作,components就会联动的修改Model里的数据。

view使用分配器去派发事件,然后通过controller控制事件的响应。按照GXT

的设计模式,view需要通过其构造函数去关联有关controller层的对象。虽

然这样有些打破了传统的MVC模式——view层和controller层没有完全的解

耦合。

? Controller:在传统的MVC模式里,Controller通过派发器对view层发出的事件作出响应。在GXT MVC的模式里,他也可以表现为Model层面的某些

操作,或者可以将事件转发到别的view里。

? Dispatcher:Dispatcher的存在是为了避免view层直接调用controller, view

通过dispatcher传播event。Dispatcher类提供一些静态方法可公调用,用

来将event传递到controllers里面。controller会注册这些dispatcher,用来

获得专门的事件类型。

GXT之旅:第七章:MVC——GXT MVC的相关类

分类: ExtGWT 2012-03-13 10:00578人阅读评论(0)收藏举报

AppEvent class

AppEvent负责承载着信息,在controller和view之间。每个AppEvent对象都会有一个专门的EventType定义。

AppEvent对象可以随意的通过setData方法,承载一个或多个datas。这样很有益于传递状态信息。当设置多个Datas的时候,我们就需要使用key-value键值对,把每个Data命名,以方便检索。

另外一个功能就是,可是使用setHistoryEvent方法,在设置AppEvent的历史事件。这就意味着,当一个事件被派发出去的时候,该之间就会被设置成历史事件。这一特性的设计,方便在dispatcher里查询历史事件。

EventType class

EventType是用来定义事件类型的,具体来说是给AppEvent起名子的。具有代表性的,我们会在AppEvents类里,定义一些列的静态fields,器field的类别就是EventType。 下面,我们就在RSSReader项目,定义应用事件

gxt gxt初学进阶教程

? 新建package:com.danielvaughan.rssreader.client.mvc.events,新建类AppEvents

? 在AppEvents类里,定义两个EventType的fields

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.events;

2.

3. import com.extjs.gxt.ui.client.event.EventType;

4.

5. public class AppEvents {

6. public static final EventType Init = new EventType();

7. public static final EventType Error = new EventType();

8. }

Controller class

Controller在应用里,承担着对事件响应和处理的角色。(www.61k.com)

一个Controller在其构造函数里,必须注册EventTypes,才可以监听事件。registerEventTypes方法就是用通过传入EventType参数,完成注册过程!

? 新建package:com.danielvaughan.rssreader.client.mvc.controllers,在此

包下,新建类AppController继承Controller

? 在构造函数里,完成事件注册

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.controllers; 2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.extjs.gxt.ui.client.mvc.AppEvent;

5. import com.extjs.gxt.ui.client.mvc.Controller;

6.

7. public class AppController extends Controller {

8. public AppController() {

9. registerEventTypes(AppEvents.Init);

gxt gxt初学进阶教程

10. registerEventTypes(AppEvents.Error);

11. }

12.

13. @Override

14. public void handleEvent(AppEvent event) {

15.

16.

17. }

18. }

当继承抽象类Controller的时候,必须要实现handleEvent抽象方法。[www.61k.com)此方法是用来定义如何处理不同EventType的。

如果想要查询一个Controller是否可以处理某个专门的AppEvent的时候,可以使用canHandle方法。

响应一个时间的处理流程如下:

?

?

?

? 事件出入总的controller 然后将事件派发到具体的某一个子controller 将事件转发到view,等待后续的操作 将如上三步整合起来。

接下来,我们要在RSSReader项目实现,AppController的handleEvent方法。

?

? orverride handleEvent 方法 目前,我们不需要在Controller层处理任何的事件,只是将所有的事件转发

到view层。因此,我们需要定义一个View

[java] view plaincopyprint?

1. private com.extjs.gxt.ui.client.mvc.View appView;

? 随着View的定义,我们将所有的evet都转发到view里——实现一个forward

的功能。

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. package com.danielvaughan.rssreader.client.mvc.controllers;

2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.extjs.gxt.ui.client.mvc.AppEvent;

5. import com.extjs.gxt.ui.client.mvc.Controller;

6. import com.extjs.gxt.ui.client.mvc.View;

7.

8. public class AppController extends Controller {

9.

10. private View appView;

11.

12. public AppController() {

13. registerEventTypes(AppEvents.Init);

14. registerEventTypes(AppEvents.Error);

15. }

16. 17. @Override

18. public void handleEvent(AppEvent event) {

19.

20. forwardToView(appView, event);

21. }

22. }

View class

View是GXT MVC架构中一部分。[www.61k.com)负责提供用户接口——显示可视化组件,响应从Controller转发过来的事件,当然也负责响应用户操作所产生的事件(AppEvents),并将其派发到Dispatcher。

正如controllers一样,views也需要实现handleEvent方法。为了保持代码整洁易懂,最好针对每一个EventType去创建一个on<EventType>方法。

比如,如果我们想要处理Init的EventType 。我们需要在handleEvent里检查其EventType,并调用对应的处理方法onInit。

[java] view plaincopyprint?

1. protected void handleEvent(AppEvent event) {

gxt gxt初学进阶教程

2. EventType eventType = event.getType();

3. if (eventType.equals(AppEvents.Init)) {

4. onInit(event);

5. }

6. }

接下来,我们在RSSReader项目里,实现View层的代码

? 新建package:com.danielvaughan.rssreader.client.mvc.views,在此包下,

新建AppView继承View

? 别忘了,orverride handleEvent方法

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.views; 2.

3. import com.extjs.gxt.ui.client.mvc.AppEvent;

4. import com.extjs.gxt.ui.client.mvc.Controller;

5. import com.extjs.gxt.ui.client.mvc.View;

6.

7. public class AppView extends View {

8.

9. public AppView(Controller controller) {

10. super(controller);

11.

12. }

13.

14. @Override

15. protected void handleEvent(AppEvent event) { 16.

17. }

18.

19. }

gxt gxt初学进阶教程

? 注意,如上的构造函数的写法。(www.61k.com)其原因是View没有无参的,空方法体的构造

函数!java基础啦

? 正如我们之前介绍的:注册了两个事件Init和Error,那么就要有对应的

on<EventType>方法

[java] view plaincopyprint?

1. private void onInit(AppEvent event) {}

2. private void onError(AppEvent event) {}

? 现在,要实现handleEvent方法里面具体的内容——根据EventType跳转到

对应的处理方法。

[java] view plaincopyprint?

1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) {

5. onInit(event);

6. } else if (eventType.equals(AppEvents.Error)) {

7. onError(event);

8. }

9. }

? 最后,我们需要让AppController和AppView之间有关联。通过override

Appcontroller的 initialize方法实现。这样当AppView里面的事件才会通过此关联操作,跳转到AppController中去!

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.controllers; 2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.danielvaughan.rssreader.client.mvc.views.AppView;

5. import com.extjs.gxt.ui.client.mvc.AppEvent;

gxt gxt初学进阶教程

6. import com.extjs.gxt.ui.client.mvc.Controller;

7. import com.extjs.gxt.ui.client.mvc.View;

8.

9. public class AppController extends Controller {

10.

11. private View appView;

12.

13. public AppController() {

14. registerEventTypes(AppEvents.Init);

15. registerEventTypes(AppEvents.Error);

16. }

17.

18. @Override

19. public void handleEvent(AppEvent event) {

20.

21. forwardToView(appView, event);

22. }

23.

24. @Override

25. public void initialize() {

26. super.initialize();

27. appView = new AppView(this);

28. }

29. }

30.

31.

32. package com.danielvaughan.rssreader.client.mvc.views;

33.

34. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

35. import com.extjs.gxt.ui.client.event.EventType;

36. import com.extjs.gxt.ui.client.mvc.AppEvent;

37. import com.extjs.gxt.ui.client.mvc.Controller;

38. import com.extjs.gxt.ui.client.mvc.View;

39.

40. public class AppView extends View {

gxt gxt初学进阶教程

41.

42. public AppView(Controller controller) {

43. super(controller);

44.

45. }

46.

47. @Override

48. protected void handleEvent(AppEvent event) {

49. EventType eventType = event.getType();

50. if (eventType.equals(AppEvents.Init)) {

51. onInit(event);

52. } else if (eventType.equals(AppEvents.Error)) {

53. onError(event);

54. }

55. }

56.

57. private void onInit(AppEvent event) {

58. }

59.

60. private void onError(AppEvent event) {

61. }

62. }

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

1. 派发(Dispatcher)不同类型的EventType

2. 监听 Dispatcher(派发器)

3. 接收事件,处理事件

4. 定义不同类型的AppEvent

5. 程序处理:转发AppEvent到派发器

6. 程序处理:用户操作,触发了事件

7. 程序处理:将事件注册到Controllers里

8. 程序处理:将Controllers注册到派发器里(Dispatcher)

GXT之旅:第七章:MVC——MVC重构项目(1)

分类: ExtGWT2012-03-13 15:27430人阅读评论(0)收藏举报

使用MVC重构RSSReader项目

现在我们已经初步了解了GXT MVC,现在我们就要利用此契机,将RSSRead项目重构一下,使其应用于MVC架构——让components之间具有良好的一致性,而不是各自的分散开来。[www.61k.com]

为了让Controller可以接收到events,需要使用Dispatcher将其注册。通常情况我们都会在程序入口类,来完成这一操作。那么我们就开动了~~~

gxt gxt初学进阶教程

? 在com.danielvaughan.rssreader.client.RSSReader类的onModuleLoad方

法里,删除掉所有的代码,仅仅保留注册FeedService的那一行。[www.61k.com)

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client;

2.

3. import com.danielvaughan.rssreader.client.services.FeedService;

4. import com.extjs.gxt.ui.client.Registry;

5. import com.google.gwt.core.client.EntryPoint;

6. import com.google.gwt.core.client.GWT;

7. 8. /**

9. * Entry point classes define <code>onModuleLoad()</code>.

10. */

11. public class RSSReader implements EntryPoint {

12.

13. /**

14. * This is the entry point method.

15. */

16. @Override

17. public void onModuleLoad() {

18. Registry.register(RSSReaderConstants.FEED_SERVICE,

19. GWT.create(FeedService.class));

20.

21. }

22. }

? 接下来,我们要获得Dispatcher的单例

[java] view plaincopyprint?

1. public void onModuleLoad() {

2. Registry.register(RSSReaderConstants.FEED_SERVICE, GWT

3. .create(FeedService.class));

4.

5. Dispatcher dispatcher = Dispatcher.get();

gxt gxt初学进阶教程

6. }

? 现在是最关键的,将Controllers注册到派发器里

[java] view plaincopyprint? 1. public void onModuleLoad() {

2. Registry.register(RSSReaderConstants.FEED_SERVICE, GWT

3. .create(FeedService.class));

4.

5. Dispatcher dispatcher = Dispatcher.get();

6. dispatcher.addController(new AppController());

7. } 重构UI 先前我们把onModuleLoad方法里面,关于UI部分的所有代码都删除了。[www.61k.com)现在我们要使用MVC的 view(AppView)带替换之前的UI代码。那么AppView的加载,将作为一个Init EventType事件来处理——既然是初始化的事件,那么其触发点,就在程序的初始化时候,也就是在onModuleLoad方法里。(我个人感觉就是使用了MVC之后,一切操作的源头都要是事件,不要直接的硬编码,所有的编码都要在对事件响应的处理方法里完成)

? 现在,找到onModuleLoad方法,同样的使用dispatcher去派发事件

[java] view plaincopyprint?

1. public void onModuleLoad() {

2. Registry.register(RSSReaderConstants.FEED_SERVICE, GWT

3. .create(FeedService.class));

4.

5. Dispatcher dispatcher = Dispatcher.get();

6. dispatcher.addController(new AppController());

7. dispatcher.dispatch(AppEvents.Init);

8. }

gxt gxt初学进阶教程

? 根据之前的AppController的事件处理,他会自动的将事件转发到AppView

的handleEvent方法中去。(www.61k.com)那么根据Init事件的处理,就是去完成程序整体的UI的创建,因此我们接下来的工作要在AppView类里面完成。在AppView类,创建两个属性——ContentPanel ,Viewport

[java] view plaincopyprint?

1. private final ContentPanel mainPanel = new ContentPanel();

2. final Viewport viewport = new Viewport();

? 先前我们已经创建好了空方法onInit,就是用来处理Init事件的,所以整个的

UI操作在此方法里实现(其实就是把原先在onModuleLoad里有关UI的代码,迁移到onInit方法里)。

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.extjs.gxt.ui.client.Style.LayoutRegion;

5. import com.extjs.gxt.ui.client.Style.Orientation;

6. import com.extjs.gxt.ui.client.event.EventType;

7. import com.extjs.gxt.ui.client.mvc.AppEvent;

8. import com.extjs.gxt.ui.client.mvc.Controller;

9. import com.extjs.gxt.ui.client.mvc.View;

10. import com.extjs.gxt.ui.client.widget.ContentPanel;

11. import com.extjs.gxt.ui.client.widget.Viewport;

12. import com.extjs.gxt.ui.client.widget.layout.BorderLayout;

13. import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;

14. import com.extjs.gxt.ui.client.widget.layout.RowLayout;

15. import com.google.gwt.user.client.ui.HTML;

16.

17. public class AppView extends View {

18. private final ContentPanel mainPanel = new ContentPanel();

19. private final Viewport viewport = new Viewport();

gxt gxt初学进阶教程

20.

21. public AppView(Controller controller) {

22. super(controller);

23.

24. }

25.

26. @Override

27. protected void handleEvent(AppEvent event) {

28. EventType eventType = event.getType();

29. if (eventType.equals(AppEvents.Init)) {

30. onInit(event);

31. } else if (eventType.equals(AppEvents.Error)) {

32. onError(event);

33. }

34. }

35.

36. private void onInit(AppEvent event) {

37. final BorderLayout borderLayout = new BorderLayout();

38. viewport.setLayout(borderLayout);

39. HTML headerHtml = new HTML();

40. headerHtml.setHTML("<h1>RSS Reader</h1>");

41. BorderLayoutData northData = new BorderLayoutData(LayoutRegion.NORTH,

42. 20);

43. northData.setCollapsible(false);

44. northData.setSplit(false);

45. viewport.add(headerHtml, northData);

46. BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);

47. centerData.setCollapsible(false);

48. RowLayout rowLayout = new RowLayout(Orientation.VERTICAL);

49. mainPanel.setHeaderVisible(false);

50. mainPanel.setLayout(rowLayout);

51. viewport.add(mainPanel, centerData);

52. }

53.

54. private void onError(AppEvent event) {

gxt gxt初学进阶教程

55. }

56. }

? 此时,如果大家现在就运行程序的话,只能看到等待消息的页面,原因是因

为我们还没有把组装好的viewport添加到应用里。[www.61k.com)我习惯上,把组装的过程和添加的过程分成两个不同的事件去处理(事件细化),这样一来代码清晰明确,通过看事件,就可以轻松了解程序的运行步骤。

? 在com.danielvaughan.rssreader.client.mvc.events.AppEvents,定义一个新

的EventType——UIReady,用来作为处理Viewport的事件

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.events;

2.

3. import com.extjs.gxt.ui.client.event.EventType;

4.

gxt gxt初学进阶教程

5. public class AppEvents {

6. public static final EventType Init = new EventType();

7. public static final EventType Error = new EventType();

8. public static final EventType UIReady = new EventType();

9. }

? 在AppController类里,注册UIReady事件

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. public AppController() { 2. registerEventTypes(AppEvents.Init);

3. registerEventTypes(AppEvents.Error);

4. registerEventTypes(AppEvents.UIReady);

5. }

? 在AppView类里,新建方法onUIReady,将Viewport 加入到RootPanel

[java] view plaincopyprint? 1. private void onUIReady(AppEvent event) { 2. RootPanel.get().add(viewport);

3. }

? 当然不要忘记,AppView的handleEvent方法。(www.61k.com]将传入的event响应到

onUIReady方法里

[java] view plaincopyprint? 1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) {

5. onInit(event);

6. } else if (eventType.equals(AppEvents.Error)) {

7. onError(event);

8. } else if (eventType.equals(AppEvents.UIReady)) {

9. onUIReady(event);

10. }

11. }

? 最后是,派发UIReady事件:RSSReader类的onModuleLoad方法,派发

事件

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. @Override

2. public void onModuleLoad() {

3. Registry.register(RSSReaderConstants.FEED_SERVICE, GWT

4. .create(FeedService.class));

5.

6. Dispatcher dispatcher = Dispatcher.get();

7. dispatcher.addController(new AppController());

8. dispatcher.dispatch(AppEvents.Init);

9. dispatcher.dispatch(AppEvents.UIReady);

10. }

? 运行后的效果如下: GXT之旅:第七章:MVC——

gxt gxt初学进阶教程

MVC重构项目(2)

分类: ExtGWT2012-03-15 17:39389人阅读评论(0)收藏举报

使用MVC重构RSSReader项目——Navigation区域

上一节,在程序的入口文件(RSSReader),我们派发了EventType为Init的AppEvent,AppController会处理此事件,将其转发到AppView。(www.61k.com]依次的,AppView会的处理该事件,去调用onInit方法,完成基础的UI创建。在此过程中负责了程序主体的区域创建。但是,唯一没有处理的,就是没有把组装好的components添加到UI。

那么现在,我们需要再分别创建几组Controller和View,分别去负责RSSReader项目其他的各个区域。首先我们要创建一对Controller-View,去处理Navigation区域。

大致思路如下:

gxt gxt初学进阶教程

? 负责navigation区域的controller,能够将Init EventType转发到对应的View

? 负责navigation区域的view,会处理Init EventType,在处理的过程中,又会派发一个新的事件(NavPanelReady)——此事件会承载着NavPanel的

实例被派发到Dispatcher中。[www.61k.com] ? AppController会监听此事件(NavPanelReady),当接收到此事件传入的时候,会将其转发到AppView。

? AppView会处理会理NavPanelReady的事件——将其传递的NavPanel实例,

加入到ViewPort上

此前,onModuleLoad方法里已经派发了UIReady事件。因此,NavPanel应该已经被添加到Viewport里,显示出来。具体实现步骤如下:

? 在com.danielvaughan.rssreader.client.mvc.events.AppEvents类,加入新的

EventType——NavPanelReady

[java] view plaincopyprint? 1. public static final EventType NavPanelReady = new EventType();

? 新建NavController extends Controller

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.controllers;

2.

3. import com.extjs.gxt.ui.client.mvc.AppEvent;

4. import com.extjs.gxt.ui.client.mvc.Controller;

5.

6. public class NavController extends Controller {

7.

8. @Override

9. public void handleEvent(AppEvent event) {

10.

11.

12. }

gxt gxt初学进阶教程

13. 14. }

? 新建NavView extends View

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.views; 2.

3. import com.extjs.gxt.ui.client.mvc.AppEvent;

4. import com.extjs.gxt.ui.client.mvc.Controller;

5. import com.extjs.gxt.ui.client.mvc.View; 6.

7. public class NavView extends View {

8.

9. public NavView(Controller controller) {

10. super(controller);

11. }

12.

13. @Override

14. protected void handleEvent(AppEvent event) { 15.

16. }

17.

18. }

? 在NavController的构造函数里,注册Init EventType

[java] view plaincopyprint?

1. public NavController() {

2. registerEventTypes(AppEvents.Init);

3. }

gxt gxt初学进阶教程

? 在NavController,定义NavView类实例,通过其initialize方法实例化

NavView——让controller与view关联起来。[www.61k.com)实现handleEvent方法,将NavController接收的事件转发到NavView里。

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.controllers; 2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.danielvaughan.rssreader.client.mvc.views.NavView;

5. import com.extjs.gxt.ui.client.mvc.AppEvent;

6. import com.extjs.gxt.ui.client.mvc.Controller;

7.

8. public class NavController extends Controller {

9.

10. private NavView navView;

11.

12. public NavController() {

13. registerEventTypes(AppEvents.Init);

14. }

15.

16. @Override

17. public void handleEvent(AppEvent event) {

18. forwardToView(navView, event);

19. }

20.

21. @Override

22. public void initialize() {

23. super.initialize();

24. navView = new NavView(this);

25. }

26.

27. }

? 将com.danielvaughan.rssreader.client.components.RssNavigationPanel类,

重命名为NavPanel。然后在NavView类里,加入NavPanel的实例属性

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import com.danielvaughan.rssreader.client.components.NavPanel;

4. import com.extjs.gxt.ui.client.mvc.AppEvent;

5. import com.extjs.gxt.ui.client.mvc.Controller;

6. import com.extjs.gxt.ui.client.mvc.View;

7.

8. public class NavView extends View {

9.

10. private final NavPanel navPanel = new NavPanel();

11.

12. public NavView(Controller controller) {

13. super(controller);

14. }

15.

16. @Override

17. protected void handleEvent(AppEvent event) {

18.

19. }

20.

21. }

? 在NavView类里实现handleEvent方法——当Init EventType接收到之后,

再派发一个新事件(此过程我习惯称之事件联动):NavPanelReady ,并且派发的同时,承载navPanel对象

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import com.danielvaughan.rssreader.client.components.NavPanel;

4. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

5. import com.extjs.gxt.ui.client.event.EventType;

6. import com.extjs.gxt.ui.client.mvc.AppEvent;

gxt gxt初学进阶教程

7. import com.extjs.gxt.ui.client.mvc.Controller; 8. import com.extjs.gxt.ui.client.mvc.Dispatcher;

9. import com.extjs.gxt.ui.client.mvc.View;

10.

11. public class NavView extends View { 12.

13. private final NavPanel navPanel = new NavPanel();

14.

15. public NavView(Controller controller) {

16. super(controller);

17. }

18.

19. @Override

20. protected void handleEvent(AppEvent event) {

21. EventType eventType = event.getType();

22.

23. if (eventType.equals(AppEvents.Init)) {

24. Dispatcher.forwardEvent(new AppEvent(AppEvents.NavPanelReady,

25. navPanel));

26. }

27. }

28.

29. }

? 既然NavView会派发NavPanelReady事件,我们希望交给AppController

注册,也就意味着,AppView会接收到此事件,做后续的操作。(www.61k.com]

[java] view plaincopyprint?

1. public AppController() {

2. registerEventTypes(AppEvents.Init);

3. registerEventTypes(AppEvents.Error);

4. registerEventTypes(AppEvents.UIReady);

5. registerEventTypes(AppEvents.NavPanelReady);

gxt gxt初学进阶教程

6. }

? 在AppView对NavPanelReady事件的处理实现如下——将NavPanelReady

事件传递的navPanel对象,对后续处理,将其添加到viewport上

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.extjs.gxt.ui.client.Style.LayoutRegion;

5. import com.extjs.gxt.ui.client.Style.Orientation;

6. import com.extjs.gxt.ui.client.event.EventType;

7. import com.extjs.gxt.ui.client.mvc.AppEvent;

8. import com.extjs.gxt.ui.client.mvc.Controller;

9. import com.extjs.gxt.ui.client.mvc.View;

10. import com.extjs.gxt.ui.client.widget.Component;

11. import com.extjs.gxt.ui.client.widget.ContentPanel;

12. import com.extjs.gxt.ui.client.widget.Viewport;

13. import com.extjs.gxt.ui.client.widget.layout.BorderLayout;

14. import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;

15. import com.extjs.gxt.ui.client.widget.layout.RowLayout;

16. import com.google.gwt.user.client.ui.HTML;

17. import com.google.gwt.user.client.ui.RootPanel;

18.

19. public class AppView extends View {

20. private final ContentPanel mainPanel = new ContentPanel();

21. private final Viewport viewport = new Viewport();

22.

23. public AppView(Controller controller) {

24. super(controller);

25.

26. }

27.

28. @Override

29. protected void handleEvent(AppEvent event) {

gxt gxt初学进阶教程

30. EventType eventType = event.getType();

31. if (eventType.equals(AppEvents.Init)) {

32. onInit(event);

33. } else if (eventType.equals(AppEvents.Error)) {

34. onError(event);

35. } else if (eventType.equals(AppEvents.UIReady)) {

36. onUIReady(event);

37. }else if (eventType.equals(AppEvents.NavPanelReady)) {

38. onNavPanelReady(event);

39. }

40. }

41.

42. private void onInit(AppEvent event) {

43. final BorderLayout borderLayout = new BorderLayout();

44. viewport.setLayout(borderLayout);

45. HTML headerHtml = new HTML();

46. headerHtml.setHTML("<h1>RSS Reader</h1>");

47. BorderLayoutData northData = new BorderLayoutData(LayoutRegion.NORTH,

48. 20);

49. northData.setCollapsible(false);

50. northData.setSplit(false);

51. viewport.add(headerHtml, northData);

52. BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);

53. centerData.setCollapsible(false);

54. RowLayout rowLayout = new RowLayout(Orientation.VERTICAL);

55. mainPanel.setHeaderVisible(false);

56. mainPanel.setLayout(rowLayout);

57. viewport.add(mainPanel, centerData);

58. }

59.

60. private void onUIReady(AppEvent event) {

61. RootPanel.get().add(viewport);

62. }

63.

64. private void onNavPanelReady(AppEvent event) {

gxt gxt初学进阶教程

65. BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST,

66. 200, 150, 300);

67. westData.setCollapsible(true);

68. westData.setSplit(true);

69. Component component = event.getData();

70. viewport.add(component, westData);

71. }

72.

73. private void onError(AppEvent event) {

74. }

75. }

? 所有的准备工作做好了,那么一切事件的触发点,我们要回到RSSReader

的onModuleLoad方法里。(www.61k.com)加入NavController

[java] view plaincopyprint? 1. @Override

2. public void onModuleLoad() {

3. final FeedServiceAsync feedService = GWT.create(FeedService.class);

4. Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);

5. Dispatcher dispatcher = Dispatcher.get();

6.

7. dispatcher.addController(new AppController());

8. dispatcher.addController(new NavController());

9.

10. // 注意:dispatcher.dispatch(AppEvents.Init);会派发Init事件,虽然只是执行

了一次派发操作,但是会派发到多个controller中去!

11. // 原因:因为AppController和NavController都注册了Init !

12. // 顺序:两个controller的接收到event的顺序是根据上面的两行代码(controller

的加入顺序)有关!

13. dispatcher.dispatch(AppEvents.Init);

14. dispatcher.dispatch(AppEvents.UIReady);

15. }

? 程序运行效果如下:

gxt gxt初学进阶教程

GXT之旅:第七章:MVC——MVC重构项目(3)

分类: ExtGWT2012-03-19 15:51343人阅读评论(0)收藏举报

使用MVC重构RSSReader项目——FeedPanel区域 下面,按照同样的逻辑,去处理FeedPanel区域。(www.61k.com]

? 在AppEvents类,定义一个新的EventType——FeedPanelReady

[java] view plaincopyprint?

1. public static final EventType FeedPanelReady = new EventType(); ? 在package:com.danielvaughan.rssreader.client.mvc.controllers,新建类FeedController extends Controller

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. package com.danielvaughan.rssreader.client.mvc.controllers;

2.

3. import com.extjs.gxt.ui.client.mvc.AppEvent;

4. import com.extjs.gxt.ui.client.mvc.Controller;

5.

6. public class FeedController extends Controller {

7.

gxt gxt初学进阶教程

8. @Override

9. public void handleEvent(AppEvent event) {

10.

11.

12. }

13.

14. }

? 在package:com.danielvaughan.rssreader.client.mvc.views,新建FeedView

extends View

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.views; 2.

3. import com.extjs.gxt.ui.client.mvc.AppEvent;

4. import com.extjs.gxt.ui.client.mvc.Controller;

5. import com.extjs.gxt.ui.client.mvc.View;

6.

7. public class FeedView extends View {

8.

9. public FeedView(Controller controller) {

10. super(controller);

11.

12. }

13.

14. @Override

15. protected void handleEvent(AppEvent event) {

16. }

17.

18. }

? 在FeedController的构造函数里,注册Init EventType

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. public FeedController() {

2. registerEventTypes(AppEvents.Init);

3. }

? 在FeedController类里,定义FeedView属性,在initialize方法了,实例化

他。(www.61k.com)并且实现handleEvent方法,将接收的event转发到feedview里。

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.controllers; 2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.danielvaughan.rssreader.client.mvc.views.FeedView;

5. import com.extjs.gxt.ui.client.mvc.AppEvent;

6. import com.extjs.gxt.ui.client.mvc.Controller;

7.

8. public class FeedController extends Controller {

9.

10. private FeedView feedView;

11.

12. public FeedController() {

13. registerEventTypes(AppEvents.Init);

14. }

15.

16. @Override

17. public void handleEvent(AppEvent event) {

18. forwardToView(feedView, event);//同样的,将接收到的event转发到feedView

19. }

20.

21. @Override

22. public void initialize() {

23. super.initialize();

24. feedView = new FeedView(this);

25. }

26.

gxt gxt初学进阶教程

27. }

? 重命名RssMainPanel为FeedPanel。[www.61k.com]在FeedView里加入FeedPanel的实

例属性

[java] view plaincopyprint? 1. private final FeedPanel feedPanel = new FeedPanel();

? 在FeedView类里,加入onInit的对应事件处理方法。其onInit方法的内容

是派发另一个事件FeedPanelReady。并且处理handleEvent方法,根据Init事件类型,调用onInti方法

[java] view plaincopyprint? 1. @Override

2. protected void handleEvent(AppEvent event) { 3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) {

5. onInit(event);

6. }

7. }

8.

9. private void onInit(AppEvent event) {

10. Dispatcher.forwardEvent(new AppEvent(AppEvents.FeedPanelReady,

11. feedPanel));

12. }

? 在AppControllers类里,注册FeedPanelReady事件

[java] view plaincopyprint?

1. public AppController() {

2. registerEventTypes(AppEvents.Init);

3. registerEventTypes(AppEvents.Error);

4. registerEventTypes(AppEvents.UIReady);

5. registerEventTypes(AppEvents.NavPanelReady);

6. registerEventTypes(AppEvents.FeedPanelReady);

gxt gxt初学进阶教程

7. }

? 在AppView类里,编写处理FeedPanelReady事件的对应方法

——onFeedPanelReady。(www.61k.com]并且修改AppView的handleEvent方法

[java] view plaincopyprint? 1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) { 5. onInit(event);

6. } else if (eventType.equals(AppEvents.Error)) {

7. onError(event);

8. } else if (eventType.equals(AppEvents.UIReady)) {

9. onUIReady(event);

10. } else if (eventType.equals(AppEvents.NavPanelReady)) {

11. onNavPanelReady(event);

12. } else if (eventType.equals(AppEvents.FeedPanelReady)) {

13. onFeedPanelReady(event);

14. }

15. }

16. private void onFeedPanelReady(AppEvent event) {

17. RowData rowData = new RowData();

18. rowData.setHeight(.5);

19. Component component = event.getData();

20. mainPanel.add(component, rowData);

21. }

? 最后,在RSSReader的onModule,加入FeedController控制器

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client;

gxt gxt初学进阶教程

2.

3. import

com.danielvaughan.rssreader.client.mvc.controllers.AppController;

4. import

com.danielvaughan.rssreader.client.mvc.controllers.FeedController;

5. import

com.danielvaughan.rssreader.client.mvc.controllers.NavController;

6. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

7. import com.danielvaughan.rssreader.client.services.FeedService;

8. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

9. import com.extjs.gxt.ui.client.Registry;

10. import com.extjs.gxt.ui.client.mvc.Dispatcher;

11. import com.google.gwt.core.client.EntryPoint;

12. import com.google.gwt.core.client.GWT;

13.

14. /**

15. * Entry point classes define <code>onModuleLoad()</code>.

16. */

17. public class RSSReader implements EntryPoint {

18.

19. /**

20. * This is the entry point method.

21. */

22. @Override

23. public void onModuleLoad() {

24. final FeedServiceAsync feedService = GWT.create(FeedService.class);

25. Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);

26. Dispatcher dispatcher = Dispatcher.get();

27.

28. dispatcher.addController(new AppController());

29. dispatcher.addController(new NavController());

30. dispatcher.addController(new FeedController());

31. // 注意:dispatcher.dispatch(AppEvents.Init);会派发Init事件,虽然只是执行

了一次派发操作,但是会派发到多个controller中去!

32. // 原因:因为AppController和NavController都注册了Init !

gxt gxt初学进阶教程

33. // 顺序:两个controller的接收到event的顺序是根据上面的两行代码(controller的加入顺序)有关!

34.

35. dispatcher.dispatch(AppEvents.Init);

36. dispatcher.dispatch(AppEvents.UIReady);

37. }

38. }

? 最后执行效果如下

? FeedPanel类的完整内容如下(取出之前的例子代码):

gxt gxt初学进阶教程

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.components;

2.

3. import com.extjs.gxt.ui.client.widget.ContentPanel;

4. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

5.

6. public class FeedPanel extends ContentPanel {

gxt gxt初学进阶教程

7. public FeedPanel() {

8. setHeading("Main");

9. setLayout(new FitLayout());

10. }

11. } GXT之旅:第七章:MVC——MVC重构项目(4)

分类: ExtGWT2012-03-22 11:41493人阅读评论(6)收藏举报

使用MVC重构RSSReader项目——Item区域

gxt gxt初学进阶教程

之前,我们已经创建了两个非常类似的Controller和View,分别服务于NavPanel和FeedPanel。[www.61k.com)现在我们继续按照同样的思路来构建ItemPanel——ItemPanelReady(EventType),ItemController和ItemView。

我们的目的是生成如下样式的应用效果:

? AppEvents class

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.events;

2.

3. import com.extjs.gxt.ui.client.event.EventType;

4.

gxt gxt初学进阶教程

5. public class AppEvents { 6. public static final EventType Init = new EventType();

7. public static final EventType Error = new EventType();

8. public static final EventType UIReady = new EventType();

9. public static final EventType NavPanelReady = new EventType();

10. public static final EventType FeedPanelReady = new EventType();

11. public static final EventType ItemPanelReady = new EventType();

12. }

? AppController class

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.controllers; 2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.danielvaughan.rssreader.client.mvc.views.AppView;

5. import com.extjs.gxt.ui.client.mvc.AppEvent;

6. import com.extjs.gxt.ui.client.mvc.Controller;

7. import com.extjs.gxt.ui.client.mvc.View;

8.

9. public class AppController extends Controller {

10.

11. private View appView;

12.

13. public AppController() {

14. registerEventTypes(AppEvents.Init);

15. registerEventTypes(AppEvents.Error);

16. registerEventTypes(AppEvents.UIReady);

17. registerEventTypes(AppEvents.NavPanelReady);

18. registerEventTypes(AppEvents.FeedPanelReady);

19. registerEventTypes(AppEvents.ItemPanelReady);

20. }

21.

22. @Override

23. public void handleEvent(AppEvent event) {

gxt gxt初学进阶教程

24. 25. forwardToView(appView, event);

26. }

27.

28. @Override

29. public void initialize() {

30. super.initialize();

31. appView = new AppView(this);

32. }

33. }

? RSSReader class

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client;

2.

3. import

com.danielvaughan.rssreader.client.mvc.controllers.AppController;

4. import

com.danielvaughan.rssreader.client.mvc.controllers.FeedController;

5. import

com.danielvaughan.rssreader.client.mvc.controllers.NavController;

6. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

7. import com.danielvaughan.rssreader.client.services.FeedService;

8. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

9. import com.extjs.gxt.ui.client.Registry;

10. import com.extjs.gxt.ui.client.mvc.Dispatcher;

11. import com.google.gwt.core.client.EntryPoint;

12. import com.google.gwt.core.client.GWT;

13.

14. /**

15. * Entry point classes define <code>onModuleLoad()</code>.

16. */

gxt gxt初学进阶教程

17. public class RSSReader implements EntryPoint { 18.

19. /**

20. * This is the entry point method.

21. */

22. @Override

23. public void onModuleLoad() {

24. final FeedServiceAsync feedService = GWT.create(FeedService.class);

25. Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);

26. Dispatcher dispatcher = Dispatcher.get();

27.

28. dispatcher.addController(new AppController());

29. dispatcher.addController(new NavController());

30. dispatcher.addController(new FeedController());

31. dispatcher.addController(new ItemController());

32.

33. dispatcher.dispatch(AppEvents.Init);

34. dispatcher.dispatch(AppEvents.UIReady);

35. }

36. }

? ItemController class

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.controllers; 2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.danielvaughan.rssreader.client.mvc.views.ItemView;

5. import com.extjs.gxt.ui.client.mvc.AppEvent;

6. import com.extjs.gxt.ui.client.mvc.Controller;

7.

8. public class ItemController extends Controller {

9.

gxt gxt初学进阶教程

10. private ItemView itemView; 11.

12. public ItemController() {

13. registerEventTypes(AppEvents.Init);

14. }

15.

16. @Override

17. public void handleEvent(AppEvent event) {

18. forwardToView(itemView, event);

19. }

20.

21. @Override

22. public void initialize() {

23. super.initialize();

24. itemView = new ItemView(this);

25. }

26. }

? ItemView class:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import com.danielvaughan.rssreader.client.components.ItemPanel;

4. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

5. import com.extjs.gxt.ui.client.event.EventType;

6. import com.extjs.gxt.ui.client.mvc.AppEvent;

7. import com.extjs.gxt.ui.client.mvc.Controller;

8. import com.extjs.gxt.ui.client.mvc.Dispatcher;

9. import com.extjs.gxt.ui.client.mvc.View;

10.

11. public class ItemView extends View {

12. private final ItemPanel itemPanel = new ItemPanel();

gxt gxt初学进阶教程

13. 14. public ItemView(Controller controller) {

15. super(controller);

16. }

17.

18. @Override

19. protected void handleEvent(AppEvent event) {

20. EventType eventType = event.getType();

21. if (eventType.equals(AppEvents.Init)) {

22. Dispatcher.forwardEvent(new AppEvent(AppEvents.ItemPanelReady,

23. itemPanel));

24. }

25. }

26.

27. }

? AppView class:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.extjs.gxt.ui.client.Style.LayoutRegion;

5. import com.extjs.gxt.ui.client.Style.Orientation;

6. import com.extjs.gxt.ui.client.event.EventType;

7. import com.extjs.gxt.ui.client.mvc.AppEvent;

8. import com.extjs.gxt.ui.client.mvc.Controller;

9. import com.extjs.gxt.ui.client.mvc.View;

10. import com.extjs.gxt.ui.client.widget.Component;

11. import com.extjs.gxt.ui.client.widget.ContentPanel;

12. import com.extjs.gxt.ui.client.widget.Viewport;

13. import com.extjs.gxt.ui.client.widget.layout.BorderLayout;

14. import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;

15. import com.extjs.gxt.ui.client.widget.layout.RowData;

16. import com.extjs.gxt.ui.client.widget.layout.RowLayout;

gxt gxt初学进阶教程

17. import com.google.gwt.user.client.ui.HTML;

18. import com.google.gwt.user.client.ui.RootPanel;

19.

20. public class AppView extends View {

21. private final ContentPanel mainPanel = new ContentPanel();

22. private final Viewport viewport = new Viewport(); 23.

24. public AppView(Controller controller) {

25. super(controller);

26.

27. }

28.

29. @Override

30. protected void handleEvent(AppEvent event) {

31. EventType eventType = event.getType();

32. if (eventType.equals(AppEvents.Init)) {

33. onInit(event);

34. } else if (eventType.equals(AppEvents.Error)) {

35. onError(event);

36. } else if (eventType.equals(AppEvents.UIReady)) {

37. onUIReady(event);

38. } else if (eventType.equals(AppEvents.NavPanelReady)) {

39. onNavPanelReady(event);

40. } else if (eventType.equals(AppEvents.FeedPanelReady)) {

41. onFeedPanelReady(event);

42. } else if (eventType.equals(AppEvents.ItemPanelReady)) {

43. onItemPanelReady(event);

44. }

45. }

46.

47. private void onInit(AppEvent event) {

48. final BorderLayout borderLayout = new BorderLayout();

49. viewport.setLayout(borderLayout);

50. HTML headerHtml = new HTML();

51. headerHtml.setHTML("<h1>RSS Reader</h1>");

gxt gxt初学进阶教程

52. BorderLayoutData northData = new BorderLayoutData(LayoutRegion.NORTH,

53. 20);

54. northData.setCollapsible(false);

55. northData.setSplit(false);

56. viewport.add(headerHtml, northData);

57. BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);

58. centerData.setCollapsible(false);

59. RowLayout rowLayout = new RowLayout(Orientation.VERTICAL);

60. mainPanel.setHeaderVisible(false);

61. mainPanel.setLayout(rowLayout);

62. viewport.add(mainPanel, centerData);

63. }

64.

65. private void onNavPanelReady(AppEvent event) {

66. BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST,

67. 200, 150, 300);

68. westData.setCollapsible(true);

69. westData.setSplit(true);

70. Component component = event.getData();

71. viewport.add(component, westData);

72. }

73.

74. private void onFeedPanelReady(AppEvent event) {

75. RowData rowData = new RowData();

76. rowData.setHeight(.5);

77. Component component = event.getData();

78. mainPanel.add(component, rowData);

79. }

80.

81. private void onItemPanelReady(AppEvent event) {

82. RowData rowData = new RowData();

83. rowData.setHeight(.5);

84. Component component = event.getData();

85. mainPanel.add(component, rowData);

86. }

gxt gxt初学进阶教程

87.

88. private void onUIReady(AppEvent event) {

89. RootPanel.get().add(viewport);

90. }

91.

92. private void onError(AppEvent event) {

93. }

94. } GXT之旅:第七章:MVC——Navigation,Main和Item区域交互(1) 分类: ExtGWT2012-04-12 12:55486人阅读评论(3)收藏举报

(刚干了一个多月的flex项目,一时半会还无法转过神来专注于GXT的东东,有好多东西自己都忘的差不多了。[www.61k.com)。。。我得好好屡屡)

使用TabPanel显示feeds

之前,我们已经通过RssMainPanel里的 ItemGrid来显示一个feed数据。现在,我们将要使用TabPanel去管理多个TabItem——其中每一个TabItem包含一个 ItemGrid,一个ItemGrid负责显示一个feed数据的多个Items内容。

? 编辑com.danielvaughan.rssreader.client.components.FeedPanel,新建

field——TabPanel

[java] view plaincopyprint?

1. private final TabPanel tabPanel = new TabPanel();

? 新建一个方法——addTab,传入TabItem参数。设置一些属性,如下:

[java] view plaincopyprint?

1. public void addTab(TabItem tabItem) {

2. tabItem.setLayout(new FitLayout());

3. tabItem.setIcon(Resources.ICONS.rss());

4. tabItem.setScrollMode(Scroll.AUTO);

5. }

gxt gxt初学进阶教程

? 因为我们只是想让一个TabItem负责显示一个feed数据内容,所以当一个

TabItem已经拥有feed数据显示到TabPanel的时候,就直接跳转到此TabItem,否则就创建一个新的TabItem

[java] view plaincopyprint? 1. public void addTab(TabItem tabItem) {

2. tabItem.setLayout(new FitLayout());

3. tabItem.setIcon(Resources.ICONS.rss());

4. tabItem.setScrollMode(Scroll.AUTO);

5.

6. String tabId = tabItem.getId();

7. TabItem existingTab = tabPanel.findItem(tabId, false); 8. if (existingTab == null) {

9. tabPanel.add(tabItem);

10. tabPanel.setSelection(tabItem);

11. } else {

12. tabPanel.setSelection(existingTab);

13. }

14. }

? 重构FeedPanel构造函数:

[java] view plaincopyprint?

1. public FeedPanel() {

2. setHeading("Main");

3. setLayout(new FitLayout());

4. add(tabPanel);

5. }

连接起来

我们现在几乎已经准备好了所有的UI,现在我们需要将它们连接起来——当用户在

Main(FeedPanel)区域选择了某条feed,则在Item(ItemPanel)区域显示出具体的内容。[www.61k.com]

gxt gxt初学进阶教程

我们可以根据用户的选择事件操作,将其选择的ModelDate在不同的components之间传递。(www.61k.com]同样的,也可以通过数据的加载事件,将ModelData在不同的components之间传递。 大致思路如下: ? 当用户在FeedList选中了一个Feed(link)的时候,一个FeedSelected AppEvent

就会搭载其Feed被派发出去。

? 当FeedSelected AppEvent被派发出来之后,FeedView接收到此事件,然后负责

页面跳转到或新建一个ItemGrid来显示Feed

?

? 当用户在ItemGrid选中了一个Item的时候,一个ItemSelected AppEvent就会

搭载其Item被派发出去。

? 当ItemSelected AppEvent被派发出来之后,ItemView接收到此事件,然后负责

页面使用ItemPanel来显示Item ?

? 当用户在TabPanel选中某个tab的时候,一个TabSelected AppEvent就会搭载

其Feed被派发出去。

? 当TabSelectedAppEvent被派发出来之后,FeedList接收到此事件,然后负责联

动选中到对应的Feed。

Implements:

? AppEvents类,新定义三个EventType

[java] view plaincopyprint?

1. public static final EventType FeedSelected = new EventType();

2. public static final EventType ItemSelected = new EventType();

3. public static final EventType TabSelected = new EventType();

? 找到com.danielvaughan.rssreader.client.lists.FeedList类,在其onRender方法

里,添加 SelectionChange监听——当用户选择不同的Feed的时候,就会触发

SelectionChangedEvent事件,其操作过程,是将传入的selectedItem,派发出

去。

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.lists;

2.

gxt gxt初学进阶教程

3. import java.util.List;

4.

5. import com.danielvaughan.rssreader.client.RSSReaderConstants;

6. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

7. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

8. import com.danielvaughan.rssreader.shared.model.Feed;

9. import com.extjs.gxt.ui.client.Registry;

10. import com.extjs.gxt.ui.client.data.BaseListLoader;

11. import com.extjs.gxt.ui.client.data.BeanModel;

12. import com.extjs.gxt.ui.client.data.BeanModelReader;

13. import com.extjs.gxt.ui.client.data.ListLoadResult;

14. import com.extjs.gxt.ui.client.data.ListLoader;

15. import com.extjs.gxt.ui.client.data.LoadEvent;

16. import com.extjs.gxt.ui.client.data.RpcProxy;

17. import com.extjs.gxt.ui.client.event.LoadListener;

18. import com.extjs.gxt.ui.client.event.SelectionChangedEvent;

19. import com.extjs.gxt.ui.client.event.SelectionChangedListener;

20. import com.extjs.gxt.ui.client.mvc.Dispatcher;

21. import com.extjs.gxt.ui.client.store.ListStore;

22. import com.extjs.gxt.ui.client.widget.LayoutContainer;

23. import com.extjs.gxt.ui.client.widget.form.ListField;

24. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

25. import com.google.gwt.user.client.Element;

26. import com.google.gwt.user.client.rpc.AsyncCallback;

27.

28. public class FeedList extends LayoutContainer {

29.

30. final ListField<BeanModel> feedList = new ListField<BeanModel>(); 31.

32. public FeedList() {

33. setLayout(new FitLayout());

34. }

35.

36. private String getTemplate() {

37. StringBuilder sb = new StringBuilder();

gxt gxt初学进阶教程

38. sb.append("<tpl for=\".\">");

39. sb.append("<div class='x-combo-list-item'><b>{title}</b>

-{description}</div>");

40. sb.append("</tpl>");

41. return sb.toString();

42. }

43.

44. @Override

45. protected void onRender(Element parent, int index) {

46. super.onRender(parent, index);

47. // 0:从Registry里获得Service

48. final FeedServiceAsync feedService = (FeedServiceAsync) Registry

49. .get(RSSReaderConstants.FEED_SERVICE);

50. // 1:定义proxy在load方法里掉用Serivce里的方法

51. RpcProxy<List<Feed>> proxy = new RpcProxy<List<Feed>>() {

52. @Override

53. protected void load(Object loadConfig,

54. AsyncCallback<List<Feed>> callback) {

55. feedService.loadFeedList(false, callback);

56.

57. }

58. };

59. // 2:定义Reader

60. BeanModelReader reader = new BeanModelReader();

61. // 3:将proxy和reader传入,定义loader

62. ListLoader<ListLoadResult<BeanModel>> loader = new

BaseListLoader<ListLoadResult<BeanModel>>(

63. proxy, reader);

64. // 4:传入loader,生成store,此时还没有load数据

65. final ListStore<BeanModel> feedStore = new ListStore<BeanModel>(loader);

66. // 5:将stroe绑定到data-backed component身上

67. feedList.setStore(feedStore);

68. feedList.setTemplate(getTemplate());

69.

gxt gxt初学进阶教程

70. feedList.addSelectionChangedListener(new SelectionChangedListener<BeanModel>() {

71. @Override

72. public void selectionChanged(SelectionChangedEvent<BeanModel> se) { 73. Feed feed = se.getSelectedItem().getBean(); 74. if (feed != null) {

75. Dispatcher.forwardEvent(AppEvents.FeedSelected, feed);//关键在这里~~~

76. }

77. }

78. });

79.

80. // 6:真正的load数据,load成功之后,data-backed component会自动的显示出来。[www.61k.com] 81. loader.load();

82.

83. add(feedList);

84. }

85. }

? 如果想要程序能够对FeedSelected事件作出响应,就必须在关联的Controller注

册——FeedController

[java] view plaincopyprint?

1. public FeedController() {

2. registerEventTypes(AppEvents.Init);

3.

4. registerEventTypes(AppEvents.FeedSelected);

5. }

? 重构ItemGrid的构造函数,增加一个参数为Feed——用来接收FeedSelected事

件传递过来的Feed

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. private final Feed feed;

2. public ItemGrid(Feed feed) {

3. setLayout(new FitLayout());

4. this.feed = feed;

5. }

? 继续在ItemGrid类,将onRender方法里面局部变量的grid,提取到方法外面,

作为ItemGrid类的属性存在。[www.61k.com]

[java] view plaincopyprint? 1. private Grid<ModelData> grid;

2.

3. @Override

4. protected void onRender(Element parent, int index) {

5. …

6. grid = new Grid<ModelData>(itemStore, columnModel);

7. }

? 继续在ItemGrid类的onRender方法里。删除如下局部变量的定义

[java] view plaincopyprint?

1. final String TEST_DATA_FILE = "http://localhost:8888/rss2sample.xml"; ? 取而代之,是使用Feed对象的UUID属性替换之前的TEST_DATA_FILE [java] view plaincopyprint?

1. RpcProxy<List<Item>> proxy = new RpcProxy<List<Item>>() {

2. @Override

3. protected void load(Object loadConfig,

4. AsyncCallback<List<Item>> callback) {

5. feedService.loadItems(feed.getUuid(), callback);

6. }

7. };

gxt gxt初学进阶教程

? 继续在ItemGrid类里,定义一个新的方法——resetSelection,用来重设Grid

的选中状态。(www.61k.com)

[java] view plaincopyprint?

1. public void resetSelection() {

2. grid.getSelectionModel().deselectAll();

3. }

? 在FeedView类,新建一个方法(onFeedSelected)用来响应,接收到的

FeedSelected事件:通过传入的event获得Feed对象;将Feed对象作为参数创建一个ItemGrid;新建TabItem,并设置一些属性,将先前新建的ItemGrid加入到Tabitem里;最后,将tabItem加入到feedPanel里。

[java] view plaincopyprint?

1. private void onFeedSelected(AppEvent event) {

2. Feed feed = event.getData();

3. final ItemGrid itemGrid = new ItemGrid(feed);

4. TabItem tabItem = new TabItem(feed.getTitle());

5. tabItem.setId(feed.getUuid());

6. tabItem.setData("feed", feed);

7. tabItem.add(itemGrid);

8. tabItem.addListener(Events.Select, new Listener<TabPanelEvent>() {//选

中之后的tab会清空item selection

9. @Override

10. public void handleEvent(TabPanelEvent be) {

11. itemGrid.resetSelection();

12. }

13. });

14. tabItem.setClosable(true);

15. feedPanel.addTab(tabItem);

16. }

? 在FeedView类的handleEvent方法里,加入对FeedSelected事件的跳转。到此

FeedSelected事件的处理流程完成

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) {

5. onInit(event);

6. }else if (eventType.equals(AppEvents.FeedSelected)) { 7. onFeedSelected(event);

8. }

9. }

? 在ItemGrid的onRender方法里,添加一个SelectionChange的监听,当用户选

择不同的Item的时候,就会触发SelectionChangedEvent事件,其操作过程,是将传入的selectedItem,派发出去。(www.61k.com)

[java] view plaincopyprint? 1. grid.getSelectionModel().addListener(Events.SelectionChange, 2. new Listener<SelectionChangedEvent<Item>>() {

3. @Override

4. public void handleEvent(SelectionChangedEvent<Item> be) {

5. Item item = be.getSelectedItem();

6. if(item!=null)

7. Dispatcher.forwardEvent(AppEvents.ItemSelected, item);

8. }

9. });

? 同样的,对于ItemSelected方法,我们要在ItemController里注册

[java] view plaincopyprint?

1. public ItemController() {

2. registerEventTypes(AppEvents.Init);

gxt gxt初学进阶教程

3. 4. registerEventTypes(AppEvents.ItemSelected);

5. }

? 在ItemView类里,针对ItemSelected AppEvent处理的方法——onItemSelected()

[java] view plaincopyprint? 1. private void onItemSelected(AppEvent event) {

2. Item item = (Item) event.getData();

3. itemPanel.displayItem(item);

4. } ? 在ItemView类里,handleEvent方法里加入针对ItemSelected事件的处理方法

跳转。[www.61k.com]到此ItemSelected事件的处理流程完成

[java] view plaincopyprint?

1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) {

5. Dispatcher.forwardEvent(new AppEvent(AppEvents.ItemPanelReady,

6. itemPanel));

7. } else if (eventType.equals(AppEvents.ItemSelected)) {

8. onItemSelected(event);

9. }

10. }

? 现在我们还少一个事件处理流程——TabSelected ,但是我们先来看看程序运行

效果哈~~~

gxt gxt初学进阶教程

GXT之旅:第七章:MVC

gxt gxt初学进阶教程

——Navigation,Main和Item区域交互(2)

分类: ExtGWT2012-04-17 16:06291人阅读评论(0)收藏举报

保持同步

我们现在需要保证,当有新的feed添加的时候,feeds列表要正确的更新出来。[www.61k.com]同时,我们也需要保证,当用户选择了某个feed的tab的时候,相对应于feeds列表中的feed会同步的被选中。

gxt gxt初学进阶教程

为了实现如上两个要求,我们要创建两个对应的events——一个feed被添加,一个feed tab被选中

? 在AppEvents类里定义两个新的EventType——FeedAdded,TabSelected

[java] view plaincopyprint? 1. public static final EventType TabSelected = new EventType();

2. public static final EventType FeedAdded = new EventType();

? 上面两个事件都属于左侧导航区域应该响应的事件。[www.61k.com]因此,在NavController

类里面注册

[java] view plaincopyprint? 1. public NavController() { 2. registerEventTypes(AppEvents.Init);

3. registerEventTypes(AppEvents.FeedAdded);

4. registerEventTypes(AppEvents.TabSelected);

5. }

? 在FeedList类里,将ListField和ListLoader的定义从onRender方法里提出来

[java] view plaincopyprint?

1. private final ListField<BeanModel> feedList = new

2. ListField<BeanModel>();

3. private ListLoader<ListLoadResult<BeanModel>> loader;

? 继续重构,定义一个新的方法reloadFeeds,其功能是负责load真正的数据。

[java] view plaincopyprint?

1. public void reloadFeeds() {

gxt gxt初学进阶教程

2. loader.load();

3. }

? 定义第二个新方法selectFeed,其功能是,使用参数feed去设置,选中适当

的ListField

[java] view plaincopyprint? 1. public void selectFeed(Feed feed) {

2. BeanModelFactory beanModelFactory = BeanModelLookup.get().getFactory(

3. feed.getClass());

4. feedList.setSelection(Arrays.asList(beanModelFactory.createModel(feed)

));

5. }

? 在NavPanel类里,重构一下其构造函数,将匿名对象new FeedList();提为

属性

[java] view plaincopyprint? 1. private FeedList feedList = new FeedList();

2.

3. public NavPanel() {

4. setHeading("Navigation");

5. setLayout(new FitLayout());

6. initToolbar();

7. add(feedList);

8. }

? 在NavPanel类里,再定义两个新方法——selectFeed,reloadFeeds方法,

相同于FeedList类里的方法。[www.61k.com)

[java] view plaincopyprint?

1. public void reloadFeeds() {

2. feedList.reloadFeeds();

3. }

4.

gxt gxt初学进阶教程

5. public void selectFeed(Feed feed) {

6. feedList.selectFeed(feed); 7. }

? 在NavView类里,新建onTabSelected方法,通过AppEvent获得其携带的

feed,feed用于调用selectFeed方法传入参数。(www.61k.com]

[java] view plaincopyprint? 1. private void onTabSelected(AppEvent event) { 2. Feed feed = (Feed) event.getData();

3. navPanel.selectFeed(feed);

4. }

? 继续,在NavView类里,新建onFeedAdded方法,调用

NavPanel.reloadFeeds方法

[java] view plaincopyprint?

1. private void onFeedAdded(AppEvent event) {

2. navPanel.reloadFeeds();

3. }

? 在NavView类里,开始修改handleEvent方法,根据事件的类型,调用与之

对应的处理方法

[java] view plaincopyprint? 1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4.

5. if (eventType.equals(AppEvents.Init)) {

6. Dispatcher.forwardEvent(new AppEvent(AppEvents.NavPanelReady,

7. navPanel));

8. } else if (eventType.equals(AppEvents.TabSelected)) {

9. onTabSelected(event);

10. } else if (eventType.equals(AppEvents.FeedAdded)) {

gxt gxt初学进阶教程

11. onFeedAdded(event); 12. }

13. }

? 在LinkFeedPopup类里的addFeed方法里,之前我们通过调用

FeedService.addExistingFeed方法来添加一个feed的link。(www.61k.com]接下来在其onSuccess方法我们触发FeedAdded事件

[java] view plaincopyprint? 1. public void addFeed(final String feedUrl) {

2. final FeedServiceAsync feedService = Registry

3. .get(RSSReaderConstants.FEED_SERVICE);

4. feedService.addExistingFeed(feedUrl, new AsyncCallback<Void>() {

5. @Override

6. public void onFailure(Throwable caught) {

7. Info.display("RSS Reader", "Failed to add feed at: " + feedUrl);

8. }

9.

10. @Override

11. public void onSuccess(Void result) {

12. tfUrl.clear();

13. Info.display("RSS Reader", "Feed at " + feedUrl

14. + " added successfully");

15. Dispatcher.forwardEvent(AppEvents.FeedAdded);

16. hide();

17. }

18. });

19. }

? 类似的,在FeedForm.save方法里,在调用FeedService.saveFeed方法时

的onSuccess方法里,加入同样的触发FeedAdded事件

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. public void save(final Feed feed) { 2. feed.setTitle(tfTitle.getValue());

3. feed.setDescription(taDescription.getValue());

4. feed.setLink(tfLink.getValue());

5.

6. final FeedServiceAsync feedService = Registry

7. .get(RSSReaderConstants.FEED_SERVICE);

8. feedService.saveFeed(feed, new AsyncCallback<Void>() {

9. @Override

10. public void onFailure(Throwable caught) {

11. Info.display("RSS Reader",

12. "Failed to save feed: " + feed.getTitle());

13. }

14.

15. @Override

16. public void onSuccess(Void result) {

17. Info.display("RSS Reader", "Feed " + feed.getTitle()

18. + " saved sucessfully");

19. Dispatcher.forwardEvent(AppEvents.FeedAdded);

20. }

21. });

22.

23. }

? 最后,在FeedView.onFeedSelected方法里,在现有的Listener内触发

TabSelected事件

[java] view plaincopyprint?

1. private void onFeedSelected(AppEvent event) {

2. final Feed feed = event.getData();

3. final ItemGrid itemGrid = new ItemGrid(feed);

4. TabItem tabItem = new TabItem(feed.getTitle());

5. tabItem.setId(feed.getUuid());

6. tabItem.setData("feed", feed);

7. tabItem.add(itemGrid);

gxt gxt初学进阶教程

8. tabItem.addListener(Events.Select, new Listener<TabPanelEvent>() {// 选

中之后的tab清空item

9. // selection

10. @Override

11. public void handleEvent(TabPanelEvent be) {

12. itemGrid.resetSelection();

13. Dispatcher.forwardEvent(new AppEvent(

14. AppEvents.TabSelected, feed));

15. }

16. });

17. tabItem.setClosable(true);

18. feedPanel.addTab(tabItem);

19. }

GXT之旅:第七章:MVC——Status toolbar

分类: ExtGWT2012-04-17 17:41289人阅读评论(0)收藏举报

一个AppEvent不仅仅可以被一个Controller所捕捉,它可以被多个Controller所捕捉,关键在于有多少个Controller注册了该AppEvent。[www.61k.com]

下面我们要结合之前代码,新建一个新的StatusController,注册之前已有的Events,使用StatusToolbar component来给用户显示系统的运行状态。

我们现在针对两个以后的事件:

?

? Feed selected Item selected

下面具体实现步骤如下:

? AppEvents类里,加入新的EventType定义——StatusToolbarReady

[java] view plaincopyprint?

1. public static final EventType StatusToolbarReady = new EventType();

? 在com.danielvaughan.rssreader.client.mvc.controllers包下,新建类

——StatusController。具体内容如下

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. package com.danielvaughan.rssreader.client.mvc.controllers; 2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.danielvaughan.rssreader.client.mvc.views.StatusView;

5. import com.extjs.gxt.ui.client.mvc.AppEvent;

6. import com.extjs.gxt.ui.client.mvc.Controller;

7.

8. public class StatusController extends Controller {

9.

10. private StatusView statusView;

11.

12. public StatusController() {

13. registerEventTypes(AppEvents.Init);

14. registerEventTypes(AppEvents.Error);

15. registerEventTypes(AppEvents.UIReady);

16. registerEventTypes(AppEvents.FeedSelected);

17. registerEventTypes(AppEvents.ItemSelected);

18. }

19.

20. @Override

21. public void handleEvent(AppEvent event) {

22. forwardToView(statusView, event);

23. }

24.

25. @Override

26. public void initialize() {

27. super.initialize();

28. statusView = new StatusView(this);

29. }

30. }

? 在com.danielvaughan.rssreader.client.mvc.views包下,新建StatusView。[www.61k.com]

具体实现如下

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import com.extjs.gxt.ui.client.mvc.AppEvent;

4. import com.extjs.gxt.ui.client.mvc.Controller;

5. import com.extjs.gxt.ui.client.mvc.View;

6.

7. public class StatusView extends View {

8.

9. public StatusView(StatusController statusController) {

10. super(statusController);

11. }

12.

13. @Override 14. protected void handleEvent(AppEvent event) {

15.

16. }

17.

18. }

? 新建好后,再定义两个新的属性——Status和ToolBar。(www.61k.com)在定义一个新的方

法,用来设置Status的显示内容

[java] view plaincopyprint?

1. private final Status status = new Status();

2. private final ToolBar toolBar = new ToolBar();

3. public void setStatus(String message) {

4. status.setText(message);

5. }

? 继续在StatusView类里,新建方法onInit,用来对应Init事件处理。其内容

一部分是装配Status和ToolBar;另一部分是派发StatusToolbarReady事件,并携带刚刚装配好的toolBar

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. private void onInit() { 2. status.setWidth("100%");

3. status.setBox(true);

4. toolBar.add(status);

5. Dispatcher.forwardEvent(new AppEvent(AppEvents.StatusToolbarReady,

6. toolBar));

7. }

? 自然的,要在handleEvent方法里编写Init事件的流程控制。[www.61k.com]

[java] view plaincopyprint? 1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) {

5. onInit();

6. setStatus("Init");

7. }

8. }

? 针对于*Ready的事件,其捕捉的Controller都是AppController,因此要在

AppController注册StatusPanelReady

[java] view plaincopyprint?

1. public AppController() {

2. registerEventTypes(AppEvents.Init);

3. registerEventTypes(AppEvents.Error);

4. registerEventTypes(AppEvents.UIReady);

5. registerEventTypes(AppEvents.NavPanelReady);

6. registerEventTypes(AppEvents.FeedPanelReady);

7. registerEventTypes(AppEvents.ItemPanelReady);

8.

gxt gxt初学进阶教程

9. registerEventTypes(AppEvents.StatusToolbarReady);

10. } ? 随着AppController里有新的事件被注册了,因此就要在响应的View里编写

事件的处理方法——编辑AppView类,新建onStatusToolbarReady方法,其内容是把AppEvent所携带的Component,加入到mainPanel里显示出来~~~

[java] view plaincopyprint?

1. private void onStatusToolbarReady(AppEvent event) {

2. Component component = event.getData();

3. mainPanel.setBottomComponent(component);

4. }

? 编辑AppView类handleEvent方法,针对StatusPanelReady事件的流程处

理。(www.61k.com]

[java] view plaincopyprint?

1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) {

5. onInit(event);

6. } else if (eventType.equals(AppEvents.Error)) {

7. onError(event);

8. } else if (eventType.equals(AppEvents.UIReady)) {

9. onUIReady(event);

10. } else if (eventType.equals(AppEvents.NavPanelReady)) {

11. onNavPanelReady(event);

12. } else if (eventType.equals(AppEvents.FeedPanelReady)) {

13. onFeedPanelReady(event);

14. } else if (eventType.equals(AppEvents.ItemPanelReady)) {

15. onItemPanelReady(event);

16. }else if (eventType.equals(AppEvents.StatusToolbarReady)) {

gxt gxt初学进阶教程

17. onStatusToolbarReady(event);

18. }

19. }

? 好像大家都忘了,事件需要被某些Controllers里注册,同样的Controllers

也需要在应用里注册!编辑整个应用的入口类——RSSReader,注册StatusController

[java] view plaincopyprint? 1. @Override

2. public void onModuleLoad() {

3. final FeedServiceAsync feedService = GWT.create(FeedService.class);

4. Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);

5. Dispatcher dispatcher = Dispatcher.get();

6.

7. dispatcher.addController(new AppController());

8. dispatcher.addController(new NavController());

9. dispatcher.addController(new FeedController());

10. dispatcher.addController(new ItemController());

11.

12. dispatcher.addController(new StatusController());//here

13.

14. dispatcher.dispatch(AppEvents.Init);

15. dispatcher.dispatch(AppEvents.UIReady);

16. }

? 回归到StatusView类,开始编写针对FeedSelected事件的处理。[www.61k.com](因为

StatusController在最后被注册,所以FeedSelected事件会先被派发到FeedController,最后才是StatusController。)

[java] view plaincopyprint?

1. @Override

2. protected void handleEvent(AppEvent event) {

gxt gxt初学进阶教程

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) {

5. onInit();

6. setStatus("Init");

7. } else if (eventType.equals(AppEvents.FeedSelected)) {

8. Feed feed = event.getData();

9. setStatus("Feed Selected - (" + feed.getTitle() + ")");

10. }

11. }

? 相似的,在StatusView类,编写针对ItemSelected事件的处理。(www.61k.com)

[java] view plaincopyprint? 1. @Override 2.

gxt gxt初学进阶教程

protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.Init)) {

5. onInit();

6. setStatus("Init");

7. } else if (eventType.equals(AppEvents.FeedSelected)) {

8. Feed feed = event.getData();

9. setStatus("Feed Selected - (" + feed.getTitle() + ")");

10. } else if (eventType.equals(AppEvents.ItemSelected)) {

11. Item item = event.getData();

12. setStatus("Item Selected - (" + item.getTitle() + ")");

13. }

14. }

? 运行效果如下:

gxt gxt初学进阶教程

GXT之旅:第八章:Portal&Drag-Drop——Portal的基本介绍

分类: ExtGWT2012-04-23 12:03296人阅读评论(0)收藏举报

第八章:Portal&Drag-Drop

本章我们要了解GXT的Portal&Drag-Drop功能。(www.61k.com)我们会首先学习如何使用Portal(非常类似谷歌的iGoogle功能)布局和Portlet,然后再以实践的方式学习GXT的拖拽功能。

我们会涉及到如下GXt功能集

?

?

?

? Portal Portlet Draggable DragSource

o GridDropTarget

o ListViewDropTarget

o TreeGridDropTarget

o TreePanelDropTarget

?

? ColumnLayout RowLayout

Portlet class

Portlet 类继承自ContentPanel,她提供了一种特殊的panel,可以在Viewport的Portal容器里,随意的更改显示位置和大小。她很像widows系统里面的桌面应用。 新建一个Portlet的过程很类似于其他容器的创建。

[java] view plaincopyprint?

1. Portlet portlet = new Portlet();

2. portlet.setHeight(150);

3. portlet.setHeading("Example Portlet");

运行效果如下:

gxt gxt初学进阶教程

gxt gxt初学进阶教程

[java] view plaincopyprint?

1. portal.setPinned(true);

设置其是否可以被重置位置。[www.61k.com]除此之外,Portlet继承ContentPanel的所有功能 Portal class

Portal是专门为Portlet设置的容器。事实上,其容器包含了一组按照ColumnLayout布局的LayoutContainer。其中每一个LayoutContainer都包含一个Portlet,布局效果为RowLayout。

Portal同样支持Portlet的拖拽功能。Portal里面会有列,每一个列里面又包含行。因此就有了表格的概念,所以当新建一个Portal的时候,我们就需要在构造函数里,设置有多少列。当然还得通过setColumnWidth()方法设置其每一列的宽度。

假如,我们想创建一个两列的,分别是30%,70%宽的Portal的时候。我们会有如下代码

[java] view plaincopyprint?

1. Portal portal = new Portal(2);

2. portal.setColumnWidth(0, 0.3);

3. portal.setColumnWidth(1, 0.7);

当Portal定义好了之后,我们要往每一列里放入Portlet(其宽度自动的跟着column的宽度适应,只需要设置高度既可)

[java] view plaincopyprint?

1. Portlet portlet1 = new Portlet();

2. portlet1.setHeight(150);

3. portlet1.setHeading("Example Portlet 1");

4. portal.add(portlet1, 0);

5.

6. Portlet portlet2 = new Portlet();

7. portlet2.setHeight(150);

gxt gxt初学进阶教程

8. portlet2.setHeading("Example Portlet 2");

9. portal.add(portlet2, 1); 生成后的效果如下:

gxt gxt初学进阶教程

gxt gxt初学进阶教程

gxt gxt初学进阶教程

左右两个Portlet可以被拖拽到不同的位置。[www.61k.com]当一个Portlet正在被拖拽的时候,其效果如下

当右侧的portlet被拖拽到左侧的时候,会自动的改变宽度

ToolButton

正是因为Portlet继承了ContentPanel,所以我们可以在其头部添加ToolButton。这样一来,可以让Portlet在功能和显示效果上,更接近桌面的应用窗口。

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. portlet.getHeader().addTool(new ToolButton("x-tool-minimize"));

2. portlet.getHeader().addTool(new ToolButton("x-tool-maximize"));

3. portlet.getHeader().addTool(new ToolButton("x-tool-close")); 如上的三行代码,就会构建出如下的效果

分类: ExtGWT 2012-04-23 14:16236人阅读评论(0)收藏举报

目前,我们的RSSReader项目里,使用的是ContentPanel容器和BorderLayout布局效果。(www.61k.com)接下来,我们要做稍微的调整,将ContentPanel替换为Portlet,

然后使用Portal去管理他们。

Portlet是一个非常理想的components,用来构成独立的,不受他人影响的用户接口。不仅仅可以统一的被Portal管理,我们还可以使用MVC,让Portal响应每一个Portlet的新建过程,并保证其独立性。

? 我们首先要做的是新增一个EventType(NewPortletCreated)到AppEvents

类里。我们会用它来触发新建Portlet过程。

[java] view plaincopyprint?

1. public static final EventType NewPortletCreated = new EventType();

? 新建类:PortalController extends Controller

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.controllers;

gxt gxt初学进阶教程

2.

3. import com.extjs.gxt.ui.client.mvc.AppEvent;

4. import com.extjs.gxt.ui.client.mvc.Controller;

5.

6. public class PortalController extends Controller {

7.

8. public PortalController() {

9.

10. }

11.

12. @Override

13. public void handleEvent(AppEvent event) {

14.

15. }

16.

17. } ? 新建类:PortalView extends View

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import

com.danielvaughan.rssreader.client.mvc.controllers.PortalController;

4. import com.extjs.gxt.ui.client.mvc.AppEvent;

5. import com.extjs.gxt.ui.client.mvc.View;

6.

7. public class PortalView extends View {

8.

9. public PortalView(PortalController controller) {

10. super(controller);

11. }

12.

13. @Override

14. protected void handleEvent(AppEvent event) {

gxt gxt初学进阶教程

15. 16. }

17.

18. }

? 回到PortalController类,加入PortalView属性到此类里。[www.61k.com]并且Override

initialize()方法

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.controllers; 2.

3. import com.danielvaughan.rssreader.client.mvc.views.PortalView;

4. import com.extjs.gxt.ui.client.mvc.AppEvent;

5. import com.extjs.gxt.ui.client.mvc.Controller;

6.

7. public class PortalController extends Controller {

8.

9. private PortalView portalView;

10.

11. @Override

12. public void initialize() {

13. super.initialize();

14. portalView = new PortalView(this);

15. }

16.

17. public PortalController() {

18.

19. }

20.

21. @Override

22. public void handleEvent(AppEvent event) {

23.

24. }

25.

26. }

gxt gxt初学进阶教程

? 构造函数里,注册EventType——NewPortletCreated,Error

[java] view plaincopyprint? 1. public PortalController() { 2. registerEventTypes(AppEvents.NewPortletCreated);

3. registerEventTypes(AppEvents.Error);

4. }

? 下面处理handleEvent方法——有错误事件的时候,记录日志;其他情况,

将事件转发到portalView

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.controllers; 2.

3. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

4. import com.danielvaughan.rssreader.client.mvc.views.PortalView;

5. import com.extjs.gxt.ui.client.event.EventType;

6. import com.extjs.gxt.ui.client.mvc.AppEvent;

7. import com.extjs.gxt.ui.client.mvc.Controller;

8. import com.google.gwt.core.client.GWT;

9.

10. public class PortalController extends Controller {

11.

12. private PortalView portalView;

13.

14. @Override

15. public void initialize() {

16. super.initialize();

17. portalView = new PortalView(this);

18. }

19.

20. public PortalController() {

21. registerEventTypes(AppEvents.NewPortletCreated);

gxt gxt初学进阶教程

22. registerEventTypes(AppEvents.Error);

23. }

24.

25. @Override

26. public void handleEvent(AppEvent event) { 27. EventType eventType = event.getType(); 28. if (eventType.equals(AppEvents.Error)) {

29. GWT.log("Error", (Throwable) event.getData());

30. } else {

31. forwardToView(portalView, event);

32. }

33. }

34.

35. }

? 接下来回到PortalView类里,新建一个属性——portal,并且是一个具有两

列的portal

[java] view plaincopyprint?

1. private final Portal portal = new Portal(2);

? Override initialize()方法:设置两列的各自宽度;并且新建一个Viewport,在

Viewport里加入portal

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import

com.danielvaughan.rssreader.client.mvc.controllers.PortalController;

4. import com.extjs.gxt.ui.client.mvc.AppEvent;

5. import com.extjs.gxt.ui.client.mvc.View;

6. import com.extjs.gxt.ui.client.widget.Viewport;

7. import com.extjs.gxt.ui.client.widget.custom.Portal;

8. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

9. import com.google.gwt.user.client.ui.RootPanel;

gxt gxt初学进阶教程

10.

11. public class PortalView extends View {

12. private final Portal portal = new Portal(2); 13.

14. public PortalView(PortalController controller) {

15. super(controller);

16. }

17.

18. @Override

19. protected void handleEvent(AppEvent event) { 20.

21. }

22.

23. @Override

24. protected void initialize() {

25. portal.setColumnWidth(0, 0.3);

26. portal.setColumnWidth(1, 0.7);

27. final Viewport viewport = new Viewport();

28. viewport.setLayout(new FitLayout());

29. viewport.add(portal);

30. RootPanel.get().add(viewport);

31. }

32. }

? 当然handleEvent()方法要处理传入的NewPortletCreated事件。[www.61k.com)但是就现在

而言,我们先不做处理。

[java] view plaincopyprint?

1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.NewPortletCreated)) {

5. }

6. }

gxt gxt初学进阶教程

? 最后,来到RSSReader类的onModuleLoad方法——去掉之前所有的代码,

修改后的内码如下:

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client;

2.

3. import

com.danielvaughan.rssreader.client.mvc.controllers.AppController;

4. import

com.danielvaughan.rssreader.client.mvc.controllers.FeedController;

5. import

com.danielvaughan.rssreader.client.mvc.controllers.ItemController;

6. import

com.danielvaughan.rssreader.client.mvc.controllers.NavController;

7. import

com.danielvaughan.rssreader.client.mvc.controllers.PortalController;

8. import

com.danielvaughan.rssreader.client.mvc.controllers.StatusController;

9. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

10. import com.danielvaughan.rssreader.client.services.FeedService;

11. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

12. import com.extjs.gxt.ui.client.Registry;

13. import com.extjs.gxt.ui.client.mvc.Dispatcher;

14. import com.google.gwt.core.client.EntryPoint;

15. import com.google.gwt.core.client.GWT;

16.

17. /**

18. * Entry point classes define <code>onModuleLoad()</code>.

19. */

20. public class RSSReader implements EntryPoint {

21.

22. /**

23. * This is the entry point method.

24. */

25. @Override

gxt gxt初学进阶教程

26. public void onModuleLoad() {

27. // final FeedServiceAsync feedService = GWT.create(FeedService.class);

28. // Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);

29. // Dispatcher dispatcher = Dispatcher.get();

30. //

31. // dispatcher.addController(new AppController());

32. // dispatcher.addController(new NavController());

33. // dispatcher.addController(new FeedController());

34. // dispatcher.addController(new ItemController());

35. //

36. // dispatcher.addController(new StatusController());

37. //

38. // dispatcher.dispatch(AppEvents.Init); 39. // dispatcher.dispatch(AppEvents.UIReady);

40.

41. final FeedServiceAsync feedService = GWT.create(FeedService.class);

42. Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);

43. Dispatcher dispatcher = Dispatcher.get();

44. dispatcher.addController(new PortalController());

45. }

46. }

GXT之旅:第八章:Portal&Drag-Drop——项目使用Portal重构(2)

分类: ExtGWT2012-04-23 15:05223人阅读评论(0)收藏举报

实际上,Portlet components并不是那么复杂,大多数的工作,我们在上一节都完成了,Portlet其实只是一个包装。(www.61k.com]

? 新建包:com.danielvaughan.rssreader.client.portlets。在此包下,新建类

NavPortlet extends Portlet(负责左侧导航区域)

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.portlets;

2.

gxt gxt初学进阶教程

3. import com.extjs.gxt.ui.client.widget.custom.Portlet;

4. import com.extjs.gxt.ui.client.widget.layout.FitLayout; 5.

6. public class NavPortlet extends Portlet { 7. public NavPortlet() {

8. setHeading("Navigation");

9. setLayout(new FitLayout());

10. setHeight(610);

11. }

12. }

? 在RSSReaderConstants类里,定义一个新的恒量NAV_PORTLET

[java] view plaincopyprint?

1. public static final String NAV_PORTLET = "navPortlet"; ? 恒量设置之后,在NavPortlet类构造函数里,用其来设置ID

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.portlets; 2.

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

4. import com.extjs.gxt.ui.client.widget.custom.Portlet;

5. import com.extjs.gxt.ui.client.widget.layout.FitLayout; 6.

7. public class NavPortlet extends Portlet {

8. public NavPortlet() {

9. setHeading("Navigation");

10. setLayout(new FitLayout());

11. setHeight(610);

12.

13. setId(RSSReaderConstants.NAV_PORTLET);

14. }

15. }

gxt gxt初学进阶教程

? 继续在此构造函数里,新建NavPanel,加入到NavPortlet里。(www.61k.com)

[java] view plaincopyprint? 1. public NavPortlet() {

2. setHeading("Navigation");

3. setLayout(new FitLayout());

4. setHeight(610);

5.

6. setId(RSSReaderConstants.NAV_PORTLET);

7.

8. NavPanel navPanel = new NavPanel();

9. navPanel.setHeaderVisible(false);

10. add(navPanel);

11. }

? NavPortlet的创建过程已经完毕,接下来需要通知portal,这一过程——通过

派发NewPortletCreated事件,实现通知的过程。

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.portlets;

2.

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

4. import com.danielvaughan.rssreader.client.components.NavPanel;

5. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

6. import com.extjs.gxt.ui.client.mvc.Dispatcher;

7. import com.extjs.gxt.ui.client.widget.custom.Portlet;

8. import com.extjs.gxt.ui.client.widget.layout.FitLayout; 9.

10. public class NavPortlet extends Portlet {

11. public NavPortlet() {

12. setHeading("Navigation");

13. setLayout(new FitLayout());

14. setHeight(610);

15.

16. setId(RSSReaderConstants.NAV_PORTLET);

gxt gxt初学进阶教程

17.

18. NavPanel navPanel = new NavPanel();

19. navPanel.setHeaderVisible(false);

20. add(navPanel);

21.

22. Dispatcher.forwardEvent(AppEvents.NewPortletCreated , this);

23. }

24. }

? NewPortletCreated事件派发出来之后,我们就需要在对应的View类里处理

该事件——编辑PortalView类,新建onNewPortletCreated()方法,根据RSSReaderConstants.NAV_PORTLET来判断将传入的portlet加入到哪一列上。[www.61k.com)

[java] view plaincopyprint? 1. @Override

2. protected void handleEvent(AppEvent event) {

3. EventType eventType = event.getType();

4. if (eventType.equals(AppEvents.NewPortletCreated)) {

5. onNewPortletCreated(event);

6. }

7. }

8.

9. private void onNewPortletCreated(AppEvent event) {

10. final Portlet portlet = (Portlet) event.getData();

11. if (portlet.getId() == RSSReaderConstants.NAV_PORTLET) {

12. portal.add(portlet, 0);

13. } else {

14. portal.add(portlet, 1);

15. }

16. }

? 目前我们所要做的就是,回到RSSReader.onModuleLoad方法,新建一个

NavPortlet实例。剩下的操作,就交给MVC自动处理了~~~

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. package com.danielvaughan.rssreader.client; 2.

3. import

com.danielvaughan.rssreader.client.mvc.controllers.PortalController;

4. import com.danielvaughan.rssreader.client.portlets.NavPortlet;

5. import com.danielvaughan.rssreader.client.services.FeedService;

6. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

7. import com.extjs.gxt.ui.client.Registry;

8. import com.extjs.gxt.ui.client.mvc.Dispatcher;

9. import com.google.gwt.core.client.EntryPoint;

10. import com.google.gwt.core.client.GWT;

11.

12. /**

13. * Entry point classes define <code>onModuleLoad()</code>.

14. */

15. public class RSSReader implements EntryPoint {

16.

17. /**

18. * This is the entry point method.

19. */

20. @Override

21. public void onModuleLoad() {

22.

23. final FeedServiceAsync feedService = GWT.create(FeedService.class);

24. Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);

25. Dispatcher dispatcher = Dispatcher.get();

26. dispatcher.addController(new PortalController());

27.

28. new NavPortlet();

29. }

30. }

? 最后,让我们来看看效果吧

gxt gxt初学进阶教程

GXT之旅:第八章:Portal&Drag-Drop——项目使用Portal重构(3)

分类: ExtGWT2012-04-23 15:49237人阅读评论(0)收藏举报

按照上一节的思路,我们来继续重构feed和item区域

? 新建两个恒量,在RSSReaderConstants类里,加入两个新的恒量

——FEED_PORTLET 和 ITEM_PORTLET

[java] view plaincopyprint?

1. public static final String FEED_PORTLET = "feedPortlet";

2. public static final String ITEM_PORTLET = "itemPortlet";

? 在包

gxt gxt初学进阶教程

com.danielvaughan.rssreader.client.portlets:新建FeedPortlet extends

Portlet;并且在构造函数中用相同于NavPortlet的代码。[www.61k.com)

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.portlets;

2.

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

gxt gxt初学进阶教程

4. import com.extjs.gxt.ui.client.widget.custom.Portlet; 5. import com.extjs.gxt.ui.client.widget.layout.FitLayout; 6.

7. public class FeedPortlet extends Portlet {

8. public FeedPortlet() {

9. setHeading("Feed");

10. setLayout(new FitLayout());

11. setHeight(350);

12. setId(RSSReaderConstants.FEED_PORTLET);

13. }

14. }

? 同样的,在FeedPortlet类里,新建FeedPanel属性,在其构造函数里,设

置头部可见性,并将FeedPanel加入到FeedPortlet里;最后,派发NewPortletCreated事件

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.portlets;

2.

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

4. import com.danielvaughan.rssreader.client.components.FeedPanel;

5. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

6. import com.extjs.gxt.ui.client.mvc.Dispatcher;

7. import com.extjs.gxt.ui.client.widget.custom.Portlet;

8. import com.extjs.gxt.ui.client.widget.layout.FitLayout; 9.

10. public class FeedPortlet extends Portlet {

11. private final FeedPanel feedPanel = new FeedPanel();

12.

13. public FeedPortlet() {

14. setHeading("Feed");

15. setLayout(new FitLayout());

16. setHeight(350);

17. setId(RSSReaderConstants.FEED_PORTLET);

18.

gxt gxt初学进阶教程

19. feedPanel.setHeaderVisible(false);

20. add(feedPanel);

21.

22. Dispatcher.forwardEvent(AppEvents.NewPortletCreated, this);

23. }

24. }

? 在包com.danielvaughan.rssreader.client.portlets:新建ItemPortlet extends

Portlet;并且在构造函数中用相同于NavPortlet的代码。(www.61k.com)

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.portlets;

2.

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

4. import com.danielvaughan.rssreader.client.components.ItemPanel;

5. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

6. import com.extjs.gxt.ui.client.mvc.Dispatcher;

7. import com.extjs.gxt.ui.client.widget.custom.Portlet;

8. import com.extjs.gxt.ui.client.widget.layout.FitLayout; 9.

10. public class ItemPortlet extends Portlet {

11. public ItemPortlet() {

12. setHeading("Item");

13. setLayout(new FitLayout());

14. setHeight(250);

15. setId(RSSReaderConstants.ITEM_PORTLET);

16. final ItemPanel itemPanel = new ItemPanel();

17. itemPanel.setHeaderVisible(false);

18. add(itemPanel);

19. Dispatcher.forwardEvent(AppEvents.NewPortletCreated, this);

20. }

21. }

? 新建FeedPortlet和ItemPortlet好之后,我们在RSSReader.onModuleLoad()

方法里面新建各自的实例

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client;

2.

3. import

com.danielvaughan.rssreader.client.mvc.controllers.PortalController;

4. import com.danielvaughan.rssreader.client.portlets.FeedPortlet;

5. import com.danielvaughan.rssreader.client.portlets.ItemPortlet;

6. import com.danielvaughan.rssreader.client.portlets.NavPortlet;

7. import com.danielvaughan.rssreader.client.services.FeedService;

8. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

9. import com.extjs.gxt.ui.client.Registry;

10. import com.extjs.gxt.ui.client.mvc.Dispatcher;

11. import com.google.gwt.core.client.EntryPoint;

12. import com.google.gwt.core.client.GWT;

13.

14. /**

15. * Entry point classes define <code>onModuleLoad()</code>.

16. */

17. public class RSSReader implements EntryPoint {

18.

19. /**

20. * This is the entry point method.

21. */

22. @Override

23. public void onModuleLoad() {

24.

25. final FeedServiceAsync feedService = GWT.create(FeedService.class);

26. Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);

27. Dispatcher dispatcher = Dispatcher.get();

28. dispatcher.addController(new PortalController());

29.

30. new NavPortlet();

31. new FeedPortlet();

32. new ItemPortlet();

33. }

gxt gxt初学进阶教程

34. }

? 最后,运行效果如下 GXT之旅:第九章:Charts图表——准备工作

分类: ExtGWT2012-05-09 14:37306人阅读评论(1)收藏举报 第九章:Charts

本章我们要了解GXT

gxt gxt初学进阶教程

的Chart功能。[www.61k.com]我们会全面了解Chart。为了消除对Chart功能的疑惑,我们会使用真实的数据展示Chart。

我们会涉及到如下GXt功能集

?

?

?

? Chart ChartModel ChartConfig BarChart

gxt gxt初学进阶教程

?

?

?

?

?

?

? CylinderBarChart FilledBarChart SketchBarChart HorizontalBarChart PieChart LineChart AreaChart Chart有些不同于GXT其他的功能集,与其说他是GXT framework的另一个核心部分,不如说他是“Open Flash Charts 2”被加入到GXT当中的。[www.61k.com]关于具体的“Open Flash Charts 2”内容可以参考http://teethgrinder.co.uk/open-flash-chart-2/

因此GXT的Chart功能,在使用上需要有一些配置步骤,这些步骤并不是那么显而易见的,这也就意味着我们在使用Chart的时候很容易遇上麻烦。因此,在我们开始之前,我们先按照基本步骤建立几个example程序,先熟悉熟悉。同时让我们了解如果少了几个步骤会显示什么样子的出错信息,有助于解决以后搭建自己程序时遇到的问题。

导入chart module

? 来到我们RSSReader项目的module配置文件——RSSReader.gwt.xml,导

入有关chart的module

[html] view plaincopyprint? 1. <?xml version="1.0" encoding="UTF-8"?>

2. <module rename-to='rssreader'>

3. <!-- Inherit the core Web Toolkit stuff. -->

4. <inherits name='com.google.gwt.user.User' />

5.

6. <!-- Inherit the default GWT style sheet. You can change -->

7. <!-- the theme of your GWT application by uncommenting -->

8. <!-- any one of the following lines. -->

9. <inherits name='com.google.gwt.user.theme.standard.Standard' />

10. <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->

11. <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->

12.

gxt gxt初学进阶教程

13. <!-- Other module inherits -->

14. <inherits name='com.extjs.gxt.ui.GXT' />

15. <inherits name='com.extjs.gxt.charts.Chart' />

16. <!-- Specify the app entry point class. -->

17. <entry-point class='com.danielvaughan.rssreader.client.RSSReader' />

18.

19. <!-- Specify the paths for translatable code -->

20. <source path='client' />

21. <source path='shared' />

22.

23. </module>

? 如果你缺少这一步,当你使用Chart组件的时候,会有如下error message:

[java] view plaincopyprint?

1. [ERROR] [rssreader] Line 26: No source code is

2. available for type com.extjs.gxt.charts.client.Chart; did you

3. forget to inherit a required module?

导入chart resource

就chart自身而言,其内容是由flash和JavaScript组成的。(www.61k.com)代码里面不单单需要引用chart module还要引用resource文件。这些resource文件需要,我们导入到项目里面。

? 找到GXT发布包里面的gxt-2.2.5\resources\chart\下所有内容,复制到项目

的WebContent\gxt\下。

? 如果上述文件忘记以用的话,会有如下error message。

[java] view plaincopyprint?

1. [WARN] 404 - GET /gxt/chart/open-flash-chart.swf (127.0.0.1) 1416

2. bytes

? 同样的gxt-2.2.5\resources\flash\下所有内容,复制到项目的

WebContent\gxt\下。

? 如果上述文件忘记以用的话,会有如下error message。

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. 18:27:08.015 [ERROR] [rssreader] Unable to load module entry point

2. class

3. com.danielvaughan.rssreader.client.RSSReader (see associated exception

for details)

4. com.google.gwt.core.client.JavaScriptException: (TypeError):

5. Cannot call method 'embedSWF' of undefined

6. stack: TypeError: Cannot call method 'embedSWF' of undefined

7. as well as the following message on the Java console:

8. [WARN] 404 - GET /gxt/flash/swfobject.js (127.0.0.1) 1408 bytes

gxt gxt初学进阶教程

? (当然,先前我都直接复制过来了,^_^)

加载chart所用的JavaScript库

? 其实大家也应该知道,页面引用flash文件,离不开swfobject.js。[www.61k.com]编辑

RSSReader.html,如下

[java] view plaincopyprint?

1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

2. <html>

gxt gxt初学进阶教程

3. <head>

4. <meta http-equiv="content-type" content="text/html; charset=UTF-8">

5. <link type="text/css" rel="stylesheet" href="RSSReader.css">

6. <link type="text/css" rel="stylesheet" href="css/item.css">

7. <link type="text/css" rel="stylesheet" href="gxt/css/gxt-all.css">

8. <script language='javascript' src='gxt/flash/swfobject.js'>

9. </script>

10. <title>RSSReader</title>

11. </head>

12. <body>

13. <div id="loading"> 14. <div class="loading-indicator"> 15. <img src="gxt/images/default/shared/large-loading.gif" width="32"

16. height="32" />RSS Reader<br /> <span id="loading-msg">Loading...</span>

17. </div>

18. </div>

19. <script type="text/javascript" language="javascript"

20. src="rssreader/rssreader.nocache.js"></script>

21. </body>

22. </html>

? 如果swfobject.js没有引入的话,控制台会报错的哦

[java] view plaincopyprint?

1. [ERROR] [rssreader] Unable to load module entry point

2. class

3. com.danielvaughan.rssreader.client.RSSReader (see associated

4. exception for

5. details)

6. com.google.gwt.core.client.JavaScriptException: (TypeError):

7. Cannot call

8. method 'embedSWF' of undefined

9. stack: TypeError: Cannot call method 'embedSWF' of undefined:

gxt gxt初学进阶教程

GXT之旅:第九章:Charts图表——Chart的基本创建(1)

分类: ExtGWT2012-05-09 17:06318人阅读评论(0)收藏举报

Chart class

作为一个java类,Chart其实就是针对Open Flash Chart 库做了包装,并且让用户在使用起来就像其他的GXT的components一样。[www.61k.com]

需要注意的是,在使用Chart的时候,需要给定一个open-flash-chart.swf的URL地址——上一节,我们拷入到RSSReader项目里面的地址。当然URL必须有效,否则Chart不会被渲染出来,除了控制室台404error之外,页面上是没有什么错误的。

比如如下的URL是有效的: [java] view plaincopyprint?

1. Chart chart = new Chart("gxt/chart/open-flash-chart.swf");

因此,如下URL是无效的:

[java] view plaincopyprint?

1. Chart chart = new Chart("wrong/path/open-flash-chart.swf");

那么就会有如下的error message

[java] view plaincopyprint?

1. [WARN] 404 - GET /wrong/path/open-flash-chart.swf (127.0.0.1) 1417

2. bytes

接下来,让我们新建一个Portlet来展示Chart

? 新建package:com.danielvaughan.rssreader.client.charts——在此package

下,新建一个FeedChart 容器,extends LayoutContainer。

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.charts;

gxt gxt初学进阶教程

2.

3. import com.extjs.gxt.ui.client.widget.LayoutContainer; 4.

5. public class FeedChart extends LayoutContainer {

6.

7. }

? 新建属性——chart,注意传入的URL

[java] view plaincopyprint?

1. private final Chart chart = new Chart("gxt/chart/open-flash-chart.swf"); ? Override onRender(),具体实现如下

[java] view plaincopyprint? 1. @Override

2. protected void onRender(Element parent, int index) {

3. super.onRender(parent, index);

4. setLayout(new FitLayout());

5. chart.setBorders(true);

6. add(chart);

7. }

? 进入package:com.danielvaughan.rssreader.client.portlets,为FeedChart

新建一个ChartPortlet [java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.portlets;

2.

3. import com.extjs.gxt.ui.client.widget.custom.Portlet;

4.

5. public class ChartPortlet extends Portlet {

6.

gxt gxt初学进阶教程

7. }

? 在ChartPortlet类,新建属性feedChart

[java] view plaincopyprint? 1. private final FeedChart feedChart = new FeedChart();

? 构造函数ChartPortlet()里定义一些基本属性:

[java] view plaincopyprint? 1. public ChartPortlet() {

2. setHeading("Chart");

3. setId(RSSReaderConstants.CHART_PORTLET);

4. setLayout(new FitLayout());

5. setHeight(250);

6. }

? 当然对于恒量CHART_PORTLET,定义:

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client;

2.

3. public class RSSReaderConstants {

4. public static final String FEED_SERVICE = "feedService";

5. public static final String FEED_STORE = "feedStore";

6. public static final String NAV_PORTLET = "navPortlet";

7. public static final String FEED_PORTLET = "feedPortlet";

8. public static final String ITEM_PORTLET = "itemPortlet";

9. public static final String FEED_DD_GROUP = "feedDDGroup";

10. public static final String ITEM_DD_GROUP = "itemDDGroup";

11. public static final String OVERVIEW_PORTLET = "overviewPortlet"; 12.

13. public static final String CHART_PORTLET = "chartPortlet";

14. }

gxt gxt初学进阶教程

? 回到,ChartPortlet构造函数。[www.61k.com]将feedChart加入到Portlet里这一完毕过程,

派发出去,并且传入自己(this)

[java] view plaincopyprint? 1. public ChartPortlet() { 2. setHeading("Chart");

3. setId(RSSReaderConstants.CHART_PORTLET);

4. setLayout(new FitLayout());

5. setHeight(250);

6.

7. Dispatcher.forwardEvent(AppEvents.NewPortletCreated, this);

8. }

? 我们想要让,ChartPortlet显示在Portal里面的第一列。所以我们需要修改

PortalView.onAddPortlet()方法。

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.mvc.views;

2.

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

4. import

com.danielvaughan.rssreader.client.mvc.controllers.PortalController;

5. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

6. import com.extjs.gxt.ui.client.event.EventType;

7. import com.extjs.gxt.ui.client.mvc.AppEvent;

8. import com.extjs.gxt.ui.client.mvc.View;

9. import com.extjs.gxt.ui.client.widget.Viewport;

10. import com.extjs.gxt.ui.client.widget.custom.Portal;

11. import com.extjs.gxt.ui.client.widget.custom.Portlet;

12. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

13. import com.google.gwt.user.client.ui.RootPanel;

14.

15. public class PortalView extends View {

16. private final Portal portal = new Portal(2);

17.

gxt gxt初学进阶教程

18. public PortalView(PortalController controller) {

19. super(controller);

20. }

21.

22. @Override

23. protected void handleEvent(AppEvent event) {

24. EventType eventType = event.getType();

25. if (eventType.equals(AppEvents.NewPortletCreated)) {

26. onNewPortletCreated(event);

27. }

28. }

29.

30. private void onNewPortletCreated(AppEvent event) {

31. final Portlet portlet = (Portlet) event.getData();

32. if (portlet.getId() == RSSReaderConstants.NAV_PORTLET

33. || portlet.getId() == RSSReaderConstants.CHART_PORTLET) { //here

34. portal.add(portlet, 0);

35. } else {

36. portal.add(portlet, 1);

37. }

38. }

39.

40. @Override

41. protected void initialize() {

42. portal.setColumnWidth(0, 0.3);

43. portal.setColumnWidth(1, 0.7);

44. final Viewport viewport = new Viewport();

45. viewport.setLayout(new FitLayout());

46. viewport.add(portal);

47. RootPanel.get().add(viewport);

48. }

49. }

? 因为NavPortlet 和 ChartPortlet都要添加到第一列,所以我们要缩短

NavPortlet的高度。[www.61k.com)

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.portlets;

2.

3. import com.danielvaughan.rssreader.client.RSSReaderConstants;

4. import com.danielvaughan.rssreader.client.components.NavPanel;

5. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

6. import com.extjs.gxt.ui.client.mvc.Dispatcher;

7. import com.extjs.gxt.ui.client.widget.custom.Portlet;

8. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

9.

10. public class NavPortlet extends Portlet {

11. public NavPortlet() {

12. setHeading("Navigation");

13. setLayout(new FitLayout());

14. setHeight(350); // here

15.

16. setId(RSSReaderConstants.NAV_PORTLET);

17.

18. NavPanel navPanel = new NavPanel();

19. navPanel.setHeaderVisible(false);

20. add(navPanel);

21.

22. Dispatcher.forwardEvent(AppEvents.NewPortletCreated , this);

23. }

24. }

? 最后,在程序入口方法RSSReader.onModuleLoad(),新建ChartPortlet

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client;

2.

3. import

com.danielvaughan.rssreader.client.mvc.controllers.PortalController;

4. import com.danielvaughan.rssreader.client.portlets.ChartPortlet;

gxt gxt初学进阶教程

5. import com.danielvaughan.rssreader.client.portlets.FeedPortlet;

6. import com.danielvaughan.rssreader.client.portlets.ItemPortlet;

7. import com.danielvaughan.rssreader.client.portlets.NavPortlet;

8. import com.danielvaughan.rssreader.client.portlets.OverviewPortlet;

9. import com.danielvaughan.rssreader.client.services.FeedService;

10. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

11. import com.extjs.gxt.ui.client.Registry;

12. import com.extjs.gxt.ui.client.mvc.Dispatcher;

13. import com.google.gwt.core.client.EntryPoint;

14. import com.google.gwt.core.client.GWT;

15.

16. /**

17. * Entry point classes define <code>onModuleLoad()</code>.

18. */

19. public class RSSReader implements EntryPoint {

20.

21. /**

22. * This is the entry point method.

23. */

24. @Override

25. public void onModuleLoad() {

26. final FeedServiceAsync feedService = GWT.create(FeedService.class);

27. Registry.register(RSSReaderConstants.FEED_SERVICE, feedService);

28. Dispatcher dispatcher = Dispatcher.get();

29. dispatcher.addController(new PortalController());

30. new NavPortlet();

31. new OverviewPortlet();

32. new FeedPortlet();

33. new ItemPortlet();

34.

35. new ChartPortlet();// here

36. }

37. }

? 此时,运行我们的RSSReader,会发现:ChartPortlet能够显示出来,但是

会在页面上有如下错误的显示效果。[www.61k.com)(低版本下,会因为没有数据而产生错

gxt gxt初学进阶教程

误,chart.setVisible =false既可解决。[www.61k.com]但是我现在的版本没有问题:GXT-2.2.5)

gxt gxt初学进阶教程

?

gxt gxt初学进阶教程

正常的显示效果如下:

GXT之旅:第九章:Charts图表——BarChart(2)

分类: ExtGWT2012-05-11 14:09246人阅读评论(0)收藏举报

ChartModel class

chartModel extends BaseModel,为 "Open Flash Chart" chart 的数据源所用。

ChartModuel 用来定义类型和数据,他会包含一个or多个ChartConfig对象用来定义各种类型的Chart。

gxt gxt初学进阶教程

ChartConfig class

ChartConfig extends BaseModel 但是一个抽象类。(www.61k.com]他作为一个基类,为其子类服务。其子类则定义了具体的Chart类型,并且提供一个层级关系的各类型的chart style 下面的图表,显示了不同类型的

gxt gxt初学进阶教程

Chart之间关系,但是他们都 extends ChartConfig

BarChart class

我们首先了解的是BarChart。以最简单的形式,我们来使用她,会有如下步骤:

?

?

?

?

?

? 新建一个createChartModelData()方法 在方法内,新建ChartModel 新建BarChart ChartConfig 给BarChart加入一些values 将BarChart加入到ChartModel 方法最后返回的是ChartModel

[java] view plaincopyprint?

1. private ChartModel createChartModel() {

2.

3. ChartModel chartModel = new ChartModel();

4. BarChart chartConfig = new BarChart();

5. chartConfig.addValues(6936,8628,41832,68376,296,10114,4693);

6. chartModel.addChartConfig(chartConfig);

7. return chartModel;

gxt gxt初学进阶教程

8.

9. } 但是现在的问题是,我们给予的values太大了远远超过Y轴,那么我们重新整理一下。[www.61k.com]新建一个getChartModel()方法

[java] view plaincopyprint? 1. private ChartModel getChartModel() {

2. ChartModel chartModel = new ChartModel(

3.

gxt gxt初学进阶教程

"Population of Western European Countries in 1950 (000's)",

4. "fontsize:14px;color:#000000");//标题

5. chartModel.setBackgroundColour("#ffffff");

6.

7. XAxis xAxis = new XAxis();//x轴

8. xAxis.addLabels("Austria", "Belgium", "France", "Germany",

9. "Luxembourg", "Netherlands", "Switzerland");

10. chartModel.setXAxis(xAxis);

11.

12. YAxis yAxis = new YAxis();//y轴

13. yAxis.setRange(0, 70000, 10000);

gxt gxt初学进阶教程

14. chartModel.setYAxis(yAxis); 15.

16. BarChart chartConfig = new BarChart();

17. chartConfig.addValues(6936, 8628, 41832, 68376, 296, 10114, 4693);

18. chartModel.addChartConfig(chartConfig);

19.

20. return chartModel;

21. }

?

?

? ? 通过ChartModel构造函数传入标题,并且指定了标题的css。(www.61k.com] 设置背景颜色 设置

gxt gxt初学进阶教程

X轴的显示标签 设置Y轴的显示标签

经过这一番折腾之后,chart看起来满意多了。将鼠标放置在显示条上,会有实际的值显示出来。

默认的BarChart显示的效果就是如上图了,我们可以通过BarStyle提供的参数传入到BarChart构造函数里。

[java] view plaincopyprint?

1. BarChart chartConfig = new BarChart(BarStyle.THREED); //立体显示

gxt gxt初学进阶教程

[java] view plaincopyprint?

1. BarChart chartConfig = new BarChart(BarStyle.GLASS);

gxt gxt初学进阶教程

gxt gxt初学进阶教程

这些仅仅是个开始,我们以一种最简单的使用方式了解他们。(www.61k.com)其实我也了解的不多,哈哈 GXT之旅:第九章:Charts图表——各种Chart(3)

分类: ExtGWT2012-05-14 17:32455人阅读评论(0)收藏举报

CylinderBarChart class

gxt gxt初学进阶教程

[java] view plaincopyprint? 1. BarChart chartConfig = new CylinderBarChart();

2. chartConfig.addValues(6936,8628,41832,68376,296,10114,4693); FilledBarChart class

FilledBarChart看起来和标准的BarChart没什么两样。(www.61k.com]但是她可以通过setOutlineColor()

gxt gxt初学进阶教程

方法设置圆柱的轮廓颜色。

gxt gxt初学进阶教程

[java] view plaincopyprint?

1. FilledBarChart chartConfig = new FilledBarChart();

gxt gxt初学进阶教程

2. chartConfig.setColour("#cc0000");

3. chartConfig.setOutlineColour("#660000");

4. chartConfig.addValues(6936,8628,41832,68376,296,10114,4693); SketchBarChart class 如下图,是一个简单的

gxt gxt初学进阶教程

SketchBarChart的实例图片。[www.61k.com)

[java] view plaincopyprint?

1. BarChart chartConfig = new SketchBarChart();

2. chartConfig.addValues(6936,8628,41832,68376,296,10114,4693);

内部类BarChart.Bar class

除了简单的创建BarChart之外呢,BarChart class内部还有一个Bar class,可以让我们更具体的定义每一个bar的显示。

如下,我们可以为每个bar定义不同的颜色

[java] view plaincopyprint?

1. BarChart chartConfig = new SketchBarChart();

2. chartConfig.addBars(new BarChart.Bar(6936, "#FF0000"));

3. chartConfig.addBars(new BarChart.Bar(8628, "#FFA500"));

4. chartConfig.addBars(new BarChart.Bar(41832, "#FFFF00"));

5. chartConfig.addBars(new BarChart.Bar(68376,"#008000"));

gxt gxt初学进阶教程

6. chartConfig.addBars(new BarChart.Bar(296, "#0000FF"));

7. chartConfig.addBars(new BarChart.Bar(10114,"#4B0082"));

8. chartConfig.addBars(new BarChart.Bar(4693, "#EE82EE"));

gxt gxt初学进阶教程

gxt gxt初学进阶教程

HorizontalBarChart class

HorizontalBarChart工作方式和标准的BarChart一样。(www.61k.com)当然,顾明思议,就是Y轴编程和X轴交换位置。值得注意的是现在Y轴的标签(国家)和X轴的values是相反序的!

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. YAxis yAxis = new YAxis();

2. yAxis.addLabels("Switzerland","Netherlands","Luxembourg","Germany","Fr

ance","Belgium","Austria");

3. yAxis.setOffset(true);

4. chartModel.setYAxis(yAxis);

5.

6. XAxis xAxis = new XAxis();

7. xAxis.setRange(0, 70000, 10000);

8. chartModel.setXAxis(xAxis);

9.

10. HorizontalBarChart chartConfig = new HorizontalBarChart();

11. chartConfig.addValues(6936,8628,41832,68376,296,10114,4693);

PieBarChart class

下面,让我们把视线从多样的BarChart转移到其他的Chart上。[www.61k.com)事实上,BarChart和PieChart之间的不同就是体现在ChartConfig的定义上。

让我们继续,通过定义一系列的颜色来区分开每个区域。

[java] view plaincopyprint?

1. private ChartModel getChartModel() {

2. ChartModel chartModel = new ChartModel();

3. PieChart chartConfig = new PieChart();

4. chartConfig.setColours("#FF0000", "#FFA500", "#FFFF00", "#008000",

5. "#0000FF", "#4B0082", "#EE82EE");

6. chartConfig.addValues(6936, 8628, 41832, 68376, 296, 10114, 4693);

7. chartModel.addChartConfig(chartConfig);

8. return chartModel;

9. }

gxt gxt初学进阶教程

gxt gxt初学进阶教程

当然,目前的图表看上去,还不是那么实用,因为每个切片上还没有标签。(www.61k.com]

gxt gxt初学进阶教程

PieChart.Slice class

正如BarChart.Bar一样,PieChart.Slice 是定义PieChart中每一个切片的——定义value和label

[java] view plaincopyprint?

1. PieChart chartConfig = new PieChart();

2.

3. chartConfig.setColours("#FF0000", "#FFA500", "#FFFF00",

"#008000","#0000FF","#4B0082", "#EE82EE");

4. chartConfig.addSlices(new PieChart.Slice(6936,"Austria"));

5. chartConfig.addSlices(new PieChart.Slice(8628,"Belgium"));

6. chartConfig.addSlices(new PieChart.Slice(41832,"France"));

7. chartConfig.addSlices(new PieChart.Slice(68376,"Germany"));

8. chartConfig.addSlices(new PieChart.Slice(296,"Luxembourg"));

9. chartConfig.addSlices(new PieChart.Slice(10114,"Netherlands"));

10. chartConfig.addSlices(new PieChart.Slice(4693,"Switzerland"));

11.

12. chartModel.addChartConfig(chartConfig);

gxt gxt初学进阶教程

LineChart

LineChart的使用方式都是类似的:

[java] view plaincopyprint? 1. private ChartModel getChartModel() { 2.

gxt gxt初学进阶教程

//model

3. ChartModel chartModel = new ChartModel("Population of Germany",

4. "font-size:14px;color:#000000");

5. chartModel.setBackgroundColour("#ffffff");

6. XAxis xAxis = new XAxis();

7. xAxis.addLabels("1950", "1960", "1970", "1980", "1990", "2000");

8. chartModel.setXAxis(xAxis);

9. YAxis yAxis = new YAxis();

10. yAxis.setRange(50000, 100000, 10000);

11. yAxis.setOffset(true);

12. chartModel.setYAxis(yAxis);

13. //config

14. LineChart chartConfig = new LineChart();

15. chartConfig.addValues(68376, 72815, 78169, 78289, 79433, 82075);

16. chartConfig.setText("Germany");//当前line的名称

17. //model+config

18. chartModel.addChartConfig(chartConfig);

19. return chartModel;

20. }

gxt gxt初学进阶教程

如果想再次加入一条line,其实很简单——需要再定义一个ChartConfig既可。[www.61k.com)让后将ChartConfig加入到model里。

[java] view plaincopyprint? 1. LineChart germanyChartConfig = new LineChart();

2. germanyChartConfig.addValues(68376,72815,78169,78289,79433,82075);

3. germanyChartConfig.setColour("#ff0000");

4. germanyChartConfig.setText("Germany");

5.

6. chartModel.addChartConfig(germanyChartConfig);

7.

8. LineChart franceChartConfig = new LineChart();

9. franceChartConfig.addValues(41832,45674,

gxt gxt初学进阶教程

50771,53950,56842,59128);

10. franceChartConfig.setColour("#000066");

11. franceChartConfig.setText("France");

12.

13. chartModel.addChartConfig(franceChartConfig);

当一个model里,拥有多组数据(config)的时候,不是所有的config必须都是同一种类型。可以让一个Linechart和BarChart同时显示在一起。例如:

[java] view plaincopyprint?

1. BarChart germanyChartConfig = new BarChart();

2. germanyChartConfig.addValues(68376,72815,78169,78289,79433,82075);

gxt gxt初学进阶教程

3. germanyChartConfig.setColour("#ff0000");

4. germanyChartConfig.setText("Germany");

5.

6. chartModel.addChartConfig(germanyChartConfig);

7.

8. LineChart franceChartConfig = new LineChart();

9. franceChartConfig.addValues(41832,45674,50771,53950,56842,59128);

10. franceChartConfig.setColour("#000066");

11. franceChartConfig.setText("France");

12.

13. chartModel.addChartConfig(franceChartConfig);

gxt gxt初学进阶教程

GXT之旅:第九章:Charts图表——各种Chart(4)

分类: ExtGWT2012-05-24 12:04246人阅读评论(1)收藏举报

AreaChart class

AreaChart extends LineChart ,因此工作方式都是相同的。[www.61k.com)不同之处是替换了单独的丝线,变成了线性区域。

[java] view plaincopyprint?

1. AreaChart germanyChartConfig = new AreaChart();

2. germanyChartConfig.addValues(68376,72815,78169,78289,79433,82075);

3. germanyChartConfig.setColour("#ff0000");

4. germanyChartConfig.setText("Germany");

5.

gxt gxt初学进阶教程

6. AreaChart franceChartConfig = new AreaChart();

7. franceChartConfig.addValues(41832,45674,50771,53950,56842,59128);

8. franceChartConfig.setColour("#000066");

9. franceChartConfig.setText("France");

gxt gxt初学进阶教程

ScatterChart class

ScatterChart是GXT中非常有用的component chart,但GXT并不是完全支持她。(www.61k.com] 比如,我们有如下数据

[java] view plaincopyprint?

1. ScatterChart chartConfig = new ScatterChart();

2. chartConfig.addPoint(41832, 68376);

3. chartConfig.addPoint(45674, 72815);

4. chartConfig.addPoint(50771, 78169);

5. chartConfig.addPoint(53950, 78289);

6. chartConfig.addPoint(56842, 79433);

7. chartConfig.addPoint(59128, 82075);

数据设置进去了,但是我们没有办法在图表上设置数据的渲染方式——只有在鼠标经过的他们的时候,才可以显示出来。

使用PieChart

在我们RSSReader项目里面,还没有显示任何一个Chart功能。虽然一个小小的demo项目里面还没有什么功能需要用到chart,但是如果往里面加还是能加进去的

gxt gxt初学进阶教程

让我们新建一个chart显示一周内每天的feed信息的发布时间的统计情况。[www.61k.com] ? 编辑com.danielvaughan.rssreader.client.charts.FeedChart,新增如下方法

——prepareData(),当然这个方法不属于Chart本身的部分,但是是做为Chart提供数据来源的。

[java] view plaincopyprint? 1. @Override 2. protected void onRender(Element parent, int index) {

3. super.onRender(parent, index);

4. setLayout(new FitLayout());

5. chart.setBorders(true);

6. chart.setVisible(false);//为了避免报错,所以一开始设置不可见,等有

chartModel的时候再设置可见

7. add(chart);

8. }

9.

10. private HashMap<String, Integer> prepareData(List<Item> items) {

11. HashMap<String, Integer> days = new HashMap<String, Integer>();

12. for (Item item : items) {

13. DateTimeFormat fmt = DateTimeFormat.getFormat("EEEE");

14. String day = fmt.format(item.getPubDate());

15. Integer dayOccurance = days.get(day);

16. if (dayOccurance == null) {

17. days.put(day, 1);

18. } else {

19. days.put(day, ++dayOccurance);

20. }

21. }

22. return days;

23. }

? 新建方法createChartModelData(List<Item> items)

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. private ChartModel createChartModelData(List<Item> items) {

2. // create chartModel 3. ChartModel chartModel = new ChartModel("Posts per week of day",

4. "font-size: 14px; font-family: Verdana; text-align: center;");

5. chartModel.setBackgroundColour("#ffffff");

6. // create PieChart

7. PieChart pie = new PieChart();

8. pie.setColours("#FF0000", "#FFA500", "#FFFF00", "#008000", "#0000FF",

9. "#4B0082", "#EE82EE");

10. // add Slice, set values

11. HashMap<String, Integer> days = prepareData(items);

12. for (String key : days.keySet()) {

13. pie.addSlices(new PieChart.Slice(days.get(key), key));

14. }

15. chartModel.addChartConfig(pie);

16.

17. return chartModel;

18. }

? 新建方法setFeed()——基本实现如下:

[java] view plaincopyprint?

1. public void setFeed(final Feed feed) {

2. final FeedServiceAsync feedService = Registry

3. .get(RSSReaderConstants.FEED_SERVICE);

4. //根据uuid获得其items

5. feedService.loadItems(feed.getUuid(), new AsyncCallback<List<Item>>() {

6. @Override

7. public void onFailure(Throwable caught) {

8. Dispatcher.forwardEvent(AppEvents.Error, caught);

9. }

10.

11. @Override

12. public void onSuccess(List<Item> items) {

13. //成功之后将items转换成ChartModel,设置到chart里。[www.61k.com)

gxt gxt初学进阶教程

14. chart.setChartModel(createChartModelData(items));

15. }

16. });

17. }

? 现在Chart已经设置了其ChartModel,那么就不会出现“Open Flash Chart”

的data error。[www.61k.com)因此我们可以大胆的设置chart visible=true

[java] view plaincopyprint? 1. public void setFeed(final Feed feed) {

2. final FeedServiceAsync feedService = Registry

3. .get(RSSReaderConstants.FEED_SERVICE);

4. // 根据uuid获得其items

5. feedService.loadItems(feed.getUuid(), new AsyncCallback<List<Item>>() {

6. @Override

7. public void onFailure(Throwable caught) {

8. Dispatcher.forwardEvent(AppEvents.Error, caught);

9. }

10.

11. @Override

12. public void onSuccess(List<Item> items) {

13. // 成功之后将items转换成ChartModel,设置到chart里。

14. chart.setChartModel(createChartModelData(items));

15. }

16. });

17. //

18. if (!chart.isVisible()) {

19. chart.setVisible(true);

20. }

21. }

? 编辑:com.danielvaughan.rssreader.client.portlets..ChartPortlet——新增一

个onFeedsDropped()

[java] view plaincopyprint?

gxt gxt初学进阶教程

1. private void onFeedsDropped(DNDEvent event) {

2. // 接收 feeds,将feed传入到feedChart中去。[www.61k.com)

3. List<BeanModel> beanModels = event.getData();

4. for (BeanModel beanModel : beanModels) {

5. Feed feed = beanModel.getBean();

6. feedChart.setFeed(feed);

7. }

8. }

? Overwrite onRender()方法。让ChartPortlet成为另外一个DropTarget,并且

和FeedPortlet拥有同样的分组FEED_DD_GROUP

[java] view plaincopyprint? 1. package com.danielvaughan.rssreader.client.portlets;

2.

3. import java.util.List;

4.

5. import com.danielvaughan.rssreader.client.RSSReaderConstants;

6. import com.danielvaughan.rssreader.client.charts.FeedChart;

7. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

8. import com.danielvaughan.rssreader.shared.model.Feed;

9. import com.extjs.gxt.ui.client.dnd.DND;

10. import com.extjs.gxt.ui.client.dnd.DropTarget;

11. import com.extjs.gxt.ui.client.event.DNDEvent;

12. import com.extjs.gxt.ui.client.mvc.Dispatcher;

13. import com.extjs.gxt.ui.client.widget.custom.Portlet;

14. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

15. import com.google.gwt.user.client.Element;

16.

17. public class ChartPortlet extends Portlet {

18. private final FeedChart feedChart = new FeedChart();

19.

20. public ChartPortlet() {

21. setHeading("Chart");

22. setId(RSSReaderConstants.CHART_PORTLET);

gxt gxt初学进阶教程

23. setLayout(new FitLayout());

24. setHeight(250);

25.

26. Dispatcher.forwardEvent(AppEvents.NewPortletCreated, this);

27. }

28.

29. private void onFeedsDropped(DNDEvent event) {

30. // 接收 feeds,将feed传入到feedChart中去。(www.61k.com)

31. List<BeanModel> beanModels = event.getData();

32. for (BeanModel beanModel : beanModels) {

33. Feed feed = beanModel.getBean();

34. feedChart.setFeed(feed);

35. }

36. }

37.

38. @Override

39. protected void onRender(Element parent, int index) {

40. super.onRender(parent, index);

41. DropTarget target = new DropTarget(this) {

42. @Override

43. protected void onDragDrop(DNDEvent event) {

44. super.onDragDrop(event);

45. onFeedsDropped(event);

46. }

47. };

48. target.setOperation(DND.Operation.COPY);

49. target.setGroup(RSSReaderConstants.FEED_DD_GROUP);

50. }

51. }

? FeedChart类的完整代码如下:

[java] view plaincopyprint?

1. package com.danielvaughan.rssreader.client.charts; 2.

gxt gxt初学进阶教程

3. import java.util.HashMap;

4. import java.util.List;

5.

6. import com.danielvaughan.rssreader.client.RSSReaderConstants;

7. import com.danielvaughan.rssreader.client.mvc.events.AppEvents;

8. import com.danielvaughan.rssreader.client.services.FeedServiceAsync;

9. import com.danielvaughan.rssreader.shared.model.Feed;

10. import com.danielvaughan.rssreader.shared.model.Item;

11. import com.extjs.gxt.charts.client.Chart;

12. import com.extjs.gxt.charts.client.model.ChartModel;

13. import com.extjs.gxt.charts.client.model.charts.PieChart;

14. import com.extjs.gxt.ui.client.Registry;

15. import com.extjs.gxt.ui.client.mvc.Dispatcher;

16. import com.extjs.gxt.ui.client.widget.LayoutContainer;

17. import com.extjs.gxt.ui.client.widget.layout.FitLayout;

18. import com.google.gwt.i18n.client.DateTimeFormat;

19. import com.google.gwt.user.client.Element;

20. import com.google.gwt.user.client.rpc.AsyncCallback;

21.

22. public class FeedChart extends LayoutContainer {

23.

24. private final Chart chart = new Chart("gxt/chart/open-flash-chart.swf"); 25.

26. private ChartModel createChartModelData(List<Item> items) {

27. ChartModel chartModel = new ChartModel("Posts per week of day",

28. "font-size: 14px; font-family: Verdana; text-align: center;");

29. chartModel.setBackgroundColour("#ffffff");

30. PieChart pie = new PieChart();

31. pie.setColours("#FF0000", "#FFA500", "#FFFF00", "#008000", "#0000FF",

32. "#4B0082", "#EE82EE");

33. HashMap<String, Integer> days = prepareData(items);

34. for (String key : days.keySet()) {

35. pie.addSlices(new PieChart.Slice(days.get(key), key));

36. }

37. chartModel.addChartConfig(pie);

gxt gxt初学进阶教程

38. return chartModel;

39. }

40.

41. @Override

42. protected void onRender(Element parent, int index) {

43. super.onRender(parent, index);

44. setLayout(new FitLayout());

45. chart.setBorders(true);

46. chart.setVisible(false);

47. add(chart);

48. }

49.

50. private HashMap<String, Integer> prepareData(List<Item> items) {

51. HashMap<String, Integer> days = new HashMap<String, Integer>();

52. for (Item item : items) {

53. DateTimeFormat fmt = DateTimeFormat.getFormat("EEEE");

54. String day = fmt.format(item.getPubDate());

55. Integer dayOccurance = days.get(day);

56. if (dayOccurance == null) {

57. days.put(day, 1);

58. } else {

59. days.put(day, ++dayOccurance);

60. }

61. }

62. return days;

63. }

64.

65. public void setFeed(final Feed feed) {

66. final FeedServiceAsync feedService = Registry

67. .get(RSSReaderConstants.FEED_SERVICE);

68. feedService.loadItems(feed.getUuid(), new AsyncCallback<List<Item>>() {

69. @Override

70. public void onFailure(Throwable caught) {

71. Dispatcher.forwardEvent(AppEvents.Error, caught);

72. }

gxt gxt初学进阶教程

73. 74. @Override

75. public void onSuccess(List<Item> items) {

76.

gxt gxt初学进阶教程

chart.setChartModel(createChartModelData(items));

77. }

78. });

79. if (!chart.isVisible()) {

80. chart.setVisible(true);

81. }

82. }

83. }

? 最后运行效果如下:

三 : NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程

小编注:本篇仅限于技术探讨,如果您对本文内容有异议,请联系我们,我们会及时处理。

话说上次吹牛吹爆了

,许愿说要写个DSM傻瓜安装教程。本来我都不想接显示器安装的,可基于三点原因,我还是接上了13年历史的显示器,安装了群晖DSM 5.0-4458

我是DSM 4.2不想去被挖矿,话说我又不是在金元帅的国家,我干嘛要去被挖矿

我想体验一下DSM 5.0的百度云同步功能,话说这个太吸引我了,关注了好久,4458正式版发布后实在难忍。

我答应大家要写个傻瓜教程。

废话真多,那就开始吧。具体步骤我会单独说明。PS:很多内容参照此贴“小白装黑群晖,2步搞定5.0-4458”在此声明和感谢。

需要准备:
1、一个闲置的U盘,容量大于64M即可。 墙裂建议用如下U盘,可以隐藏成灰群晖,小巧方便。


2、一台显示器,用于连接NAS,在第一次启动时要选择不同的菜单,装完就不需要了。
3、DSM软件,一是官方3612xs机型5.0-4458版本的PAT文件(174.9M),二是Gnoboot-alpha7-4458.img文件(32M),三是win32diskimager文件(13.6M)。为了方便小白,我分享到网盘了,感谢原作者!(下载地址)

4、电脑上安装好群晖助手(Synology Assistant)群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程5、电脑网线、NAS网线都接入同一个路由器或交换机,确保正常使用。当然要推荐电磁炉了,千兆LAN口实乃NAS必备良伴。

由于我是数据无损升级,所以先看看系统信息,各位新安装朋友可以忽略

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程这里是真实MAC地址,网络唤醒必须。群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程好了,走过路过不要错过啊,大家瞧一瞧看一看啊,

操作步骤: (常规主板版)
1、把U盘插到电脑的USB口,在win7里面打开win32diskimager,把Gnoboot-alpha7-4458.img烧录到U盘里。(我这个就是傻瓜教程,不会用?看图会吧) 不要写错盘了,数据丢了别哭。

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程2、把装好启动程序的U盘和显示器都接到NAS上,当然还有鼠标和键盘。。。进主板的bios设置从U盘启动,各位看官请看图

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程F10 保持启动

正式安装-----开机后屏幕上会出现三个选项,选择第二项gnoboot-me,(这步是关键,因为默认是第一项,装完DSM就可以从默认的第一项启动了)进入后会出现4458的版本安装

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程

回车
群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程

继续回车

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程不管等着

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程巴拉巴拉,OK

等屏幕上全部显示结束后,转到电脑上运行群晖助手,这时应该会出现查找到1台nas的提示

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程我是升级安装,这里显示数据损毁,请淡定。我就很淡定,好嘛

双击(网页安装)或右键选择安装(助手安装)----PS:网上的各位老大建议网页安装。

我是一个不(bu)怕(kan)困(jiao)难(cheng)的人,最后选择了助手安装,大家表学我,数据丢失了别找我,我这不是提醒了吗

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程选择从本地安装PAT文件,按屏幕提示一步步完成就好了。群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程

扩展:nas群晖dsm 进阶教程 / 群晖nas重新安装dsm / dsm 5.0 4458 下载

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程我是相当的幸运,没有格式化数据区,也就是说我的电影都在的,妥妥的

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程安装完成,输入IP地址,华丽丽的DSM5.0登陆界面出现了,哇卡卡卡卡卡

用户:admin 密码:空白不用填写

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程扁平化啊扁平化,乔纳肾威武

剩下的就是折腾吧。。。。

操作步骤: (D510主板版,主板含256M 储存器)
1、把U盘插到电脑的USB口,写入老毛桃启动盘群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程

2.把win32diskimagerGnoboot-alpha7-4458.img拷贝到U盘里去

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程2、把装好老毛桃的U盘和显示器都接到NAS上,当然还有鼠标和键盘。。。进主板的bios设置从U盘启动 ,进入winpe群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程3.在winpe中打开win32diskimager,把Gnoboot-alpha7-4458.img烧录到板载储存盘里。(记得分区工具看看哪个是板载盘,只有256M的哦)

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程

4.烧录完成后,重启电脑,并del进入bios设置成板载储存器启动(SMI USB DISK)

群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程群晖 NAS群晖DSM 进阶教程 篇一:NAS群晖DSM 5.0-4458 傻瓜安装教程

启动后就和上面正式安装的步骤一样一样了。

好了,这次应该傻瓜吧,简单吧,随到随学,学不会免费再学。学费请小编发金币我把。

我终于知道金币是可以换礼物和现金劵的啊,哈哈哈哈,那就多来点吧。

祝大家折腾快乐,也感谢Gnoboot的编写者,让我们可以用官方pat文件安装启动DSM,可以第一时间尝鲜。也感谢上面引用贴的作者,让我少打了很多字。

追加修改(2014-03-22 ):特此补充

1.新安装的朋友在选择硬盘模式时候请选择BASIC模式不要使用官方推荐的SHR模式。

2.此教程及软件适合全新安装及4.2含4.2升级,更低版本请自行搜索。

3.本篇安装的为DSM5.0官方正式版,非破解版。

扩展:nas群晖dsm 进阶教程 / 群晖nas重新安装dsm / dsm 5.0 4458 下载

本文标题:NAS群晖DSM进阶教程-photoshop进阶教程:打造超酷的3D网页
本文地址: http://www.61k.com/1125248.html

61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1