Pyqt5 信号槽机制可参考:https://blog.51cto.com/9291927/2422187

信号槽是Qt的核心机制,也是PyQt编程中对象进行通信的机制。在Qt中,QObject对象和PyQt中所有继承自QWidget的控件都支持信号槽机制。当信号发射时,连接的槽函数会自动执行。在PyQt5中,信号与槽函数通过object.signal.connect()方法进行连接。

mymainwindow.py  通过QtDesigner设计并转换

from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(800, 600)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.centralwidget)self.horizontalLayout_2.setObjectName("horizontalLayout_2")self.verticalLayout = QtWidgets.QVBoxLayout()self.verticalLayout.setObjectName("verticalLayout")self.horizontalLayout = QtWidgets.QHBoxLayout()self.horizontalLayout.setObjectName("horizontalLayout")self.pushButton_1 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_1.setObjectName("pushButton_1")self.horizontalLayout.addWidget(self.pushButton_1)self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_2.setObjectName("pushButton_2")self.horizontalLayout.addWidget(self.pushButton_2)self.line = QtWidgets.QFrame(self.centralwidget)self.line.setFrameShape(QtWidgets.QFrame.VLine)self.line.setFrameShadow(QtWidgets.QFrame.Sunken)self.line.setObjectName("line")self.horizontalLayout.addWidget(self.line)self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_3.setObjectName("pushButton_3")self.horizontalLayout.addWidget(self.pushButton_3)self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)self.pushButton_4.setObjectName("pushButton_4")self.horizontalLayout.addWidget(self.pushButton_4)self.verticalLayout.addLayout(self.horizontalLayout)self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)self.tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)self.tableWidget.setObjectName("tableWidget")self.tableWidget.setColumnCount(0)self.tableWidget.setRowCount(0)self.tableWidget.horizontalHeader().setCascadingSectionResizes(False)self.tableWidget.verticalHeader().setVisible(False)self.verticalLayout.addWidget(self.tableWidget)self.horizontalLayout_2.addLayout(self.verticalLayout)MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 23))self.menubar.setObjectName("menubar")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "按键精灵"))self.pushButton_1.setText(_translate("MainWindow", "录制"))self.pushButton_2.setText(_translate("MainWindow", "停止"))self.pushButton_3.setText(_translate("MainWindow", "回放"))self.pushButton_4.setText(_translate("MainWindow", "停止"))self.tableWidget.setSortingEnabled(True)

mylistener.py 文件,定义MyWindow类,继承自Ui_MainWindow,并在其中定义信号与槽

import sys
import os
import threading
import time
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QCheckBox, QTableWidgetItem
from mymainwindow import *
from pynput import mouse, keyboard
from record import Recorder
from playback import PlayBack
import ctypesclass MyWindow(QMainWindow, Ui_MainWindow):def __init__(self, parent=None):super(MyWindow, self).__init__(parent)self.setupUi(self)self.inittable()self.getscripts()self.pushButton_1.clicked.connect(self.start_record)self.pushButton_2.clicked.connect(self.getscripts)self.pushButton_2.clicked.connect(self.stop_record)self.pushButton_3.clicked.connect(self.start_playback)self.pushButton_4.clicked.connect(self.stop_playback)#self.pushButton_4.clicked.connect(self.reset_button)self.__mouse_thread: mouse.Listener = Noneself.__key_thread: keyboard.Listener = Noneself.__playback_thread: PlayBack = Nonedef start_record(self):self.setWindowState(Qt.WindowMinimized)self.pushButton_1.setDisabled(True)self.pushButton_3.setDisabled(True)self.pushButton_4.setDisabled(True)filename = time.strftime("%Y_%m_%d_%H_%M_%S_", time.localtime(time.time())) + "Record.txt"file = os.path.join(os.getcwd(), filename)mylistener = Recorder(file)self.__mouse_thread = mouse.Listener(on_click=mylistener.on_click)self.__key_thread = keyboard.Listener(on_press=mylistener.on_press, on_release=mylistener.on_release)self.__mouse_thread.start()self.__key_thread.start()def stop_record(self):if self.__mouse_thread is not None:if self.__mouse_thread.isAlive():self.__mouse_thread.stop()if self.__mouse_thread is not None:if self.__key_thread.isAlive():self.__key_thread.stop()self.pushButton_1.setDisabled(False)self.pushButton_3.setDisabled(False)self.pushButton_4.setDisabled(False)def inittable(self):# 设置行数和列数self.tableWidget.setColumnCount(3)self.tableWidget.setRowCount(1)self.tableWidget.setColumnWidth(0, 100)self.tableWidget.setColumnWidth(1, 300)self.tableWidget.setColumnWidth(2, 300)# 设置数据标题self.tableWidget.horizontalHeader().setStyleSheet("QHeaderView::section{background:skyblue;}")self.tableWidget.setHorizontalHeaderItem(0, QTableWidgetItem("序号"))self.tableWidget.setHorizontalHeaderItem(1, QTableWidgetItem("文件名"))self.tableWidget.setHorizontalHeaderItem(2, QTableWidgetItem("修改时间"))self.tableWidget.horizontalHeader().setStretchLastSection(True)def getscripts(self):# 获取当前路径下的txt文件cwdpath = os.getcwd()filelist = []for file in os.listdir(cwdpath):if file.endswith(".txt"):filelist.append(file)row_num = len(filelist)self.tableWidget.setRowCount(row_num)# 设置数据条目for row in range(row_num):# 第一列为checkboxitem_checked = QTableWidgetItem()item_checked.setText(str(row + 1))item_checked.setCheckState(Qt.Unchecked)item_checked.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)self.tableWidget.setItem(row, 0, item_checked)# 第二列为文件名item_name = QTableWidgetItem(filelist[row])item_name.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)self.tableWidget.setItem(row, 1, item_name)# 第三列为文件修改时间filepath = os.path.join(cwdpath, filelist[row])mtime = os.stat(filepath).st_mtimemtime_str = time.strftime('%Y_%m_%d %H:%M:%S', time.localtime(mtime))item_time = QTableWidgetItem(mtime_str)item_time.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)self.tableWidget.setItem(row, 2, item_time)def get_checkedfiles(self):rownum = self.tableWidget.rowCount()filelist = []for i in range(rownum):if self.tableWidget.item(i, 0).checkState() == Qt.Checked:filename = self.tableWidget.item(i, 1).text()file = os.path.join(os.getcwd(), filename)filelist.append(file)return filelistdef start_playback(self):filelist = self.get_checkedfiles()if len(filelist) != 0:self.setWindowState(Qt.WindowMinimized)self.pushButton_1.setDisabled(True)self.pushButton_2.setDisabled(True)self.pushButton_3.setDisabled(True)self.__playback_thread = PlayBack(filelist)self.__playback_thread.start()self.__playback_thread.finished.connect(self.reset_button)def reset_button(self):self.pushButton_1.setDisabled(False)self.pushButton_2.setDisabled(False)self.pushButton_3.setDisabled(False)self.pushButton_4.setDisabled(False)def stop_playback(self):if self.__playback_thread is not None:if self.__playback_thread.isRunning():self.__playback_thread.stop()if __name__ == '__main__':app = QApplication(sys.argv)myWin = MyWindow()myWin.show()sys.exit(app.exec_())

record.py 启动线程对鼠标键盘进行监控

import os
import time
from pynput import mouse
from pynput.mouse import Button
from pynput import keyboard
from _datetime import datetimeclass Recorder(object):def __init__(self, file):self.file = filedef on_click(self, x, y, button, pressed):if button == Button.left:button_name = 'Left'elif button == Button.middle:button_name = 'Middle'elif button == Button.right:button_name = 'Right'else:button_name = 'Unknown'if pressed:msg = 'mouse {0} Presses at {1} {2} \n'.format(button_name, x, y)else:msg = 'mouse {0} Released at {1} {2} \n'.format(button_name, x, y)with open(self.file, "a") as f:timestr = datetime.now().strftime("%Y_%m_%d_%H_%M_%S.%f")[:-3]f.write(timestr)f.write(" ")f.write(msg)def on_press(self, key):# msg = 'key {0} pressed \n'.format(key)try:msg = 'key alphanumeric {0} pressed \n'.format(key.char)except AttributeError:msg = 'key special {0} pressed \n'.format(key)with open(self.file, "a") as f:timestr = datetime.now().strftime("%Y_%m_%d_%H_%M_%S.%f")[:-3]f.write(timestr)f.write(" ")f.write(msg)def on_release(self, key):# msg = 'key {0} released \n'.format(key)try:msg = 'key alphanumeric {0} released \n'.format(key.char)except AttributeError:msg = 'key special {0} released \n'.format(key)# Stop listenerif key == keyboard.Key.esc:return Falsewith open(self.file, "a") as f:timestr = datetime.now().strftime("%Y_%m_%d_%H_%M_%S.%f")[:-3]f.write(timestr)f.write(" ")f.write(msg)

playback.py 对录制文件进行解析,并回放

import ctypes
import re
from _datetime import datetime
import timefrom PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMainWindow
from pynput.mouse import Button, Controller as MController
from pynput.keyboard import Key, Controller as KController
import threadingfrom mymainwindow import Ui_MainWindowclass PlayBack(QThread):# trigger = pyqtSignal()def __init__(self, filelist):super(PlayBack, self).__init__()self.filelist = filelistself._running = Truedef run(self):time.sleep(3)self.playback_allfiles()# self.trigger.emit()def stop(self):self._running = Falsedef playback_allfiles(self):for file in self.filelist:self.playback_file(file)def playback_file(self, file):with open(file, "r") as f:timestmpA = 0for line in f:if self._running:if timestmpA != 0:timeB = datetime.strptime(line.split(" ")[0], "%Y_%m_%d_%H_%M_%S.%f")timestmpB = timeB.timestamp()timedelta = timestmpB - timestmpAtime.sleep(timedelta)if "mouse" in line:# print("This is the mouse operation")pattern = re.compile(r"(\d+) (\d+)")match = re.search(pattern, line)if match:x = match.group(1)y = match.group(2)mouse = MController()mouse.position = (x, y)if "Presses" in line:if "Left" in line:mouse.press(button=Button.left)print("Mouse Left press at ({0},{1})".format(x, y))elif "Right" in line:mouse.click(button=Button.right)print("Mouse Right press at ({0},{1})".format(x, y))elif "Middle" == line:mouse.click(button=Button.middle)print("Mouse Middle press at ({0},{1})".format(x, y))else:print("Unkonwn Mouse Action")elif "Released" in line:if "Left" in line:mouse.release(button=Button.left)print("Mouse Left release at ({0},{1})".format(x, y))elif "Right" in line:mouse.release(button=Button.right)print("Mouse Right release at ({0},{1})".format(x, y))elif "Middle" == line:mouse.release(button=Button.middle)print("Mouse Middle release at ({0},{1})".format(x, y))else:print("Unkonwn Mouse Action")else:print("Error:There is no mouse position")elif "key" in line:# print("This is the keyboard operation")keyboard = KController()if "special" in line:pattern = re.compile(r"special (.+?) ")match = re.search(pattern, line)if match:key = eval(match.group(1))else:print("Error:There is no key action")elif "alphanumeric" in line:pattern = re.compile(r"alphanumeric (.+?) ")match = re.search(pattern, line)if match:key = match.group(1)else:print("Error:There is no key action")if "pressed" in line:keyboard.press(key)print("Keyboard pressed {0}".format(key))elif "released" in line:keyboard.release(key)print("Keyboard released {0}".format(key))timeA = datetime.strptime(line.split(" ")[0], "%Y_%m_%d_%H_%M_%S.%f")timestmpA = timeA.timestamp()else:break

实际效果如图

使用Python开发测试小工具-录制回放工具的实现相关推荐

  1. 太强了,Python 开发桌面小工具,让代码替我们干重复的工作~

    作者 | Cherish 来源 | 杰哥的IT之旅 决定写这篇文章的初衷是来源于一位小伙伴的问题,关于"如何根据数据源用 Python 自动生成透视表",这个问题背后有个非常好的解 ...

  2. 太强了!Python 开发桌面小工具,让代码替我们干重复的工作!

    作者:Cherish 来源:https://www.jianshu.com/p/91128d442198 决定写这篇文章的初衷是来源于一位小伙伴的问题,关于"如何根据数据源用 Python ...

  3. Python 开发桌面小工具,让代码替我们干重复的工作!

    作者:Cherish 来源:https://www.jianshu.com/p/91128d442198 本文为读者投稿 决定写这篇文章的初衷是来源于一位小伙伴的问题,关于"如何根据数据源用 ...

  4. 通用流量录制回放工具 jvm-sandbox-repeater 尝鲜 (三)—— repeater plugin 开发

    本文作者陈恒捷是TesterHome社区主编,第十届MTSC大会上海站-开源专场出品人.先后在PP助手.PPmoney.荔枝等公司从事测试效能提升相关工作,在测试技术及效率提升方面有丰富的经验积累. ...

  5. 太强了~Python 开发桌面小工具,让代码替我们干重复的工作

    决定写这篇文章的初衷是来源于一位小伙伴的问题,关于"如何根据数据源用 Python 自动生成透视表",这个问题背后有个非常好的解决思路,让代码替我们做重复的工作,从而减轻工作量,减 ...

  6. 控件获取图像可从几方面取得?_基于图像特征与布局刻画的移动测试脚本跨平台录制回放...

    一. 引言 移动应用在全球范围内有着越发举足轻重的地位,因此移动应用的快速迭代和频繁的需求变更的特点引发了对应用质量保障的要求不断提高.在大型设备集群上迁移测试脚本是移动应用质量保障的关键技术之一,因 ...

  7. 通用流量录制回放工具 jvm-sandbox-repeater 尝鲜 (二)——repeater-console 使用

    本文作者陈恒捷是TesterHome社区主编,第十届MTSC大会上海站-开源专场出品人.先后在PP助手.PPmoney.荔枝等公司从事测试效能提升相关工作,在测试技术及效率提升方面有丰富的经验积累. ...

  8. 通用流量录制回放工具 jvm-sandbox-repeater 尝鲜 (四)——新版带界面 console 的使用

    本文作者陈恒捷是TesterHome社区主编,第十届MTSC大会上海站-开源专场出品人.先后在PP助手.PPmoney.荔枝等公司从事测试效能提升相关工作,在测试技术及效率提升方面有丰富的经验积累. ...

  9. python开发微信小程序-Python 开发者的微信小程序开发实践

    导读 在知乎上,有人提问"如何使用 Python 开发微信小程序". 其实微信小程序作为一个前端的机制,Python 并不能插上边.只不过可以作为后端接口为微信小程序提供数据服务而 ...

最新文章

  1. Python 标准库之 fcntl
  2. 腾讯精选练习 50 题(Leetcode)笔记 PDF下载!
  3. STS中applicationContext.xml配置文件
  4. Java渐变进度条_Android ProgressBar自定义图片进度,自定义渐变色进度条
  5. Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)
  6. Java黑皮书课后题第5章:**5.38(十进制转八进制)编写程序,提示用户输入一个十进制整数,然后显示对应的八进制值。(不要是使用Java的Integer类的任何方法)
  7. ci框架的session类,怎么使用ci的session类
  8. ERA5、ERA-interm是啥
  9. e300氛围灯哪里调节_黑色的奔驰E300有了亚光膜的加持 一出场就惊艳四座
  10. STL中的序列式容器——vector(向量)
  11. Windows 7语言包下载
  12. python简单编程--ATM银行管理系统
  13. 【Web前端面试笔试题】2022.08
  14. 角度与弧度之间的换算
  15. [论文]欠驱动水下机器人的平面轨迹规划与跟踪控制设计
  16. 如何修改QColorDialog窗口的背景颜色和上面的字体
  17. 中国建设银行数据治理实践的三高、四落、八行为
  18. 地质灾害防治网格化管理平台
  19. js将字符串按照逗号分割
  20. 42个面向前端开发人员的很棒JavaScript 库和框架

热门文章

  1. 无法启动调试 绑定句柄无效
  2. Windows安装torch-points3d点云工具箱
  3. linux 下获得当前目录,上级目录,文件夹名
  4. 推荐3dMax三维设计十大插件
  5. 组织上线 | 资源共享,协作自如
  6. 一文尽览 | APA自动泊车:系统定义与原理尽览!
  7. 排列组合之——全组合(c语言)
  8. Linux基础命令---gzip
  9. SublimeText3配置Python编译环境
  10. 考研中如何运用【伽马函数】