获取更多文章和更新,请关注我的个人主页:www.leiting6.cn

上上一篇文章中,介绍了用autohotkey脚本配合快捷键在Windows下给窗口分屏,但是没有做出界面总是有点不开心,经过几天研究,终于成功了!
exe软件和ahk脚本下载地址:点击跳转

脚本源码

自认为注释已经很充分了,配合autohotkey中文帮助应该不难理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
global _WinTitle                ;要分屏的窗口名称
global _MousePosx, _MousePosy ;鼠标坐标
global EditBs, EditDfa ;Block Size和Distance from edge的编辑框
;Bs:分屏窗口的大小 Dfa:分屏窗口到屏幕底边的距离
global _ReadBs, _ReadDfa ;从ini文件中读出来的Bs和Dfa值

#Persistent ;让脚本持久运行(即直到用户关闭或遇到 ExitApp)。
#SingleInstance,force
Menu, Tray, NoStandard
programName := "WinSpliter"
Menu, Tray, Click, 1 ;单击执行OnClick
Menu, Tray, Add, 设置(config), OnClick ;增加右键菜单
Menu, Tray, Add, 退出(Quit),OnExit
Menu, Tray, Default, 设置(config)
Menu, Tray, Tip, %programName% ;鼠标悬停
;return

while True ;主程序从这里开始,无限循环检测是否有拖拽窗口行为
{
DetectWinDrag()
}

OnExit: ;右键托盘点击退出则关闭app
ExitApp
return

OnClick: ;点击托盘图标或者右键点击设置,检测是否存在设置窗口
IFWinNotExist WinSpliter Config ;如果设置窗口没打开,则打开设置界面
ShowWinConfig()
return

ShowWinConfig() ;显示设置窗口
{
IniRead, _ReadBs, config.ini, config, Bs, 60 ;从ini中读取Bs值,如果没有,则置为60
IniRead, _ReadDfa, config.ini, config, Dfa, 60 ;从ini中读取Dfa值,如果没有,则置为60

if (_ReadBs=A_space) OR (_ReadBs<0) OR (_ReadFfa=A_space) OR (_ReadDfa<0) ;增加容错率,当Bs/Dfa等于空或者小于0时不执行动作
{
MsgBox Ini value error, set default! ;如果数值异常,则报错,并重置为60
_ReadBs := 60
_ReadDfa := 60
}

WinSet, TransColor, Off ;设置窗口不需要透明,分屏窗口是透明的,这里需要关闭
Gui, Font, S15 CDefault, Verdana ;添加窗口控件
Gui, Add, Text, x22 y29 w200 h30 , 方块大小
Gui, Add, Text, x22 y119 w200 h30 , 底边距离
Gui, Font, S12 CDefault, Verdana
Gui, Add, Text, x22 y59 w200 h20 , Block size
Gui, Add, Text, x22 y149 w200 h20 , Distance from edge
Gui, Add, Edit, x242 y39 w60 h30 vEditBs, %_ReadBs%
Gui, Add, Edit, x242 y129 w60 h30 vEditDfa, %_ReadDfa%
; Generated using SmartGUI Creator 4.0
Gui, Show, x285 y202 h189 w326, WinSpliter Config
Return

GuiClose:
GuiControlGet, _VarBs,, EditBs ;从设置窗口获取Bs/Dfa数值
GuiControlGet, _VarDfa,, EditDfa
IniWrite, %_VarBs%, config.ini, config, Bs ;关闭时保存Bs/Dfa数值到ini文件
IniWrite, %_VarDfa%, config.ini, config, Dfa
IfWinExist WinSpliter Config ;增加容错率,如果有设置窗口则销毁当前GUI
Gui, Destroy
return
}

ShowWinSplit()
{
;从ini文件中读出来的Bs和Dfa值
IniRead, _ReadBs, config.ini, config, Bs, 60
IniRead, _ReadDfa, config.ini, config, Dfa, 60

BtW = %_ReadBs% ;按钮宽度
BtH := BtW*2 ;按钮高度
BtW2 := BtW*2 ;2倍按钮宽度
BtW3 := BtW*3
BtW4 := BtW*4
BtW5 := BtW*5
BtW6 := BtW*6
BtW7 := BtW*7
BtW8 := BtW*8
BtW9 := BtW*9
BtW10 := BtW*10
BtW11 := BtW*11
BtW12 := BtW*12
TextPosx := BtW*7-100
TextPosy := BtH+10
CustomColor = EEAA99 ; 可以为任意 RGB 颜色 (在下面会被设置为透明).
Gui +LastFound +AlwaysOnTop -Caption +ToolWindow ; +ToolWindow 避免显示任务栏按钮和 alt-tab 菜单项.
Gui, Color, %CustomColor%
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Gui, Add, Button, x0 y0 w%BtW% h%BtH% gTest1, 1# ;点击不同的分屏按钮会连接到各自的子程序
Gui, Add, Button, x%BtW% y0 w%BtW% h%BtH% gTest2, 2#
Gui, Add, Button, x%BtW2% y0 w%BtW% h%BtH% gTest3, 3#

Gui, Add, Button, x%BtW4% y0 w%BtW% h%BtW% gTest4, 4#
Gui, Add, Button, x%BtW5% y0 w%BtW% h%BtW% gTest5, 5#
Gui, Add, Button, x%BtW4% y%BtW% w%BtW% h%BtW% gTest6, 6#
Gui, Add, Button, x%BtW5% y%BtW% w%BtW% h%BtW% gTest7, 7#

Gui, Add, Button, x%BtW4% y%BtW% w%BtW% h%BtW% gTest6, 6#
Gui, Add, Button, x%BtW5% y%BtW% w%BtW% h%BtW% gTest7, 7#

Gui, Add, Button, x%BtW7% y0 w%BtW2% h%BtH% gTest8, 8#
Gui, Add, Button, x%BtW9% y0 w%BtW% h%BtH% ,

Gui, Add, Button, x%BtW11% y0 w%BtW% h%BtH% ,
Gui, Add, Button, x%BtW12% y0 w%BtW2% h%BtH% gTest9, 9#

Gui, Add, Text, x%TextPosx% y%TextPosy% w200 h20 +Center, Select Split Option

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 让此颜色的所有像素透明且让文本显示为半透明 (150):
WinSet, TransColor, %CustomColor% 150

_GuiPosy := A_ScreenHeight - BtH - _ReadDfa ;控制分屏窗口距离屏幕底边的距离
Gui, Show, xCenter y%_GuiPosy% NoActivate ; NoActivate 让当前活动窗口继续保持活动状态.
return

Test1: ;通过各自的子程序传递参数对当前窗口进行分屏
Split(1)
return

Test2:
Split(2)
return

Test3:
Split(3)
return

Test4:
Split(4)
return

Test5:
Split(5)
return

Test6:
Split(6)
return

Test7:
Split(7)
return

Test8:
Split(8)
return

Test9:
Split(9)
return
}

DetectWinDrag() ;检测是否有窗口拖拽行为
{ ;基本原理:当按键按下时记录当前窗口位置,延时一段时间,鼠标抬起时窗口位置变化则发生拖拽
static DragFlag = 0
CoordMode, Mouse ;获取的坐标是相对于整个屏幕的
MouseGetPos, _MousePosx, _MousePosy, _MouseWin ;获取当前鼠标的坐标和鼠标下的窗口
GetKeyState, _LButtonState, LButton, P
if _LButtonState = D ;如果鼠标是按下状态
{
if DragFlag = 0 ;且拖拽标志位为0
{
DragFlag := 1
WinGetPos, _WinPosx, _WinPosy,,, ahk_id %_MouseWin% ;将鼠标坐标暂存变量1和2都设置为当前坐标值
WinGetPos, _WinPosx2, _WinPosy2,,, ahk_id %_MouseWin%
WinGetTitle, _WinTitle, A ;获取当前窗口的标题
}
}
else if _LButtonState = U ;当鼠标抬起
{
if DragFlag = 1
{
DragFlag = 0
Sleep 500
IfWinExist ,,Select Split Option ;增加容错率,如果有分屏窗口,在摧毁当前GUI
Gui, Destroy
}
}
Sleep 50
if DragFlag = 1
{
WinGetPos, _WinPosx2, _WinPosy2,,, ahk_id %_MouseWin% ;将此时的窗口坐标存到暂存变量2中
if (_WinPosx > 0) AND (_WinPosy > 0) AND (_WinPosx2 > 0) AND (_WinPosy2 > 0) ;增加容错率,拖拽前后的坐标都大于0才进行下面动作
{
if (_WinPosx != _WinPosx2) OR (_WinPosy != _WinPosy2) ;当前后坐标不相等的时候,显示分屏窗口
{
ShowWinsplit()
}
}
}
}

Split(num) ;当前窗口三分屏函数
{
w := A_ScreenWidth/3+15 ;窗口宽度=屏幕横像素/3+15,直接除以3,3个窗口排不满,原因未知
h := A_ScreenHeight ;窗口高度=屏幕纵像素
pox_x = 0
pox_y = 0 ;窗口位置纵坐标=0,即窗口放到最顶部

if (num=1)
{
pos_x := 0 ;如果1,则窗口横坐标位置=0,即窗口放到屏幕左上角,宽度为1/3屏幕,高度为屏幕高度
pos_y := 0
w := A_ScreenWidth/3+15
h := A_ScreenHeight
}

else if(num=2)
{
pos_x := A_ScreenWidth/3
pos_y := 0
w := A_ScreenWidth/3+15
h := A_ScreenHeight
}

else if(num=3)
{
pos_x := A_ScreenWidth/3*2
pos_y := 0
w := A_ScreenWidth/3+15
h := A_ScreenHeight
}

else if(num=4)
{
pos_x := 0
pos_y := 0
w := A_ScreenWidth/2+15
h := A_ScreenHeight/2+15
}

else if(num=5)
{
pos_x := A_ScreenWidth/2
pos_y := 0
w := A_ScreenWidth/2+15
h := A_ScreenHeight/2+15
}

else if(num=6)
{
pos_x := 0
pos_y := A_ScreenHeight/2
w := A_ScreenWidth/2+15
h := A_ScreenHeight/2+15
}

else if(num=7)
{
pos_x := A_ScreenWidth/2
pos_y := A_ScreenHeight/2
w := A_ScreenWidth/2+15
h := A_ScreenHeight/2+15
}

else if(num=8)
{
pos_x := 0
pos_y := 0
w := A_ScreenWidth/3*2+15
h := A_ScreenHeight
}

else if(num=9)
{
pos_x := A_ScreenWidth/3
pos_y := 0
w := A_ScreenWidth/3*2+15
h := A_ScreenHeight
}

else
return ;如果函数传入其他数字,则return退出函数

;WinRestore %_WinTitle% ;如果当前窗口为最大化或者最小化状态,直接使用WinMove函数是不能移动和改变其大小的
;所以先使用WinRestore取消其最大化或者最小化状态,A表示当前窗口
WinMove, %_WinTitle%,, pos_x, pox_y, w, h ;调用WinMove函数,按照设定值改变窗口位置和大小
;WinMove, %_WinTitle%,, pos_x,pos_y, w, h
IfWinExist ,,Select Split Option ;增加容错率,如果有分屏窗口,在摧毁当前GUI
Gui Destroy
}

软件效果

image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png

使用方法

  • 双击WinSpliter.exe,软件会常驻后台,屏幕右下角托盘区会出现图标
  • 鼠标右键点击托盘图标,会出现菜单,设置进入软件设置界面,退出则关闭软件进程
  • 鼠标左键点击图片图标,则直接进入设置界面,方块大小决定了分屏窗口的图形大小,数值越大图形越大;底边距离决定了分屏窗口离屏幕底边的距离,数值越大离底边越远
  • 鼠标左键按下拖动任意窗口(经测试大部分窗口都有效,少部分app窗口拖动不会触发,待后续优化),按下状态稍作保持(正常情况下几百毫秒),屏幕上会出现分屏窗口;鼠标按下状态下移动到1#~9#分屏按钮上,在分屏窗口消失前迅速点击某一个分屏按钮,分屏动作立即完成

不足和限制

由于完成时间很短,现在功能还停留在初级阶段,还存在一些问题。

  • 分屏窗口触发有不灵敏和迟滞现象,甚至有时候不会触发分屏
  • 部分app窗口拖拽不会触发分屏窗口
  • 出于容错率考虑,只有当窗口的左上角顶点(实际上,窗口左上角顶点为窗口的坐标点)在屏幕内才时拖拽窗口才会触发分屏;也就是说,如果窗口拖拽前是最大化或者左上角顶点在屏幕外,拖拽则不会触发分屏,需要先脱回屏内再进行后续操作