`
nciky1984
  • 浏览: 19535 次
  • 来自: 0
文章分类
社区版块
存档分类
最新评论

如何编写自定义Swing组件(上)

阅读更多

本文纯属金山词霸产物,如果看不懂请参考英文原文

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组件基础 Swing组件是构建GUI的基础,包括按钮(JButton)、...

    swing自定义JTabbedPane组件外观

    总之,自定义`JTabbedPane`外观涉及的主要知识点包括:Swing组件模型、UI设计模式、可绘制组件、布局管理和API的使用。通过理解和实践这些概念,开发者可以创建出满足特定需求的、具有独特外观的`JTabbedPane`组件。

    swing组件介绍(一)

    综上所述,"swing组件介绍(一)"可能会涵盖Swing的基本概念、核心组件、布局管理、事件处理以及一些实用工具类,帮助初学者理解Swing在开发Java桌面应用中的重要性和用法。对于深入学习Swing,开发者还需要了解高级...

    java基于Swing组件的GUI设计

    首先,Swing组件是轻量级的,它们大部分是用Java实现的,这使得Swing应用程序可以在不同的操作系统上保持一致的外观和行为。例如,JFrame是Swing中的顶级容器,它通常作为应用程序的主窗口;JButton用于创建可点击的...

    swing组件的详细介绍

    2. **跨平台一致性**:Swing组件是轻量级的,它们不依赖于底层操作系统,从而确保在不同平台上具有一致的外观和行为。 3. **外观和感觉(LookAndFeel)**:用户可以轻松改变程序的视觉样式,实现自定义的LookAnd...

    Swing 扩展组件 Swing 扩展组件

    Swing扩展组件是Java Swing库中的一...同时,Swing组件的事件处理机制和模型-视图-控制器(MVC)设计模式也为程序的可维护性和可扩展性提供了保障。因此,深入理解和使用Swing扩展组件对于Java GUI开发者来说至关重要。

    swing 组件 demo

    此外,Swing组件还支持事件处理,通过实现EventListener接口或使用匿名内部类,可以编写代码来响应用户的操作,如按钮点击、文本输入等。 总结来说,"Swing组件demo"涵盖了Swing GUI开发中的基本元素和功能,通过...

    几个漂亮的SWING组件(源代码)

    标题提到的"几个漂亮的SWING组件(源代码)"很可能是包含了一些自定义或者美化过的Swing组件示例,供开发者参考学习。 在Swing组件库中,有许多基础和高级组件,包括但不限于: 1. **JFrame**: 这是大多数Swing...

    swing各个组件实例演示

    本教程将深入探讨Swing组件的实例应用,帮助开发者更好地理解和掌握Swing在实际编程中的运用。 一、Swing组件基础 Swing组件主要由JComponent类及其子类构成,包括按钮(JButton)、文本框(JTextField)、标签...

    Swing 组件大全

    综上所述,"Swing组件大全"不仅涵盖了Swing库中的所有核心组件,还涵盖了数据库操作、Excel文件处理和自定义布局管理,是学习和开发Swing应用的宝贵资源。通过深入理解和实践这些知识点,开发者可以构建出功能强大且...

    j2ee的应用-swing组件介绍

    Swing组件的一个重要特点是轻量级,这意味着它们不依赖于操作系统特定的图形库,因此可以在不同的操作系统上保持一致的外观和行为。此外,Swing还提供了可定制的外观,称为LookAndFeel,可以改变整个应用程序的视觉...

    Swing组件教案及示例程序

    这个“Swing组件教案及示例程序”压缩包文件显然包含了关于如何使用Swing来创建丰富的桌面应用程序的教学材料和实际示例。Swing提供了一套组件,如按钮、文本框、菜单等,使得开发者能够构建出美观且功能丰富的应用...

    java Swing用户界面组件

    9. **事件处理**:Swing通过EventListener接口和EventObject类实现了事件驱动编程,用户可以通过实现特定的监听器接口来处理组件上的事件,如ActionListener、MouseListener等。 10. **自定义外观**:通过LookAnd...

    Java Swing'组件集合

    本篇文章将深入探讨Java Swing组件集合,帮助初学者更好地理解和使用这些组件。 首先,Swing 提供了丰富的组件集,包括按钮(JButton)、文本框(JTextField)、标签(JLabel)、复选框(JCheckBox)、单选按钮...

    swing自制组件(一)

    总的来说,"swing自制组件(一)"这个主题是关于Java Swing编程中的组件扩展,通过分析"RichJLabel.java"我们可以深入理解Swing组件的自定义机制,并学习到如何利用Java Swing创建具有特殊功能的用户界面元素。...

    基于Java的开源的Swing组件 JIDE.zip

    **Java Swing组件与JIDE库** Java Swing是Java标准版(Java SE)的一部分,它提供了一组用于构建桌面应用程序的用户界面组件。Swing库基于Java AWT(Abstract Window Toolkit),但提供了更丰富的特性和更好的跨...

    Java Swing自定义观感(仅以自定义treeUI为例)

    Java Swing是Java GUI编程的重要工具,它提供了丰富的组件和接口,允许开发者构建用户界面。"Look and Feel"(观感)是Swing中一个关键的概念,它决定了应用程序的视觉样式和交互体验。Java Swing默认提供了多种观感...

    基于Swing组件编写华容道Java程序

    在本项目中,“基于Swing组件编写华容道Java程序”是一个使用Java语言,并借助NetBeans集成开发环境(IDE)创建的可视化游戏应用。Swing是Java的一个图形用户界面(GUI)工具包,它提供了丰富的组件库,允许开发者...

    深入学习jfc swing组件

    6. **可扩展性与自定义**: Swing组件可通过继承或实现特定接口来自定义外观和行为。例如,可以通过JTable类创建自定义的表格组件,或者通过LookAndFeel更改整个应用的视觉样式。 7. **高级组件**: Swing还提供了...

Global site tag (gtag.js) - Google Analytics