//splitter 拆分条 import win.ui.ctrl.metaProperty; namespace win.ui.ctrl ; class splitter{ ctor(parent,tParam){ if( tParam ){ tParam.style |=0x100/*_BS_PATTERN*/ tParam.cls = "splitter" if(tParam.edge) tParam.exstyle |= 0x100/*_WS_EX_WINDOWEDGE*/; if( tParam.center===null || tParam.center ) tParam.style |= 0x200/*_SS_CENTERIMAGE*/ this.horz =tParam.horz; //是否为水平拆分; this.ltMin = 20; this.rbMin = 20; } }; onCreate =function(){ var x0,y0, ,c1w,c1h, ,c2w,c2h, ,spx,spy,spw,sph, ,oldPos,moveOffset, ,dragging,leftButtonDown; var hDc; var hCur = ::LoadCursor( ,topointer( this.horz ? 0x7F85/*_IDC_SIZENS*/ : 0x7F84/*_IDC_SIZEWE*/ ) ); var limit =function(moveOffset){ var ret = moveOffset; var scaleX,scaleY = this._parentForm.getScale(); var max; if(moveOffset<0){ if(! this.horz){ max =-c2w+(this.rbMin*scaleY); if(moveOffset < max) ret =max; }else { max = -c2h+(this.rbMin*scaleX); if(moveOffset < max) ret = max; } }else { if(! this.horz){ max =c1w-(this.ltMin*scaleY); if(moveOffset > max) ret = max; }else { max =c1h-(this.ltMin*scaleX); if(moveOffset > max) ret = max; } } return ret; } var splitMove = function(offset){ if( !this.horz ){ if(this.ltControl[1]){ for(k,ctrl in this.ltControl){ var x,y,cx,cy = ctrl.getPos(); ctrl.setPos(x,y,cx-offset,cy); } } else{ var x,y,cx,cy = this.ltControl.getPos(); this.ltControl.setPos(x,y,cx-offset,cy); } if(this.rbControl[1]){ for(k,ctrl in this.rbControl){ var x,y,cx,cy = ctrl.getPos(); ctrl.setPos(x-offset,y,cx+offset,cy); } } else { var x,y,cx,cy = this.rbControl.getPos(); this.rbControl.setPos(x-offset,y,cx+offset,cy); } this.setPos(spx-offset,spy); } else { if(this.ltControl[1]){ for(k,ctrl in this.ltControl){ var x,y,cx,cy = ctrl.getPos(); ctrl.setPos(x,y,cx,cy-offset); } } else { var x,y,cx,cy = this.ltControl.getPos(); this.ltControl.setPos(x,y,cx,cy-offset); } if(this.rbControl[1]){ for(k,ctrl in this.rbControl){ var x,y,cx,cy = ctrl.getPos(); ctrl.setPos(x,y-offset,cx,cy+offset); } } else { var x,y,cx,cy = this.rbControl.getPos() this.rbControl.setPos(x,y-offset,cx,cy+offset); } this.setPos(spx,spy-offset); } } this.splitMove = function(offset){ var ltControl = this.ltControl[1] || this.ltControl; var rbControl = this.rbControl[1] || this.rbControl; _,_,c1w,c1h = ltControl.getPos(); _,_,c2w,c2h = rbControl.getPos(); spx,spy,spw,sph = this.getPos(); var dx,dy = this.dpiScale(1,1); if( this.horz ){ splitMove( limit(-offset*dy) ); } else { splitMove( limit(-offset*dx) ); } }; this.splitAt = function(topLeft){ var ltControl = this.ltControl[1] || this.ltControl; var rbControl = this.rbControl[1] || this.rbControl; _,_,c1w,c1h = ltControl.getPos(); _,_,c2w,c2h = rbControl.getPos(); spx,spy,spw,sph = this.getPos(); var dx,dy = this.dpiScale(1,1); if( this.horz ){ splitMove( limit(-(topLeft*dy-spy)) ); } else { splitMove( limit(-(topLeft*dx-spx)) ); } }; this.wndproc = function(hwnd,message,wParam,lParam){ select(message) { case 0x200/*_WM_MOUSEMOVE*/{ if(leftButtonDown){ var x,y =..win.getMessagePos(lParam); dragging = true; if( ! this.horz ){ moveOffset = limit(x0 - x); if(oldPos){ this._drawSplitter(hDc,oldPos,spy,spw,sph); } this._drawSplitter(hDc,spx-moveOffset,spy,spw,sph); oldPos =spx-moveOffset; } else { moveOffset =limit(y0-y); if(oldPos){ this._drawSplitter(hDc,spx,oldPos,spw,sph); } this._drawSplitter(hDc,spx,spy-moveOffset,spw,sph); oldPos = spy-moveOffset; } } } case 0x20/*_WM_SETCURSOR*/ { ::SetCursor(hCur); return true; } case 0x201/*_WM_LBUTTONDOWN*/ { if((this.ltControl===null)or(this.rbControl===null)){ return ; } ..win.setCapture(hwnd); var ltControl = this.ltControl[1] || this.ltControl; var rbControl = this.rbControl[1] || this.rbControl; leftButtonDown = true; x0,y0 =..win.getMessagePos(lParam); _,_,c1w,c1h = ltControl.getPos(); _,_,c2w,c2h = rbControl.getPos(); spx,spy,spw,sph = this.getPos(); oldPos = 0; if(hDc)::ReleaseDC(this.parent.hwnd,hDc); hDc =::GetDC(this.parent.hwnd); if( ! this.horz ){ this._drawSplitter(hDc,spx,spy,spw,sph); oldPos = spx; } else { this._drawSplitter(hDc,spx,spy,spw,sph); oldPos = spy; } } case 0x202/*_WM_LBUTTONUP*/ { if( leftButtonDown ){ if(hDc){ if(oldPos!=0){ if( ! this.horz ){ this._drawSplitter(hDc,oldPos,spy,spw,sph); } else { this._drawSplitter(hDc,spx,oldPos,spw,sph); } } ::ReleaseDC(this.parent.hwnd,hDc); hDc = null; } ..win.releaseCapture(); leftButtonDown = false; if(dragging){ splitMove(moveOffset) dragging = false; if(this.onSplitterMoved){ this.onSplitterMoved(this.getRect().ltrb()); } this.redraw(); } } } } } }; _drawSplitter =function(hDc,x,y,width,height){ var sbmp ='\u00AA\u0055\u00AA\u0055'; var hbmp =::CreateBitmap(4,4,1,1,sbmp); var brush =::CreatePatternBrush(hbmp); var brush_old =::SelectObject(hDc,brush); ::PatBlt(hDc,x,y,width,height,0x5A0049/*_PATINVERT*/); ::SelectObject(hDc,brush_old); ::DeleteObject(brush); ::DeleteObject(hbmp); }; _preadjust = function(){ if( !(this.ltControl && this.rbControl) )return; var ltControl = this.ltControl[1] || this.ltControl; var rbControl = this.rbControl[1] || this.rbControl; var ltX,ltY,ltCx,ltCy = ltControl.getPos(); var rbX,rbY,rbCx,rbCy = rbControl.getPos(); var x,y,cx,cy = this.getPos(); if( this.horz ){ var lt = ltY+ltCy; owner.setPos(x,lt); if(this.rbControl[1]){ for(i,ctrl in this.rbControl){ var rbX,rbY,rbCx,rbCy = ctrl.getPos(); var top = i == 1 ? lt + cy : rbY + (lt - y); ctrl.setPos(rbX , top,rbCx,rbY + rbCy - (top) ); } } else { this.rbControl.setPos(rbX , lt + cy,rbCx,rbY + rbCy - (lt + cy) ); } } else{ var lt = ltX + ltCx; owner.setPos(ltX + ltCx ,y); if(this.rbControl[1]){ for(i,ctrl in this.rbControl){ var rbX,rbY,rbCx,rbCy = ctrl.getPos(); var left = i == 1 ? lt + cx : rbX + (lt - x); ctrl.setPos(left , rbY, rbX + rbCx - (left),rbCy ); } } else { this.rbControl.setPos(lt + cx , rbY, rbX + rbCx - (lt + cx),rbCy ); } } }; @_metaProperty; } splitter._metaProperty = metaProperty( split =function(ctrl1,ctrl2 ){ var c1 = ctrl1[1] || ctrl1; var c2 = ctrl2[1] || ctrl2; if( owner.horz ){ if( c1.top < c2.top ){ owner[["ltControl"]] = ctrl1; owner[["rbControl"]] = ctrl2; } else { owner[["ltControl"]] = ctrl2; owner[["rbControl"]] = ctrl1; } } else { if( c1.left < c2.left ){ owner[["ltControl"]] = ctrl1; owner[["rbControl"]] = ctrl2; } else { owner[["ltControl"]] = ctrl2; owner[["rbControl"]] = ctrl1; } } }; ); ..win.registerClassEx("splitter",,"static"); //感谢: 琴鸣 贡献最初的源码 /**details(用法说明) 要点: 1. 使用控件的 split 函数拆分多个控件。 例如: winform.splitter1.split( winform.edit1,winform.edit2 ) 参数也可以是控件数组,每个控件数组必须包含位于拆分条同一侧的控件。 例如: winform.splitter1.split( winform.edit1,{ winform.edit2,winform.edit3} ) 2. 在调整窗口大小时,拆分条会负责让被拆分的控件吸附在自己的两侧。 但是被拆分控件以及拆分条本身的其他固定边距属性、自适应大小属性应当自行根据需要设置。 end details**/ //@guide [教程 - 使用拆分控件](doc://library-guide/std/win/ui/ctrl/splitter.html) [范例 - 使用拆分条](doc://example/Windows/Controls/splitter.html) [范例 - 自缩放编辑框](doc://example/Windows/edit/onOk.html) /**intellisense() !splitter.ltControl = 拆分条左边或上边的控件。\n可以是控件对象,也可以是包含控件的数组。\n只能调用 split 函数修改此属性。\n!static. !splitter.rbControl = 拆分条右边或下边的控件。\n可以是控件对象,也可以是包含控件的数组。\n只能调用 split 函数修改此属性。\n!static. !splitter.split( = 指定需要拆分的控件。 !splitter.split(.(前面的控件,后面的控件) = 指定需要拆分的控件。\n参数可以是控件对象,也可以是包含控件对象的数组。\n同一数组中的控件必须位于拆分条的同一侧。\n被折分的控件可在控件属性中指定是否支持自动调整大小。\n调整窗口大小时拆分条会自动贴近前面数组中的第一个控件。\n\n也可以将更多控件可放入子窗口并以 custom 控件作为容器加载,然后再拆分。\n\nlistbox 反复改变高度会因为自动适应项目行高而越来越小,\n要用拆分条改变 listbox 高度时最好也放入 custom 容器 !splitter.splitAt(__/*拆分位置*/) = 在指定的位置拆分。\n水平拆分条参数指定窗口上边距,垂直拆分条则参数指定的是窗口左边距。\n参数应当指定 DPI 缩放以前的值,函数会自动缩放。 !splitter.splitMove(__/*相对移动距离*/) = 移动拆分条到相对于当前位置的指定距离,\n并在新位置拆分绑定的窗口。\n参数必须指定 DPI 缩放前的距离。 !splitter.horz = 是否水平拆分条 !splitter.ltMin = 前面的控件最小尺寸,应指定 DPI 缩放与窗体缩放前的设计时大小。\n这个属性只会限制拖动拆分条、split、splitMove 函数。\n窗口调整大小时按预设缩放规则调整,不检查 ltMin 属性。 !splitter.rbMin = 后面的控件最小尺寸,应指定 DPI 缩放与窗体缩放前的设计时大小。\n这个属性只会限制拖动拆分条、split、splitMove 函数。\n窗口调整大小时按预设缩放规则调整,不检查 rbMin 属性。 !splitter.cls = 设计时类名 !splitter.className = 运行时类名 !splitter.hwnd = 控件句柄 !splitter.id = 控件ID !splitter.text = 控件文本 !splitter._parentForm = 返回创建控件的容器窗口(win.form对象),所有窗口控件都拥有此只读属性。\n对于使用窗体设计器创建的窗口,也就是返回设计时窗体容器。\n\n即使子窗口移除子窗口样式、更改父子关系,或以 orphanWindow显示,\n控件的 _parentForm 始终都不会改变\n!winform. !splitter.getParent() = 返回父窗口\n!splitter. !splitter.setParent(__/*控件对象*/) = 改变父窗口 !splitter.translateAccelerator = @.translateAccelerator = function(msg){ \n __/*返回是否快捷键*/\n} !splitter.adjust = @.adjust = function( cx,cy,wParam ) { \n __ \n}; !splitter.adjust() = 调整窗口 - 自定义事件函数 !splitter.hide = 控件是否隐藏 !splitter.disabled = 是否禁用 !splitter.left = 左侧坐标 !splitter.right = 右侧坐标 !splitter.top = 顶部坐标 !splitter.bottom = 底部坐标 !splitter.width = 宽度 !splitter.height = 高度 !splitter.redraw() = 刷新 !splitter.redrawTransparent() = 刷新\n透明背景时请使用此函数替代redraw() !splitter.show(true__) = 显示控件 !splitter.getRect() = 控件区块位置(::RECT结构体) !splitter.getRect(true) = 控件屏幕区块位置(::RECT结构体) !splitter.setRect(rc) = 设置控件区块位置(::RECT结构体) !splitter.setRect(rc,true) = 设置控件屏幕区块位置(::RECT结构体) !splitter.getClientRect() = 控件客户区块位置(::RECT结构体)\n!rect. !splitter.theme = 外观主题,例如\nwinform.button.theme = "Explorer"\nwinform.button.theme = false !splitter.modifyStyle(.(remove,add,swpFlags) = 修改窗口样式,所有参数都是可选参数,\n@remove 用数值指定要移除的样式,可使用 _WS_ 前缀的常量\n@add 用数值指定要添加的样式,可使用 _WS_ 前缀的常量\n@swpFlags 可选用数值指定调整窗口选项,可使用 _SWP_ 前缀的常量\n如果指定了 @swpFlag ,则使用该参数调用::SetWindowPos\n细节请参考 win.modifyStyle 函数源码 !splitter.modifyStyleEx(.(remove,add,swpFlags) = 修改窗口扩展样式,所有参数都是可选参数,\n@remove 用数值指定要移除的样式,可使用 _WS_EX_ 前缀的常量\n@add 用数值指定要添加的样式,可使用 _WS_EX_ 前缀的常量\n@swpFlags 可选用数值指定调整窗口选项,可使用 _SWP_ 前缀的常量\n如果指定了 @swpFlag ,则使用该参数调用::SetWindowPos\n细节请参考 win.modifyStyle 函数源码 !splitter.capture = 是否捕获全局鼠标消息 !splitter.close() = 关闭控件窗口 !splitter.invalidate(__/*可选使用::RECT()对象指定客户区*/) = 使窗口绘图区无效 !splitter.invalidate(__/*可选使用::RECT()对象指定客户区*/,0) = 使窗口绘图区无效\n不刷新背景 !splitter.update() = 重绘invalidate函数指定的区块 !splitter.setPos(.(x坐标,y坐标,宽,高,插入位置,参数) = 调整窗口位置或排序,所有参数可选\n同时指定x,y坐标则移动位置\n同时指定宽高则改变大小\n指定插入位置(句柄或_HWND前缀常量)则调整Z序 !splitter.getPos() = 返回相对坐标,宽,高\nx,y,cx,cy=win.getPos(hwnd) !splitter.sendMessage(.(msg,wParam,lParam) = 发送窗口消息\n此函数用法请参考 ::User32.SendMessage !splitter.postMessage(.(msg,wParam,lParam) = 投递窗口消息到消息队列中\n此函数用法请参考 ::User32.PostMessage !splitter.onSplitterMoved = @.onSplitterMoved = function(l,t,r,b){ __/*拆分条已被用户手动拖拽移动到新位置,l,r,r,b 分别为左上右下坐标。\n调用 splitAt,splitMove 函数修改位置不会回调此函数。\n窗体缩放时自动调整位置不会回调此函数。*/ } ?win.ui.ctrl.static = !splitter. win.ui.ctrl.splitter() = 拆分条控件\n!splitter. win.ui.ctrl.splitter = 拆分条控件支持库 end intellisense**/