Tab/Vbox 布局

Tab/Vbox layout

我有一个应用程序使用标签布局,在绑定到每个标签的每个表单面板之间共享相同的网格面板作为 xtype 小部件。

我的主标签布局如下:

Ext.define('cardioCatalogQT.view.main.Main', {
    extend: 'Ext.tab.Panel',
    xtype: 'main-view',
    controller: 'main-view',
    requires: [
        'cardioCatalogQT.view.main.MainController',
        'cardioCatalogQT.view.main.MainModel',
        'Ext.ux.form.ItemSelector',
        'Ext.tip.QuickTipManager',
        'Ext.layout.container.Card'
    ],

    style: 'background-color:#dfe8f5;',
    width: '100%',
    height: 400,

    layout: 'vbox',
    defaults: {
        bodyPadding: 5
    },
    items: [{
            title:'Main',
            region: 'south',
            xtype: 'form',
            itemId: 'Ajax',
            flex: 1,
            styleHtmlContent: true,
            items:[{
                xtype: 'image',
                src: 'resources/images/R3D3.png',
                height: 50,
                width: 280
            },{
                title: 'Ad Hoc Sandbox for Cohort Discovery'
            }] ,
            lbar:[{
                text: 'Initiate advanced request',
                xtype: 'button',

                handler: function(button){
                    var url = 'https://url_here';
                    //cardioCatalogQT.service.UtilityService.http_auth(button);
                    window.open(url);
                }
            }]
        },
        /*{
            xtype: 'resultsGrid'
            //disabled: true
        },*/
        /*{
            xtype: 'searchGrid'
            //disabled: true
        },*/
        {
            xtype: 'demographicGrid'
            //disabled: true
        },
        {
            xtype: 'vitalGrid'
            //disabled: true
        },
        {
            xtype: 'labGrid'
            //disabled: true
        },
        {
            xtype: 'diagnosisGrid'
            //disabled: true

        },
        {
            xtype: 'medicationGrid'
            //disabled: true
        },
        {
            xtype: 'procedureGrid'
            //disabled: true
        },
        {
            xtype: 'queryGrid'
            //disabled: true
        }
    ]
}); 

共享相同网格小部件(具体来说,demographicGrid、vitalGrid、labGrid、diagnosisGrid、procedureGrid 和 medicationGrid,每个都在主视图中由 xtype 引用)的各个选项卡如下所示:

/**
 * Widget with template to render to Main view
 */

Ext.define('cardioCatalogQT.view.grid.DemographicGrid', {
    extend: 'Ext.form.Panel',
    alias: 'widget.demographicGrid',
    itemId: 'demographicGrid',
    store: 'Payload',

    requires: [
        'cardioCatalogQT.view.main.MainController'
    ],


    config: {
        variableHeights: false,
        title: 'Demographics',
        xtype: 'form',
        width: 200,
        bodyPadding: 10,
        defaults: {
            anchor: '100%',
            labelWidth: 100
        },


        // inline buttons
        dockedItems: [ {
            xtype: 'toolbar',
            height: 100,
            items: [{
                xtype: 'button',
                text: 'Constrain sex',
                itemId: 'showSex',
                hidden: false,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#sexValue').show();
                        button.up('grid').down('#hideSex').show();
                        button.up('grid').down('#showSex').hide();
                    }
                }
            }, {
                xtype: 'button',
                text: 'Hide sex constraint',
                itemId: 'hideSex',
                hidden: true,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#sexValue').hide();
                        button.up('grid').down('#sexValue').setValue('');
                        button.up('grid').down('#hideSex').hide();
                        button.up('grid').down('#showSex').show();
                    }
                }
            },{ // Sex
                xtype: 'combo',
                itemId: 'sexValue',
                queryMode: 'local',
                editable: false,
                value: 'eq',
                triggerAction: 'all',
                forceSelection: true,
                fieldLabel: 'Select sex',
                displayField: 'name',
                valueField: 'value',
                hidden: true,
                store: {
                    fields: ['name', 'value'],
                    data: [
                        {name: 'female', value: 'f'},
                        {name: 'male', value: 'm'}
                    ]
                }
            }, {
                xtype: 'button',
                text: 'Constrain age',
                itemId: 'showAge',
                hidden: false,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#ageComparator').show();
                        button.up('grid').down('#ageValue').show();
                        button.up('grid').down('#hideAge').show();
                        button.up('grid').down('#showAge').hide();
                    }
                }
            }, {
                xtype: 'button',
                text: 'Hide age',
                itemId: 'hideAge',
                hidden: true,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#ageComparator').hide();
                        button.up('grid').down('#ageValue').hide();
                        button.up('grid').down('#upperAgeValue').hide();
                        button.up('grid').down('#ageComparator').setValue('');
                        button.up('grid').down('#ageValue').setValue('');
                        button.up('grid').down('#upperAgeValue').setValue('');
                        button.up('grid').down('#hideAge').hide();
                        button.up('grid').down('#showAge').show();
                    }
                }
            }, { // Age
                xtype: 'combo',
                itemId: 'ageComparator',
                queryMode: 'local',
                editable: false,
                value: '',
                triggerAction: 'all',
                forceSelection: true,
                fieldLabel: 'Select age that is',
                displayField: 'name',
                valueField: 'value',
                hidden: true,
                store: {
                    fields: ['name', 'value'],
                    data: [
                        {name: '=', value: 'eq'},
                        {name: '<', value: 'lt'},
                        {name: '<=', value: 'le'},
                        {name: '>', value: 'gt'},
                        {name: '>=', value: 'ge'},
                        {name: 'between', value: 'bt'}
                    ]
                },

                listeners: {
                    change: function(combo, value) {
                        // use component query to  toggle the hidden state of upper value
                        if (value === 'bt') {
                            combo.up('grid').down('#upperAgeValue').show();
                        } else {
                            combo.up('grid').down('#upperAgeValue').hide();
                        }
                    }
                }
            },{
                xtype: 'numberfield',
                itemId: 'ageValue',
                fieldLabel: 'value of',
                value: '',
                hidden: true
            },{
                xtype: 'numberfield',
                itemId: 'upperAgeValue',
                fieldLabel: 'and',
                hidden: true
            },{
                xtype: 'button',
                text: 'Constrain race/ethnicity',
                itemId: 'showRace',
                hidden: false,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#raceValue').show();
                        button.up('grid').down('#hideRace').show();
                        button.up('grid').down('#showRace').hide();
                    }
                }
            }, {
                xtype: 'button',
                text: 'Hide race/ethnicity constraint',
                itemId: 'hideRace',
                hidden: true,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#raceValue').hide();
                        button.up('grid').down('#raceValue').setValue('');
                        button.up('grid').down('#hideRace').hide();
                        button.up('grid').down('#showRace').show();
                    }
                }
            },{ // Race
                xtype: 'combo',
                itemId: 'raceValue',
                queryMode: 'local',
                editable: false,
                value: 'eq',
                triggerAction: 'all',
                forceSelection: true,
                fieldLabel: 'Select race',
                displayField: 'name',
                valueField: 'value',
                hidden: true,
                store: {
                    fields: ['name', 'value'],
                    data: [
                        {name: 'female', value: 'f'},
                        {name: 'male', value: 'm'}
                    ]
                }
            },{
                //minWidth: 80,
                text: 'Add to search',
                xtype: 'button',
                itemId: 'searchClick',
                handler: 'onSubmitDemographics'
            }]
        },
            {
                xtype:'searchGrid'
            }
        ]

    }


});

选项卡中每个表单面板之间的唯一区别是项目组件。这些表单面板中的每一个都引用 'searchGrid' 的 xtype 并像附图中那样呈现它:

问题是我有 6 个相同网格的实例。这在大多数情况下都有效,但它导致了一些与控制我的网格中的复选框以及一些奇怪的网格存储加载行为相关的问题,老实说,使用这种反模式跟踪组件是一个 PITA。

我想以某种方式在较低的垂直面板中拥有我的 searchGrid 的单个实例,而较高的垂直面板具有我需要根据每个选项卡的要求更改的项目组件。项目控件如何变化的示例是

我想要的行为是,当我单击一个选项卡时,上方的项目组件会将我带到不同的表单面板,而下方的面板则固定在搜索网格上。

但是,我目前将 searchGrid 绑定到每个选项卡的表单面板,因为这是我可以让它工作的唯一方法。

searchGrid 网格面板如下所示:

Ext.define('cardioCatalogQT.view.grid.Search', {
    extend: 'Ext.grid.Panel',

    xtype: 'framing-buttons',
    store: 'Payload',
    itemId: 'searchGrid',

    requires: [
        'cardioCatalogQT.view.main.MainController'
    ],

    columns: [
        {text: "ID", width: 50, sortable: true, dataIndex: 'id'},
        {text: "Type", width: 120, sortable: true, dataIndex: 'type'},
        {text: "Key", flex: 1, sortable: true, dataIndex: 'key'},
        {text: "Criteria", flex: 1, sortable: true, dataIndex: 'criteria'},
        {text: "DateOperator", flex: 1, sortable: true, dataIndex: 'dateComparatorSymbol'},
        {text: "When", flex: 1, sortable: true, dataIndex: 'dateValue'},
        {text: "Count", flex: 1, sortable: true, dataIndex: 'n'}
    ],
    columnLines: true,
    selModel: {
        type: 'checkboxmodel',
        listeners: {
            selectionchange: 'onSelectionChange'
        }
    },

    // When true, this view acts as the default listener scope for listeners declared within it.
    // For example the selectionModel's selectionchange listener resolves to this.
    defaultListenerScope: false,

    // This view acts as a reference holder for all components below it which have a reference config
    // For example the onSelectionChange listener accesses a button using its reference
    //referenceHolder: true,

    // inline buttons
    dockedItems: [{
        xtype: 'toolbar',
        dock: 'bottom',
        ui: 'footer',
        layout: {
            pack: 'center'
        }
    }, {
        xtype: 'toolbar',
        items: [{
            //reference: 'andButton',
            text: 'AND',
            itemId: 'andButton',
            tooltip: 'Add the selected criteria as AND',
            iconCls: 'and',
            disabled: true,
            handler: 'onCriterionAnd'
        },'-',{
            //reference: 'orButton',
            text: 'OR',
            itemId: 'orButton',
            tooltip: 'Add the selected criteria as OR',
            iconCls: 'or',
            disabled: true,
            handler: 'onCriterionOr'
        },'-',{
            //reference: 'notButton',
            text: 'NOT',
            itemId: 'notButton',
            tooltip: 'Add the selected criteria as NOT',
            iconCls: 'not',
            disabled: true,
            handler: 'onCriterionNot'
        },'-',{
            //reference: 'removeButton',  // The referenceHolder can access this button by this name
            text: 'Remove',
            itemId: 'removeButton',
            tooltip: 'Remove the selected item',
            iconCls: 'remove',
            disabled: true,
            handler: 'onCriterionRemove'
        },'-', { // SaveQuery
            //reference: 'SaveQuery',
            text: 'Save',
            itemId: 'saveQuery',
            tooltip: 'save the current filter',
            iconCls: 'save',
            disabled: true,
            handler: 'onFilterSave'
        }]
    }],

    height: 1000,
    frame: true,
    iconCls: 'icon-grid',
    alias: 'widget.searchGrid',
    title: 'Search',

    initComponent: function() {
        this.width = 750;
        this.callParent();
    }
});

我曾尝试使用 Vbox 布局来获得我想要的行为,但并不成功。根据 Tab 单击,上部 Vbox 面板更改为不同的表单面板,而下部 Vbox 面板保持固定,这似乎并不少见。任何见解将是最受欢迎的。

如果我没理解错的话,我的这个小测试应该完全符合你的要求,使用区域 northcenter.

的边框布局
<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="ext-theme-gray.css">
    <title>Test app</title>
    <script type="text/javascript" src="ext-all-dev.js"></script>
    <script>
    Ext.onReady(function() {
        var Viewport = Ext.create('Ext.container.Viewport',{
            layout:'border',
            items:[{
                xtype:'tabpanel',
                region:'north',
                items:[{
                    xtype:'panel',
                    title:'A',
                    items:[{xtype:'button',text:'Clickme'}]
                },{
                    xtype:'panel',
                    title:'B',
                    items:[{xtype:'textfield'}]
                }]
            },{
                xtype:'gridpanel',
                title:'center',
                region:'center',
                columns:[{
                    dataIndex:'A',
                    text:'A'
                },{
                    dataIndex:'B',
                    text:'B'
                }]
            }]
        })
        Ext.create('Ext.app.Application',{
            name:'TestApp',
            autoCreateViewport: true,
            views:[
                Viewport
            ]
        });
    });
    </script>
</head>
<body>
</body>
</html>

PS: 我使用的是 ExtJS 4.2.2,但它应该也适用于其他 Ext 版本。