本文纯属金山词霸产物,如果看不懂请参考英文原文
How to Write a Custom Swing Component
如何编写自定义Swing组件
by Kirill Grouchnikov
02/22/2007
当提到比较awt组件和swing组件的区别时, 首先被提到的就是Swing 是轻量级的(lightweight).确切的说其按钮、框架和菜单都没有使用本地化控制(native controls).所有组件包括渲染和事件处理都是靠纯java控制的。这给我们提供了很多方法去创建真正与平台无关的组件,而创建一个在所有平台上外观一致的自定义组件并非一件简单的事,这篇文章将演示如何创建自定义组件的过程并高亮显示重点、步骤和易犯的错误。
基础部分
Swing architecture overview这篇文章提供了非常优秀的swing结构和开发的高级概述(high-level overview)。虽然创建组件要遵循一些规则会略微有点麻烦,不过最终代码会更容易理解。它遵循”不重复发明轮子”的原则。最初你会想要把所有的东西都集中到一个类里,包括扩展API,模型处理(状态和通知),事务处理,布局和绘制。但是按照MVC (model-view-controller)结构将其划分为多个类可以让你的组件代码更容易理解,并且从长远来说更加容易扩展。
所有核心Swing组件的主要部分如下:
- 组件(component)类本身,他负责提供创建、修改和查询组件状态的API
- 模型接口和和模型接口的默认实现,它负责处理组件的业务逻辑和组件改变通知
- UI delegate 负责处理组件布局,事件处理(鼠标和键盘事件)以及组件的绘制。
本文将配图展示创建一个自定义组件,类似WINDOWS Vista Explorer 中新的 view slider (如图1)。这个组件按看上去很像一个滑标嵌入一个pop-up menu。但他和常规的JSlider又有所不同,首先,它会含有关联标签(labels)和图标(icon)的选项(control points),其次,若range是相邻的,(如Small Icons和Medium Icons),能够动态的修改图标大小,若range是非关联的(如Tiles-Details),滑块只能滑动到这些选项上,不能滑动到这些选项之间的位置。
图1:Windows Vista OS 中的 View slider
组件类:UI Delegate 装配
自定义组件的第一个类就是组件本身的API,这个API足够简单并且委托大部分业务逻辑给模型(参考下一章),除此之外,为了设置合适的UI delegate,你需要增加一个样板(boilerplate)(详细介绍请参考 Enhancing Swing Applications 一文),最终,你的代码应该是类似这样的:
private static final String uiClassID = "FlexiSliderUI";
public void setUI(FlexiSliderUI ui) {
super.setUI(ui);
}
public void updateUI() {
if (UIManager.get(getUIClassID()) != null) {
setUI((FlexiSliderUI) UIManager.getUI(this));
} else {
setUI(new BasicFlexiSliderUI());
}
}
public FlexiSliderUI getUI() {
return (FlexiSliderUI) ui;
}
public String getUIClassID() {
return uiClassID;
}
这里需要注意的一点是:你需要提供一个可靠的UI delegate,如果当前安装的look and feel 没有提供特殊的UI delegate时,这个UI delegate将处理组件的绘制,布局和事件处理。
模型接口
这可能是这个组件最重要的接口了。它将从业务层面表现的你的组件功能。模型接口不要包含任何和界面绘制相关的方法(像setFont或getPreferredSize)。我们的组件将遵循LinearGradientPaint API并且定义模型为一些range序列:
public static class Range {
private boolean isDiscrete;
private double weight;
public Range(boolean isDiscrete, double weight) {
this.isDiscrete = isDiscrete;
this.weight = weight;
}
...
}
模型中设置和查询range的API
public void setRanges(Range... range);
public int getRangeCount();
public Range getRange(int rangeIndex);
另外,模型还提供set和get当前值的API,这个Value类包含有Range对象
public static class Value {
public Range range;
public double rangeFraction;
public Value(Range range, double rangeFraction) {
this.range = range;
this.rangeFraction = rangeFraction;
}
...
}
这个模型还提供当前值对象的get和set方法:
模型接口的最后一部分为增加/移除变化监听器(ChangeListeners)的方法,他遵循swing核心组件的model接口风格(参考BoundedRangeModel);
void addChangeListener(ChangeListener x);
void removeChangeListener(ChangeListener x);
模型实现
模型的实现类非常简单,参考DefaultBoundedRangeModel,变化监听器(ChangeListeners)使用EventListenerList来保存。当模型值被改变时将触发ChangeEvent:
protected void fireStateChanged() {
ChangeEvent event = new ChangeEvent(this);
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ChangeListener.class) {
((ChangeListener) listeners[i + 1]).stateChanged(event);
}
}
}
以上为swing 核心组件源代码,我们从后向前检索所有listener.提取出stateChanged方法实现来执行。相关方法非常简单,检查值是否有效,并且复制slider ranges数组(之所以这样做是为了让那些恶意程序代码不能直接作用于model)
模型的单元测试
对UI组件进行单元测试是非常困难的,而模型必须被彻底地测试—记住,和损失模型的尾零(trailing zero)相比,损失一个像素并无大碍,使用一个简单的测试来确认你的默认模型实现的正确性:
(译注:尾零部分没有翻译,因为不熟,原文the model should be thoroughly tested--remember that the loss of a pixel is nothing compared to the loss of a trailing zero in the model, especially if that zero multiplies an automatic payment by 10)
public void testSetValue2() {
FlexiRangeModel model = new DefaultFlexiRangeModel();
FlexiRangeModel.Range range0 = new FlexiRangeModel.Range(true, 0.0);
model.setRanges(range0);
try {
// should fail since range0 is discrete
FlexiRangeModel.Value value = new FlexiRangeModel.Value(range0, 0.5);
model.setValue(value);
} catch (IllegalArgumentException iae) {
return;
}
assertTrue(false);
}
组件类:API
回到组件类来,我们增加缺少的构造函数和模型的get方法.一些和 UI相关联的设置(如图标和标签文字)保存在组件类本身中(不属于模型)。组件的构造器类似LinearGradientPaint,当接收到null或者不一致的参数时将抛出异常
public JFlexiSlider(Range[] ranges, Icon[] controlPointIcons,
String[] controlPointTexts) throws NullPointerException,
IllegalArgumentException
这个实现非常简单,首先,检查3个数组非空并且数组长度符合要求,然后,创建DefaultFlexiRangeModel对象并且设置它的ranges.复制图标和文字数组,最后调用updateUI方法安装并且初始化look-and-feel delegate.这个类增加的API如下:
public int getControlPointCount();
public Icon getControlPointIcon(int controlPointIndex);
public String getControlPointText(int controlPointIndex);
public FlexiRangeModel getModel();
public FlexiRangeModel.Value getValue();
public void setValue(FlexiRangeModel.Value value);
注意最后两个方法其实就是调用了模型中的相应方法,只是为了方便而已。前三个方法主要是提供给UI delegate,也可以被应用程序所使用。
待续...
- 大小: 58.1 KB
分享到:
相关推荐
本主题主要关注如何自定义Swing组件,以便满足特定需求或实现独特功能。下面我们将深入探讨自定义Swing组件的基本概念、步骤以及相关知识点。 一、Swing组件基础 Swing组件是构建GUI的基础,包括按钮(JButton)、...
总之,自定义`JTabbedPane`外观涉及的主要知识点包括:Swing组件模型、UI设计模式、可绘制组件、布局管理和API的使用。通过理解和实践这些概念,开发者可以创建出满足特定需求的、具有独特外观的`JTabbedPane`组件。
综上所述,"swing组件介绍(一)"可能会涵盖Swing的基本概念、核心组件、布局管理、事件处理以及一些实用工具类,帮助初学者理解Swing在开发Java桌面应用中的重要性和用法。对于深入学习Swing,开发者还需要了解高级...
首先,Swing组件是轻量级的,它们大部分是用Java实现的,这使得Swing应用程序可以在不同的操作系统上保持一致的外观和行为。例如,JFrame是Swing中的顶级容器,它通常作为应用程序的主窗口;JButton用于创建可点击的...
2. **跨平台一致性**:Swing组件是轻量级的,它们不依赖于底层操作系统,从而确保在不同平台上具有一致的外观和行为。 3. **外观和感觉(LookAndFeel)**:用户可以轻松改变程序的视觉样式,实现自定义的LookAnd...
Swing扩展组件是Java Swing库中的一...同时,Swing组件的事件处理机制和模型-视图-控制器(MVC)设计模式也为程序的可维护性和可扩展性提供了保障。因此,深入理解和使用Swing扩展组件对于Java GUI开发者来说至关重要。
此外,Swing组件还支持事件处理,通过实现EventListener接口或使用匿名内部类,可以编写代码来响应用户的操作,如按钮点击、文本输入等。 总结来说,"Swing组件demo"涵盖了Swing GUI开发中的基本元素和功能,通过...
标题提到的"几个漂亮的SWING组件(源代码)"很可能是包含了一些自定义或者美化过的Swing组件示例,供开发者参考学习。 在Swing组件库中,有许多基础和高级组件,包括但不限于: 1. **JFrame**: 这是大多数Swing...
本教程将深入探讨Swing组件的实例应用,帮助开发者更好地理解和掌握Swing在实际编程中的运用。 一、Swing组件基础 Swing组件主要由JComponent类及其子类构成,包括按钮(JButton)、文本框(JTextField)、标签...
综上所述,"Swing组件大全"不仅涵盖了Swing库中的所有核心组件,还涵盖了数据库操作、Excel文件处理和自定义布局管理,是学习和开发Swing应用的宝贵资源。通过深入理解和实践这些知识点,开发者可以构建出功能强大且...
Swing组件的一个重要特点是轻量级,这意味着它们不依赖于操作系统特定的图形库,因此可以在不同的操作系统上保持一致的外观和行为。此外,Swing还提供了可定制的外观,称为LookAndFeel,可以改变整个应用程序的视觉...
这个“Swing组件教案及示例程序”压缩包文件显然包含了关于如何使用Swing来创建丰富的桌面应用程序的教学材料和实际示例。Swing提供了一套组件,如按钮、文本框、菜单等,使得开发者能够构建出美观且功能丰富的应用...
9. **事件处理**:Swing通过EventListener接口和EventObject类实现了事件驱动编程,用户可以通过实现特定的监听器接口来处理组件上的事件,如ActionListener、MouseListener等。 10. **自定义外观**:通过LookAnd...
本篇文章将深入探讨Java Swing组件集合,帮助初学者更好地理解和使用这些组件。 首先,Swing 提供了丰富的组件集,包括按钮(JButton)、文本框(JTextField)、标签(JLabel)、复选框(JCheckBox)、单选按钮...
总的来说,"swing自制组件(一)"这个主题是关于Java Swing编程中的组件扩展,通过分析"RichJLabel.java"我们可以深入理解Swing组件的自定义机制,并学习到如何利用Java Swing创建具有特殊功能的用户界面元素。...
**Java Swing组件与JIDE库** Java Swing是Java标准版(Java SE)的一部分,它提供了一组用于构建桌面应用程序的用户界面组件。Swing库基于Java AWT(Abstract Window Toolkit),但提供了更丰富的特性和更好的跨...
Java Swing是Java GUI编程的重要工具,它提供了丰富的组件和接口,允许开发者构建用户界面。"Look and Feel"(观感)是Swing中一个关键的概念,它决定了应用程序的视觉样式和交互体验。Java Swing默认提供了多种观感...
在本项目中,“基于Swing组件编写华容道Java程序”是一个使用Java语言,并借助NetBeans集成开发环境(IDE)创建的可视化游戏应用。Swing是Java的一个图形用户界面(GUI)工具包,它提供了丰富的组件库,允许开发者...
6. **可扩展性与自定义**: Swing组件可通过继承或实现特定接口来自定义外观和行为。例如,可以通过JTable类创建自定义的表格组件,或者通过LookAndFeel更改整个应用的视觉样式。 7. **高级组件**: Swing还提供了...