ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]

时间:2022-01-19 05:30:49

支持Form颜色选择组件、日期时间选择组件、带图标的下拉列表、多选下来列表、动态下拉列表树等组件

开发环境:

System:Windows

WebBrowser:IE6+、Firefox3+

JavaEE Server:tomcat5.0.2.8、tomcat6

IDE:eclipse、MyEclipse 8

开发依赖库:

JavaEE5、ext 2.2.2

Email:hoojo_@126.com

Blog:http://blog.csdn.net/IBM_hoojo

http://hoojo.cnblogs.com/

 

一、ColoFieldr组件

可以选择一些常用的颜色

ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]

需要用到的文件

ColorField组件文件:Ext.form.ColorField.js

ColorField运行示例文件:Ext.hoo.for.ColorField.js

代码如下

Color.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>form Component -- DateTimeField</title>
        <meta http-equiv="pragma" content="no-cache"/>
        <meta http-equiv="cache-control" content="no-cache"/>
        <meta http-equiv="expires" content="0"/>
        <meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
        <meta http-equiv="author" content="hoojo"/>
        <meta http-equiv="email" content="hoojo_@126.com"/>
        <meta http-equiv="ext-lib" content="version 2.2"/>
        <meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>        
        <link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
        <script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
        <script type="text/javascript" src="../ext2/ext-all.js"></script>
        <script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
        <script type="text/javascript" src="Ext.form.ColorField.js"></script>
        <script type="text/javascript" src="Ext.hoo.for.ColorField.js"></script>
  </head>
  
  <body>
      <div id="show" style="float: left; margin: 100px 0 0 100px;"></div>
  </body>
</html>

Ext.form.ColorField.js

/**
 * @class Ext.form.ColorField
 * @extends Ext.form.TriggerField
 * Provides a very simple color form field with a ColorMenu dropdown.
 * Values are stored as a six-character hex value without the '#'.
 * I.e. 'ffffff'
 * @constructor
 * Create a new ColorField
 * <br />Example:
 * <pre><code>
var cf = new Ext.form.ColorField({
    fieldLabel: 'Color',
    hiddenName:'pref_sales',
    showHexValue:true
});
</code></pre>
 * @param {Object} config
 */
Ext.form.ColorField = function(config){
    Ext.form.ColorField.superclass.constructor.call(this, config);
    //this.on('render', this.handleRender);
};
 
Ext.extend(Ext.form.ColorField, Ext.form.TriggerField,  {
    /**
     * @cfg {Boolean} showHexValue
     * True to display the HTML Hexidecimal Color Value in the field
     * so it is manually editable.
     */
    showHexValue : false,
    
    /**
     * @cfg {String} triggerClass
     * An additional CSS class used to style the trigger button.  The trigger will always get the
     * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-color-trigger'
     * which displays a calendar icon).
     */
    triggerClass : 'x-form-color-trigger',
    
    /**
     * @cfg {String/Object} autoCreate
     * A DomHelper element spec, or true for a default element spec (defaults to
     * {tag: "input", type: "text", size: "10", autocomplete: "off"})
     */
    // private
    defaultAutoCreate : {tag: "input", type: "text", size: "10",
                         autocomplete: "off", maxlength:"6"},
    
    /**
     * @cfg {String} lengthText
     * A string to be displayed when the length of the input field is
     * not 3 or 6, i.e. 'fff' or 'ffccff'.
     */
    lengthText: "Color hex values must be either 3 or 6 characters.",
    
    //text to use if blank and allowBlank is false
    blankText: "Must have a hexidecimal value in the format ABCDEF.",
    
    /**
     * @cfg {String} color
     * A string hex value to be used as the default color.  Defaults
     * to 'FFFFFF' (white).
     */
    defaultColor: 'FFFFFF',
    
    maskRe: /[a-f0-9]/i,
    // These regexes limit input and validation to hex values
    regex: /[a-f0-9]/i,
 
    //private
    curColor: 'ffffff',
    initComponent:function(){   
        Ext.form.ColorField.superclass.initComponent.call(this);   
        this.addEvents('click','change', 'select');  
    },        
    onChange: function (field, newVal, oldVal) {
        alert(newVal);
    },
    onRender : function(ct, position){
        Ext.form.ColorField.superclass.onRender.call(this, ct, position);
        this.handleRender();
    },
    // private
    validateValue : function(value){
        if(!this.showHexValue) {
            return true;
        }
        if(value.length<1) {
            this.el.setStyle({
                'background-color':'#' + this.defaultColor
            });
            if(!this.allowBlank) {
                this.markInvalid(String.format(this.blankText, value));
                return false
            }
            return true;
        }
        if(value.length!=3 && value.length!=6 ) {
            this.markInvalid(String.format(this.lengthText, value));
            return false;
        }
        this.setColor(value);
        return true;
    },
 
    // private
    validateBlur : function(){
        return !this.menu || !this.menu.isVisible();
    },
    
    // Manually apply the invalid line image since the background
    // was previously cleared so the color would show through.
    markInvalid : function( msg ) {
        Ext.form.ColorField.superclass.markInvalid.call(this, msg);
        this.el.setStyle({
            'background-image': 'url(../lib/resources/images/default/grid/invalid_line.gif)'
        });
    },
 
    /**
     * Returns the current color value of the color field
     * @return {String} value The hexidecimal color value
     */
    getValue : function(){
        return this.curValue || this.defaultValue || "FFFFFF";
    },
 
    /**
     * Sets the value of the color field.  Format as hex value 'FFFFFF'
     * without the '#'.
     * @param {String} hex The color value
     */
    setValue : function(hex){
        Ext.form.ColorField.superclass.setValue.call(this, hex);
        this.setColor(hex);
    },
    
    /**
     * Sets the current color and changes the background.
     * Does *not* change the value of the field.
     * @param {String} hex The color value.
     */
    setColor : function(hex) {
        this.curColor = hex;
        
        this.el.setStyle( {
            'background-color': '#' + hex,
            'background-image': 'none'
        });
        if(!this.showHexValue) {
            this.el.setStyle({
                'text-indent': '-100px'
            });
            if(Ext.isIE) {
                this.el.setStyle({
                    'margin-left': '100px'
                });
            }
        }
    },
    
    handleRender: function() {
        this.setDefaultColor();
    },
    
    setDefaultColor : function() {
        this.setValue(this.defaultColor);
    },
 
    // private
    menuListeners : {
        select: function(m, d){
            this.setValue(d);
        },
        show : function(){ // retain focus styling
            this.onFocus();
        },
        hide : function(){
            this.focus();
            var ml = this.menuListeners;
            this.menu.un("select", ml.select,  this);
            this.menu.un("show", ml.show,  this);
            this.menu.un("hide", ml.hide,  this);
        }
    },
    
    //private
    handleSelect : function(palette, selColor) {
        this.setValue(selColor);
        this.fireEvent("click", this, selColor);        
        this.fireEvent("change", this, selColor);        
        this.fireEvent("select", this, selColor); 
    },
 
    // private
    // Implements the default empty TriggerField.onTriggerClick function to display the ColorPicker
    onTriggerClick : function(){
        if(this.disabled){
            return;
        }
        if(this.menu == null){
            this.menu = new Ext.menu.ColorMenu();
            this.menu.palette.on('select', this.handleSelect, this );
        }
        this.menu.on(Ext.apply({}, this.menuListeners, {
            scope:this
        }));
        this.menu.show(this.el, "tl-bl?");
    }
});

Ext.hoo.for.ColorField.js

/**
 * @function 颜色选择器
 * @auhor: hoojo
 * @createDate: Sep 11, 2010 10:35:15 PM
 * @blog: blog.csdn.net/IBM_hoojo
 * @email: hoojo_@126.com
 * @class Ext.hoo.form.ColorField
 * @extends Ext.form.ColorField
 */
Ext.ns("Ext.hoo.form");
Ext.hoo.form.ColorField = Ext.extend(Ext.form.ColorField, {
    constructor: function () {
        Ext.hoo.form.ColorField.superclass.constructor.call(this, {
            //fieldLabel: "plase selected",
            renderTo: "show",
            width: 160,
            defaultColor: "00FF00",
            curColor: "00FF00",
            showHexValue: true,
            listeners: {
                "select": function (f, v) {
                    alert(this.getValue() + "##" + v);
                }
            }
        });        
    }
});
 
Ext.onReady(function () {
    Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
    Ext.QuickTips.init();
    Ext.form.Field.prototype.msgTarget = "qtip";
    
    new Ext.hoo.form.ColorField();
});

二、日期时间选择控件

可以选择日期、时间

ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]

需要用到的文件

Spinner.js

Spinner.css

SpinnerField.js

日期时间组件:Ext.ux.form.DateTimeField.js

示例:Ext.hoo.form.DateTimeField.js

代码如下

dateTimeFieldExample.htm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>form Component -- MultiComboBox</title>
        <meta http-equiv="pragma" content="no-cache"/>
        <meta http-equiv="cache-control" content="no-cache"/>
        <meta http-equiv="expires" content="0"/>
        <meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
        <meta http-equiv="author" content="hoojo"/>
        <meta http-equiv="email" content="hoojo_@126.com"/>
        <meta http-equiv="ext-lib" content="version 3.2"/>
        <meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>        
        <link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css"/>
        <link rel="stylesheet" type="text/css" href="../css/Spinner.css"/>
        <script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
        <script type="text/javascript" src="../ext/ext-all.js"></script>
        <script type="text/javascript" src="../ext/build/locale/ext-lang-zh_CN-min.js"></script>
        <script type="text/javascript" src="Spinner.js"></script>
        <script type="text/javascript" src="SpinnerField.js"></script>
        <script type="text/javascript" src="Ext.ux.form.DateTimeField.js"></script>
        <script type="text/javascript" src="Ext.hoo.form.DateTimeField.js"></script>
  </head>
  
  <body>
      <div id="show" style="float: left; margin: 100px 0 0 100px;"></div>
  </body>
</html>

Spinner.css

/*!
 * Ext JS Library 3.1.1
 * Copyright(c) 2006-2010 Ext JS, LLC
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
.x-form-spinner-proxy{
    /*background-color:#ff00cc;*/
}
.x-form-field-wrap .x-form-spinner-trigger {
    background:transparent url('../images/spinner.gif') no-repeat 0 0;
}
 
.x-form-field-wrap .x-form-spinner-overup{
    background-position:-17px 0;
}
.x-form-field-wrap .x-form-spinner-clickup{
    background-position:-34px 0;
}
.x-form-field-wrap .x-form-spinner-overdown{
    background-position:-51px 0;
}
.x-form-field-wrap .x-form-spinner-clickdown{
    background-position:-68px 0;
}
 
 
.x-trigger-wrap-focus .x-form-spinner-trigger{
    background-position:-85px 0;
}
.x-trigger-wrap-focus .x-form-spinner-overup{
    background-position:-102px 0;
}
.x-trigger-wrap-focus .x-form-spinner-clickup{
    background-position:-119px 0;
}
.x-trigger-wrap-focus .x-form-spinner-overdown{
    background-position:-136px 0;
}
.x-trigger-wrap-focus .x-form-spinner-clickdown{
    background-position:-153px 0;
}
.x-trigger-wrap-focus .x-form-trigger{
    border-bottom: 1px solid #7eadd9;
}
 
.x-form-field-wrap .x-form-spinner-splitter {
    line-height:1px;
    font-size:1px;
    background:transparent url('../images/spinner-split.gif') no-repeat 0 0;
    position:absolute;
    cursor: n-resize;
}
 
.x-trigger-wrap-focus .x-form-spinner-splitter{
    background-position:-14px 0;
}
 
.x-date-bottom {
    font-size: 12px;
}
 
.x-date-menu {
    height: 200px;
}

图片

spinner.gif ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]

spinner-split.gif ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]

Spinner.js

/*!
 * Ext JS Library 3.1.1
 * Copyright(c) 2006-2010 Ext JS, LLC
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
/**
 * @class Ext.ux.Spinner
 * @extends Ext.util.Observable
 * Creates a Spinner control utilized by Ext.ux.form.SpinnerField
 */
Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
    incrementValue: 1,
    alternateIncrementValue: 5,
    triggerClass: 'x-form-spinner-trigger',
    splitterClass: 'x-form-spinner-splitter',
    alternateKey: Ext.EventObject.shiftKey,
    defaultValue: 0,
    accelerate: false,
 
    constructor: function(config){
        Ext.ux.Spinner.superclass.constructor.call(this, config);
        Ext.apply(this, config);
        this.mimicing = false;
    },
 
    init: function(field){
        this.field = field;
 
        field.afterMethod('onRender', this.doRender, this);
        field.afterMethod('onEnable', this.doEnable, this);
        field.afterMethod('onDisable', this.doDisable, this);
        field.afterMethod('afterRender', this.doAfterRender, this);
        field.afterMethod('onResize', this.doResize, this);
        field.afterMethod('onFocus', this.doFocus, this);
        field.beforeMethod('onDestroy', this.doDestroy, this);
    },
 
    doRender: function(ct, position){
        var el = this.el = this.field.getEl();
        var f = this.field;
 
        if (!f.wrap) {
            f.wrap = this.wrap = el.wrap({
                cls: "x-form-field-wrap"
            });
        }
        else {
            this.wrap = f.wrap.addClass('x-form-field-wrap');
        }
 
        this.trigger = this.wrap.createChild({
            tag: "img",
            src: Ext.BLANK_IMAGE_URL,
            cls: "x-form-trigger " + this.triggerClass
        });
 
        if (!f.width) {
            this.wrap.setWidth(el.getWidth() + this.trigger.getWidth());
        }
 
        this.splitter = this.wrap.createChild({
            tag: 'div',
            cls: this.splitterClass,
            style: 'width:13px; height:2px;'
        });
        this.splitter.setRight((Ext.isIE) ? 1 : 2).setTop(10).show();
 
        this.proxy = this.trigger.createProxy('', this.splitter, true);
        this.proxy.addClass("x-form-spinner-proxy");
        this.proxy.setStyle('left', '0px');
        this.proxy.setSize(14, 1);
        this.proxy.hide();
        this.dd = new Ext.dd.DDProxy(this.splitter.dom.id, "SpinnerDrag", {
            dragElId: this.proxy.id
        });
 
        this.initTrigger();
        this.initSpinner();
    },
 
    doAfterRender: function(){
        var y;
        if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
            this.el.position();
            this.el.setY(y);
        }
    },
 
    doEnable: function(){
        if (this.wrap) {
            this.wrap.removeClass(this.field.disabledClass);
        }
    },
 
    doDisable: function(){
        if (this.wrap) {
            this.wrap.addClass(this.field.disabledClass);
            this.el.removeClass(this.field.disabledClass);
        }
    },
 
    doResize: function(w, h){
        if (typeof w == 'number') {
            this.el.setWidth(w - this.trigger.getWidth());
        }
        this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
    },
 
    doFocus: function(){
        if (!this.mimicing) {
            this.wrap.addClass('x-trigger-wrap-focus');
            this.mimicing = true;
            Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {
                delay: 10
            });
            this.el.on('keydown', this.checkTab, this);
        }
    },
 
    // private
    checkTab: function(e){
        if (e.getKey() == e.TAB) {
            this.triggerBlur();
        }
    },
 
    // private
    mimicBlur: function(e){
        if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
            this.triggerBlur();
        }
    },
 
    // private
    triggerBlur: function(){
        this.mimicing = false;
        Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
        this.el.un("keydown", this.checkTab, this);
        this.field.beforeBlur();
        this.wrap.removeClass('x-trigger-wrap-focus');
        this.field.onBlur.call(this.field);
    },
 
    initTrigger: function(){
        this.trigger.addClassOnOver('x-form-trigger-over');
        this.trigger.addClassOnClick('x-form-trigger-click');
    },
 
    initSpinner: function(){
        this.field.addEvents({
            'spin': true,
            'spinup': true,
            'spindown': true
        });
 
        this.keyNav = new Ext.KeyNav(this.el, {
            "up": function(e){
                e.preventDefault();
                this.onSpinUp();
            },
 
            "down": function(e){
                e.preventDefault();
                this.onSpinDown();
            },
 
            "pageUp": function(e){
                e.preventDefault();
                this.onSpinUpAlternate();
            },
 
            "pageDown": function(e){
                e.preventDefault();
                this.onSpinDownAlternate();
            },
 
            scope: this
        });
 
        this.repeater = new Ext.util.ClickRepeater(this.trigger, {
            accelerate: this.accelerate
        });
        this.field.mon(this.repeater, "click", this.onTriggerClick, this, {
            preventDefault: true
        });
 
        this.field.mon(this.trigger, {
            mouseover: this.onMouseOver,
            mouseout: this.onMouseOut,
            mousemove: this.onMouseMove,
            mousedown: this.onMouseDown,
            mouseup: this.onMouseUp,
            scope: this,
            preventDefault: true
        });
 
        this.field.mon(this.wrap, "mousewheel", this.handleMouseWheel, this);
 
        this.dd.setXConstraint(0, 0, 10)
        this.dd.setYConstraint(1500, 1500, 10);
        this.dd.endDrag = this.endDrag.createDelegate(this);
        this.dd.startDrag = this.startDrag.createDelegate(this);
        this.dd.onDrag = this.onDrag.createDelegate(this);
    },
 
    onMouseOver: function(){
        if (this.disabled) {
            return;
        }
        var middle = this.getMiddle();
        this.tmpHoverClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-overup' : 'x-form-spinner-overdown';
        this.trigger.addClass(this.tmpHoverClass);
    },
 
    //private
    onMouseOut: function(){
        this.trigger.removeClass(this.tmpHoverClass);
    },
 
    //private
    onMouseMove: function(){
        if (this.disabled) {
            return;
        }
        var middle = this.getMiddle();
        if (((Ext.EventObject.getPageY() > middle) && this.tmpHoverClass == "x-form-spinner-overup") ||
        ((Ext.EventObject.getPageY() < middle) && this.tmpHoverClass == "x-form-spinner-overdown")) {
        }
    },
 
    //private
    onMouseDown: function(){
        if (this.disabled) {
            return;
        }
        var middle = this.getMiddle();
        this.tmpClickClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-clickup' : 'x-form-spinner-clickdown';
        this.trigger.addClass(this.tmpClickClass);
    },
 
    //private
    onMouseUp: function(){
        this.trigger.removeClass(this.tmpClickClass);
    },
 
    //private
    onTriggerClick: function(){
        if (this.disabled || this.el.dom.readOnly) {
            return;
        }
        var middle = this.getMiddle();
        var ud = (Ext.EventObject.getPageY() < middle) ? 'Up' : 'Down';
        this['onSpin' + ud]();
    },
 
    //private
    getMiddle: function(){
        var t = this.trigger.getTop();
        var h = this.trigger.getHeight();
        var middle = t + (h / 2);
        return middle;
    },
 
    //private
    //checks if control is allowed to spin
    isSpinnable: function(){
        if (this.disabled || this.el.dom.readOnly) {
            Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
            return false;
        }
        return true;
    },
 
    handleMouseWheel: function(e){
        //disable scrolling when not focused
        if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
            return;
        }
 
        var delta = e.getWheelDelta();
        if (delta > 0) {
            this.onSpinUp();
            e.stopEvent();
        }
        else
            if (delta < 0) {
                this.onSpinDown();
                e.stopEvent();
            }
    },
 
    //private
    startDrag: function(){
        this.proxy.show();
        this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
    },
 
    //private
    endDrag: function(){
        this.proxy.hide();
    },
 
    //private
    onDrag: function(){
        if (this.disabled) {
            return;
        }
        var y = Ext.fly(this.dd.getDragEl()).getTop();
        var ud = '';
 
        if (this._previousY > y) {
            ud = 'Up';
        } //up
        if (this._previousY < y) {
            ud = 'Down';
        } //down
        if (ud != '') {
            this['onSpin' + ud]();
        }
 
        this._previousY = y;
    },
 
    //private
    onSpinUp: function(){
        if (this.isSpinnable() == false) {
            return;
        }
        if (Ext.EventObject.shiftKey == true) {
            this.onSpinUpAlternate();
            return;
        }
        else {
            this.spin(false, false);
        }
        this.field.fireEvent("spin", this);
        this.field.fireEvent("spinup", this);
    },
 
    //private
    onSpinDown: function(){
        if (this.isSpinnable() == false) {
            return;
        }
        if (Ext.EventObject.shiftKey == true) {
            this.onSpinDownAlternate();
            return;
        }
        else {
            this.spin(true, false);
        }
        this.field.fireEvent("spin", this);
        this.field.fireEvent("spindown", this);
    },
 
    //private
    onSpinUpAlternate: function(){
        if (this.isSpinnable() == false) {
            return;
        }
        this.spin(false, true);
        this.field.fireEvent("spin", this);
        this.field.fireEvent("spinup", this);
    },
 
    //private
    onSpinDownAlternate: function(){
        if (this.isSpinnable() == false) {
            return;
        }
        this.spin(true, true);
        this.field.fireEvent("spin", this);
        this.field.fireEvent("spindown", this);
    },
 
    spin: function(down, alternate){
        var v = parseFloat(this.field.getValue());
        var incr = (alternate == true) ? this.alternateIncrementValue : this.incrementValue;
        (down == true) ? v -= incr : v += incr;
 
        v = (isNaN(v)) ? this.defaultValue : v;
        v = this.fixBoundries(v);
        this.field.setRawValue(v);
    },
 
    fixBoundries: function(value){
        var v = value;
 
        if (this.field.minValue != undefined && v < this.field.minValue) {
            v = this.field.minValue;
        }
        if (this.field.maxValue != undefined && v > this.field.maxValue) {
            v = this.field.maxValue;
        }
 
        return this.fixPrecision(v);
    },
 
    // private
    fixPrecision: function(value){
        var nan = isNaN(value);
        if (!this.field.allowDecimals || this.field.decimalPrecision == -1 || nan || !value) {
            return nan ? '' : value;
        }
        return parseFloat(parseFloat(value).toFixed(this.field.decimalPrecision));
    },
 
    doDestroy: function(){
        if (this.trigger) {
            this.trigger.remove();
        }
        if (this.wrap) {
            this.wrap.remove();
            delete this.field.wrap;
        }
 
        if (this.splitter) {
            this.splitter.remove();
        }
 
        if (this.dd) {
            this.dd.unreg();
            this.dd = null;
        }
 
        if (this.proxy) {
            this.proxy.remove();
        }
 
        if (this.repeater) {
            this.repeater.purgeListeners();
        }
    }
});
 
//backwards compat
Ext.form.Spinner = Ext.ux.Spinner;

SpinnerField.js

/*!
 * Ext JS Library 3.1.1
 * Copyright(c) 2006-2010 Ext JS, LLC
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
Ext.ns('Ext.ux.form');
 
/**
 * @class Ext.ux.form.SpinnerField
 * @extends Ext.form.NumberField
 * Creates a field utilizing Ext.ux.Spinner
 * @xtype spinnerfield
 */
Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
    actionMode: 'wrap',
    deferHeight: true,
    autoSize: Ext.emptyFn,
    onBlur: Ext.emptyFn,
    adjustSize: Ext.BoxComponent.prototype.adjustSize,
 
    constructor: function(config) {
        var spinnerConfig = Ext.copyTo({}, config, 'incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass');
 
        var spl = this.spinner = new Ext.ux.Spinner(spinnerConfig);
 
        var plugins = config.plugins
            ? (Ext.isArray(config.plugins)
                ? config.plugins.push(spl)
                : [config.plugins, spl])
            : spl;
 
        Ext.ux.form.SpinnerField.superclass.constructor.call(this, Ext.apply(config, {plugins: plugins}));
    },
 
    // private
    getResizeEl: function(){
        return this.wrap;
    },
 
    // private
    getPositionEl: function(){
        return this.wrap;
    },
 
    // private
    alignErrorIcon: function(){
        if (this.wrap) {
            this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
        }
    },
 
    validateBlur: function(){
        return true;
    }
});
 
Ext.reg('spinnerfield', Ext.ux.form.SpinnerField);
 
//backwards compat
Ext.form.SpinnerField = Ext.ux.form.SpinnerField;

Ext.ux.form.DateTimeField.js

Ext.ns('Ext.ux.form');
Ext.ux.form.TimePickerField = function(config){
    Ext.ux.form.TimePickerField.superclass.constructor.call(this, config);
}
Ext.extend(Ext.ux.form.TimePickerField, Ext.form.Field, {
    defaultAutoCreate: {
        tag: 'div'
    },
    cls: 'x-form-timepickerfield',
    hoursSpinner: null,
    minutesSpinner: null,
    secondsSpinner: null,
    spinnerCfg: {
        width: 40
    },
    spinnerFixBoundries: function(value){
        if (value < this.field.minValue) {
            value = this.field.maxValue;
        }
        if (value > this.field.maxValue) {
            value = this.field.minValue;
        }
        return this.fixPrecision(value);
    },
    onRender: function(ct, position){
        Ext.ux.form.TimePickerField.superclass.onRender.call(this, ct, position);
        this.rendered = false;
        this.date = new Date();
        var values = {};
        if (this.value) {
            values = this._valueSplit(this.value);
            this.date.setHours(values.h);
            this.date.setMinutes(values.m);
            this.date.setSeconds(values.s);
            delete this.value;
        }
        else {
            values = {
                h: this.date.getHours(),
                m: this.date.getMinutes(),
                s: this.date.getSeconds()
            };
        }
        var spinnerWrap = Ext.DomHelper.append(this.el, {
            tag: 'div'
        });
        var cfg = Ext.apply({}, this.spinnerCfg, {
            renderTo: spinnerWrap,
            readOnly: this.readOnly,
            disabled: this.disabled,
            listeners: {
                spin: {
                    fn: this.onSpinnerChange,
                    scope: this
                },
                valid: {
                    fn: this.onSpinnerChange,
                    scope: this
                },
                afterrender: {
                    fn: function(spinner){
                        spinner.wrap.applyStyles('float: left');
                    },
                    single: true
                }
            }
        });
        this.hoursSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {
            minValue: 0,
            maxValue: 23,
            cls: 'first',
            value: values.h
        }));
        this.minutesSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {
            minValue: 0,
            maxValue: 59,
            value: values.m
        }));
        this.secondsSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {
            minValue: 0,
            maxValue: 59,
            value: values.s
        }));
        Ext.DomHelper.append(spinnerWrap, {
            tag: 'div',
            cls: 'x-form-clear-left'
        });
        this.rendered = true;
    },
    _valueSplit: function(v){
        var split = v.split(':');
        return {
            h: split.length > 0 ? split[0] : 0,
            m: split.length > 1 ? split[1] : 0,
            s: split.length > 2 ? split[2] : 0
        };
    },
    onSpinnerChange: function(){
        if (!this.rendered) {
            return;
        }
        this.fireEvent('change', this, this.getRawValue());
    },
    disable: function(){
        Ext.ux.form.TimePickerField.superclass.disable.call(this);
        this.hoursSpinner.disable();
        this.minutesSpinner.disable();
        this.secondsSpinner.disable();
    },
    enable: function(){
        Ext.ux.form.TimePickerField.superclass.enable.call(this);
        this.hoursSpinner.enable();
        this.minutesSpinner.enable();
        this.secondsSpinner.enable();
    },
    setReadOnly: function(r){
        Ext.ux.form.TimePickerField.superclass.setReadOnly.call(this, r);
        this.hoursSpinner.setReadOnly(r);
        this.minutesSpinner.setReadOnly(r);
        this.secondsSpinner.setReadOnly(r);
    },
    clearInvalid: function(){
        Ext.ux.form.TimePickerField.superclass.clearInvalid.call(this);
        this.hoursSpinner.clearInvalid();
        this.minutesSpinner.clearInvalid();
        this.secondsSpinner.clearInvalid();
    },
    getRawValue: function(){
        if (!this.hoursSpinner) {
            this.date = new Date();
            return {
                h: this.date.getHours(),
                m: this.date.getMinutes(),
                s: this.date.getSeconds()
            };
        }
        else {
            return {
                h: this.hoursSpinner.getValue(),
                m: this.minutesSpinner.getValue(),
                s: this.secondsSpinner.getValue()
            };
        }
    },
    setRawValue: function(v){
        this.hoursSpinner.setValue(v.h);
        this.minutesSpinner.setValue(v.m);
        this.secondsSpinner.setValue(v.s);
    },
    isValid: function(preventMark){
        return this.hoursSpinner.isValid(preventMark) &&
        this.minutesSpinner.isValid(preventMark) &&
        this.secondsSpinner.isValid(preventMark);
    },
    validate: function(){
        return this.hoursSpinner.validate() &&
        this.minutesSpinner.validate() &&
        this.secondsSpinner.validate();
    },
    getValue: function(){
        var v = this.getRawValue();
        return String.leftPad(v.h, 2, '0') + ':' +
        String.leftPad(v.m, 2, '0') +
        ':' +
        String.leftPad(v.s, 2, '0');
    },
    setValue: function(value){
        if (!this.rendered) {
            this.value = value;
            return;
        }
        value = this._valueSplit(value);
        this.setRawValue(value);
        this.validate();
    }
});
 
Ext.form.TimePickerField = Ext.ux.form.TimePickerField;
Ext.reg('timepickerfield', Ext.form.TimePickerField);
Ext.ns('Ext.ux.form');
Ext.DateTimePicker = Ext.extend(Ext.DatePicker, {
    timeFormat: 'g:i:s A',
    timeLabel: '时间',
    timeWidth: 100,
    initComponent: function(){
        Ext.DateTimePicker.superclass.initComponent.call(this);
        this.id = Ext.id();
    },
    onRender: function(container, position){
        Ext.DateTimePicker.superclass.onRender.apply(this, arguments);
        var table = Ext.get(Ext.DomQuery.selectNode('table tbody', container.dom));
        var tfEl = Ext.DomHelper.insertBefore(table.last(), {
            tag: 'tr',
            children: [{
                tag: 'td',
                cls: 'x-date-bottom',
                html: this.timeLabel,
                style: 'width:30;'
            }, {
                tag: 'td',
                cls: 'x-date-bottom ux-timefield',
                style: "height: 20px;",
                colspan: '2'
            }]
        }, true);
        this.tf.render(table.child('td.ux-timefield'));
        var p = this.getEl().parent('div.x-layer');
        if (p) {
            p.setStyle("height", p.getHeight() + 31);
        }
    },
    setValue: function(value){
        var old = this.value;
        if (!this.tf) {
            this.tf = new Ext.ux.form.TimePickerField();
            this.tf.ownerCt = this;
        }
        this.value = this.getDateTime(value);
    },
    getDateTime: function(value){
        if (this.tf) {
            var dt = new Date();
            var timeval = this.tf.getValue();
            value = Date.parseDate(value.format(this.dateFormat) + ' ' + this.tf.getValue(), this.format);
        }
        return value;
    },
    selectToday: function(){
        if (this.todayBtn && !this.todayBtn.disabled) {
            this.value = this.getDateTime(new Date());
            this.fireEvent("select", this, this.value);
        }
    }
});
Ext.reg('datetimepickerfield', Ext.DateTimePicker);
if (parseInt(Ext.version.substr(0, 1), 10) > 2) {
    Ext.menu.DateTimeItem = Ext.DateTimePicker;
    Ext.override(Ext.menu.DateMenu, {
        initComponent: function(){
            this.on('beforeshow', this.onBeforeShow, this);
            if (this.strict = (Ext.isIE7 && Ext.isStrict)) {
                this.on('show', this.onShow, this, {
                    single: true,
                    delay: 20
                });
            }
            Ext.apply(this, {
                plain: true,
                showSeparator: false,
                items: this.picker = new Ext.DatePicker(Ext.apply({
                    internalRender: this.strict || !Ext.isIE,
                    ctCls: 'x-menu-date-item'
                }, this.initialConfig))
            });
            Ext.menu.DateMenu.superclass.initComponent.call(this);
            this.relayEvents(this.picker, ["select"]);
            this.on('select', this.menuHide, this);
            if (this.handler) {
                this.on('select', this.handler, this.scope || this);
            }
        }
    });
}
else {
    Ext.menu.DateTimeItem = function(config){
        Ext.menu.DateTimeItem.superclass.constructor.call(this, new Ext.DateTimePicker(config), config);
        this.picker = this.component;
        alert(this.picker);
        this.addEvents('select');
        
        this.picker.on("render", function(picker){
            picker.getEl().swallowEvent("click");
            picker.container.addClass("x-menu-date-item");
        });
        
        this.picker.on("select", this.onSelect, this);
    };
    
    Ext.extend(Ext.menu.DateTimeItem, Ext.menu.DateMenu, {
        onSelect: function(picker, date){
            this.fireEvent("select", this, date, picker);
            Ext.menu.DateTimeItem.superclass.handleClick.call(this);
        }
    });
}
 
Ext.menu.DateTimeMenu = function(config){
    Ext.menu.DateTimeMenu.superclass.constructor.call(this, config);
    this.plain = true;
    var di = new Ext.menu.DateTimeItem(config);
    this.add(di);
    this.picker = di;
    this.relayEvents(di, ["select"]);
    
    this.on('beforeshow', function(){
        if (this.picker) {
            this.picker.hideMonthPicker(true);
        }
    }, this);
};
Ext.extend(Ext.menu.DateTimeMenu, Ext.menu.Menu, {
    cls: 'x-date-menu',
    beforeDestroy: function(){
        this.picker.destroy();
    },
    hide: function(deep){
        if (this.picker.tf.innerList) {
            if ((Ext.EventObject.within(this.picker.tf.innerList)) || (Ext.get(Ext.EventObject.getTarget()) == this.picker.tf.innerList)) 
                return false;
        }
        if (this.el && this.isVisible()) {
            this.fireEvent("beforehide", this);
            if (this.activeItem) {
                this.activeItem.deactivate();
                this.activeItem = null;
            }
            this.el.hide();
            this.hidden = true;
            this.fireEvent("hide", this);
        }
        if (deep === true && this.parentMenu) {
            this.parentMenu.hide(true);
        }
    }
});
 
Ext.ux.form.DateTimeField = Ext.extend(Ext.form.DateField, {
    dateFormat: 'Y-m-d',
    timeFormat: 'H:i:s',
    defaultAutoCreate: {
        tag: "input",
        type: "text",
        size: "20",
        autocomplete: "off"
    },
    initComponent: function(){
        Ext.ux.form.DateTimeField.superclass.initComponent.call(this);
        this.format = this.dateFormat + ' ' + this.timeFormat;
        this.afterMethod('afterRender', function(){
            this.getEl().applyStyles('top:0');
        });
    },
    getValue: function(){
        return this.parseDate(Ext.form.DateField.superclass.getValue.call(this)) || '';
    },
    onTriggerClick: function(){
        if (this.disabled) {
            return;
        }
        if (this.menu == null) {
            this.menu = new Ext.menu.DateTimeMenu();
        }
        Ext.apply(this.menu.picker, {
            minDate: this.minValue,
            maxDate: this.maxValue,
            disabledDatesRE: this.ddMatch,
            disabledDatesText: this.disabledDatesText,
            disabledDays: this.disabledDays,
            disabledDaysText: this.disabledDaysText,
            format: this.format,
            timeFormat: this.timeFormat,
            dateFormat: this.dateFormat,
            showToday: this.showToday,
            minText: String.format(this.minText, this.formatDate(this.minValue)),
            maxText: String.format(this.maxText, this.formatDate(this.maxValue))
        });
        if (this.menuEvents) {
            this.menuEvents('on');
        }
        else {
            this.menu.on(Ext.apply({}, this.menuListeners, {
                scope: this
            }));
        }
        this.menu.picker.setValue(this.getValue() || new Date());
        this.menu.show(this.el, "tl-bl?");
    }
});
Ext.reg('datetimefield', Ext.ux.form.DateTimeField);

Ext.hoo.form.DateTimeField.js

/**
 * @function 可以选择日期的DateTimeField
 * @auhor: hoojo
 * @createDate: Sep 16, 2010 9:25:12 PM
 * @blog: blog.csdn.net/IBM_hoojo
 * @email: hoojo_@126.com
 * @class Ext.hoo.form.DateTimeField
 * @extends Ext.ux.form.DateTimeField
 */
Ext.ns("Ext.hoo.form");
Ext.hoo.form.DateTimeField = Ext.extend(Ext.ux.form.DateTimeField, {
    constructor: function () {
        Ext.hoo.form.DateTimeField.superclass.constructor.call(this, {
            renderTo: "show",
            height: 222,
            dateFormat: 'Y-m-d',
            timeFormat: 'H:i:s',
            listeners: {
                select: function () {
                    alert(this.getValue() + "##" + this.getRawValue());
                }
            }
        });
    }
});
 
Ext.onReady(function () {
    Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
    Ext.QuickTips.init();
    Ext.form.Field.prototype.msgTarget = "qtip";
    
    new Ext.hoo.form.DateTimeField();
});

三、带图标的下列列表

效果图如下

ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]

需要的文件

combo_icon.gif

ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]

iconCombobox 插件文件: Ext.ux.IconCombo.js

示例文件: Ext.hoo.form.WebBroserIconComboBox.js

代码如下

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>form Component -- iconCombo</title>
        <meta http-equiv="pragma" content="no-cache"/>
        <meta http-equiv="cache-control" content="no-cache"/>
        <meta http-equiv="expires" content="0"/>
        <meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
        <meta http-equiv="author" content="hoojo"/>
        <meta http-equiv="email" content="hoojo_@126.com"/>
        <meta http-equiv="ext-lib" content="version 2.2"/>
        <meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>        
        <link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
        <link rel="stylesheet" type="text/css" href="../css/iconCombo.css"/>
        <style type="text/css">
            .ffCls {
                background: url(../images/combo_icon.gif) no-repeat 1px -15px;
            }
            
            .ieCls {
                background: url(../images/combo_icon.gif) no-repeat 1px 2px;
            }
            
            .operaCls {
                background: url(../images/combo_icon.gif) no-repeat 1px -68px;
            }
            
            .chromeCls {
                background: url(../images/combo_icon.gif) no-repeat 1px -85px;
            }
            
            .maxCls {
                background: url(../images/combo_icon.gif) no-repeat 1px -32px;
            }
            
            .ttCls {
                background: url(../images/combo_icon.gif) no-repeat 1px -50px;
            }
            
            .sfCls {
                background: url(../images/combo_icon.gif) no-repeat 1px -103px;
            }
            
            .twCls {
                background: url(../images/combo_icon.gif) no-repeat 1px -121px;
            }
            
            .flockCls {
                background: url(../images/combo_icon.gif) no-repeat 1px -139px;
            }
        </style>
        <script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
        <script type="text/javascript" src="../ext2/ext-all.js"></script>
        <script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
        <script type="text/javascript" src="Ext.ux.IconCombo.js"></script>
        <script type="text/javascript" src="Ext.hoo.form.WebBroserIconComboBox.js"></script>
  </head>
  
  <body>
      <div id="show" style="padding: 100px 0 0 300px;"></div>
  </body>
</html>

Ext.ux.IconCombo.js 文件代码

/**
 * @class Ext.ux.IconCombo
 * @extends Ext.form.ComboBox
 * @param {Object} config Configuration options
 */
Ext.ux.IconCombo = function(config) {
    // call parent constructor
    Ext.ux.IconCombo.superclass.constructor.call(this, config);
    this.tpl = config.tpl || '<tpl for="."><div class="x-combo-list-item">'
            + '<table><tbody><tr>' + '<td>' + '<div class="{'
            + this.iconClsField + '}"></div></td>' + '<td>{'
            + this.displayField + '}</td>' + '</tr></tbody></table>'
            + '</div></tpl>';
};
 
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
    defaultIconCls: "ux-icon-combo-icon",
    emptyText: "plase selected",
    setIconCls : function() {
        var record = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if (record) {
            this.flag.className = record.get(this.iconClsField) || defaultIconCls || "ux-icon-combo-icon";
            //this.flag.style.backgroundImage = rec.get(this.iconClsField);
        }
    },
    setValue : function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    },
    onRender: function(ct, position) {
            Ext.ux.IconCombo.superclass.onRender.call(this, ct, position);
            
            var wrap = this.el.up("div.x-form-field-wrap");
            this.wrap.applyStyles({
                position : "relative"
            });
            this.el.addClass("ux-icon-combo-input");
            //textfield中显示的图片div
            this.flag = Ext.DomHelper.append(wrap, {
                tag : "div",
                style : "position:absolute; left: 5px; top: 1px;"
            });
            //默认图片样式
            this.flag.className = this.defaultIconCls;
        }
});

Ext.hoo.form.WebBroserIconComboBox.js

/**
 * @function 带图片的combobox
 * @auhor: hoojo
 * @createDate: Sep 10, 2010 11:16:12 PM
 * @blog: blog.csdn.net/IBM_hoojo
 * @email: hoojo_@126.com
 * @class Ext.hoo.form.WebBroserIconComboBox
 * @extends Ext.ux.IconCombo
 */
Ext.ns("Ext.hoo.form");
Ext.hoo.form.WebBroserIconComboBox = Ext.extend(Ext.ux.IconCombo, {
    constructor: function () {
        Ext.hoo.form.WebBroserIconComboBox.superclass.constructor.call(this, {
            /*fieldLabel: "web broser type",
            labelWidth: 73,*/
            renderTo: /*Ext.getBody(),*/"show",
            width: 200,
            store: new Ext.data.SimpleStore({
                fields: ["shortName", "name", "iconCls"],
                data: [
                    ["ff", "Mozilla Firefox" , "ffCls"],
                    ["IE", "Internet Explorer" , "IECls"],
                    ["opera", "Opera" , "operaCls"],
                    ["chrome", "Google Chrome" , "chromeCls"],
                    ["max", "Maxthon" , "maxCls"],
                    ["tt", "TecentTraveler" , "ttCls"],
                    ["sf", "Safari" , "sfCls"],
                    ["tw", "TheWorld" , "twCls"],
                    ["flock", "Flock" , "flockCls"]
                ]
            }),
            valueField: "shortName",
            displayField: "name",
            iconClsField: "iconCls",
            triggerAction: "all",
            editable: false,
            mode: "local"
        });
        this.on("select", function (field, e) {
            alert(field.getValue() + "###" + field.getRawValue());
        }, this);
    }
});
 
Ext.onReady(function () {
    Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
    Ext.QuickTips.init();
    Ext.form.Field.prototype.msgTarget = "qtip";
    
    new Ext.hoo.form.WebBroserIconComboBox();
});

四、多选下列列表组件

可以同时选择多个选项

ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]

核心文件

多选下拉列表组件:Ext.form.MultiComboBox.js

示例文件:Ext.hoo.form.InterestMultiComboBox.js

代码如下

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>form Component -- MultiComboBox</title>
        <meta http-equiv="pragma" content="no-cache"/>
        <meta http-equiv="cache-control" content="no-cache"/>
        <meta http-equiv="expires" content="0"/>
        <meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
        <meta http-equiv="author" content="hoojo"/>
        <meta http-equiv="email" content="hoojo_@126.com"/>
        <meta http-equiv="ext-lib" content="version 2.2"/>
        <meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>        
        <link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
        <style type="text/css">
            .checked{
                background-image: url("../ext2/resources/images/default/menu/checked.gif");
            }
            .unchecked{
                background-image: url("../ext2/resources/images/default/menu/unchecked.gif");
            }
            
            .x-combo-list-item {
                line-height: 18px; 
            }
        </style>
        <script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
        <script type="text/javascript" src="../ext2/ext-all.js"></script>
        <script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
        <script type="text/javascript" src="Ext.form.MultiComboBox.js"></script>
        <script type="text/javascript" src="Ext.hoo.form.InterestMultiComboBox.js"></script>
  </head>
  
  <body>
  <center>
      <div id="show" style="padding-top: 200px;"></div>
  </center>
  </body>
</html>

Ext.form.MultiComboBox.js

Ext.form.MultiComboBox = Ext.extend(Ext.form.TriggerField, {
    defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
    listClass: '',
    selectedClass: 'x-combo-selected',
    triggerClass : 'x-form-arrow-trigger',
    shadow:'sides',
    listAlign: 'tl-bl?',
    maxHeight: 300,
    triggerAction: 'query',
    minChars : 4,
    typeAhead: false,
    queryDelay: 500,
    pageSize: 0,
    selectOnFocus: false,
    queryParam: 'query',
    loadingText: 'Loading...',
    resizable: false,
    handleHeight : 8,
    editable: true,
    allQuery: '',
    mode: 'remote',
    minListWidth : 70,
    forceSelection:false,
    typeAheadDelay : 250,
    displaySeparator:';',
    valueSeparator:',',
    lazyInit : true,
 
    initComponent : function(){
        Ext.form.ComboBox.superclass.initComponent.call(this);
        this.addEvents(
            'expand',
            'collapse',
            'beforeselect',
            'select',
            'beforequery'
        );
        if(this.transform){
            this.allowDomMove = false;
            var s = Ext.getDom(this.transform);
            if(!this.hiddenName){
                this.hiddenName = s.name;
            }
            if(!this.store){
                this.mode = 'local';
                var d = [], opts = s.options;
                for(var i = 0, len = opts.length;i < len; i++){
                    var o = opts[i];
                    var value = (Ext.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
                    if(o.selected) {
                        this.value = value;
                    }
                    d.push([value, o.text]);
                }
                this.store = new Ext.data.SimpleStore({
                    'id': 0,
                    fields: ['value', 'text'],
                    data : d
                });
                this.valueField = 'value';
                this.displayField = 'text';
            }
            s.name = Ext.id(); // wipe out the name in case somewhere else they have a reference
            if(!this.lazyRender){
                this.target = true;
                this.el = Ext.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
                Ext.removeNode(s); // remove it
                this.render(this.el.parentNode);
            }else{
                Ext.removeNode(s); // remove it
            }
 
        }
        this.selectedIndex = -1;
        if(this.mode == 'local'){
            if(this.initialConfig.queryDelay === undefined){
                this.queryDelay = 10;
            }
            if(this.initialConfig.minChars === undefined){
                this.minChars = 0;
            }
        }
    },
 
    // private
    onRender : function(ct, position){
        Ext.form.ComboBox.superclass.onRender.call(this, ct, position);
        var disValue="";
        if(this.hiddenName){
            this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
                    'before', true);
          var hvalue=this.hiddenValue !== undefined ? this.hiddenValue :
                this.value !== undefined ? this.value : '';
          var hvalueArray=hvalue.split(this.valueSeparator);
          
          for(var i=0;i<this.store.data.length;i++){
                 var r = this.store.getAt(i);   
                 var newValue = r.data[this.displayField];
                  var v=r.data[this.valueField];
                  for(var j=0;j<hvalueArray.length;j++){
                      if(hvalueArray[j]==v){
                          disValue+=newValue+this.displaySeparator;
                      }
                  }
                 
          }     
            this.hiddenField.value =this.hiddenValue !== undefined ? this.hiddenValue :
                this.value !== undefined ? this.value : '';
            this.el.dom.removeAttribute('name');
        }
        if(Ext.isGecko){
            this.el.dom.setAttribute('autocomplete', 'off');
        }
 
        if(!this.lazyInit){
            this.initList();
        }else{
            this.on('focus', this.initList, this, {single: true});
        }
 
        if(!this.editable){
            this.editable = true;
            this.setEditable(false);
        }
        this.setValue(disValue);
    },
 
    initList : function(){
        if(!this.list){
            var cls = 'x-combo-list';
 
            this.list = new Ext.Layer({
                shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
            });
 
            var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
            this.list.setWidth(lw);
            this.list.swallowEvent('mousewheel');
            this.assetHeight = 0;
 
            if(this.title){
                this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
                this.assetHeight += this.header.getHeight();
            }
 
            this.innerList = this.list.createChild({cls:cls+'-inner'});
            this.innerList.on('mouseover', this.onViewOver, this);
            this.innerList.on('mousemove', this.onViewMove, this);
            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'))
 
            if(this.pageSize){
                this.footer = this.list.createChild({cls:cls+'-ft'});
                this.pageTb = new Ext.PagingToolbar({
                    store:this.store,
                    pageSize: this.pageSize,
                    renderTo:this.footer
                });
                this.assetHeight += this.footer.getHeight();
            }
 
            if(!this.tpl){
                //alert(cls);
                //x-combo-list-item
                this.tpl = '<tpl for="."><div class="'+cls+'-item"><span class="unchecked" style="padding-bottom: 1px;" id="checkBox_{' + this.displayField + '}">&nbsp;&nbsp;&nbsp;&nbsp;</span>{' + this.displayField + '}</div></tpl>';
            }
            this.view = new Ext.DataView({
                applyTo: this.innerList,
                tpl: this.tpl,
                singleSelect: true,
                selectedClass: this.selectedClass,
                itemSelector: this.itemSelector || '.' + cls + '-item'
            });
 
            this.view.on('click', this.onViewClick, this);
 
            this.bindStore(this.store, true);
 
            if(this.resizable){
                this.resizer = new Ext.Resizable(this.list,  {
                   pinned:true, handles:'se'
                });
                this.resizer.on('resize', function(r, w, h){
                    this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
                    this.listWidth = w;
                    this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
                    this.restrictHeight();
                }, this);
                this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
            }
        }
    },
 
    bindStore : function(store, initial){
        if(this.store && !initial){
            this.store.un('beforeload', this.onBeforeLoad, this);
            this.store.un('load', this.onLoad, this);
            this.store.un('loadexception', this.collapse, this);
            if(!store){
                this.store = null;
                if(this.view){
                    this.view.setStore(null);
                }
            }
        }
        if(store){
            this.store = Ext.StoreMgr.lookup(store);
 
            this.store.on('beforeload', this.onBeforeLoad, this);
            this.store.on('load', this.onLoad, this);
            this.store.on('loadexception', this.collapse, this);
 
            if(this.view){
                this.view.setStore(store);
            }
        }
    },
 
    // private
    initEvents : function(){
        Ext.form.ComboBox.superclass.initEvents.call(this);
 
        this.keyNav = new Ext.KeyNav(this.el, {
            "up" : function(e){
                this.inKeyMode = true;
                this.selectPrev();
            },
 
            "down" : function(e){
                if(!this.isExpanded()){
                    this.onTriggerClick();
                }else{
                    this.inKeyMode = true;
                    this.selectNext();
                }
            },
 
            "enter" : function(e){
                this.onViewClick();
                //return true;
            },
 
            "esc" : function(e){
                this.collapse();
            },
 
            "tab" : function(e){
                this.onViewClick(false);
                return true;
            },
 
            scope : this,
 
            doRelay : function(foo, bar, hname){
                if(hname == 'down' || this.scope.isExpanded()){
                   return Ext.KeyNav.prototype.doRelay.apply(this, arguments);
                }
                return true;
            },
 
            forceKeyDown : true
        });
        this.queryDelay = Math.max(this.queryDelay || 10,
                this.mode == 'local' ? 10 : 250);
        this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);
        if(this.typeAhead){
            this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);
        }
        if(this.editable !== false){
            this.el.on("keyup", this.onKeyUp, this);
        }
        if(this.forceSelection){
            this.on('blur', this.doForce, this);
        }
    },
 
    onDestroy : function(){
        if(this.view){
            this.view.el.removeAllListeners();
            this.view.el.remove();
            this.view.purgeListeners();
        }
        if(this.list){
            this.list.destroy();
        }
        this.bindStore(null);
        Ext.form.ComboBox.superclass.onDestroy.call(this);
    },
 
    // private
    fireKey : function(e){
        if(e.isNavKeyPress() && !this.list.isVisible()){
            this.fireEvent("specialkey", this, e);
        }
    },
 
    // private
    onResize: function(w, h){
        Ext.form.ComboBox.superclass.onResize.apply(this, arguments);
        if(this.list && this.listWidth === undefined){
            var lw = Math.max(w, this.minListWidth);
            this.list.setWidth(lw);
            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
        }
    },
 
    // private
    onDisable: function(){
        Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);
        if(this.hiddenField){
            this.hiddenField.disabled = this.disabled;
        }
    },
    setEditable : function(value){
        if(value == this.editable){
            return;
        }
        this.editable = value;
        if(!value){
            this.el.dom.setAttribute('readOnly', true);
            this.el.on('mousedown', this.onTriggerClick,  this);
            this.el.addClass('x-combo-noedit');
        }else{
            this.el.dom.setAttribute('readOnly', false);
            this.el.un('mousedown', this.onTriggerClick,  this);
            this.el.removeClass('x-combo-noedit');
        }
    },
 
    // private
    onBeforeLoad : function(){
        if(!this.hasFocus){
            return;
        }
        this.innerList.update(this.loadingText ?
               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
        this.restrictHeight();
        this.selectedIndex = -1;
    },
 
    // private
    onLoad : function(){
        if(!this.hasFocus){
            return;
        }
        if(this.store.getCount() > 0){
            this.expand();
            this.restrictHeight();
            if(this.lastQuery == this.allQuery){
                if(this.editable){
                    this.el.dom.select();
                }
                if(!this.selectByValue(this.value, true)){
                    this.select(0, true);
                }
            }else{
                this.selectNext();
                if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){
                    this.taTask.delay(this.typeAheadDelay);
                }
            }
        }else{
            this.onEmptyResults();
        }
    },
 
    // private
    onTypeAhead : function(){
        if(this.store.getCount() > 0){
            var r = this.store.getAt(0);
            var newValue = r.data[this.displayField];
            var len = newValue.length;
            var selStart = this.getRawValue().length;
            if(selStart != len){
                this.setRawValue(newValue);
                this.selectText(selStart, newValue.length);
            }
        }
    },
    // private
    onSelect : function(record, index){
        if(this.fireEvent('beforeselect', this, record, index) !== false){
            var r = this.store.getAt(index);
            var newValue = r.data[this.displayField];
            var check=document.getElementById("checkBox_"+newValue);
            if(check.className=="checked"){
                check.className="unchecked"
            }else{
                check.className="checked"
            }
            var value=""; 
            var hiddenValue="";
            for(var i=0;i<this.store.data.length;i++){
                 var r = this.store.getAt(i);   
                 newValue = r.data[this.displayField];
                 check=document.getElementById("checkBox_"+newValue);
                 if(check.className=="checked"){
                     value+= r.data[this.displayField]+this.displaySeparator;
                     hiddenValue+= r.data[this.valueField]+this.valueSeparator;
                 }
            }
            if(value.length>1){
                value=value.substring(0,value.length-this.displaySeparator.length);
            }
            if(hiddenValue.length>1){
                hiddenValue=hiddenValue.substring(0,value.length-this.valueSeparator.length);
            }
            this.setValue(value);
            this.hiddenField.value=hiddenValue;
            this.fireEvent('select', this, record, index);
        }
    },
    getValue : function(){
        if(this.valueField){
            return typeof this.value != 'undefined' ? this.value : '';
        }else{
            return Ext.form.ComboBox.superclass.getValue.call(this);
        }
    },
 
    /**
     * Clears any text/value currently set in the field
     */
    clearValue : function(){
        if(this.hiddenField){
            this.hiddenField.value = '';
        }
        this.setRawValue('');
        this.lastSelectionText = '';
        this.applyEmptyText();
    },
    setValue : function(v){
        var text = v;
        if(this.valueField){
            var r = this.findRecord(this.valueField, v);
            if(r){
                text = r.data[this.displayField];
            }else if(this.valueNotFoundText !== undefined){
                text = this.valueNotFoundText;
            }
        }
        this.lastSelectionText = text;
        Ext.form.ComboBox.superclass.setValue.call(this, text);
        this.value = v;
    },
 
    // private
    findRecord : function(prop, value){
        var record;
        if(this.store.getCount() > 0){
            this.store.each(function(r){
                if(r.data[prop] == value){
                    record = r;
                    return false;
                }
            });
        }
        return record;
    },
 
    // private
    onViewMove : function(e, t){
        this.inKeyMode = false;
    },
 
    // private
    onViewOver : function(e, t){
        if(this.inKeyMode){ // prevent key nav and mouse over conflicts
            return;
        }
        var item = this.view.findItemFromChild(t);
        if(item){
            var index = this.view.indexOf(item);
            this.select(index, false);
        }
    },
 
    // private
    onViewClick : function(doFocus){
        var index = this.view.getSelectedIndexes()[0];
        var r = this.store.getAt(index);
        if(r){
            this.onSelect(r, index);
        }
        if(doFocus !== false){
            this.el.focus();
        }
    },
 
    // private
    restrictHeight : function(){
        this.innerList.dom.style.height = '';
        var inner = this.innerList.dom;
        var fw = this.list.getFrameWidth('tb');
        var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
        this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
        this.list.beginUpdate();
        this.list.setHeight(this.innerList.getHeight()+fw+(this.resizable?this.handleHeight:0)+this.assetHeight);
        this.list.alignTo(this.el, this.listAlign);
        this.list.endUpdate();
    },
 
    // private
    onEmptyResults : function(){
        this.collapse();
    },
 
    /**
     * Returns true if the dropdown list is expanded, else false.
     */
    isExpanded : function(){
        return this.list && this.list.isVisible();
    },
    selectByValue : function(v, scrollIntoView){
        if(v !== undefined && v !== null){
            var r = this.findRecord(this.valueField || this.displayField, v);
            if(r){
                this.select(this.store.indexOf(r), scrollIntoView);
                return true;
            }
        }
        return false;
    },
    select : function(index, scrollIntoView){
        
        this.selectedIndex = index;
        this.view.select(index);
        if(scrollIntoView !== false){
            var el = this.view.getNode(index);
            if(el){
                this.innerList.scrollChildIntoView(el, false);
            }
        }
    },
 
    // private
    selectNext : function(){
        var ct = this.store.getCount();
        if(ct > 0){
            if(this.selectedIndex == -1){
                this.select(0);
            }else if(this.selectedIndex < ct-1){
                this.select(this.selectedIndex+1);
            }
        }
    },
 
    // private
    selectPrev : function(){
        var ct = this.store.getCount();
        if(ct > 0){
            if(this.selectedIndex == -1){
                this.select(0);
            }else if(this.selectedIndex != 0){
                this.select(this.selectedIndex-1);
            }
        }
    },
 
    // private
    onKeyUp : function(e){
        if(this.editable !== false && !e.isSpecialKey()){
            this.lastKey = e.getKey();
            this.dqTask.delay(this.queryDelay);
        }
    },
 
    // private
    validateBlur : function(){
        return !this.list || !this.list.isVisible();   
    },
 
    // private
    initQuery : function(){
        this.doQuery(this.getRawValue());
    },
 
    // private
    doForce : function(){
        if(this.el.dom.value.length > 0){
            this.el.dom.value =
                this.lastSelectionText === undefined ? '' : this.lastSelectionText;
            this.applyEmptyText();
        }
    },
    doQuery : function(q, forceAll){
        if(q === undefined || q === null){
            q = '';
        }
        var qe = {
            query: q,
            forceAll: forceAll,
            combo: this,
            cancel:false
        };
        if(this.fireEvent('beforequery', qe)===false || qe.cancel){
            return false;
        }
        q = qe.query;
        forceAll = qe.forceAll;
        if(forceAll === true || (q.length >= this.minChars)){
            if(this.lastQuery !== q){
                this.lastQuery = q;
                if(this.mode == 'local'){
                    this.selectedIndex = -1;
                    if(forceAll){
                        this.store.clearFilter();
                    }else{
                        this.store.filter(this.displayField, q);
                    }
                    this.onLoad();
                }else{
                    this.store.baseParams[this.queryParam] = q;
                    this.store.load({
                        params: this.getParams(q)
                    });
                    this.expand();
                }
            }else{
                this.selectedIndex = -1;
                this.onLoad();   
            }
        }
    },
 
    // private
    getParams : function(q){
        var p = {};
        //p[this.queryParam] = q;
        if(this.pageSize){
            p.start = 0;
            p.limit = this.pageSize;
        }
        return p;
    },
    /**
     * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
     */
    collapse : function(){
        if(!this.isExpanded()){
            return;
        }
        this.list.hide();
        Ext.getDoc().un('mousewheel', this.collapseIf, this);
        Ext.getDoc().un('mousedown', this.collapseIf, this);
        this.fireEvent('collapse', this);
    },
    // private
    collapseIf : function(e){
        if(!e.within(this.wrap) && !e.within(this.list)){
            this.collapse();
        }
    },
    
    /**
     * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
     */
    expand : function(){
        if(this.isExpanded() || !this.hasFocus){
            return;
        }
        this.list.alignTo(this.wrap, this.listAlign);
        var hvalueArray=this.hiddenField.value.split(this.valueSeparator);
        for(var i=0;i<this.store.data.length;i++){
             var r = this.store.getAt(i);   
             var newValue = r.data[this.displayField];
              var v=r.data[this.valueField];
              for(var j=0;j<hvalueArray.length;j++){
                  if(hvalueArray[j]==v){
                      document.getElementById("checkBox_"+newValue).className="checked";
                  }
              }
             
        } 
        this.list.show();
        Ext.getDoc().on('mousewheel', this.collapseIf, this);
        Ext.getDoc().on('mousedown', this.collapseIf, this);
        this.fireEvent('expand', this);
    },
 
    // private
    // Implements the default empty TriggerField.onTriggerClick function
    onTriggerClick : function(){
        if(this.disabled){
            return;
        }
        if(this.isExpanded()){
            this.collapse();
            this.el.focus();
        }else {
            this.onFocus({});
            if(this.triggerAction == 'all') {
                this.doQuery(this.allQuery, true);
            } else {
                this.doQuery(this.getRawValue());
            }
            this.el.focus();
        }
    }
});
Ext.reg('multicombo', Ext.form.MultiComboBox);

Ext.hoo.form.InterestMultiComboBox.js

/**
 * @function 支持多选的combox 
 * @auhor: hoojo
 * @createDate: Sep 10, 2010 10:32:00 PM
 * @blog: blog.csdn.net/IBM_hoojo
 * @email: hoojo_@126.com
 * @class Ext.hoo.form.InterestMultiComboBox
 * @extends Ext.form.MultiComboBox
 */
Ext.ns("Ext.hoo.form");
Ext.hoo.form.InterestMultiComboBox = Ext.extend(Ext.form.MultiComboBox, {
     constructor: function () {
         Ext.hoo.form.InterestMultiComboBox.superclass.constructor.call(this, {
             renderTo: "show",
             width: 250,
            mode: "local",
            fieldLabel: "多选下拉框",
            store: new Ext.data.SimpleStore({
                fields: ["textAttr", "valueAttr"],
                data: [
                    ["打球", "batting"],
                    ["看书", "lookbook"],
                    ["睡觉", "sleeping"],
                    ["购物", "shopping"],
                    ["打游戏", "games"],
                    ["唱歌", "sing"]
                ]
            }),
            editable: true,
            emptyText:"请选择",
            //allowBlank: false,
            valueField: "textAttr",
            displayField: "valueAttr",
            labelSeparator: ":",
            valueSeparator: "#",
            displaySeparator: ",",
            //value:"batting,sleeping",
            hiddenName: "interest",
            forceSelection: true,
            triggerAction: "all"
         });
         this.on("select", function (field, record, index) {
             alert(field.getValue() + "%%%%" + field.getRawValue() + Ext.fly("interest").dom.value);
         }, this);
     }
});
 
Ext.onReady(function () {
    Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
    Ext.QuickTips.init();
    Ext.form.Field.prototype.msgTarget = "qtip";
    
    new Ext.hoo.form.InterestMultiComboBox();
});

五、动态Combobox Tree(下拉列表树)组件

ExtJS Form扩展组件[ColorFiled, DateTimeFiled, IconCombo, MultiComboBox, DynamicTreeCombox]

可以多选、单选、checkbox

需要的文件

动态下列列表树插件:Ext.ux.form.DynamicTreeCombox.js

示例文件:Ext.hoo.form.DynaTreeCombo.js

代码如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>form Component -- MultiComboBox</title>
        <meta http-equiv="pragma" content="no-cache"/>
        <meta http-equiv="cache-control" content="no-cache"/>
        <meta http-equiv="expires" content="0"/>
        <meta http-equiv="content-Type" content="text/html; charset=utf-8"/>
        <meta http-equiv="author" content="hoojo"/>
        <meta http-equiv="email" content="hoojo_@126.com"/>
        <meta http-equiv="ext-lib" content="version 2.2"/>
        <meta http-equiv="blog" content="http://blog.csdn.net/IBM_hoojo"/>        
        <link rel="stylesheet" type="text/css" href="../ext2/resources/css/ext-all.css"/>
        <script type="text/javascript" src="../ext2/adapter/ext/ext-base.js"></script>
        <script type="text/javascript" src="../ext2/ext-all.js"></script>
        <script type="text/javascript" src="../ext2/build/locale/ext-lang-zh_CN-min.js"></script>
        <script type="text/javascript" src="Ext.ux.form.DynamicTreeCombox.js"></script>
        <script type="text/javascript" src="Ext.hoo.form.DynaTreeCombo.js"></script>
  </head>
  
  <body>
      <div id="show" style="float: left; margin: 100px 0 0 100px;"></div>
      <div id="showBasic" style="float: left; margin: 100px 0 0 100px;"></div>
      <div id="showConstom" style="float: left; margin: 100px 0 0 100px;"></div>
  </body>
</html>

Ext.ux.form.DynamicTreeCombox.js

Ext.ns("Ext.ux.form");   
Ext.ux.form.DynamicTreeCombox = Ext.extend(Ext.form.ComboBox, {   
    initComponent:function(){   
        Ext.ux.form.DynamicTreeCombox.superclass.initComponent.call(this);   
        this.addEvents('beforeClickNode','afterClickNode', 'select');   
        if(!this.tree){   
            var root = this.root || new Ext.tree.AsyncTreeNode();
            this.tree = new Ext.tree.TreePanel({   
                containerScroll: true,   
                rootVisible: false, 
                border: false,
                root: root   
            });   
            this.tree.loader = new Ext.tree.TreeLoader(this.loaderConfig||{dataUrl:"",baseAttrs:{}});   
            this.tree.loader.addListener("beforeload",this.beforeLoad,this);   
            this.tree.loader.addListener("load",this.onLoad,this);   
            this.tree.addListener('collapsenode',this.onNodeCollapse,this);   
            this.tree.addListener('expandnode',this.onNodeExpand,this);   
        }   
        var fieldMp = {   
            text: "text",   
            qtip: "qtip",   
            parentFuncId: "id",   
            icon: "icon"  
        };   
        if(!this.fieldMapping){   
            this.fieldMapping = fieldMp;   
        }else{   
            Ext.applyIf(this.fieldMapping, fieldMp);   
        }   
    },   
    initList:function(){   
        if(!this.list){   
            var cls = 'x-combo-list';   
            this.list = new Ext.Layer({   
                shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false  
            });   
            var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);   
            this.list.setWidth(lw);   
            this.list.swallowEvent('mousewheel');   
            this.innerList = this.list.createChild({cls:cls+'-inner'});   
            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));   
            this.innerList.setHeight("100%");   
        }   
    },   
       
    doQuery:function(){   
        if(this.expandAll){   
            var loader=this.tree.loader;   
            if(loader.baseAttrs){   
                Ext.apply(loader.baseAttrs,{expanded:this.expandAll});   
            }else{   
                loader.baseAttrs={expanded:this.expandAll};   
            }              
        }   
        if(!this.tree.rendered){   
            this.tree.render(this.innerList);   
            this.tree.addListener("click",this.clickNode,this);   
        }   
        this.expand();   
    },   
       
    beforeLoad:function(loader,node){   
        if(node!=node.getOwnerTree().root){                                                                                                                    
            loader.baseParams.parentFuncId=node.attributes[this.fieldMapping.parentFuncId];                                                                                                                    
        }   
    },   
    
    onLoad:function(loader,node,res){   
        var nodeArr=node.childNodes;   
        for(var i=0,j=nodeArr.length;i<j;i++){   
            if(nodeArr[i].attributes[this.fieldMapping.icon]){   
                nodeArr[i].getUI().getIconEl().src=nodeArr[i].attributes[this.fieldMapping.icon];   
            }   
            nodeArr[i].setText(nodeArr[i].attributes[this.fieldMapping.text]);   
            nodeArr[i].ui.textNode.setAttribute("qtip", nodeArr[i].attributes[this.fieldMapping.qtip]);   
        }      
    },   
       
    clickNode:function(node){   
        if(this.fireEvent('beforeClickNode',this,node)){   
            this.setValue(node.attributes[this.displayField]); 
            this.value = node.attributes[this.valField || "id"]; 
        }   
        this.fireEvent("afterClickNode",this,node);        
        this.fireEvent("select",this,node);        
        this.collapse();   
    },   
    onNodeCollapse:function(node){   
        this.list.setHeight(this.tree.getEl().getHeight()+2);   
    },   
    
    getValue: function () {
        return this.value;
    },
    
    onNodeExpand:function(node){   
        this.list.setHeight(this.tree.getEl().getHeight()+2);   
    },   
       
    onDestroy:function(){   
        if(this.view){   
            this.view.el.removeAllListeners();   
            this.view.el.remove();   
            this.view.purgeListeners();   
        }   
        if(this.tree.loader){   
            this.tree.loader.purgeListeners();   
        }   
        if(this.tree){   
            this.tree.el.removeAllListerers();   
            this.tree.el.remove();   
            this.tree.purgeListeners();   
        }   
        if(this.innerList){   
            this.innerList.destroy();   
        }   
        if(this.list){   
            this.list.destroy();   
        }   
        Ext.form.ComboBox.superclass.onDestroy.call(this);   
    }   
});   
  
Ext.reg("treecombox",Ext.ux.form.DynamicTreeCombox);

Ext.hoo.form.DynaTreeCombo.js

/**
 * @function 动态tree的combobox,本地数据
 * @auhor: hoojo
 * @createDate: Sep 11, 2010 6:33:13 PM
 * @blog: blog.csdn.net/IBM_hoojo
 * @email: hoojo_@126.com
 * @class Ext.hoo.form.DynaTreeCombo
 * @extends Ext.ux.form.DynamicTreeCombox
 */
Ext.ns("Ext.hoo.form");
Ext.hoo.form.DynaTreeCombo = Ext.extend(Ext.ux.form.DynamicTreeCombox, {
    constructor: function () {
        Ext.hoo.form.DynaTreeCombo.superclass.constructor.call(this, {
            renderTo: "show",
            expandAll: false,
            readOnly: true,
            width: 200,
            displayField: "text",
            valField: "id",
            root: new Ext.tree.AsyncTreeNode({
                text: "ExtJS",
                id: "0",
                children: [{
                    text: "adpter",
                    qtip: "这是一个adpter的tip",
                    children: [{
                        text: "ext",
                        leaf: true,
                        qtip: "这是一个ext的tip",
                        checked: true
                    },{
                        text: "yui",
                        leaf: true
                    },{
                        text: "jquery",
                        leaf: true
                    },{
                        text: "prototype",
                        leaf: true,
                        checked: false
                    }]
                },{
                    text: "air",
                    checked: false,
                    children: [{
                        text: "air.jsb",
                        leaf: true
                    },{
                        text: "ext-air.js",
                        leaf: true
                    }]
                },{
                    text: "docs"
                }]
            })
        });
        this.on("select", function (field, node) {
            alert(field.getValue() + "###" + field.getRawValue() + "##" + node.text);
        }, this);
        this.on("check", function (field, node) {
            alert(field.getValue() + "###" + field.getRawValue() + "##" + node.text);
        }, this);
    }
});
 
/**
 * @function DynamicTreeCombox 后台数据
 * @auhor: hoojo
 * @createDate: Sep 11, 2010 10:30:27 PM
 * @blog: blog.csdn.net/IBM_hoojo
 * @email: hoojo_@126.com
 */
Ext.hoo.form.AsyncBasicDynaTreeCombo = Ext.extend(Ext.ux.form.DynamicTreeCombox, {
    constructor: function () {
        Ext.hoo.form.AsyncBasicDynaTreeCombo.superclass.constructor.call(this, {
            renderTo: "showBasic",
            expandAll: false,
            readOnly: true,
            width: 200,
            displayField: "text",
            valField: "id",
            loaderConfig:{   
                dataUrl: "../ServiceDataServlet?method=basic"//加载树的URL   
            }
        });
        this.on("select", function (field, node) {
            alert(field.getValue() + "###" + field.getRawValue() + "##" + node.text);
        }, this);
    }
});
 
/**
 * @function 后台数据 
 * @auhor: hoojo
 * @createDate: Sep 11, 2010 10:30:59 PM
 * @blog: blog.csdn.net/IBM_hoojo
 * @email: hoojo_@126.com
 */
 
Ext.hoo.form.AsyncConstomDynaTreeCombo = Ext.extend(Ext.ux.form.DynamicTreeCombox, {
    constructor: function () {
        Ext.hoo.form.AsyncConstomDynaTreeCombo.superclass.constructor.call(this, {
            renderTo: "showConstom",
            expandAll: false,
            readOnly: true,
            width: 200,
            displayField: "text",
            valField: "id",
            loaderConfig:{   
                dataUrl: "../ServiceDataServlet?method=constom", 
                baseParams:{parentFuncId:""}//如果传递parentFuncId就会查询当前id下的节点
            },   
            //后台数据中没有text、qtip、icon、parentFuncId属性,需加上fieldMapping进行属性映射,如果后台返回数据中有此属性可省略 
            fieldMapping: {  
                text: "text",//映射node的text字段   
                qtip: "tip",//映射node的qtip字段   
                parentFuncId: "text"//映射动态请求后台的text属性作为请求参数   
                //icon: "img"
            }
        });
        this.on("select", function (field, node) {
            alert(field.getValue() + "###" + field.getRawValue() + "##" + node.text);
        }, this);
    }
});
 
Ext.onReady(function () {
    Ext.BLANK_IMAGE_URL = "../ext2/resources/images/default/s.gif";
    Ext.QuickTips.init();
    Ext.form.Field.prototype.msgTarget = "qtip";
    
    new Ext.hoo.form.DynaTreeCombo();
    new Ext.hoo.form.AsyncBasicDynaTreeCombo();
    new Ext.hoo.form.AsyncConstomDynaTreeCombo();
});

ServiceDataServlet.java

package com.hoo.servlet;
 
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class ServiceDataServlet extends HttpServlet {
 
    private static final long serialVersionUID = 1L;
 
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        response.setContentType("text/json");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        String method = request.getParameter("method");
        StringBuilder sb = new StringBuilder();
        if ("basic".equals(method)) {
            sb.append("[")
                .append("{").append("text:\"").append("adpter").append("\", qtip: \"").append("qtip提示:ADPTER").append("\",");
                sb.append("children: [")
                    .append("{").append("text:\"").append("ext").append("\", qtip: \"").append("qtip提示:ext").append("\",")
                    .append("leaf: true").append("},")
                    .append("{").append("text:\"").append("jquery")
                    .append("\",").append("leaf: true").append("}]").append("},")
                    .append("{").append("text:\"").append("air").append("\",");
                    sb.append("children: [")
                        .append("{").append("text:\"").append("air.jsb")
                        .append("\",").append("leaf: true").append("},")
                        .append("{").append("text:\"").append("ext-air.js")
                        .append("\",").append("leaf: true").append("}]").append("},")
                        .append("{").append("text:\"").append("readMe.text").append("\",")
                        .append("leaf: true}");
            sb.append("]");
        }
        if ("constom".equals(method)) {
            sb.append("[")
                .append("{").append("text:\"").append("adpter").append("\", tip: \"").append("ADPTER").append("\",");
                sb.append("children:[")
                    .append("{").append("text:\"").append("ext").append("\", tip: \"").append("EXT").append("\",")
                    .append("leaf: true").append("},")
                    .append("{").append("text:\"").append("jquery").append("\", tip: \"").append("JQUERY").append("\",")
                    .append("leaf: true").append("}]},")
                    .append("{").append("text:\"").append("air").append("\", tip: \"").append("AIR").append("\",");
                    sb.append("children:[")
                        .append("{").append("text:\"").append("air.jsb").append("\", tip: \"").append("AIR.JSB").append("\",")
                        .append("leaf: true").append("},")
                        .append("{").append("text:\"").append("ext-air.js").append("\", tip: \"").append("EXT-AIR.JS").append("\",")
                        .append("leaf: true").append("}]").append("},")
                        .append("{").append("text:\"").append("readMe.text").append("\", tip: \"").append("README.TEXT").append("\",")
                        .append("leaf: true}");
            sb.append("]");
        }
        out.print(sb.toString());
        out.flush();
        out.close();
    }
 
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }
}