动效画布控件,用于游戏、动画与自绘界面。
在 winform.add 的参数表中指定 cls="canvas" 创建。
自绘事件与动画接口与 plus 控件相同(onDrawBackground,onDrawForeground,onDrawComplete,startAnimation,onAnimation),
但画布是常驻的 PARGB 内存位图(GDI+ 最快的格式),不做伽马校正合成,
动画跟随显示器刷新(不用窗口定时器),比 plus 快数倍且帧间隔稳定。
画布总是不透明,没有文本、图标、皮肤、圆角、边框等 plus 功能;
调用 orphanWindow(true) 可转为透明分层窗口,盖在其他控件上面显示特效
动效画布控件
返回创建控件的容器窗口(win.form对象),所有窗口控件都拥有此只读属性。
对于使用窗体设计器创建的窗口,也就是返回设计时窗体容器。
即使子窗口移除子窗口样式、更改父子关系,或以 orphanWindow显示,
控件的 _parentForm 始终都不会改变
uiCtrlCanvasObject.adjust = function( cx,cy,wParam ) {
/*父窗口改变大小后会自动触发此事件函数。
注意 onSize 是 adjust 事件的别名,作用相同。
所有 win.form 创建的窗体和控件都支持 adjust 事件,
重复赋值 adjust 会追加事件触发器而非替换原来的值。
cx 参数为窗口客户区宽度,cy 参数为窗口客户区高度,
wParam 参数来自 _WM_SIZE 消息的 wParam 参数,一般不用管。
一般不建议添加一个 wndproc 仅仅是为了处理 _WM_SIZE 消息,
定义 adjust 事件是更好的选择。
如果主动调用此函数,则检查并执行所有之前添加的 adjust 事件函数。
省略调用参数时 cx,cy 参数默认设为窗口大小*/
};
uiCtrlCanvasObject.afterDpiChanged = function(scaleX,scaleY,origScaleX,origScaleY){
/*DPI 缩放后回调此函数。
scaleX,scaleY 为 DPI 缩放倍数(例如 2 表示 200% 缩放)。
origScaleX,origScaleY 为缩放前的倍数。*/
}
动画运行中为 true,停止后为 null
onAnimation 上次返回的状态值,动画停止后为 null
文本颜色(0xAARRGGBB 格式),仅原样传给绘图事件
是否允许跟随父窗体自动缩放
背景色(0xAARRGGBB 格式),每帧用它清空画布。
为 null 时:子窗口使用父窗口背景色,分层窗口为全透明。
子窗口画布总是不透明(忽略透明分量)
背景色(0xBBGGRR 格式,也可以指定 0xAARRGGBB 格式),修改后立即重绘
画布的内存位图(PARGB 格式 gdip.bitmap 对象,与 GDI 位图共用同一块内存)。
尺寸改变时会重建,不要长期保存此对象,也不要删除它。
尚未绘制过时为 null
底部坐标
是否捕获全局鼠标消息
在目标窗口区域内居中,并调整以保证显示在父窗口或屏幕工作区内。
参数 @1 可指定目标窗口或者目标窗口句柄,设为 0 表示桌面,
省略目标窗口则默认取父窗口或所有者窗口。
重新设置间隔时间或回调函数
运行时类名
删除定时器。
参数如果为 null 则忽略不执行,
否则定时器ID必须是 setInterval 函数或setTimeout函数的返回值。
请注意如果定时器被删除,ID 可能被重新分配给其他定时器。
在定时器回调函数中返回 0,false 以删除定时器是更稳妥的方式
删除定时器。
参数如果为 null 则忽略不执行,
否则定时器ID必须是 setInterval 函数或setTimeout函 数的返回值。
请注意如果定时器被删除,ID 可能被重新分配给其他定时器。
在定时器回调函数中返回 0,false 以删除定时器是更稳妥的方式
控件窗口客户区宽度,只读属性
控件窗口客户区宽度,只读属性。
关闭控件窗口
设计时类名
鼠标指针,可指定 gdi.loadCursor 支持的名字,例如 "hand",也可以指定光标句柄
是否禁用
响应 WM_GETDLGCODE 的返回值。
默认为 0x81/_DLGC_WANTARROWS | _DLGC_WANTCHARS/,方向键与字符键都交给画布。
设为 4/_DLGC_WANTALLKEYS/ 可接收全部按键(包括回车、Tab、Esc)
将 @x,@y 表示的像素值乘以窗体当前 DPI 缩放倍数并返回,
省略 @y 参数时仅返回 @x 转换后的值
窗口当前使用的 DPI 横坐标缩放系数,
该值由界面系统自动维护,任何情况下都不应手动修改,
这是一个以小数表示百分比的数,例如 1.25 表示 125%,
窗口未使用缩放或未完成缩放初始化时,值可能为 null,
如果要获取屏幕缩放设置应改用 gdi.getDpiScale 函数
窗口当前使用的 DPI 纵坐标缩放系数,
该值由界面系统自动维护,任何情况下都不应手动修改,
这是一个以小数表示百分比的数,例如 1.25 表示 125%,
窗口未使用缩放或未完成缩放初始化时,值可能为 null,
如果要获取屏幕缩放设置应改用 gdi.getDpiScale 函数
禁用 DPI 自动缩放,
不指定参数启用 DPI 自动缩放,默认已启用
前景色(0xAARRGGBB 格式),仅原样传给 onDrawForeground
控件客户区块位置(::RECT结构体)
返回gdip.font字体
注意字体生命期由控件管理
标准库 win.ui 创建的所有窗体与控件对象都拥有此属性。
win.form 创建的窗体对象返回自身,其他控件对象返回创建控件的容器窗口( _parentForm 属性 )
返回父窗口
返回相对父窗口客户区的坐标,宽,高,
参数为true返回屏幕坐标,宽,高,
x,y,cx,cy=win.getPos(hwnd)
控件区块位置(::RECT结构体)
控件屏幕区块位置(::RECT结构体)
获取顶层父窗口,这个函数会查找 orphanWindow 的父窗口
返回 X 轴、Y 轴方向缩放比例,DPI 缩放比例共 4 个返回值,
scaleX,scaleY,dpiScaleX,dpiScale 。
win.ui 创建的所有窗体与控件对象都提供此方法。
高度
控件句柄
控件ID
画板默认图像插值模式,默认为 null(使用 GDI+ 默认的双线性插值,贴图快)。
需要高质量缩放时可指定 7/_InterpolationModeHighQualityBicubic/
使窗口绘图区无效
使窗口绘图区无效
不刷新背景
uiCtrlCanvasObject.invoke(threadFunction,...invoke(
function(...){
/*
在创建当前控件的线程执行回调函数(等待并获取函数返回值)。
owner 参数指向当前控件(真实对象而非线程代理),其他附加参数转发为回调参数。
工作线程本就可以直接调此对象的属性或方法(在界面线程内执行)。
但 invoke 方法适合在界面线程批量执行连续的代码,并创建安全的闭包上下文。
此函数属于线程回调函数,应遵守线程规则,所有数据自参数与返回值交换。
不可直接访问线程函数外部的对象(不同线程拥有隔离的上下文)。
此函数主要用于跨线程调用界面线程的对象。
*/
}
)
uiCtrlCanvasObject.isDialogMessage = function(hParent,msg){/*在控件范围内替代父窗口的 isDialogMessage,
可用于在控件范围内屏蔽对话框快捷键*/}
标准库 win.ui 创建的所有窗体与控件对象都拥有此属性。
win.form 创建的窗体对象返回 true,其他控件对象返回 false 。
左侧坐标
修改窗口样式,所有参数都是可选参数,
@remove 用数值指定要移除的样式,可使用 WS 前缀的常量
@add 用数值指定要添加的样式,可使用 WS 前缀的常量
@swpFlags 可选用数值指定调整窗口选项,可使用 SWP 前缀的常量
如果指定了 @swpFlag ,则使用该参数调用::SetWindowPos
细节请参考 win.modifyStyle 函数源码
修改窗口扩展样式,所有参数都是可选参数,
@remove 用数值指定要移除的样式,可使用 WS_EX 前缀的常量
@add 用数值指定要添加的样式,可使用 WS_EX 前缀的常量
@swpFlags 可选用数值指定调整窗口选项,可使用 SWP 前缀的常量
如果指定了 @swpFlag ,则使用该参数调用::SetWindowPos
细节请参考 win.modifyStyle 函数源码
是否响应鼠标,默认为 true(不指定即为 true)。
设为 false 时鼠标穿透到下层窗口(例如父窗体),适合纯装饰的背景动画。
运行时也可以修改
如果当前是子窗口,
移除窗口的WS_CHILD样式,使窗口孤立出来悬浮于原位置,
悬浮窗口如影随形的跟随父窗口移动或改变大小,控件原来的固定边距等参数仍然有效
创建悬浮窗口,
悬浮窗口仍然显示在原来的位置,
可选参数 @transparent 如果为 true 则转换为分层透明窗口,
可选利用 @buddy 参数将只有句柄的窗口托管在悬浮窗口之上实现相同的效果,
伙伴窗口总是会保持在悬浮窗口前面,并保持相同的大小、位置
投递窗口消息到消息队列中
此函数用法请参考 ::User32.PostMessage
uiCtrlCanvasObject.preadjust = function( cx,cy,wParam ) {
/*窗口缩放后重绘前、触发 adjust 事件之前触发此事件。
所有 win.form 创建的窗体和控件都支持此事件,
与 adjust 事件不同,对 preadjust 重复赋值则覆盖而不是追加事件。
cx 参数为窗口宽度,cy 参数为窗口高度,
wParam 为 _WM_SIZE 消息参数。*/
};
在窗口所在界面线程发布消息,
运行界面线程所有所有调用subscribe函数订阅此消息的函数,
可添加任意个触发参数
立即重绘:依次回调绘图事件,然后显示到屏幕。
分层窗口模式下调用 updateLayered
刷新重绘,默认不重绘背景。
如果控件未指定 background 或 backgroundColor 属性但启用了“剪切背景”属性(默认设置)仍然会重绘背景。
刷新重绘
如果控件添加了透明样式 _WS_EX_TRANSPARENT 则重绘窗口背景
uiCtrlCanvasObject.reduce(
[/*参数 1 @array 指定要循环处理每个元素的数组或表。
@array 指定为 false 则取消之前创建的防抖单例循环。
参数 2 @callback 指定回调函数。
回调函数中可返回本次间隔延时,以毫秒为单位。
返回 0、null、false、以及不能转换为非 0 数的值中断处理。
回调参数为:当前数组元素值,当前索引,数组长度,本轮动画已执行毫秒数,
处理到数组尾部时回调参数 @1 为 null,
如果此时仍然返回可转换为非 0 数的值,将转到第一个数组元素重复循环。
参数 3 @debounce 指定是否创建为防抖单例循环,默认为 true。*/],
function(value,index,length,currentTime){
if(value){
var duration = 2000;
var x = currentTime/duration;
var change = 1+length*(x * x * x * x);
var delay = (duration / length) / change;
return delay;
}
}
)
按设计时位置参数、重新调整控件位置以适应窗口当前缩放比例。
父窗口缩放时会自动执行此操作。
默认在启动窗口消息循环时会自适应调整所有控件。
所以在启动消息循环前添加控件不必调用此函数。
如果指定了参数则调整窗口大小,
无论是否实际调整窗口大小,发送 _WM_SIZE 消息给窗口
右侧坐标
根据控件当前位置、缩放比例,更新控件的设计时位置参数。
以避免下次窗口缩放自适应调整控件当前位置更改被清除,
控件所有调整位置的属性或成员函数已自动调用此函数。
发送窗口消息
此函数用法请参考 ::User32.SendMessage
设置焦点
可选在参数中指定新的控件文本
如果启用了编辑模式,此函数将光标移动文本尾部
设置 gdip.font 字体
字体由控件接管并负责释放
uiCtrlCanvasObject.setInterval(回调函数,延时毫秒数,...setInterval(
function(){
/*参数@1指定执行函数,参数@2指定执行间隔,
可选指定一个或多个回调参数,不指定回调参数则默认为:
hwnd,message,timerId,tick,
如果在定时器中执行了win.delay等继续消息循环的代码,
在定时器退出前不会再触发同一定时器(重入)。
定时器回调函数返回数值可修改时间间隔,
返回false取消该定时器*/
},1000
)
改变父窗口
调整窗口位置或排序,所有参数可选
同时指定x,y坐标则移动位置
同时指定宽高则改变大小
指定插入位置(句柄或_HWND前缀常量)则调整Z序
设置控件区块位置(::RECT结构体)
设置控件屏幕区块位置(::RECT结构体)
禁止重绘
恢复重绘
推迟执行指定的函数或代码
此函数异步执行参数中指定的函数,不会阻塞当前代码继续执行,
延时参数是可选参数,以毫秒为单位,默认为0毫秒
可选用附加参数指定调用延时函数的实参
返回值为定时器ID
显示控件
画板默认抗锯齿模式,默认为 4/_GdipSmoothingModeAntiAlias/
立即重绘一帧并返回整帧的副本(PARGB 格式 gdip.bitmap 对象)。
不依赖窗口显示,隐藏的窗口也可以截图,适合无界面测试。
调用者负责释放返回的位图
启动动画:立即回调一次 onAnimation 并重绘,之后跟随显示器刷新每帧回调。
动画由后台线程等待系统合成器刷新后通知界面线程,不使用窗口定时器,帧间隔稳定。
参数都可以省略。
参数 @interval 省略或小于 25 毫秒时每帧回调;
大于等于 25 毫秒时按刷新周期的整数倍降频,例如 50 在 60Hz 屏幕上为每 3 帧回调一次。
参数 @beginning 指定初始状态值,默认为 0;
@change,@duration 原样传给 onAnimation。
动画运行中再次调用会重新计时
交互状态表(由 win.ui.tracker 维护),包含 hover,active,focus,disabled 等字段
停止动画并重绘一次
获取下一个支持tab控制焦点的控件
参数@1为true会自动移动焦点到该控件
参数@2为true则获取上一个控件,否则获取下一个控件
uiCtrlCanvasObject.textRenderingHint = _GdipTextRenderingHint/*画板默认文本渲染模式,默认为 4(抗锯齿,不对齐像素,移动的文字不抖动)*/
将参数 x,y 指定的屏幕坐标转换为当前控件客户区坐标。
返回 2 个值:x,y
将参数 x,y 指定的当前控件客户区坐标转换为屏幕坐标。
返回 2 个值:x,y
顶部坐标
uiCtrlCanvasObject.translateAccelerator = function(msg){
/*返回是否快捷键*/
}
重绘invalidate函数指定的区块
分层窗口模式下重绘并更新到屏幕,一般不需要直接调用。
画布调用 orphanWindow(true) 后转为透明分层窗口,背景默认透明,
可盖在其他控件上面显示粒子等特效
窗口是否有效,
窗口未关闭返回 true ,
窗口已关闭或正在关闭返回 false
当前控件窗口是否显示。
仅检查当前窗口的可见性样式(窗口 是否具有 _WS_VISIBLE 样式)。
不考虑父窗口是否可见,不考虑是否被其他窗口遮挡。
如果需要同时判断父窗口的可见性,应改用 win.isVisible 函数。
循环执行等待函数,并等待非 null 返回值。
当等待函数的第 1,第 2 个返回值不全等于 null 值,或当前控件窗口关闭都会停止等待。
等待函数返回的值也就是 wait 函数的返回值(最多转发 3 个返回值)。
如果指定超时,超过指定毫秒时返回 null 。
除等待函数以外,所有参数可选
循环执行等待函数,并等待返回真值(Truthy)。
当等待函数的首个返回值为真值(Truthy) ,或当前控件窗口关闭都会停止等待。
等待函数首个返回值也就是 waitUntil 函数的返回值(仅返回单个值)。
如果指定超时,超过指定毫秒时返回 null 。
除等待函数以外,所有参数可选
宽度
uiCtrlCanvasObject.onAnimation = function(prevState,beginning,change,timestamp,duration,deltaMs){
/*startAnimation 启动的动画每帧回调此函数,回调后自动重绘。
跟随显示器刷新(60Hz 屏幕约 16.7 毫秒一帧,高刷屏更快),按 timestamp 或 deltaMs 推进动画,不要按帧计数。
参数 @timestamp 为动画已运行的毫秒数(高精度小数),@deltaMs 为距上一帧的毫秒数,首次回调都为 0。
窗口隐藏或最小化时暂停回调,恢复后的 deltaMs 包含暂停时长(游戏应限制单帧最大步长)。
其他参数为 startAnimation 的参数,@prevState 为上次的返回值。
返回值全等于 null 停止动画(返回 false 不会停止)*/
return true;
}
uiCtrlCanvasObject.onDrawBackground = function(graphics,rc,backgroundColor,color){
/*自绘背景。每帧先用背景色铺底,然后回调此函数。
底色为 bgcolor,未指定时为父窗口背景色,透明分层窗口为全透明。
graphics 为 GDI+ 画板(gdip.graphics 对象),画在常驻的 PARGB 内存位图上。
rc 为画布区块(::RECT 结构体,设备像素),就地修改不影响上游。
backgroundColor 为背景色(0xAARRGGBB),可能为 null。
返回值不影响绘图*/
}
uiCtrlCanvasObject.onDrawComplete = function(graphics,rc,hMemBitmap){
/*一帧绘制完成,显示到屏幕之前回调此函数。
可用 owner.bitmap 访问整帧(PARGB 格式 gdip.bitmap),
例如传给 sys.mediaFoundation 的 writeFrame 录制视频。
hMemBitmap 为画布的 GDI 位图句柄(不要释放或存储此句柄)*/
}
uiCtrlCanvasObject.onDrawForeground = function(graphics,rc){
/*自绘内容,在 onDrawBackground 之后回调。
graphics 为 GDI+ 画板(gdip.graphics 对象),
rc 为画布区块(::RECT 结构体,设备像素),就地修改不影响上游*/
}
uiCtrlCanvasObject.onDropFiles = function(files){
/*接受系统拖放,files是拖放的所有文件路径名数组,嵌入编辑框必须是edit控件,richedit*/
}
uiCtrlCanvasObject.onFocusGot = function(){
/*获得键盘焦点*/
}
uiCtrlCanvasObject.onFocusLost = function(){
/*失去键盘焦点,游戏可在这里自动暂停*/
}
uiCtrlCanvasObject.onKeyDown = function(keyCode,lParam,repeat){
/*按键按下,按住不放自动重复时 repeat 为重复次数,首次按下为 0。
点击画布会自动获得键盘焦点*/
}
uiCtrlCanvasObject.onKeyUp = function(keyCode,lParam){
/*按键弹起*/
}
uiCtrlCanvasObject.onMouseActivate = function(hwndTop,hitTest,message){
return _MA_/*鼠标点击并且将要激活窗口时触发此事件
hwndTop表示被激活的顶层窗口,
hitTest参数请参考WM_NCHITTEST消息
message为鼠标消息ID
返回值的作用请参数MSDN*/
}
uiCtrlCanvasObject.onMouseClick = function(wParam,lParam){
var x,y = win.getMessagePos(lParam);
/*鼠标左键在画布上单击*/
}
uiCtrlCanvasObject.onMouseDown = function(wParam,lParam){
var x,y = win.getMessagePos(lParam);
/*鼠标左键按下,x,y 为画布客户区坐标(设备像素)*/
}
uiCtrlCanvasObject.onMouseDrag = function(wParam,lParam){
var x,y = win.getMessagePos(lParam);
/*鼠标左键按下拖动,自动捕获鼠标,允许拖出画布范围*/
}
uiCtrlCanvasObject.onMouseEnter = function(wParam,lParam){
/*鼠标移入*/
}
uiCtrlCanvasObject.onMouseLeave = function(wParam,lParam){
/*鼠标移出*/
}
uiCtrlCanvasObject.onMouseMove = function(wParam,lParam){
var x,y = win.getMessagePos(lParam);
/*鼠标移动*/
}
uiCtrlCanvasObject.onMouseUp = function(wParam,lParam){
var x,y = win.getMessagePos(lParam);
/*鼠标左键弹起*/
}
uiCtrlCanvasObject.onMouseWheel = function(flags,delta,lParam){
/*滚动鼠标滚轮,delta 为滚动量(向上为正,一格为 120)*/
}
uiCtrlCanvasObject.onRightMouseDown = function(wParam,lParam){
var x,y = win.getMessagePos(lParam);
/*鼠标右键按下*/
}
uiCtrlCanvasObject.onSize = function( width,height,wParam ) {
/*父窗口改变大小后会自动触发此事件函数。
注意 onSize 是 adjust 事件的别名,作用相同
所有 win.form 创建的窗体和控件都支持 onSize(或 adjust)事件,
重复赋值 onSize(或 adjust)会追加事件触发器而非替换原来的值。
width 参数为窗口客户区宽度,height 参数为窗口客户区高度,
wParam 参数来自 _WM_SIZE 消息的 wParam 参数,一般不用管。
一般不建议添加一个 wndproc 仅仅是为了处理 _WM_SIZE 消息,
定义 onSize 事件是更好的选择。
};*/