问题描述
我看到了许多示例,这些示例允许我打开程序并使用winwait,然后使用winexist将gui停靠到该程序。
相反,我想做的是将gui停靠在任何活动窗口上。香港专业教育学院尝试了一百万种方法,请帮忙。
(同样,当我确实将它附加到窗口时,它也不会完全居中出现,因为在主脚本中,只要我尝试这样做:
GET,HEAD
当我按热键说x y无效时,它将引发错误
以下:我自己没有完全编写的脚本。我自己想出了数学方法,但从我不记得的资料中大量借用了数学。它几乎可以满足我的需求,但不能完全满足
WinGetPos cX,cY,cW,cH,ahk_id %ChildhWnd%
offset1 := (mw / 2) - (cw /2)
解决方法
在那里几乎没有错误,并且必须在窗口切换部分添加一些额外的逻辑和魔法。
另外,我将把这个脚本转换成传统语法以外的形式,改为使用现代表达式语法。
因此,首先,在MainhWnd := WinExist()
这一行。
我们想从当前活动的窗口开始,所以让我们像这样使用A
(docs):MainhWnd := WinExist("A")
然后这部分代码:
WinGetPos,mX,mY,mW,mH,ahk_id %MainhWnd%
;WinGetPos cX,cY,cW,cH,ahk_id %ChildhWnd% <--------{why cant i put child window here-+
; |
offset2 := (mw / 2) ; - (cw /2) <------------------------with offset subtraction here <-+
cX := mX + offset2
cY := mY
Gui,show,x%cX% y%cY%
在这里您无法获得子窗口的位置,因为它尚不存在。
如果gui是预先确定的,则只需知道其宽度即可。
而且,如果其宽度不变,则也不必每次移动窗口都获得其宽度。
因此,也许只需将预定宽度存储在变量中就可以了。
如果宽度不能预先确定,您可以例如快速显示gui并抓住其宽度,然后立即将其移动。
ChildWindowWidthHalf := 349/2
WinGetPos,% "ahk_id " MainhWnd
offset2 := (mw / 2) - ChildWindowWidthHalf
cX := mX + offset2
cY := mY
Gui,% "x" cX " y" cY
在这里您还可以看到我抛弃传统语法并切换到expression的第一次出现,例如,此处将字符串与变量连接起来:ahk_id %MainhWnd%
→% "ahk_id " MainhWnd
基本上,单个%
后跟一个空格,这会强制命令的参数对表达式进行求值,而不是期望使用遗留文本参数。
如果这一切对您来说都是全新的,我建议您查阅文档上的this页。
然后介绍HookProc
函数中的问题:
HookProc(hWinEventHook,event,hwnd)
{
global MainHwnd,ChildhWnd
if (hwnd = MainHwnd)
{
SetWinDelay,-1
WinGetPos hX,hY,hW,hH,ahk_id %MainhWnd%
WinGetPos cX,ahk_id %ChildhWnd%
offset1 := (hw / 2) - (cw / 2)
X := hX + offset1
Y := hY
WinMove ahk_id %ChildhWnd%,X,Y,w%cw%,h%ch%
}
}
首先在这里global MainHwnd,ChildhWnd
我们可以放弃变量MainHwnd
,因为它对我们没有用。我们希望MainHwnd
是当前活动的窗口,而不是脚本开始时确定的一个窗口。
还可以添加此变量ChildWindowWidthHalf
。
if (hwnd = MainHwnd)
此检查对我们也没有意义,应将其完全删除。
虽然,我强烈建议您使用此if (hwnd = WinActive("A"))
替换它,以便您过滤掉与当前活动的窗口移动无关的消息。
这个:SetWinDelay,-1
没有理由每次都设置它,我们只需在脚本顶部设置一次即可。
对此:
WinGetPos hX,ahk_id %MainhWnd%
WinGetPos cX,ahk_id %ChildhWnd%
offset1 := (hw / 2) - (cw / 2)
我们对MainhWnd
并不感兴趣,如上所述,让我们用从Windows消息中直接获得的hwnd替换它。传递给HookProc
函数的第3个参数的hwnd。WinGetPos,hX,% "ahk_id " hwnd
然后我们可以摆脱获得子窗口位置的麻烦。没用了
然后让我们也切换偏移量以再次使用预定的子窗口宽度:offset1 := (hW / 2) - ChildWindowWidthHalf
然后进入WinMove
command:WinMove ahk_id %ChildhWnd%,h%ch%
使用错误。 width和height参数的前面没有w
和h
字符。无论如何,我们没有理由改变窗口的宽度或高度。它应该是这样的:WinMove,% "ahk_id " ChildhWnd,% X,% Y
现在您应该有一个 working 脚本,如下所示:
SetWinDelay,-1
hookProcAdr := RegisterCallback("HookProc")
hHook := SetWinEventHook(0x800B,0x800B,hookProcAdr,0) ; EVENT_OBJECT_LOCATIONCHANGE
Gui,+hwndChildhWnd +AlwaysOnTop
Gui,add,text,% "some text in a small gui that will move around with a notepad window"
Gui,Button,Button
MainhWnd := WinExist("A")
ChildWindowWidthHalf := 349/2
WinGetPos,% "x" cX " y" cY
return
HookProc(hWinEventHook,hwnd)
{
global ChildhWnd,ChildWindowWidthHalf
if (hwnd = WinActive("A"))
{
WinGetPos,% "ahk_id " hwnd
offset1 := (hW / 2) - ChildWindowWidthHalf
X := hX + offset1
Y := hY
WinMove,% Y
}
}
SetWinEventHook(eventMin,eventMax,hmodWinEventProc,lpfnWinEventProc,idProcess,idThread,dwFlags)
{
DllCall("CoInitialize","uint",0)
return DllCall("SetWinEventHook",eventMin,dwFlags)
}
但这只会在窗口移动时更新子窗口的位置,而不是在激活另一个窗口时更新。
因此,您还需要抓住一个窗口来获得焦点。
用一个外壳钩可以很好地做到这一点。
我将在代码中用注释来说明,这是相关的文档链接:
RegisterShellHookWindow,RegisterWindowMessage,OnMessage
;register our script to receive shell messages
DllCall("RegisterShellHookWindow",UInt,ChildhWnd)
;define a unique message which we'll monitor
MsgId := DllCall("RegisterWindowMessage",Str,"SHELLHOOK")
;monitors the the message and fires the our
;user defined function "MsgMonitor"
OnMessage(MsgId,"MsgMonitor")
MsgMonitor(wParam,lParam) ;wParam = message,lParam = hwnd
{
;HSHELL_WINDOWACTIVATED = 0x04
;HSHELL_RUDEAPPACTIVATED = 0x8004
if (wParam = 0x8004 || wParam = 0x8004)
;we can borrow the HookProc function so we dont
;need to type the same code again
;first two parameters arent needed
HookProc("whatever","whatever",lParam)
}
现在您终于应该得到像这样的成品了:
SetWinDelay,Button
;register our script to receive shell messages
DllCall("RegisterShellHookWindow",ChildhWnd)
;define a unique message which we'll monitor
MsgId := DllCall("RegisterWindowMessage","SHELLHOOK")
;monitors the the message and fires the our
;user defined function "MsgMonitor"
OnMessage(MsgId,"MsgMonitor")
MainhWnd := WinExist("A")
ChildWindowWidthHalf := 349/2
WinGetPos,% "x" cX " y" cY
return
MsgMonitor(wParam,lParam)
}
HookProc(hWinEventHook,dwFlags)
}