通过 ScrollBind 类为 GUI 界面提供了滚动页面功能,可以将一个子窗口绑定到父控件,实现滚动区域的自动调整和支持鼠标滚轮、方向键、翻页键滚动。
; ScrollBind(简单生成可滚动的子页面) By FeiYue
;
; 使用方法:
; 参考下面的例子,将父控件和GUI子窗口绑定即可
#NoEnv
#SingleInstance force
; 在GUI创建过程避免中途触发GuiSize线程
Critical, % (bak:=A_IsCritical)?"":""
; 先备份GUI主窗口的句柄
Gui, +Hwndgui_id -DPIScale +ReSize ; +AlwaysOnTop
Gui, Margin, 15, 15
Gui, Color, DDEEFF
Gui, Font, s12
Gui, Add, Tab3, HwndhMyTab w350, 第1页|第2页|第3页|第4页
For k,v in StrSplit("第1页|第2页|第3页|第4页", "|") {
Gui, Tab, % k
; 添加一个文本控件作为父控件,获取父控件句柄
Gui, Add, Text, Hwndparent_id w300 h400
;----------------------------
; 新建一个GUI子窗口,获取子窗口句柄
Gui, New, +Hwndsub_id -DPIScale
Gui, Color, DDEEFF
Gui, Font, s12
Loop 50
Gui, Add, Button, w250 gRunButton, %v% %A_Index%
; 利用ScrollBind类,将GUI子窗口绑定到父控件中
ScrollBind.Bind(parent_id, sub_id)
; 绑定之后备份父子两个句柄用于调整大小
parent_id%k%:=parent_id, sub_id%k%:=sub_id
;----------------------------
; 利用GUI主窗口的句柄返回默认的GUI
Gui, %gui_id%: Default
}
Gui, Tab
; 获取Tab3控件的高度用于编辑控件对齐
GuiControlGet, p, Pos, %hMyTab%
Gui, Add, Edit, ym w500 h%pH% HwndhMyEdit
Gui, Show, Center, 简单生成可滚动的子页面 - By FeiYue
; 在GUI创建完毕后允许GuiSize线程触发
Critical, %bak%
; 可选的左键任意拖动窗口
OnMessage(0x201, Func("LButton_Down"))
LButton_Down() {
if (A_Gui!="") and (A_GuiControl="")
SendMessage, 0xA1, 2
}
return
; 使用函数可避免修改全局变量
RunButton() {
k:=A_GuiControl
Gui, +OwnDialogs
MsgBox, 4096, Tip, % k
}
; 使用函数可避免修改全局变量
GuiSize() {
global
local id, w, h, k, v
Critical
; 只响应GUI主窗口的调整大小消息
Gui, +Hwndid
if (ErrorLevel=1) or (id!=gui_id)
return
w:=Floor(A_GuiWidth-350-15*3), h:=Floor(A_GuiHeight-15*2)
GuiControl, Move, %hMyEdit%, w%w% h%h%
GuiControl, Move, %hMyTab%, h%h%
; 对GUI子窗口的调整大小,先确保创建完毕
For k,v in StrSplit("第1页|第2页|第3页|第4页", "|")
if (parent_id%k% and sub_id%k%) {
h:=Floor(A_GuiHeight-15*2-60)
GuiControl, Move, % parent_id%k%, h%h%
ScrollBind.ReSize(sub_id%k%, 300, h)
}
}
GuiClose() {
ExitApp
}
;===== 下面是 ScrollBind 类 =====
; 这个类只用于绑定父控件和GUI子窗口,不干涉子窗口的生成
Class ScrollBind { ;-- 类开始
__New(args*) {
; 不生成实体对象,只使用类对象本身
return this.base
}
; 核心的绑定函数,参数是父控件的句柄和GUI子窗口的句柄
Bind(parent_id, sub_id) {
static init:=0
if !DllCall("IsWindow", "Ptr",parent_id)
or !DllCall("IsWindow", "Ptr",sub_id)
return
if (!init) {
init:=1, this.Scroll_ID:=[]
OnMessage(WM_MOUSEWHEEL:=0x20A, this.WM_MOUSEWHEEL.Bind(this))
OnMessage(WM_KeyDown:=0x100, this.WM_KEYDOWN.Bind(this))
OnMessage(WM_VSCROLL:=0x115, this.WM_VSCROLL.Bind(this))
OnMessage(WM_HSCROLL:=0x114, this.WM_VSCROLL.Bind(this))
}
; 避免Gui,Show触发GuiSize线程中断当前线程
Critical, % (bak:=A_IsCritical)?"":""
VarSetCapacity(rect,16)
DllCall("GetClientRect", "Ptr",parent_id, "Ptr",&rect)
w:=NumGet(rect, 8, "Int"), h:=NumGet(rect, 12, "Int")
Gui, %sub_id%: +Parent%parent_id% -Caption +ToolWindow -Border
Gui, %sub_id%: Show, NA x0 y0 w%w% h%h%
this.UpdateScrollBars(sub_id, w, h)
this.Scroll_ID[parent_id]:=sub_id
this.Scroll_ID[sub_id]:=sub_id
Critical, %bak%
}
; 调整GUI子窗口的大小
ReSize(sub_id, w, h) {
DllCall("MoveWindow","Ptr",sub_id,"int",0,"int",0,"int",w,"int",h,"int",1)
this.UpdateScrollBars(sub_id, w, h)
}
; 当鼠标在可滚动的子窗口上时,可以用鼠标滚轮来滚动
WM_MOUSEWHEEL(wParam) {
Critical
if (A_Gui="")
return
MouseGetPos,,,, id, 2
if (this.Scroll_ID[id])
or (this.Scroll_ID[id:=DllCall("GetParent","ptr",id)])
or (this.Scroll_ID[id:=DllCall("GetParent","ptr",id)])
{
id:=this.Scroll_ID[id], wParam:=(wParam>>16&0xFFFF)>0x7FFF
Loop 4
this.WM_VSCROLL(wParam, 0, 0x115, id)
return 1
}
}
; 当鼠标在可滚动的子窗口上时,可以用方向键和翻页键来滚动
WM_KEYDOWN(wParam) {
static arr:={ GetKeyVK("Up"):0, GetKeyVK("Down"):1
, GetKeyVK("PgUp"):2, GetKeyVK("PgDn"):3 }
Critical
if (A_Gui="") or (!arr.HasKey(wParam))
return
MouseGetPos,,,, id, 2
if (this.Scroll_ID[id])
or (this.Scroll_ID[id:=DllCall("GetParent","ptr",id)])
or (this.Scroll_ID[id:=DllCall("GetParent","ptr",id)])
{
id:=this.Scroll_ID[id], wParam:=arr[wParam]
this.WM_VSCROLL(wParam, 0, 0x115, id)
return 1
}
}
; thanks lexikos, FeiYue 作了改进
UpdateScrollBars(GuiHwnd, GuiWidth, GuiHeight) {
static SIF_RANGE:=1, SIF_PAGE:=2, SB_HORZ:=0, SB_VERT:=1
if (GuiWidth<0 or GuiHeight<0)
return
DetectHiddenWindows, % (bak:=A_DetectHiddenWindows)?"On":"On"
WinGet, List, ControlListHwnd, ahk_id %GuiHwnd%
DetectHiddenWindows, %bak%
Left:=Top:=9999, Right:=Bottom:=0
Loop, Parse, List, `n
{
GuiControlGet, c, Pos, %A_LoopField%
Left:=Min(Left, cX), Top:=Min(Top, cY)
Right:=Max(Right, cX+cW), Bottom:=Max(Bottom, cY+cH)
}
Left-=8, Top-=8, Right+=8, Bottom+=8
ScrollWidth:=Right-Left, ScrollHeight:=Bottom-Top
;-- Initialize SCROLLINFO
VarSetCapacity(si, 28, 0)
NumPut(28, si) ; cbSize
NumPut(SIF_RANGE | SIF_PAGE, si, 4) ; fMask
;-- Update horizontal scroll bar
NumPut(ScrollWidth, si, 12) ; nMax
NumPut(GuiWidth, si, 16) ; nPage
DllCall("SetScrollInfo", "Ptr",GuiHwnd, "uint",SB_HORZ, "Ptr",&si, "int",1)
;-- Update vertical scroll bar
NumPut(ScrollHeight, si, 12) ; nMax
NumPut(GuiHeight, si, 16) ; nPage
DllCall("SetScrollInfo", "Ptr",GuiHwnd, "uint",SB_VERT, "Ptr",&si, "int",1)
x:=(Left<0 && Right<GuiWidth) ? Min(-Left, GuiWidth-Right) : 0
y:=(Top<0 && Bottom<GuiHeight) ? Min(-Top, GuiHeight-Bottom) : 0
if (x || y)
DllCall("ScrollWindow", "Ptr",GuiHwnd, "int",x, "int",y, "int",0, "int",0)
}
; thanks lexikos, FeiYue 作了改进
WM_VSCROLL(wParam, lParam, msg, hwnd) {
static SIF_ALL:=0x17, SCROLL_STEP:=10
Critical
bar:=(msg=0x115)
VarSetCapacity(si, 28, 0), NumPut(28, si, "UInt") ; cbSize
NumPut(SIF_ALL, si, 4, "UInt") ; fMask
if !DllCall("GetScrollInfo", "Ptr",hwnd, "Int",bar, "Ptr",&si)
return
VarSetCapacity(rect,16), DllCall("GetClientRect", "Ptr",hwnd, "Ptr",&rect)
h:=bar ? NumGet(rect, 12, "Int") : NumGet(rect, 8, "Int")
new_pos:=old_pos:=NumGet(si, 20, "UInt") ; nPos
Switch (wParam & 0xFFFF) {
Case 0: new_pos-=SCROLL_STEP ; SB_LINEUP
Case 1: new_pos+=SCROLL_STEP ; SB_LINEDOWN
Case 2: new_pos-=h-SCROLL_STEP ; SB_PAGEUP
Case 3: new_pos+=h-SCROLL_STEP ; SB_PAGEDOWN
Case 4, 5: new_pos:=wParam>>16 ; SB_THUMBPOSITION, SB_THUMBTRACK
Case 6: new_pos:=NumGet(si, 8, "Int") ; nMin ; SB_TOP
Case 7: new_pos:=NumGet(si, 12, "Int") ; nMax ; SB_BOTTOM
Default: return
}
min:=NumGet(si, 8, "Int") ; nMin
max:=NumGet(si, 12, "Int") - NumGet(si, 16, "UInt") ; nMax-nPage
new_pos:=Min(Max(min, new_pos), max)
(bar) ? (x:=0, y:=old_pos-new_pos) : (x:=old_pos-new_pos, y:=0)
DllCall("ScrollWindow", "Ptr",hwnd, "Int",x, "Int",y, "Int",0, "Int",0)
NumPut(new_pos, si, 20, "Int") ; nPos
DllCall("SetScrollInfo", "Ptr",hwnd, "Int",bar, "Ptr",&si, "Int",1)
}
} ;-- 类结束
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。

评论(0)