文章目录
- 1 简介
- 2 通用功能
- 2.1 暂停/休眠/耗时
- 2.2 自动防故障功能
- 3 鼠标控制
- 3.1 移动鼠标
- 3.2 获取鼠标指针位置
- 3.3 点击鼠标
- 3.4 拖动鼠标
- 3.5 滚动鼠标
- 3.6 常用方法
- 4 键盘控制
- 4.1 输入字符串 write
- 4.2 按键操作 press
- 4.3 按下 & 释放
- 4.4 组合键 hotkey
- 4.5 键名
- 5 屏幕图像处理
- 5.1 获取屏幕尺寸(分辨率×分辨率)
- 5.2 获取屏幕快照
- 5.3 像素及匹配
- 5.4 图像定位
- `locateOnScreen`
- `locateCenterOnScreen`
- `locateAllOnScreen`
- 6 对话框
- 6.1 alert()函数
- 6.2 confirm()函数
- 6.3 prompt()函数
- 6.4 password()函数
- 特例 Windows 平台
- W:0 窗口对象介绍
- W:1 获取窗口
- W:2 操作窗口
- 汉字的输入
- 简单定位 mouseInfo
- 脚本录制
1 简介
PyAutoGUI
是一个纯Python的GUI自动化工具,通过它可以让程序自动控制鼠标和键盘的一系列操作来达到自动化测试的目的。
PyAutoGUI
设计简洁,全部被封装在pyautogui
单个模块中,因此Python程序中只要import pyautogui
之后便可通过.
符号访问pyautogui
中的函数、变量。
pyautogui
大致分为通用功能、鼠标控制、键盘控制、屏幕窗口、消息窗 5 大类。
官档: Cheat Sheet — PyAutoGUI documentation
参考: 【pyautogui】pyautogui基础简介、安装、鼠标移动、点击、截图、图像匹配查找等 - 知乎 (zhihu.com)
参考: 《 Python编程快速上手:让繁琐工作自动化(第2版) (阿尔·斯维加特) 》
2 通用功能
2.1 暂停/休眠/耗时
-
全局暂停
pyautogui.PAUSE
pyautogui.PAUSE
这个变量默认值是 0.1 秒,每条指令之间的时间间隔import pyautogui print(pyautogui.PAUSE) # 默认 0.1 秒 pyautogui.PAUSE = 0.2 # 设置全局暂停 0.2 秒
注意
pyautogui.PAUSE
为所有的pyautogui
自带api
函数增加延迟。如果不设置,则默认延迟时间是0.1秒 -
临时休眠
pyautogui.sleep()
如果需要在脚本的开始处设置一个暂停, 这样用户可以设置脚本将单击的窗口。
PyAutoGUI
有一个sleep()函数, 它的作用与time.sleep()
函数相同(它只是让你不必在脚本中添加import time
) -
倒计时
countdown()
countdown()
函数, 它可以打印出倒计时的数字, 给用户一个视觉上的指示, 说明脚本即将继续执行。import pyautogui pyautogui.countdown(5)
-
duration 、interval关键字参数
很多方法都有 duration 、interval关键字参数, 可以让操作之间有一个延迟
pyautogui.moveTo(100, 100, duration=0.25) pyautogui.click(100, 100, duration=0.25)
2.2 自动防故障功能
import pyautogui
pyautogui.FAILSAFE # 默认是True,表示启动防故障功能
如果你的程序出现错误, 无法使用键盘和鼠标关闭程序, 你可以使用PyAutoGUI
的故障安全功能, 快速地将鼠标指针滑动到屏幕的4个角之一。 每个PyAutoGUI
函数调用在执行动作后都有1/10
秒的延迟, 以便让你有足够的时间将鼠标指针移动到一个角落。
如果你发现自己需要停止PyAutoGUI
程序, 只需将鼠标指针移向角落即可。
如果设置成False, 则需要使用注销功能,才能结束程序。
3 鼠标控制
3.1 移动鼠标
-
pyautogui.moveTo()
函数将鼠标指针立即移动到屏幕的指定位置。 表示x、 y坐标的整数值分别构成了函数的第一个和第二个参数。 可选的duration整数或浮点数关键字参数指定了将鼠标指针移到目的位置所需的秒数; 如果不指定, 默认值是0, 表示立即移动(在pyautogui
函数中, 所有的duration关键字参数都是可选的)import pyautogui for i in range(10): # Move mouse in a square.pyautogui.moveTo(100, 100, duration=0.25)pyautogui.moveTo(200, 100, duration=0.25)pyautogui.moveTo(200, 200, duration=0.25)pyautogui.moveTo(100, 200, duration=0.25)
这个例子根据提供的坐标, 以正方形的模式顺时针移动鼠标指针, 移动了10次。 每次移动耗时0.25秒, 因为有关键字参数指定duration=0.25。 如果没有指定函数调用的第三个参数, 鼠标指针就会马上从一个点移到另一个点
-
pyautogui.move()
函数 以 “相对于当前的位置” 移动鼠标指针。import pyautogui for i in range(10): # Move mouse in a square.pyautogui.move(100, 0, duration=0.25) # rightpyautogui.move(0, 100, duration=0.25) # downpyautogui.move(-100, 0, duration=0.25) # leftpyautogui.move(0, -100, duration=0.25) # up
上面的例子同样以正方形的模式移动鼠标指针, 只是它从代码开始运行时鼠标指针所在的位置开始, 按正方形移动。
3.2 获取鼠标指针位置
调用pyautogui.position()
函数, 可以确定鼠标指针当前的位置。 它将返回函数调用时, 鼠标指针x、 y坐标的元组。
import pyautogui
for _ in range(10):print(pyautogui.position()) # 打印信息: Point(x=1763, y=373)pyautogui.sleep(1)if pyautogui.position() == pyautogui.Point(0, 0): # 鼠标移动到左上角,终端循环break
说明 Point 是个有名元组,
Point = collections.namedtuple("Point", "x y")
,当元组使用即可
3.3 点击鼠标
-
单击鼠标
默认情况下,
pyautogui.click()
单击将使用鼠标左键, 单击发生在鼠标指针当前所在位置。如果希望单击在鼠标指针当前位置以外的地方发生, 可以传入x、 y坐标作为可选的第一个和第二个参数。
pyautogui.click(10,10) # 鼠标点击指定位置,默认 PRIMARY 键 pyautogui.click(10,10,button='left') # 单击左键 pyautogui.click(1000,300,button='right') # 单击右键 pyautogui.click(1000,300,button='middle') # 单击中键## 为了更方便,下面的函数包装了click,不需要传参 button pyautogui.leftClick(10,10) # 单击左键 pyautogui.rightClick(10,10) # 单击右键 pyautogui.middleClick(10,10) # 单击中键## click 原型 def click( x=None, y=None, clicks=1, interval=0.0, button=PRIMARY, duration=0.0, tween=linear, logScreenshot=None, _pause=True )
-
双击鼠标
pyautogui.doubleClick(10,10)
-
三击鼠标
pyautogui.tripleClick(10,10)
-
按下 & 释放
pyautogui.mouseDown() # 鼠标按下 pyautogui.mouseUp() # 鼠标释放
click()
函数只是这两个函数调用的方便封装 .
3.4 拖动鼠标
“拖动” 意味着移动鼠标指针, 同时按住一个按键不放。 例如, 可以通过拖动文件图标, 在文件夹之间移动文件, 或在日历应用中移动预约。
pyautogui.dragTo(x, y)
绝对位置pyautogui.drag(x, y)
相对位置
import pyautoguipyautogui.sleep(5)
distance = 300
change = 20
pyautogui.click()while distance > 0:pyautogui.drag(distance, 0, duration=0.2)distance = distance - changepyautogui.drag(0, distance, duration=0.2)pyautogui.drag(-distance, 0, duration=0.2)distance = distance - changepyautogui.drag(0, -distance, duration=0.2)
在运行这个程序时, 会有5秒的休眠, 让你选中铅笔或画笔工具, 并让鼠标指针停留在画图工具的窗口上。
然后 pyautogui
将控制鼠标, 单击画图程序获得焦点。 画图程序获取焦点后,将绘制一个正方形旋转图案, 如下所示。
通过控制鼠标在Paint中绘制图像, 可以利用这个Paint程序的各种笔刷样式来创建图像, 实现其他高级功能, 如渐变或颜色填充。 你可以自己预选笔刷设置, 然后运行螺旋绘图程序
3.5 滚动鼠标
最后一个pyautogui
鼠标函数是scroll()。 你向它提供一个整型参数, 说明向上或向下滚动多少单位。 单位的意义在每个操作系统和应用上不一样, 所以你必须试验, 看看在你当前的情况下能滚动多远。
滚动发生在鼠标的当前位置。 传递正整数表示向上滚动, 传递负整数表示向下滚动。
pyautogui.scroll(-100)
另外还有一个水平滚动, (Currently just Linux)
pyautogui.hscroll(100) # 向右滚动100 pyautogui.hscroll(-100) # 向左滚动100
3.6 常用方法
函数 | 介绍 |
---|---|
moveTo(x,y,duration) | 将鼠标指针立即移动到屏幕的指定位置,耗时 duration 秒 |
move(dx,dy,duration) | 相对于"当前的位置"移动鼠标指针,耗时 duration 秒 |
position() | 获取鼠标位置 |
click(x,y,clicks,button) | 在 (x, y) 处点击鼠标 button 键 clicks 次 |
leftClick(x,y) | 左击 |
rightClick(x,y) | 右击 |
middleClick(x,y) | 中击 |
doubleClick(x,y) | 双击 |
dragTo(x, y) | 拖动鼠标,绝对位置 |
drag(x, y) | 拖动鼠标,相对位置 |
scroll(offset) | 滚动鼠标,传递正整数表示向上滚动, 传递负整数表示向下滚动 |
4 键盘控制
4.1 输入字符串 write
pyautogui.write()
函数向计算机发送虚拟按键操作。
这些操作产生什么效果, 取决于当前获得焦点的窗口和文本输入框。 可能需要先向文本框发送一次鼠标单击事件, 确保它获得焦点。
默认情况下, write() 函数将立即输出完整字符串。 但是, 你可以传入可选的第二个参数, 在每个字符之间添加短时间暂停。 例如, pyautogui.write(‘Hello, world!’,0.25)将在输出H后等待0.25秒, 输出e以后再等待0.25秒, 以此类推。 这种渐进的打字机效果, 对于较慢的应用可能有用, 它们处理按键事件的速度不够快, 跟不上PyAutoGUI
。
对于A或!这样的字符, PyAutoGUI
将自动模拟按住Shift键。
下面的代码, 针对 windows 系统
import pyautogui
import osos.system('start /max notepad.exe') # windows 平台
pyautogui.sleep(1)
pyautogui.click()
for i in range(10):pyautogui.write("Hello World!\n")
4.2 按键操作 press
pyautogui.press('enter', 5) # 连按5次回车
4.3 按下 & 释放
pyautogui.keyDown('A') : 模拟按键按下;
pyautogui.keyUp('A') : 模拟按键释放;
方便起见, PyAutoGUI
提供了press()
函数, 它调用了这两个函数, 模拟完整的按键事件。
4.4 组合键 hotkey
“快捷键”或“热键”是一种按键组合, 它调用某种应用功能。 复制选择内容的常用快捷键是Ctrl-C
( 在Windows和Linux操作系统上) 或Command-C
( 在macOS上) 。 用户按住Ctrl键, 然后按C键, 然后释放C键和Ctrl键。 要用PyAutoGUI
的keyDown()
和keyUp()
函数来做到这一点, 必须输入以下代码:
pyautogui.keyDown('ctrl')
pyautogui.keyDown('c')
pyautogui.keyUp('c')
pyautogui.keyUp('ctrl')
这相当复杂。 作为替代, 可以使用pyautogui.hotkey()
函数, 它接收多个键字符串参数, 按顺序按下, 再按相反的顺序释放。 例如对于Ctrl-C快捷键, 代码就像下面这样简单:
pyautogui.hotkey('ctrl', 'c')
4.5 键名
不是所有的键都很容易用单个文本字符来表示。
在PyAutoGUI
中, 一些特俗的键表示为短的字符串: 'esc’表示Esc键, 'enter’表示Enter键。
`pyautogui.press('win')` # 按下 windows 键
针对特殊按键表示的字符串, 可以向write()函数传递这些键字符串的列表。 例如, 以下的调用表示按a键, 然后是b键, 然后是左箭头两次, 最后是X和Y键:
pyautogui.write(['a', 'b', 'left', 'left', 'X', 'Y']) # 每一个字符串代表一个按键,可以解决特殊按键的表示方法
# 因为按下左箭头将移动键盘光标, 代码会输出 `XYab`
可以查看pyautogui.KEY_NAMES
列表
print(pyautogui.KEY_NAMES)
常用的键字符串列表
键盘按键字符串 | 含义 |
---|---|
`1234567890-= ~!@#$%^&*()_+ a~z A~Z [] {}\ | ;':",./<>? |
‘f1’, ‘f2’ … ‘f24’, ‘fn’, | 功能键 |
‘enter’ ( or ‘return’ or ‘\n’ ) | 回车键 |
‘esc’ | Esc键 |
‘shift’, ‘shiftleft’, ‘shiftright’ | Shift键 |
‘ctrl’, ‘ctrlleft’, ‘ctrlright’ | Ctrl键 |
‘alt’,‘altleft’, ‘altright’, | Alt键 |
‘\t’, ‘tab’ | Tab键 |
‘backspace’ 、 ‘delete’ | Backspace键和Delete键 |
‘pageup’ 、 ‘pagedown’ | Page Up键和Page Down键 |
‘home’ 、 ‘end’ | Home键和End键 |
‘up’ 、 ‘down’ 、 ‘left’ 、 ‘right’ | 上下左右箭头键 |
‘volumemute’ 、 ‘volumedown’ 、 ‘volumeup’ | 静音、 减小音量、 放大音量键(有些键盘没有这些键, 但 你的操作系统仍能理解这些模拟的按键) |
‘pause’ | Pause键 |
‘capslock’ 、 ‘numlock’ 、 ‘scrolllock’ | Caps Lock键、 Num lock键和Scroll Lock键 |
‘insert’ | Ins键或Insert键 |
‘printscreen’ | Prtsc键或Print Screen键 |
win’, ‘winleft’, ‘winright’ | Win键(在Windows操作系统上) |
‘command’ | Command键(在macOS上) |
‘option’ | Option键(在macOS上) |
5 屏幕图像处理
5.1 获取屏幕尺寸(分辨率×分辨率)
print(pyautogui.size()) # Size(width=3840, height=2160)
pyautogui.size()
函数返回两个整数的元组, 包含屏幕的宽度和高度的像素数。 返回的是屏幕的实际尺寸,和缩放比率没有关系
获取缩放比例的方法
import ctypes scale_factor = ctypes.windll.shcore.GetScaleFactorForDevice(0)
5.2 获取屏幕快照
PyAutoGUI
拥有屏幕快照的功能,可以根据当前屏幕的内容创建图形文件。 这些函数返回一个pillow的Image对象, 包含当前屏幕的内容。
# 全屏截图
im = pyautogui.screenshot()
# 保存截图
im.save("hello.jpg") # 区域截图,并保存到im.png
im = pyautogui.screenshot('im.png', region=(0, 0, 830, 300))
现在可以调用 im
对象的 Image 类的方法。
5.3 像素及匹配
-
获取像素
pixel()
import pyautoguipix = pyautogui.pixel(0, 0) print(pix) # (24, 24, 24)
-
像素匹配
pixelMatchesColor()
isMatch = pyautogui.pixelMatchesColor(0, 0, (24, 24, 24)) print(isMatch) # TrueisMatch = pyautogui.pixelMatchesColor(0, 0, (25, 24, 24)) print(isMatch) # False# tolerance 容错 isMatch = pyautogui.pixelMatchesColor(0, 0, (25, 25, 23), tolerance=1) # 允许差值为1 print(isMatch) # True
5.4 图像定位
如果事先不知道PyAutoGUI
应该单击哪里, 该怎么办? 可以使用图像识别功能, 向PyAutoGUI
提供希望单击的图像, 让它去弄清楚坐标。
locateOnScreen
locateOnScreen()
函数返回, 是屏幕上首次发现该图像时左边的x坐标、 顶边的y坐标、 宽度以及高度。
例如:事先截取了图像,比如屏幕左下角的 window 图片,保存为submit.png, 那么locateOnScreen('submit.png')
函数将返回图像所在处的坐标。
import pyautoguiregion = pyautogui.locateOnScreen('submit.png')
print(region) # Box(left=0, top=2080, width=96, height=80)
print(pyautogui.center(region)) # Point(x=48, y=2120)
请注意, 要成功识别, 屏幕上的图像必须与提供的图像完全匹配。 即使只差一个像素, locateOnScreen()
函数也会引发ImageNotFoundException
异常。
locateCenterOnScreen
定位并求中间点的位置
center = pyautogui.locateCenterOnScreen('submit.png')
print(center) # Point(x=48, y=2120)
增加容错率 指定查找范围 以及可信度
region = pyautogui.locateOnScreen('submit.png', grayscale=True, region=(0, 1000, 100, 2080), confidence=0.9)
-
将
grayscale=True
传递给locateOnScreen
,以略微加速(大约 30%)。这降低了图像和截图的颜色饱和度,加快了定位速度,但可能会导致错误匹配。 -
将
region=(0, 1000, 100, 2080)
传递给locateOnScreen
,指定查找范围 -
将
confidence=0.9
传递给locateOnScreen
,指定可信赖度
locateAllOnScreen
如果该图像在屏幕上能够找到多处,locateAllOnScreen()
函数将返回一个Generator对象。 可以将它传递给list(), 返回一个元组的列表
list(pyautogui.locateAllOnScreen('submit.png'))
6 对话框
PyAutoGUI
利用 PyMsgBox
中的消息框函数提供了一种跨平台的纯 Python
方法来显示 javascript
样式的消息框。
6.1 alert()函数
单击按钮后返回 button
的值
ret = pyautogui.alert(text='text', title='title', button='alert')
print(ret) # alert
6.2 confirm()函数
显示带有多个按钮的消息框。按钮的数量和文字可以自己设置。单击按钮返回该按钮的文本。
pyautogui.confirm(text='text', title='title') # 默认按钮值
pyautogui.confirm(text='text', title='title', buttons=['OK', 'Cancel', '狠心退出']) # 自定义按钮值
6.3 prompt()函数
显示一个包含 确认,取消 按钮和文本输入栏的消息框,用户可以输入指定内容。当点击确认按钮后,返回输入框中的值;若点击取消,则返回 None
pyautogui.prompt(text='text', title='title', default='请输入文本信息')
6.4 password()函数
显示一个包含 确认,取消 按钮和文本输入栏的消息框,输入的字符显示为"*"。如果点击确认则返回输入的文本;如果单击“取消”,则为 None
。
pyautogui.password(text='text', title='title', default='密码', mask='*')
利用对话框,可以很方便的设置需要操作的对象. 前面的案例都是使用 sleep() 方法来阻塞程序,等待用户选择好操作的对象。现在利用对话框就很方便了。例如:
import pyautoguidef doAuto():for i in range(10):pyautogui.write("Hello World!\n", 0.1)def main():ret = pyautogui.confirm(text='text', title='title')if ret != "OK":returndoAuto()if __name__ == '__main__':main()
完全可以打开记事本,然后点击确定,就可以让代码继续执行下去
特例 Windows 平台
W:0 窗口对象介绍
Win32Window 对象的属性:
-
left、 right、 top、 bottom: 一个整数, 表示窗口边的x或y坐标。
-
topleft、 topright、 bottomleft、 bottomright: 两个整数的命名元组, 表示窗
口角的(x, y)坐标。 -
midleft、 midright、 midleft、 midright: 两个整数的命名元组, 表示窗口边中
间的(x, y)坐标。 -
width, height: 一个整数, 表示窗口的一个维度, 以像素为单位。
-
size: 两个整数的命名元组, 表示窗口的(宽度, 高度) 。
-
area: 一个整数, 表示窗口的面积, 以像素为单位。
-
center: 两个整数的命名元组, 表示窗口的中心(x, y) 坐标。
-
centerx、 centery: 一个整数, 表示窗口中心的x或y坐标。
-
box: 4个整数的命名元组, 表示窗口(左侧、 顶部、 宽度、 高度) 。
-
title: 窗口顶部标题栏中的文本字符串。
import pyautoguifw = pyautogui.getActiveWindow() print(fw) print(fw.left) print(fw.topleft) print(fw.midleft) print(fw.width, fw.height) print(fw.size) print(fw.area) print(fw.center) print(fw.centerx, fw.centery) print(fw.box) print(fw.title)
-
属性方法:
- isMinimized
- isMaximized
- isActive
- title
- visible
W:1 获取窗口
-
获取活动窗口
pyautogui.getActiveWindow() -> Win32Window
获取所有可见窗口
pyautogui.getAllWindows()
-
获取所有包含点(x, y) 的可见窗口的Window对象列表
pyautogui.getWindowsAt(x, y)
-
获取所有在标题栏中包含字符串title的可见窗口的Window对象的列表
pyautogui.getWindowsWithTitle(title)
-
获取所有可见窗口的字符串列表
pyautogui.getAllTitles()
W:2 操作窗口
窗口属性不仅可以告诉你窗口的大小和位置, 还可以做更多的事情。 你也可以设置它们的值, 以便调整窗口大小或移动窗口。
import pyautoguifw = pyautogui.getActiveWindow()if bool(fw.isMaximized):fw.restore()
pyautogui.sleep(2)
fw.top += 300
或者使用下面的方法
-
win.move(xOffset, yOffset)
-
win.moveTo(newLeft, newTop)
-
win.resize(widthOffset, heightOffset)
-
win.resizeTo(width, height)
-
win.maximize() # 最大化
-
win.minimize() # 最小化
-
win.restore() # 如果是最大/小化,则恢复成正常状态
-
win.close()
-
win.position() # returns (x, y) of top-left corner
-
win.moveRel(x=0, y=0) # moves relative to the x, y of top-left corner of the window
-
win.clickRel(x=0, y=0, clicks=1, interval=0.0, button=’left’) # click relative to the x, y of top-left corner of the window
汉字的输入
从pyautogui
控制键盘的方式来看,这个库只管模拟发送按键,至于这些按键能不能变成中文,还要依靠中文输入法来实现。
这种方式比较烦。
更为便捷的方式是使用 pyperclip 库, 如下所示
import pyautogui
import pyperclippyperclip.copy("你好,世界\n")
pyautogui.hotkey('ctrl', 'v')
简单定位 mouseInfo
编写一个能自动单击屏幕的程序的难点之一, 就是找到你想单击的物品的x坐标和y坐标。 pyautogui.mouseInfo()函数可以帮助你解决这个问题。
pyautogui.mouseInfo()
函数可以单独使用,而不是作为程序的一部分。 它启动了一个名为MouseInfo
的小应用程序, 该应用程序是PyAutoGUI
的一部分。
import pyautogui
pyautogui.mouseInfo()
该窗口提供了关于鼠标指针当前位置的信息, 以及鼠标指针处的像素的颜色, 以3个整数的RGB元组和十六进制值的形式显示。 颜色本身会出现
在窗口中的颜色框中。
- Copy All、 Copy XY、 Copy RGB和Copy RGB Hex按钮将对应的信息复制到剪贴板上。
- Log All、 Log XY、 Log RGB和Log RGB Hex按钮将对应的信息写入窗口中的大文本字段。
- 可以通过单击Save Log按钮, 保存这个文本字段中的文本。
- 可以通过使用 F1, F2 … F8 功能键类实现
有了一些关键点的坐标,可以在以后的PyAutoGUI
脚本中使用这些坐标
脚本录制
PyAutoGUI
中居然没有回调函数,也就是我想要在某个点按下鼠标,然后打印出鼠标的位置, 基本上是不可能的。不过好在还有一个库 pynput
, 它有键鼠监听器,只是自动化执行脚本的时候,没有过场动画之类。而且没有考虑到屏幕缩放。
所以最好的方式,是用 pynput
录制脚本,用 pyautogui
执行脚本。
本来还打算写一篇 pynput
的文章了,但是还是放弃了,PyAutoGUI
就耗了我一天时间,实在没兴趣再写了。
有兴趣可以参考 官档 pynput Package Documentation — pynput 1.7.6 documentation
直接附上示例代码:
from tkinter import Tk, Button, Label
from pynput import mouse
# import pymsgbox
from tkinter.simpledialog import askstringrect = 0class Rect:def __init__(self, x, y, width, height):self.p1 = (x, y)self.p2 = (x+width, y+height)def __str__(self) -> str:return str(self.p1) + str(self.p2)def getScreenRatio2():import ctypesscale_factor = ctypes.windll.shcore.GetScaleFactorForDevice(0)return scale_factor/100def constains(rect: Rect, x, y):if rect.p1[0] <= x <= rect.p2[0] and rect.p1[1] <= y <= rect.p2[1]:return Truereturn Falsedef on_move(x, y):print('Pointer moved to {0}'.format((x, y)))def on_click(x, y, button, pressed):print(f'{'press' if pressed else 'release'}({button}) at {(x, y)}')if button == mouse.Button.middle:# Stop listenerreturn Falseif pressed:print(constains(rect, x, y), rect, x, y)if not constains(rect, x, y):f.write(f"pyautogui.moveTo({x, y}, duration=dur)\n") # 默认左键f.write("pyautogui.click(duration=dur)\n\n") # 默认左键def on_scroll(x, y, dx, dy):print('Scrolled {0} at {1}'.format('down' if dy < 0 else 'up',(x, y)))# ...or, in a non-blocking fashion:
listener = Nonedef getListener():global listenerlistener = mouse.Listener(# on_move=on_move,on_click=on_click,on_scroll=on_scroll)def move_window(event):global rectrect = Rect(tk.winfo_x()*scale, tk.winfo_y()*scale,tk.winfo_width()*scale, (tk.winfo_height()+27)*scale)f = Nonedef doStart():global fgetListener()listener.start()b1.config(state='disabled')b2.config(state='normal')f = open(filename, 'w', encoding='utf-8')f.write("import pyautogui\n")f.write("pyautogui.PAUSE = 0.2\n")f.write("dur = 0.25\n")def doStop():listener.stop()b1.config(state='normal')b2.config(state='disabled')f.close()def doQuit():if listener:listener.stop()tk.destroy()x = y = 0def StartMove(event):global x, yx = event.xy = event.ydef StopMove(event):global x, yx = Noney = Nonedef OnMotion(event):# global x, ydeltax = event.x - xdeltay = event.y - yx1 = tk.winfo_x() + deltaxy1 = tk.winfo_y() + deltaytk.geometry("+%s+%s" % (x1, y1))# tk.geometry("+%s+%s" % (event.x, event.y))if __name__ == '__main__':# filename = pymsgbox.prompt('请输入脚本名称', '脚本', default='自动生成脚本_pyautogui.py')filename = askstring(title="脚本", prompt="请输入脚本名称",initialvalue="自动生成脚本_pyautogui.py")print(filename)if filename:tk = Tk()scale = getScreenRatio2()tk.overrideredirect(1)tk.attributes('-topmost', 'true')grip = Label(bitmap="gray25")b1 = Button(tk, text="🐟", command=doStart, state='normal', fg="red")b2 = Button(tk, text="🛑", command=doStop, state='disabled', fg="red")b3 = Button(tk, text="❌", command=doQuit)grip.grid(row=0, column=0)grip.bind("<ButtonPress-1>", StartMove)grip.bind("<ButtonRelease-1>", StopMove)grip.bind("<B1-Motion>", OnMotion)b1.grid(row=0, column=1)b2.grid(row=0, column=2)b3.grid(row=0, column=3)tk.bind('<Configure>', move_window)tk.mainloop()
小程序说明:
- 输入脚本文件名称
- b1 开始录制
- b2 停止录制
- b3 退出程序
- grip 用来实现拖动界面
最初只是想写个简单的信息打印, 然后就想着直接输出 pyautogui
的脚本文件, 然后又想着还是加个控制按钮吧, 先用 ttk.Button
觉得太大,然后又用回tk.Button
, 感觉窗口框架比按钮还长, 更丑了, 又写成无框样式, 觉得界面没法移动, 又去学习无框拖动方法. 最后写完了,感觉整个代码好乱,结构一点也不清楚,不想看了,有机会再重构,至少可以把无框界面那块给封装成一个类
最后说一句写这个代码的感受,Python 真的太简洁了, 能够随心所欲地尝试。
Python 少即是多,好玩,有趣,有料!