【pyautogui】PyAutoGUI 的简单使用

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 暂停/休眠/耗时

  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秒

  2. 临时休眠 pyautogui.sleep()

    如果需要在脚本的开始处设置一个暂停, 这样用户可以设置脚本将单击的窗口。PyAutoGUI有一个sleep()函数, 它的作用与time.sleep()函数相同(它只是让你不必在脚本中添加import time

  3. 倒计时 countdown()

    countdown()函数, 它可以打印出倒计时的数字, 给用户一个视觉上的指示, 说明脚本即将继续执行。

    import pyautogui
    pyautogui.countdown(5)
    
  4. 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)  # right
        pyautogui.move(0, 100, duration=0.25)  # down
        pyautogui.move(-100, 0, duration=0.25)  # left
        pyautogui.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 pyautogui

pyautogui.sleep(5)
distance = 300
change = 20
pyautogui.click()

while distance > 0:
    pyautogui.drag(distance, 0, duration=0.2)
    distance = distance - change
    pyautogui.drag(0, distance, duration=0.2)
    pyautogui.drag(-distance, 0, duration=0.2)
    distance = distance - change
    pyautogui.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 os

os.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键。 要用PyAutoGUIkeyDown()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 像素及匹配

  1. 获取像素 pixel()

    import pyautogui
    
    pix = pyautogui.pixel(0, 0)
    print(pix)  # (24, 24, 24)
    
  2. 像素匹配 pixelMatchesColor()

    isMatch = pyautogui.pixelMatchesColor(0, 0, (24, 24, 24))
    print(isMatch)  # True
    
    isMatch = 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 pyautogui

region = 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 pyautogui


def 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":
        return
    doAuto()


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 pyautogui
    
    fw = 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 pyautogui

fw = 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 pyperclip

pyperclip.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 askstring

rect = 0


class 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 ctypes
    scale_factor = ctypes.windll.shcore.GetScaleFactorForDevice(0)
    return scale_factor/100


def constains(rect: Rect, x, y):
    if rect.p1[0] <= x <= rect.p2[0] and rect.p1[1] <= y <= rect.p2[1]:
        return True
    return False


def 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 listener
        return False
    if 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 = None


def getListener():
    global listener
    listener = mouse.Listener(
        # on_move=on_move,
        on_click=on_click,
        on_scroll=on_scroll)


def move_window(event):
    global rect
    rect = Rect(tk.winfo_x()*scale, tk.winfo_y()*scale,
                tk.winfo_width()*scale, (tk.winfo_height()+27)*scale)


f = None


def doStart():
    global f
    getListener()
    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 = 0


def StartMove(event):
    global x, y
    x = event.x
    y = event.y


def StopMove(event):
    global x, y
    x = None
    y = None


def OnMotion(event):
    # global x, y
    deltax = event.x - x
    deltay = event.y - y
    x1 = tk.winfo_x() + deltax
    y1 = tk.winfo_y() + deltay
    tk.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 少即是多,好玩,有趣,有料!

  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值