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

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, QtWidgets


class 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.translate
        MainWindow.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 ctypes


class 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 = None
        self.__key_thread: keyboard.Listener = None
        self.__playback_thread: PlayBack = None

    def 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):
            # 第一列为checkbox
            item_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_mtime
            mtime_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 filelist

    def 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 datetime


class Recorder(object):

    def __init__(self, file):
        self.file = file

    def 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 listener
        if key == keyboard.Key.esc:
            return False
        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)

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

import ctypes
import re
from _datetime import datetime
import time

from 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 threading

from mymainwindow import Ui_MainWindow


class PlayBack(QThread):
    # trigger = pyqtSignal()
    def __init__(self, filelist):
        super(PlayBack, self).__init__()
        self.filelist = filelist
        self._running = True

    def run(self):
        time.sleep(3)
        self.playback_allfiles()
        # self.trigger.emit()

    def stop(self):
        self._running = False

    def playback_allfiles(self):
        for file in self.filelist:
            self.playback_file(file)

    def playback_file(self, file):
        with open(file, "r") as f:
            timestmpA = 0
            for 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 - timestmpA
                        time.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

实际效果如图

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值