【pyautogui】PyAutoGUI 的简单使用

news2024/11/17 11:45:32

文章目录

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

  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 少即是多,好玩,有趣,有料!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1517032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VC-旅游系统-213-(代码+说明)

转载地址: http://www.3q2008.com/soft/search.asp?keyword旅游系统 旅游信息管理系统开题报告 一、研究目的 旅游信息管理系统能帮助旅行社在游客的市场开拓、游客的信息管理、客户服务等方面进行综合处理。使旅行社能够准确的掌握客户的市场动态&#xff0c;充分了解对客户…

【endnote】advanced science

今天投稿advanced science时&#xff0c;用endnote改格式&#xff0c;一大堆问题 发现标准引用格式如下&#xff0c;显示所有作者&#xff0c;不显示titile等 首先&#xff0c;上网下载了advanced science的格式ens&#xff0c;然后导入到endnote 发现不对&#xff0c;于是乎调…

【Python】科研代码学习:十二 PEFT(高效参数的训练,Adapter适配器)

【Python】科研代码学习&#xff1a;十二 PEFT PEFT简单训练教程简单推理教程Adapter 适配器Merge Adapter 架构关系 PEFT 【HF官网-Doc-PEFT&#xff1a;API】 首先日常问题&#xff0c;是什么&#xff0c;为什么&#xff0c;怎么用 PEFT (Prameter-Efficient Fine-Tuning)&a…

如何在数据库中存储小数:FLOAT、DECIMAL还是BIGINT?

前言 这里还是用前面的例子: 在线机票订票系统的数据表设计。此时已经完成了大部分字段的设计&#xff0c;可能如下: CREATE TABLE flights ( flight_id INT AUTO_INCREMENT PRIMARY KEY, flight_number VARCHAR(10), departure_airport_code VARCHAR(3), arrival_air…

HAProxy——高性能负载均衡器

目录 一.常见的Web集群调度器 二.HAProxy基本介绍 1.HAProxy是什么&#xff1f; 2.HAProxy的特性 3.HAProxy常用的8种负载均衡调度算法 3.1 轮询&#xff1a;RR&#xff08;Round Robin&#xff09; 3.2 最小连接数&#xff1a;LC&#xff08;Least Connections&#xff…

【TB作品】MSP430单片机,音乐播放器,四首音乐,八音盒,Proteus仿真

文章目录 题目要求仿真结果实验报告&#xff1a;基于MSP430单片机的八音盒设计实验目的实验设备实验原理总结 代码和仿真图 题目要求 八音盒 本设计利用MSP430单片机结合内部定时器及LED/LCD,设计一个八音盒,按下单键可以演奏预先设置的歌曲旋律。 基本要求: 使用LED/LCD显示器…

分销商城小程序开发可以为商家带来哪些好处

分销小程序的开发帮助商家更多地维系客户&#xff0c;市场竞争越来越激烈&#xff0c;各大商家争抢流量&#xff0c;拼命获客&#xff0c;小程序分销堪比商家的营销神器。 分销商城小程序是指商家通过小程序分销与分销商建立利润分享合作伙伴关系&#xff0c;允许分销商将参与小…

C语言例3-11:使用算术运算符的例子。

代码如下&#xff1a; int main(void) {int a12, b10;float c2.0, d0.5;double e6.5, f13.0;printf("-a %d\n",-a);printf("ab %d\n",ab);printf("a-b %d\n",a-b);printf("a*b %d\n",a*b);printf("a/b %d\n"…

第 7 场 小白入门赛

第5题 &#xff1a;兽之泪【算法赛】 AC_Code:C #include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include<stack> #include<cmath> #include <unordered_set> #include &…

【数据结构高阶】图

目录 一、图的基本概念 二、 图的存储结构 2.1 邻接矩阵 2.2.1 邻接矩阵存储模式的代码实现 2.2.2 邻接矩阵存储的优缺点 2.2 邻接表 2.2.1 无向图的邻接表 2.2.2 有向图的邻接表 2.2.3 邻接表存储模式的代码实现 2.2.4 邻接表存储的优缺点 三、图的遍历 3.1 图的…

[linux]信号处理:信号编码、基本API、自定义函数和集合操作的详解

一、信号的概述 1、定义 信号是 Linux 进程间通信的最古老的方式。信号是软件中断&#xff0c;它是在软件层次 上对中断机制的一种模拟&#xff0c;是一种异步&#xff08;不等待&#xff09;通信的方式 。信号可以导致一个正在运行的进程被 另一个正在运行的异步进程中断&a…

RHEL8部署baichuan2环境

前置 1、安装NVIDIA驱动 https://www.nvidia.cn/Download/index.aspx?langcn 阿里云 Alibaba Cloud Linux 3.2104 LTS 64位&#xff0c;需要选择RHEL8&#xff0c;如果没有RHEL8&#xff0c;则选最下面那个选择所有操作系统 点击搜索&#xff0c;下载这里有安装步骤&#x…

Datawhale【Sora原理与技术实战】| 学习笔记3

目录 一. 训练 Sora 模型二. 数据预处理三. 视频 VQVAE四. Diffusion Transformer 一. 训练 Sora 模型 Open-Sora 在下图中总结了 Sora 可能使用的训练流程&#xff1a; 链路: 二. 数据预处理 目前主流 LLM 框架缺乏针对 video 数据 统一便捷的管理和处理能力&#xff0c;…

天水麻辣烫:麻辣鲜香,地城风情尽在其中

天水麻辣烫&#xff0c;这道源自甘肃天水的地道美食&#xff0c;早已成为当地饮食文化中不可或缺的一部分。追溯其源头&#xff0c;它脱胎于上世纪80、90年代的麻辣粉&#xff0c;那时的麻辣粉&#xff0c;以土豆粉和土豆片为主&#xff0c;辅以香辣的油泼辣子&#xff0c;简单…

【C++ 】stack 和 queue

1. 标准库中的stack stack 的介绍&#xff1a; 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行 元素的插入与提取操作 2. stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其…

月结常见工单异常情况处理

1. 上月已经结算的工单&#xff0c;本月打开投料或者报工&#xff0c;或者增加产出 或者撤销报工修正报工 如果针对结算的订单&#xff0c;打开重新投料。 月末对工单重新结算&#xff0c;转出差异 KKS2单个处理&#xff08;KKS1集中处理&#xff09; 差异计算 KO88单个结算…

ThreadLocal基本原理

ThreadLocal基本原理 一、定义 ThreadLocal是java中所提供的线程本地存储机制&#xff0c;可以利用改机制将数据缓存在线程内部&#xff0c;该线程可以在任意时刻、任意方法中获取数据 二、底层原理 ThreadLocal底层是通过ThreadLocalMap来实现的&#xff0c;每个Thread对象中…

短剧APP系统开发:打造全新的掌上剧场体验

随着移动互联网的普及和人们娱乐方式的多样化&#xff0c;短剧已经成为现代人生活中不可或缺的一部分。为了满足用户对高质量、便捷观看短剧的需求&#xff0c;我们致力于开发一款功能全面、操作简便的短剧APP系统&#xff0c;为用户带来前所未有的掌上剧场体验。 一、系统开发…

AJAX 04 回调函数地狱和 Promise 链式调用、async 和 await、事件循环

AJAX 学习 AJAX 04 进阶01 同步代码和异步代码02 回调函数地狱和 Promise 链式调用(1) 回调函数地狱(2) Promise 链式调用(3) Promise 链式应用 03 async 和 await(1) async 和 await 使用(2) async函数和await捕获错误 04 事件循环-EventLoop(1) 事件循环(2) 事件循环练习(3) …

FREERTOS简介、移植和系统配置(基于STM32F103)

本文基础内容参考的是正点原子的FREERTOS课程。 这是基于HAL库的 正点原子手把手教你学FreeRTOS实时系统 这是基于标准库的 正点原子FreeRTOS手把手教学-基于STM32 基础知识&#xff0c;直接参考正点原子《FreeRTOS开发指南V1.1》基于标准库的&#xff0c;此处不再赘述。 本文…