ExtJS 4 中的自定义溢出处理程序实现
Posted
技术标签:
【中文标题】ExtJS 4 中的自定义溢出处理程序实现【英文标题】:Custom overflowHandler implementation in ExtJS 4 【发布时间】:2012-09-29 14:47:26 【问题描述】:我有两个toolbars
的面板。如何实现自定义类以用作overflowHandler
,它将组件移动到第一个工具栏溢出时的第二个工具栏?
我尝试使用Ext.layout.container.boxOverflow.Menu
的代码,但我的第二个工具栏只是隐藏了。
这是我的代码,它与来自 ExtJS 4
分发的 toolbar overflow
示例混合在一起。
Ext.require(['Ext.window.Window', 'Ext.toolbar.Toolbar', 'Ext.menu.ColorPicker', 'Ext.form.field.Date']);
Ext.onReady(function()
/**
* Override for implementing tbar2
*/
Ext.override(Ext.panel.Panel,
bridgeToolbars : function ()
var toolbar;
this.callParent(arguments);
if (this.tbar2)
if (Ext.isArray(this.tbar2))
toolbar =
xtype : 'toolbar',
items : this.tbar2
;
else if (!toolbar.xtype)
toolbar.xtype = 'toolbar';
toolbar.dock = 'top';
toolbar.isTbar2 = true;
this.dockedItems = this.dockedItems.concat(toolbar);
this.tbar2 = null;
,
onRender : function ()
this.callParent(arguments);
var topBars = this.getDockedItems('toolbar[dock="top"]'),
i,
len;
for (i = 0, len = topBars.length; i < len; i++)
if (topBars[i].isTbar2)
this.tbar2 = topBars[i];
break;
,
/**
* Lazy creates new toolbar and returns it
* @param Ext.panel.Panel panel
* @param String position
* @return Ext.toolbar.Toolbar
*/
getDynamicTBar : function (position)
var panel = this,
params,
tb;
position = position || 'top';
if (position === 'tbar2')
tb = panel.tbar2;
params = dock : 'top', isTbar2 : true;
else
tb = panel.getDockedItems('toolbar[dock="' + position + '"]');
params = dock : position;
if (tb.length > 0)
tb = tb[0];
if (!tb)
console.log('created tb at ' + position);
tb = Ext.create('Ext.toolbar.Toolbar', params);
panel.addDocked(tb);
return tb;
);
Ext.define('Ext.layout.container.boxOverflow.TBar2',
extend : 'Ext.layout.container.boxOverflow.None',
constructor : function ()
this.tbar2Items = [];
return this.callParent(arguments);
,
beginLayout : function (ownerContext)
this.callParent(arguments);
this.clearOverflow(ownerContext);
,
beginLayoutCycle : function (ownerContext, firstCycle)
this.callParent(arguments);
if (!firstCycle)
this.clearOverflow(ownerContext);
this.layout.cacheChildItems(ownerContext);
,
getOverflowCls : function ()
return Ext.baseCSSPrefix + this.layout.direction + '-box-overflow-body';
,
_asLayoutRoot : isRoot : true ,
clearOverflow : function ()
if (this.tbar2)
this.tbar2.suspendLayouts();
this.tbar2.hide();
this.tbar2.resumeLayouts(this._asLayoutRoot);
this.tbar2Items.length = 0;
,
handleOverflow : function (ownerContext)
var me = this,
layout = me.layout,
owner = layout.owner,
names = layout.getNames(),
startProp = names.x,
sizeProp = names.width,
plan = ownerContext.state.boxPlan,
available = plan.targetSize[sizeProp],
childItems = ownerContext.childItems,
len = childItems.length,
childContext,
comp, i, props,
tbarOwner = owner.ownerCt;
owner.suspendLayouts();
// Hide all items which are off the end, and store them to allow them to be restored
// before each layout operation.
me.tbar2Items.length = 0;
for (i = 0; i < len; i++)
childContext = childItems[i];
props = childContext.props;
if (props[startProp] + props[sizeProp] > available)
comp = childContext.target;
me.tbar2Items.push(comp);
owner.remove(comp, false);
owner.resumeLayouts();
if (!me.tbar2 && (tbarOwner instanceof Ext.panel.Panel))
me.tbar2 = tbarOwner.getDynamicTBar('tbar2');
me.tbar2.suspendLayouts();
me.tbar2.show();
Ext.each(me.tbar2Items, function(item, index)
me.tbar2.add(item);
);
me.tbar2.resumeLayouts(me._asLayoutRoot);
);
var handleAction = function(action)
Ext.example.msg('<b>Action</b>', 'You clicked "' + action + '"');
;
var colorMenu = Ext.create('Ext.menu.ColorPicker',
handler: function(cm, color)
Ext.example.msg('Color Selected', '<span style="color:#' + color + ';">You choose 0.</span>', color);
);
var showDate = function(d, value)
Ext.example.msg('<b>Action date</b>', 'You picked ' + Ext.Date.format(value, d.format));
;
var fromPicker = false;
Ext.create('Ext.window.Window',
title: 'Standard',
closable: false,
height:250,
width: 500,
bodyStyle: 'padding:10px',
contentEl: 'content',
autoScroll: true,
tbar: Ext.create('Ext.toolbar.Toolbar',
layout:
overflowHandler: 'TBar2'
,
items: [
xtype:'splitbutton',
text: 'Menu Button',
iconCls: 'add16',
handler: Ext.Function.pass(handleAction, 'Menu Button'),
menu: [text: 'Menu Item 1', handler: Ext.Function.pass(handleAction, 'Menu Item 1')]
,'-',
xtype:'splitbutton',
text: 'Cut',
iconCls: 'add16',
handler: Ext.Function.pass(handleAction, 'Cut'),
menu: [text: 'Cut menu', handler: Ext.Function.pass(handleAction, 'Cut menu')]
,
text: 'Copy',
iconCls: 'add16',
handler: Ext.Function.pass(handleAction, 'Copy')
,
text: 'Paste',
iconCls: 'add16',
menu: [text: 'Paste menu', handler: Ext.Function.pass(handleAction, 'Paste menu')]
,'-',
text: 'Format',
iconCls: 'add16',
handler: Ext.Function.pass(handleAction, 'Format')
,'->',
fieldLabel: 'Action',
labelWidth: 70,
width: 180,
xtype: 'datefield',
labelSeparator: '',
enableKeyEvents: true,
listeners:
expand: function()
fromPicker = true;
,
collapse: function()
fromPicker = false;
,
change: function(d, newVal, oldVal)
if (fromPicker || !d.isVisible())
showDate(d, newVal);
,
keypress:
buffer: 500,
fn: function(field)
var value = field.getValue();
if (value !== null && field.isValid())
showDate(field, value);
,
text: 'Sell',
iconCls: 'money-down',
enableToggle: true,
toggleHandler: function(button, pressed)
Ext.example.msg('<b>Action</b>', 'Right ToggleButton ' + (pressed ? 'Buy' : 'Sell'));
button.setText(pressed ? 'Buy' : 'Sell')
button.setIconCls(pressed ? 'money-up' : 'money-down')
,
text: 'Choose a Color',
menu: colorMenu // <-- submenu by reference
]
)
).show();
);
【问题讨论】:
您使用的具体版本是什么? 【参考方案1】:我们需要为工具栏布局实现overflowHandler,它会添加第二个工具栏,当工具栏的容器宽度不够而无法显示时,将组件从第一个工具栏包装到第二个工具栏。 首先,我们需要重写 Ext.panel.Panel:
Ext4.override(Ext4.panel.Panel,
bridgeToolbars: function ()
var toolbar;
this.callParent(arguments);
if (this.tbar2)
if (Ext4.isArray(this.tbar2))
toolbar =
xtype: 'toolbar',
items: this.tbar2
;
else if (!toolbar.xtype)
toolbar.xtype = 'toolbar';
toolbar.dock = 'top';
toolbar.isTbar2 = true;
this.dockedItems = this.dockedItems.concat(toolbar);
this.tbar2 = null;
,
onRender: function ()
this.callParent(arguments);
var topBars = this.getDockedItems('toolbar[dock="top"]'),
i,
len;
for (i = 0, len = topBars.length; i < len; i++)
if (topBars[i].isTbar2)
this.tbar2 = topBars[i];
break;
,
/**
* Creates, if not exists, and returns toolbar at passed position
* @param Ext.panel.Panel panel
* @param String position
* @return Ext.toolbar.Toolbar
*/
getDynamicTBar: function (position)
var panel = this,
params,
tb;
position = position || 'top';
if (position === 'tbar2')
tb = panel.tbar2;
params =
dock: 'top',
isTbar2: true,
layout:
overflowHandler: 'Scroller'
;
else
tb = panel.getDockedItems('toolbar[dock="' + position + '"]');
params =
dock: position
;
if (tb.length > 0)
tb = tb[0];
if (!tb)
tb = Ext4.create('Ext4.toolbar.Toolbar', params);
panel.addDocked(tb);
if (position === 'tbar2')
panel.tbar2 = tb;
return tb;
);
接下来,我们需要创建 Ext4.layout.container.boxOverflow.TBar2 类(它的名字很长,因为 ExtJS 在硬编码的 Ext4.layout.container.boxOverflow 命名空间中搜索 handleOverflow(字符串的实例))。
/**
* @class Ext4.layout.container.boxOverflow.TBar2
* Class for using as overflowHandler
* @extends Ext.layout.container.boxOverflow.None
*/
Ext4.define('Ext4.layout.container.boxOverflow.TBar2',
extend: 'Ext4.layout.container.boxOverflow.None',
/**
* @private
* @property Boolean initialized
*/
initialized: false,
constructor: function ()
/**
* @private
* @property Array tbar2Items
* List of moved components
*/
this.tbar2Items = [];
return this.callParent(arguments);
,
beginLayout: function (ownerContext)
if (!this.initialized)
this.layout.owner.ownerCt.on('afterlayout', this.createTBar2, this);
this.initialized = true;
this.callParent(arguments);
this.clearOverflow(ownerContext);
,
beginLayoutCycle: function (ownerContext, firstCycle)
this.callParent(arguments);
if (!firstCycle)
this.clearOverflow(ownerContext);
this.layout.cacheChildItems(ownerContext);
,
getOverflowCls: function ()
return Ext4.baseCSSPrefix + this.layout.direction + '-box-overflow-body';
,
/**
* @private
* @property Object _asLayoutRoot
*/
_asLayoutRoot:
isRoot: true
,
clearOverflow: function ()
// If afterlayout is not processing and tbar2 already created,
// we can to move components from tbar2 to first toolbar, because now
// there isn't any overflow
if (!this.processing && this.tbar2)
this.tbar2.items.each(function (item)
this.tbar1.add(item);
// change ui from saved property, or CSS will be incorrect
item.ui = item.origUI;
, this);
this.tbar2.removeAll(false);
this.tbar2.hide();
this.tbar2Items.length = 0;
,
/**
* @private
* Creates tbar2 and does other routines
*/
createTBar2: function ()
// if afterlayout event is still processing,
// or we don't need to handle toolbar overflow, just return from function
if (this.processing || !this.doTbar2)
return;
this.processing = true;
this.doTbar2 = false;
var me = this,
ownerContext = this.mOwnerContext,
layout = me.layout,
owner = layout.owner,
names = layout.getNames(),
startProp = names.x,
sizeProp = names.width,
plan = ownerContext.state.boxPlan,
available = plan.targetSize[sizeProp],
childItems = ownerContext.childItems,
len = childItems.length,
childContext,
comp, i, props,
tbarOwner = owner.ownerCt;
me.tbar1 = owner;
// save components which will be moved
owner.suspendLayouts();
me.tbar2Items.length = 0;
for (i = 0; i < len; i++)
childContext = childItems[i];
props = childContext.props;
if (props[startProp] + props[sizeProp] > available)
comp = childContext.target;
me.tbar2Items.push(comp);
// save original ui property
comp.origUI = comp.ui;
owner.remove(comp, false);
owner.resumeLayouts();
// add tbar2 to the layout cycle (you can see very similar code in clearOverflow
// method of Ext.layout.container.boxOverflow.Menu)
tbarOwner.suspendLayouts();
me.tbar2 = tbarOwner.getDynamicTBar('tbar2');
me.tbar2.show();
// moving components
Ext4.each(me.tbar2Items, function (item, index)
me.tbar2.insert(index, item);
item.ui = item.origUI;
);
tbarOwner.resumeLayouts(this._asLayoutRoot);
this.processing = false;
,
handleOverflow: function (ownerContext)
// set flag and store context for later using
this.doTbar2 = true;
this.mOwnerContext = ownerContext;
);
请注意我使用 ExtJS 4 引导(因为在我的网络应用程序中也有 ExtJD 2.3),所以在你的代码中你可能必须使用 Ext.
而不是 Ext4.
【讨论】:
以上是关于ExtJS 4 中的自定义溢出处理程序实现的主要内容,如果未能解决你的问题,请参考以下文章