深入探索GXT:构建强大Web应用的基石
立即解锁
发布时间: 2025-08-18 00:43:31 阅读量: 2 订阅数: 2 

### 深入探索GXT:构建强大Web应用的基石
#### 1. 初步认识GXT
GXT的使用与GWT有相似之处,但也存在一些细微差别。GXT具备许多超越GWT基础功能的出色特性。在使用GXT前,我们可以通过一些小测验来加深对它的了解:
1. GXT与哪个JavaScript库密切相关?
2. 哪个GXT替代方案封装了Smart Client JavaScript库?
3. 哪个GXT替代方案的大部分工作在服务器端完成?
4. 哪个GXT替代方案的名称和外观容易与Ext GWT混淆?
5. 开发GXT的公司叫什么名字?
6. GXT Java库文件的名称是什么?
7. GXT的许可证是什么?
8. 必须在哪个文件中继承GXT模块?
9. 必须在哪里包含对GXT CSS的引用?
10. 必须将gxt.jar库文件复制到哪里?
#### 2. GXT组件概览
在搭建好开发环境后,我们可以通过Ext GWT Explorer示例应用来了解GXT的各种组件。这个示例展示了GXT中所有可用的不同组件,并提供了使用它们的示例代码,是理解GXT组件和学习代码实现的宝贵资源,其在线地址为:http://www.sencha.com/examples/explorer.html 。
GXT中有一系列丰富的组件,下面为大家介绍一些基础且重要的组件:
|组件名称|描述|
| ---- | ---- |
|Component|GXT中所有可视化元素的基类(com.extjs.gxt.ui.client.widget.Component),基于GWT的Widget构建,所有GXT组件都参与GXT的创建、附加和分离生命周期,自动使用懒加载渲染,继承了基本的隐藏、显示、启用和禁用功能。|
|BoxComponent|所有GXT可视化元素直接或间接继承自Component,使用BoxComponent间接继承的组件会额外继承大小和相关方法。可定位或调整大小的组件(如Button、TreePanel或Grid)是BoxComponent的子类,而像TreeItem这种只存在于包含组件内部的组件则直接继承自Component。|
|Container|一种可以包含其他组件的BoxComponent,继承自com.extjs.gxt.ui.client.widget.Container<T>类,具备附加、分离和管理子组件的能力,但容器本身不处理组件的布局和渲染,这由其子类完成。|
|LayoutContainer|通过继承ScrollContainer类间接继承自Container,ScrollContainer为Container添加了内容滚动支持,LayoutContainer自身则添加了使用布局来布局子组件的能力。|
|FlowLayout|LayoutContainer的默认布局,将组件添加到容器中,但不处理子组件的大小和定位。第一个组件在容器的左上角渲染,后续组件依次添加到前一个组件的右侧。|
|ContentPanel|继承自LayoutContainer,是用户界面开发中非常有用的构建块。它具有单独的头部、底部和主体部分,可以显示顶部和底部工具栏,还具备折叠和展开的功能,并且在头部有一些预定义的工具按钮可用于自定义功能。|
#### 3. 懒加载渲染机制
GWT通过操作DOM(文档对象模型)元素来工作,GWT小部件是添加到DOM和从DOM中移除的HTML片段。例如,一个GWT按钮小部件的HTML代码如下:
```html
<button type="button" class="gwt-Button" style="position: absolute; left: 80px; top: 45px; ">Click Me!</button>
```
在GWT中,小部件初始化时HTML会同时创建,添加到面板时HTML已存在。而GXT组件使用懒加载渲染,初始化时不会立即创建HTML,只有在调用组件的render方法时才会创建,这样可以避免未使用的HTML占用内存。即使组件的HTML未创建,也可以在渲染前配置组件的属性,例如可以在将TextField添加到容器并生成HTML之前设置其值。如果将GXT组件添加到GWT面板,会立即调用render方法;如果添加到GXT容器,则由容器调用组件的render方法。
下面通过代码展示LayoutContainer和懒加载渲染的工作方式:
```java
LayoutContainer layoutContainer = new LayoutContainer();
Button button = new Button("Click me");
layoutContainer.add(button);
// 此时还未创建HTML
RootPanel.get().add(layoutContainer);
// 添加到RootPanel后,LayoutContainer的render方法被调用,同时调用子组件的render方法,创建HTML并添加到DOM
```
如果后续要添加第二个按钮:
```java
LayoutContainer layoutContainer = new LayoutContainer();
Button button = new Button("Click me");
layoutContainer.add(button);
RootPanel.get().add(layoutContainer);
Button anotherButton = new Button("Click me too");
layoutContainer.add(anotherButton);
// 由于LayoutContainer已渲染,第二个按钮的HTML未创建,需要调用layout方法
layoutContainer.layout();
```
#### 4. 事件机制
事件用于通知程序发生了某些事情,例如用户与应用程序交互(如点击按钮)或组件状态改变。每个操作会触发一个事件,任何监听该事件的组件都有机会做出响应,这就是观察者模式。在GXT中,可以为组件添加监听器,当事件触发时,监听器会被通知并处理事件。事件的基类是com.extjs.gxt.ui.client.event.BaseEvent,GXT提供了广泛的事件类型。
GWT和GXT的小部件并非响应所有浏览器事件,这是为了降低内存使用和避免内存泄漏。如果小部件需要响应某个浏览器事件,需要通过调用sinkEvents方法注册该事件。例如,默认情况下Component可能响应onClick事件,但不响应onDoubleClick事件,可以通过sink onDoubleClick事件来扩展组件以响应双击事件。同样,也可以通过吞掉事件来阻止事件触发,例如吞掉按钮的onClick事件后,点击按钮时将不再触发事件。
#### 5. 示例应用:RSS阅读器项目初始化
我们将使用一个RSS阅读器作为示例应用,以充分利用GXT的各种功能。首先,需要创建一个新的GXT项目并进行一些清理工作:
1. **删除不必要的文件**:删除GreetingService.java、GreetingServiceAsync.java、GreetingServiceImpl.java和FieldVerifier.java。
2. **清理RSSReader类**:移除RSSReader类的内容,只保留onModuleLoad方法的定义。
3. **修改web.xml文件**:移除项目war\WEB - INF目录下web.xml文件中的greet servlet定义,使其内容如下:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>RSSReader.html</welcome-file>
</welcome-file-list>
</web-app>
```
4. **编辑RSSReader.html文件**:确保文件中只包含项目所需的最少代码,注意有效的DOCTYPE对GXT正确渲染很重要:
```html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link type="text/css" rel="stylesheet" href="RSSReader.css">
<link type="text/css" rel="stylesheet" href="gxt/css/gxt-all.css">
<title>RSSReader</title>
<script type="text/javascript" language="javascript" src="rssreader/rssreader.nocache.js"></script>
</head>
<body>
</body>
</html>
```
5. **清理CSS文件**:打开RSSReader.css文件,删除其中的内容,使其成为一个空白文件。
6. **编译并运行应用**:此时应用应该只显示一个标题为RSSReader的空白页面。
#### 6. 添加Viewport组件
Viewport是LayoutContainer的子类,它会填充浏览器窗口并监控窗口大小的变化,触发子组件进行相应的大小调整,在构建用户期望表现得像桌面应用的程序时非常有用。我们将使用Viewport作为应用的基础面板,并将其直接添加到GWT的根面板中,Viewport在添加到根面板时会自动进行布局,无需调用layout()方法。
以下是添加Viewport的步骤:
1. 在RSSReader.java源文件的onModuleLoad方法中添加以下代码:
```java
public void onModuleLoad() {
Viewport viewport = new Viewport();
RootPanel.get().add(viewport);
}
```
2. 为了证明Viewport已加载,在war目录下的RSSReader.css文件中添加以下CSS定义:
```css
.x-viewport
{
background-color: #070;
}
```
3. 启动应用后,浏览器窗口最初会是空白白色的,直到JavaScript代码执行并渲染Viewport,此时浏览器窗口将变为深绿色。
#### 7. 使用BorderLayout布局
布局类定义了添加到LayoutContainer的组件的定位和显示方式,布局的基类是com.extjs.gxt.ui.client.widget.Layout。这里我们使用BorderLayout,它能方便地布局全屏应用的组件,将布局组件划分为多个布局区域:中心区域和围绕它的其他区域(北、南、东、西),支持用户通过分割条调整区域大小,允许区域展开、折叠或隐藏。
在我们的应用中,只使用北、西和中心布局区域。在使用BorderLayout添加子组件之前,需要使用BorderLayoutData对象定义组件添加后的行为。创建BorderLayoutData对象时,必须定义它应用的布局区域,还可以选择指定其初始大小以及区域的最大和最小大小。
以下是在示例应用中使用BorderLayout的步骤:
1. 在示例应用类的onModuleLoad方法中创建一个新的BorderLayout并设置Viewport使用它:
```java
public void onModuleLoad() {
Viewport viewport = new Viewport();
final BorderLayout borderLayout = new BorderLayout();
viewport.setLayout(borderLayout);
RootPanel.get().add(viewport);
}
```
2. 创建北布局区域的BorderLayoutData,设置高度为20px,不可折叠且不可调整大小:
```java
BorderLayoutData northData = new BorderLayoutData(LayoutRegion.NORTH,20);
northData.setCollapsible(false);
northData.setSplit(false);
```
3. 创建一个HTML小部件作为头部,并使用之前定义的BorderLayoutData将其添加到Viewport的北位置:
```java
HTML headerHtml = new HTML();
headerHtml.setHTML("<h1>RSS Reader</h1>");
viewport.add(headerHtml, northData);
```
4. 定义中心和西布局区域的BorderLayoutData,西区域可折叠和调整大小,初始宽度为200px,最小宽度为150px,最大宽度为300px:
```java
BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);
centerData.setCollapsible(false);
BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST, 200, 150, 300);
westData.setCollapsible(true);
westData.setSplit(true);
```
5. 创建两个新的ContentPanel并分别添加到Viewport的西和中心面板:
```java
ContentPanel mainPanel = new ContentPanel();
ContentPanel navPanel = new ContentPanel();
viewport.add(mainPanel, centerData);
viewport.add(navPanel, westData);
```
6. 运行应用,检查屏幕显示是否符合预期。
通过以上步骤,我们完成了一个使用GXT组件和布局的基础应用框架搭建,后续可以在此基础上继续完善和扩展RSS阅读器的功能。
下面是一个简单的mermaid流程图,展示了添加组件和布局的主要步骤:
```mermaid
graph TD;
A[创建Viewport] --> B[设置BorderLayout];
B --> C[创建North布局数据];
B --> D[创建Center布局数据];
B --> E[创建West布局数据];
C --> F[创建Header HTML并添加到North];
D --> G[创建MainPanel并添加到Center];
E --> H[创建NavPanel并添加到West];
F --> I[运行应用];
G --> I;
H --> I;
```
通过以上内容,我们对GXT的组件、渲染机制、事件处理以及布局方式有了初步的了解,并通过RSS阅读器示例应用进行了实践操作。希望这些知识能帮助大家在开发Web应用时更好地运用GXT。
### 深入探索GXT:构建强大Web应用的基石
#### 8. Loading消息与用户交互体验
在GXT应用中,加载消息(Loading messages)是提升用户体验的重要部分。当应用执行一些耗时操作时,如数据加载、请求处理等,向用户显示加载消息可以让用户知道应用正在处理任务,避免用户因长时间等待而产生困惑或不耐烦。
虽然文档中没有详细给出如何实现加载消息的代码,但一般来说,在GXT中可以结合组件的状态和事件机制来实现。例如,当一个ContentPanel开始加载数据时,可以显示一个加载消息,数据加载完成后隐藏该消息。以下是一个简单的伪代码示例:
```java
ContentPanel contentPanel = new ContentPanel();
// 显示加载消息
contentPanel.mask("Loading data...");
// 模拟数据加载
Timer timer = new Timer() {
@Override
public void run() {
// 数据加载完成,隐藏加载消息
contentPanel.unmask();
}
};
timer.schedule(3000); // 模拟3秒加载时间
```
#### 9. 自定义组件与扩展功能
GXT允许开发者创建自定义组件来满足特定的业务需求。自定义组件可以基于现有的GXT组件进行扩展,添加新的功能或修改现有行为。
例如,我们可以创建一个自定义的按钮组件,该按钮在点击时除了触发普通的点击事件外,还会执行一些额外的操作。以下是一个简单的自定义按钮组件示例:
```java
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
public class CustomButton extends Button {
public CustomButton(String text) {
super(text);
addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
// 执行额外操作
System.out.println("Custom action executed!");
// 调用父类的点击处理逻辑
super.componentSelected(ce);
}
});
}
}
```
使用自定义按钮的代码如下:
```java
CustomButton customButton = new CustomButton("Custom Click");
customButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
System.out.println("Button clicked!");
}
});
```
#### 10. 按钮、工具提示与弹出框的使用
- **按钮(Buttons)**:按钮是GXT中常见的交互组件,用于触发各种操作。可以为按钮添加事件监听器,当用户点击按钮时执行相应的逻辑。例如:
```java
Button simpleButton = new Button("Simple Click");
simpleButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
System.out.println("Simple button clicked!");
}
});
```
- **工具提示(Tooltip)**:工具提示可以为组件提供额外的信息,当用户将鼠标悬停在组件上时显示。在GXT中,可以为组件设置工具提示,以下是为按钮设置工具提示的示例:
```java
Button tooltipButton = new Button("With Tooltip");
tooltipButton.setToolTip("This is a tooltip for the button.");
```
- **弹出框(Popup)**:弹出框用于显示临时的信息或提供额外的交互界面。例如,当用户点击按钮时弹出一个包含详细信息的弹出框:
```java
Button popupButton = new Button("Show Popup");
final Popup popup = new Popup();
HTML popupContent = new HTML("<p>This is a popup content.</p>");
popup.add(popupContent);
popupButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
popup.showRelativeTo(popupButton);
}
});
```
#### 11. 选择监听器与文本框交互
- **选择监听器(SelectionListener)**:选择监听器用于监听组件的选择事件,如列表项的选择、按钮的点击等。例如,监听列表框的选择事件:
```java
import com.extjs.gxt.ui.client.widget.ListBox;
import com.extjs.gxt.ui.client.event.ListBoxEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
ListBox listBox = new ListBox();
listBox.add("Item 1");
listBox.add("Item 2");
listBox.add("Item 3");
listBox.addSelectionListener(new SelectionListener<ListBoxEvent>() {
@Override
public void componentSelected(ListBoxEvent ce) {
System.out.println("Selected item: " + ce.getSelectedItem());
}
});
```
- **文本框(TextField)**:文本框用于用户输入文本信息。可以为文本框添加事件监听器,如按键监听器(KeyListener),当用户按下某个键时执行相应的操作。以下是一个简单的文本框按键监听器示例:
```java
import com.extjs.gxt.ui.client.widget.TextField;
import com.extjs.gxt.ui.client.event.KeyEvent;
import com.extjs.gxt.ui.client.event.KeyListener;
TextField<String> textField = new TextField<String>();
textField.addKeyListener(new KeyListener() {
@Override
public void componentKeyPress(KeyEvent event) {
if (event.getKeyCode() == KeyCodes.KEY_ENTER) {
System.out.println("User pressed Enter with text: " + textField.getValue());
}
}
});
```
#### 12. 综合应用与功能扩展
将上述所学的组件、事件和布局知识结合起来,可以构建一个功能更加丰富的RSS阅读器应用。例如,在之前的布局基础上,添加文本框用于用户输入RSS源地址,添加按钮用于刷新数据,使用列表框显示新闻列表等。
以下是一个简单的综合应用示例代码:
```java
import com.extjs.gxt.ui.client.widget.Viewport;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.TextField;
import com.extjs.gxt.ui.client.widget.Button;
import com.extjs.gxt.ui.client.widget.ListBox;
import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.google.gwt.user.client.ui.RootPanel;
public class RSSReaderApp {
public static void onModuleLoad() {
Viewport viewport = new Viewport();
BorderLayout borderLayout = new BorderLayout();
viewport.setLayout(borderLayout);
// 北布局区域
BorderLayoutData northData = new BorderLayoutData(LayoutRegion.NORTH, 20);
northData.setCollapsible(false);
northData.setSplit(false);
ContentPanel northPanel = new ContentPanel();
northPanel.setHeading("RSS Reader");
TextField<String> rssUrlField = new TextField<String>();
rssUrlField.setEmptyText("Enter RSS URL");
Button refreshButton = new Button("Refresh");
refreshButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
String url = rssUrlField.getValue();
System.out.println("Refreshing with URL: " + url);
// 这里可以添加实际的刷新逻辑
}
});
northPanel.add(rssUrlField);
northPanel.add(refreshButton);
viewport.add(northPanel, northData);
// 西布局区域
BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST, 200, 150, 300);
westData.setCollapsible(true);
westData.setSplit(true);
ContentPanel westPanel = new ContentPanel();
westPanel.setHeading("Navigation");
ListBox categoryListBox = new ListBox();
categoryListBox.add("Category 1");
categoryListBox.add("Category 2");
categoryListBox.add("Category 3");
westPanel.add(categoryListBox);
viewport.add(westPanel, westData);
// 中心布局区域
BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);
centerData.setCollapsible(false);
ContentPanel centerPanel = new ContentPanel();
centerPanel.setHeading("News List");
ListBox newsListBox = new ListBox();
centerPanel.add(newsListBox);
viewport.add(centerPanel, centerData);
RootPanel.get().add(viewport);
}
}
```
#### 13. 总结与展望
通过以上内容,我们全面了解了GXT的各种组件、渲染机制、事件处理、布局方式以及如何创建自定义组件和构建综合应用。GXT为开发者提供了丰富的工具和功能,能够帮助我们快速构建出功能强大、用户体验良好的Web应用。
在未来的开发中,我们可以进一步探索GXT的更多高级功能,如数据绑定、图表展示、远程数据交互等。同时,结合其他前端和后端技术,如HTML5、CSS3、服务器端框架等,可以打造更加复杂和完善的Web应用系统。
以下是一个总结表格,梳理了GXT的主要组件和功能:
|组件/功能|描述|
| ---- | ---- |
|Component|GXT中所有可视化元素的基类,参与生命周期管理和懒加载渲染|
|BoxComponent|可定位和调整大小的组件的基类|
|Container|包含其他组件的容器,具备管理子组件的能力|
|LayoutContainer|支持使用布局来布局子组件|
|FlowLayout|LayoutContainer的默认布局|
|ContentPanel|具有头部、底部和主体部分,可折叠和展开的容器|
|Events|支持观察者模式,可监听各种事件|
|Viewport|填充浏览器窗口并监控窗口大小变化|
|BorderLayout|方便布局全屏应用的组件|
|Custom Components|可基于现有组件扩展自定义功能|
|Buttons、Tooltip、Popup|提供用户交互和信息展示的组件|
|SelectionListener、KeyListener|用于监听组件的选择和按键事件|
下面是一个mermaid流程图,展示了构建GXT应用的主要步骤:
```mermaid
graph TD;
A[初始化项目] --> B[创建Viewport和布局];
B --> C[添加组件和布局数据];
C --> D[实现事件处理和交互];
D --> E[添加自定义组件和功能];
E --> F[综合应用和测试];
```
希望通过本文的介绍,大家能够更好地掌握GXT的开发技巧,在Web应用开发中发挥出GXT的强大优势。
0
0
复制全文
相关推荐










