Nine, PyQt5 multi-threaded programming

(3) Multi-thread programming

It's a good idea if only one thing is done at a time, but in fact many things are going on at the same       time, so in order to simulate this state in Python, a threading mechanism is introduced. When this happens , it is called a multi-threaded program. Multi-threading is widely used, and developers can use multi-threaded programs to perform operations in segments, which can greatly improve the running speed and performance of the program .
      We first briefly introduce the classification and overview of threads, and then explain in detail the two main classes of thread programming in Python-QTimer timer class and QThread thread class, and explain the specific implementation of threads in detail. After that, we can become familiar with the basics of thread programming using Python, and apply threads to deal with multitasking problems in actual development.

1. Thread overview

      Everything in the world will do a lot of work at the same time. For example, the human body performs activities such as breathing, blood circulation, and thinking at the same time. Users can use the computer to listen to music and print documents, and these activities can be carried out simultaneously. This is called concurrency in Python , and everything that is done concurrently is called a thread.

1. Definition and classification of threads

      First understand a concept - the process. The basic unit of resource allocation and resource scheduling in the system is called a process . In fact, processes are very common. For QQ, Word, and even input methods we use, each independently executed program is a process in the system .
      Each process can contain multiple threads at the same time . For example, QQ is a chat software, but it has many functions, such as sending and receiving messages, playing music, viewing web pages, and downloading files. These tasks can run simultaneously without interfering with each other. , This is the concurrency mechanism using threads. We regard the QQ software as a process, and each of its functions is a thread that can run independently.
insert image description here
      The above mentioned that a process can include multiple threads, but the computer has only one CPU, so how do these threads run concurrently? The Windows operating system is a multi-tasking operating system. It uses processes as units. Each independently executed program is called a process . In the system, each process can be allocated a limited amount of CPU time (also called a CPU time slice). , the CPU executes a process in a segment time, and then jumps to another process for execution in the next time slice. Since the CPU switching is fast, it makes each process appear to be executing at the same time.
insert image description here
      A thread is the execution process in a process. A process can include multiple threads at the same time, and each thread can also get a short period of program execution time. In this way, a process can have multiple concurrently executing threads.

2. Advantages and disadvantages of multithreading

      In general, software that requires user interaction must respond to user actions as quickly as possible in order to provide a good user experience, but at the same time it must perform the necessary calculations to present data to the user as quickly as possible, At this time, multithreading can be used to achieve.

1. Advantages of multithreading

      The most efficient way to increase responsiveness to the user is to use multithreading. On a computer with one processor, multithreading can be achieved by processing data in the background by taking advantage of the small time periods between user events. Effect. The advantages of multithreading are as follows:

  • Communicate with web servers and databases over the network.
  • Perform operations that take a significant amount of time.
  • Separate tasks with different priorities.
  • Allows the UI to be responsive while allocating time to background tasks.

2. Disadvantages of multithreading

Multithreading has both advantages and disadvantages. It is generally recommended not to use too many threads in the program, which can minimize the use of operating system resources and improve performance. The possible negative effects of using multithreading on the program are as follows:

  • The system will use memory for context information needed by processes and threads. Therefore, the number of processes and threads that can be created is limited by available memory.
  • Tracing a large number of threads will take a lot of processor time. If there are too many threads, most of them will not produce noticeable progress. If most threads are in one process, threads in other processes are scheduled infrequently.
  • Using multiple threads to control code execution is very complex and can lead to many bugs.
  • Destroying threads requires awareness of possible problems and handling them.

There are two main ways to implement multithreading in PyQt5, one is to use the QTimer timer module ; the other is to use the QThread thread module .

2. QTimer: timer

      In the PyQt5 program, if you need to perform an operation periodically , you can use the QTimer class to implement it. The QTimer class represents a timer, which can periodically emit a timeout signal. The length of the time interval is specified in the start() method, in milliseconds Unit, if you want to stop the timer, you need to use the stop() method.
When using the QTimer class, you first need to import:

from PyQt5.QtCore import QTimer

Example: Shuangseqiu lottery number picker

      Use PyQt5 to realize the function of simulating double color ball number selection.
      (1) Create a window in the Qt Designer of PyQt5, set the background, and add 7 Label tags and two PushButton buttons.
      (2) Save the designed window as a .ui file, and use the PyUIC tool to convert it into a .py file, and use the qrcTOpy tool to convert the resource file used to store pictures into a .py file. The code for this part is as follows:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(435, 294)
        MainWindow.setWindowTitle("双色球彩票选号器")    # 设置窗口标题
        # 设置窗口背景图片
        MainWindow.setStyleSheet("border-image: url(./image/双色球彩票选号器.png)")
        self.centralwidget=QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        # 创建第一个红球数字的标签
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(97, 178,31, 31))
        # 设置标签的字体
        font = QtGui.QFont()    # 创建字体对象
        font.setPointSize(16)    # 设置字体大小
        font.setBold(True)      # 设置粗体
        font.setWeight(75)    # 设置字体
        self.label.setFont(font)    # 为标签设置字体
        # 设置标签的文字颜色
        self.label.setStyleSheet("color:rgb(255,255,255);")
        self.label.setObjectName("label")

        # 第2、3、4、5、6个红球和一个蓝球标签的代码的创建及设置代码与第一个红球标签的代码一样
        # 创建第2个红球
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(128, 178, 31, 31))
        self.label_2.setFont(font)  # 为标签设置字体
        self.label_2.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_2.setObjectName("label_2")
        # 创建第3个红球
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(159, 178, 31, 31))
        self.label_3.setFont(font)  # 为标签设置字体
        self.label_3.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_3.setObjectName("label_3")
        # 创建第4个红球
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(190, 178, 31, 31))
        self.label_4.setFont(font)  # 为标签设置字体
        self.label_4.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_4.setObjectName("label_4")
        # 创建第个5红球
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        self.label_5.setGeometry(QtCore.QRect(221, 178, 31, 31))
        self.label_5.setFont(font)  # 为标签设置字体
        self.label_5.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_5.setObjectName("label_5")
        # 创建第6个红球
        self.label_6 = QtWidgets.QLabel(self.centralwidget)
        self.label_6.setGeometry(QtCore.QRect(252, 178, 31, 31))
        self.label_6.setFont(font)  # 为标签设置字体
        self.label_6.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_6.setObjectName("label_6")
        # 创建第7个红球
        self.label_7 = QtWidgets.QLabel(self.centralwidget)
        self.label_7.setGeometry(QtCore.QRect(283, 178, 31, 31))
        self.label_7.setFont(font)  # 为标签设置字体
        self.label_7.setStyleSheet("color:rgb(255,255,255);")  # 设置标签的文字颜色
        self.label_7.setObjectName("label_7")

        # 创建“开始”按钮
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(310, 235, 51, 51))
        # 设置按钮的背景图片
        self.pushButton.setStyleSheet("border-image: url(./image/开始.png);")
        self.pushButton.setText("")
        self.pushButton.setObjectName("pushButton")
        # 创建“停止”按钮
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(370, 235, 51, 51))
        # 设置按钮的背景图片
        self.pushButton_2.setStyleSheet("border-image: url(./image/停止.png);")
        self.pushButton_2.setText("")
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)
        # 初始化双色球数字的Label标签的默认文本
        self.label.setText("00")
        self.label_2.setText("00")
        self.label_3.setText("00")
        self.label_4.setText("00")
        self.label_5.setText("00")
        self.label_6.setText("00")
        self.label_7.setText("00")
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

      (3) Since the background of the control will follow the background of the window by default when using the Qt Designer to set the window, set the background of the 7 Label tags to be transparent in the setupUi() method of the .py file.

        # 设置显示双色球数字的Label标签背景透明
        self.label.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_2.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_3.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_4.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_5.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_6.setAtrribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_7.setAtrribute(QtCore.Qt.WA_TranslucentBackground)

      (4) Then define three slot functions strat(), num() and stop(), which are used to start the timer, randomly generate the double-color ball number, and stop the timer respectively.

# 自定义槽函数,用来开始计时器
    def start(self):
        self.timer = QTimer(MainWindow)    # 创建计时器对象
        self.timer.start()     # 开始计时器
        self.timer.timeout.connect(self.num)      # 设置计时器要执行的槽函数

    # 定义槽函数,用来设置7个Label标签中的数字
    def num(self):
        import random
        self.label.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第一个红球数字
        self.label_2.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第二个红球数字
        self.label_3.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第三个红球数字
        self.label_4.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第四个红球数字
        self.label_5.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第五个红球数字
        self.label_6.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第六个红球数字
        self.label_7.setText("{0:02d}".format(random.randint(1, 16)))     # 随机生成蓝球数字

    # 定义槽函数,用来停止计时器
    def stop(self):
        self.timer.stop()

      Since the random number class and the QTimer class are used, the corresponding modules need to be imported.

from PyQt5.QtCore import QTimer
import random

      (5) Bind custom slot functions to the clicked signals of the "Start" and "Stop" buttons in the setupUi() method of the .py file, so that corresponding operations can be performed when the buttons are clicked.

		# 为“开始”按钮绑定单击信号
        self.pushButton.clicked.connect(self.start)
        # 为“停止”按钮绑定单击信号
        self.pushButton_2.clicked.connect(self.stop)

      (6) Add a __main__ method to the .py file.

# 主函数
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    global MainWindow
    MainWindow = QtWidgets.QMainWindow()     # 创建窗体对象
    ui = Ui_MainWindow()      # 创建PyQt5设计的窗体对象
    MainWindow.show()      # 调用PyQt5窗体的方法对窗体对象进行初始化设置
    ui.setupUi(MainWindow)     # 显示窗体
    sys.exit(app.exec_())     # 程序关闭时退出进程

The complete code is as follows:

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(435, 294)
        MainWindow.setWindowTitle("双色球彩票选号器")    # 设置窗口标题
        # 设置窗口背景图片
        MainWindow.setStyleSheet("border-image: url(./image/双色球彩票选号器.png)")
        self.centralwidget=QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        # 创建第一个红球数字的标签
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(97, 178,31, 31))
        # 设置标签的字体
        font = QtGui.QFont()    # 创建字体对象
        font.setPointSize(16)    # 设置字体大小
        font.setBold(True)      # 设置粗体
        font.setWeight(75)    # 设置字体
        self.label.setFont(font)    # 为标签设置字体
        # 设置标签的文字颜色
        self.label.setStyleSheet("color:rgb(255,0,0);")
        self.label.setObjectName("label")

        # 第2、3、4、5、6个红球和一个蓝球标签的代码的创建及设置代码与第一个红球标签的代码一样
        # 创建第2个红球
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        # self.label_2.setGeometry(QtCore.QRect(128, 178, 31, 31))
        self.label_2.setGeometry(QtCore.QRect(134, 178, 31, 31))
        self.label_2.setFont(font)  # 为标签设置字体
        self.label_2.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_2.setObjectName("label_2")
        # 创建第3个红球
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        # self.label_3.setGeometry(QtCore.QRect(159, 178, 31, 31))
        self.label_3.setGeometry(QtCore.QRect(171, 178, 31, 31))
        self.label_3.setFont(font)  # 为标签设置字体
        self.label_3.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_3.setObjectName("label_3")
        # 创建第4个红球
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        # self.label_4.setGeometry(QtCore.QRect(190, 178, 31, 31))
        self.label_4.setGeometry(QtCore.QRect(205, 178, 31, 31))
        self.label_4.setFont(font)  # 为标签设置字体
        self.label_4.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_4.setObjectName("label_4")
        # 创建第个5红球
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        # self.label_5.setGeometry(QtCore.QRect(221, 178, 31, 31))
        self.label_5.setGeometry(QtCore.QRect(239, 178, 31, 31))
        self.label_5.setFont(font)  # 为标签设置字体
        self.label_5.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_5.setObjectName("label_5")
        # 创建第6个红球
        self.label_6 = QtWidgets.QLabel(self.centralwidget)
        # self.label_6.setGeometry(QtCore.QRect(252, 178, 31, 31))
        self.label_6.setGeometry(QtCore.QRect(273, 178, 31, 31))
        self.label_6.setFont(font)  # 为标签设置字体
        self.label_6.setStyleSheet("color:rgb(255,0,0);")  # 设置标签的文字颜色
        self.label_6.setObjectName("label_6")
        # 创建第7个红球
        self.label_7 = QtWidgets.QLabel(self.centralwidget)
        self.label_7.setGeometry(QtCore.QRect(283, 178, 31, 31))
        self.label_7.setGeometry(QtCore.QRect(307, 178, 31, 31))
        self.label_7.setFont(font)  # 为标签设置字体
        self.label_7.setStyleSheet("color:rgb(0,0,255);")  # 设置标签的文字颜色
        self.label_7.setObjectName("label_7")

        # 创建“开始”按钮
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(310, 235, 51, 51))
        # 设置按钮的背景图片
        self.pushButton.setStyleSheet("border-image: url(./image/开始.png);")
        self.pushButton.setText("")
        self.pushButton.setObjectName("pushButton")
        # 创建“停止”按钮
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(370, 235, 51, 51))
        # 设置按钮的背景图片
        self.pushButton_2.setStyleSheet("border-image: url(./image/停止.png);")
        self.pushButton_2.setText("")
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)
        # 初始化双色球数字的Label标签的默认文本
        self.label.setText("00")
        self.label_2.setText("00")
        self.label_3.setText("00")
        self.label_4.setText("00")
        self.label_5.setText("00")
        self.label_6.setText("00")
        self.label_7.setText("00")
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        # 设置显示双色球数字的Label标签背景透明
        self.label.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_2.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_3.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_4.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_5.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_6.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.label_7.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        # 为“开始”按钮绑定单击信号
        self.pushButton.clicked.connect(self.start)
        # 为“停止”按钮绑定单击信号
        self.pushButton_2.clicked.connect(self.stop)

    # 自定义槽函数,用来开始计时器
    def start(self):
        self.timer = QTimer(MainWindow)    # 创建计时器对象
        self.timer.start()     # 开始计时器
        self.timer.timeout.connect(self.num)      # 设置计时器要执行的槽函数

    # 定义槽函数,用来设置7个Label标签中的数字
    def num(self):
        import random
        self.label.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第一个红球数字
        self.label_2.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第二个红球数字
        self.label_3.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第三个红球数字
        self.label_4.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第四个红球数字
        self.label_5.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第五个红球数字
        self.label_6.setText("{0:02d}".format(random.randint(1, 33)))     # 随机生成第六个红球数字
        self.label_7.setText("{0:02d}".format(random.randint(1, 16)))     # 随机生成蓝球数字

    # 定义槽函数,用来停止计时器
    def stop(self):
        self.timer.stop()


# 主函数
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    global MainWindow
    MainWindow = QtWidgets.QMainWindow()     # 创建窗体对象
    ui = Ui_MainWindow()      # 创建PyQt5设计的窗体对象
    MainWindow.show()      # 调用PyQt5窗体的方法对窗体对象进行初始化设置
    ui.setupUi(MainWindow)     # 显示窗体
    sys.exit(app.exec_())     # 程序关闭时退出进程

Run the program, click the "Start" button, the red ball and the blue ball will roll at the same time, click the "Stop" button, the red ball and the blue ball will stop rolling, and the number currently displayed is the number selected by the program.
insert image description here

insert image description here

1. QThread: thread class

      PyQt5 implements threads by using the QThread class. This section introduces how to use the QThread class to implement threads, and introduces the life cycle of threads.

1. Implementation of threads

      The QThread class is the core thread class in PyQt5. To implement a thread, you need to create a subclass of the QThread class and implement its run() method.

Common methods and descriptions of the QThread class

method illustrate
run() The starting point of the thread, after calling start(), the newly created thread will call this method.
start() Start the thread.
wait() Block the thread.
sleep() Sleeps the thread in seconds.
msleep() Sleeps the thread in milliseconds.
usleep() Sleeps the thread in microseconds.
quit() Exits the thread's event loop with return code 0 (success), equivalent to exit(0).
exit() Exit the thread's event loop, and return code, if it returns 0, it means success, any non-zero value means error.
terminate() Forcibly terminate the thread, the wait() method should be used after terminate() to ensure that when the thread terminates, all threads waiting for the thread to complete will be woken up; in addition, it is not recommended to use this method to terminate the thread.
setPriority()
  • Set the thread priority, the values ​​are as follows:
  • QThread.IdlePriority: idle priority;
  • QThread.LowestPriority: lowest priority;
  • QThread.LowPriority: low priority;
  • QThread.NormalPriority: the system default priority;
  • QThread.HighPriority: high priority;
  • QThread.HighestPriority: the highest priority;
  • QThread.TimeCriticalPriority: Assign execution as frequently as possible;
  • QThread.InheritPriority: Default value, use the same priority as the created thread.
isFinished() Is it done.
isRunning() is running.

Commonly used signals and descriptions of the QThread class

Signal illustrate
started Emitted from this thread when the associated thread starts executing, before the run() method is called.
finished Emitted from this thread before the associated thread has completed execution.

Example: stacking counts in threads

      Create a new .py file in PyCharm, use the QThread class to create a thread, superimpose the output number every 1 second in the rewritten run() method, and exit the thread when the number is 10; finally add the main running method .
The complete code is as follows:

from PyQt5.QtCore import QThread    # 导入线程模块


class Thread(QThread):   # 创建线程类
    def __init__(self):
        super(Thread, self).__init__()

    def run(self):     # 重写run()方法
        num = 0      # 定义一个变量,用来叠加输出
        while True:    # 定义无限循环
            num = num + 1   # 变量叠加
            print(num)     # 输出变量
            Thread.sleep(1)    # 使线程休眠1秒
            if num == 10:     # 如果数字到10
                Thread.quit()    # 退出线程


if __name__ == "__main__":
    import sys     # 导入模块
    from PyQt5.QtWidgets import QApplication
    app = QApplication(sys.argv)    # 创建应用对象
    thread = Thread()      # 创建线程对象
    thread.start()     # 启动线程
    sys.exit(app.exec_())

      Run the program, output a number every 1 second in the console of PyCharm, when the number is 10, exit the program.
insert image description here

2. Thread life cycle

      Everything has a beginning and end, just like a person's life, which goes through youth, adulthood, and old age... This is a person's life cycle.
insert image description here
      A thread also has its own life cycle, which includes 5 states, namely birth state, ready state, running state, suspended state (including dormancy, waiting and blocking, etc.), and death state. The birth state is the state when the thread is created ; when the thread object calls the start() method, the thread is in the ready state (also known as the executable state); when the thread obtains system resources, it enters the running state .
      Once a thread enters the running state, it transitions between the ready and running states, and may also enter the suspended or dead state. When the thread in the running state calls sleep(), wait() or blocks, it will enter the suspended state; when the sleep ends or the blocking occurs, the thread will re-enter the ready state ; when the thread's run() method is executed , or when an error or exception occurs in the thread, the thread enters the dead state .
insert image description here

3. Application of threads

      Use the QThread class in PyQt5 to simulate the story of the tortoise and the hare.

Example: The Tortoise and the Hare

      Create a window in the Qt Designer designer, add two Label controls to it, which are used to identify the game records of the rabbit and the tortoise; add two TextEdit controls, which are used to display the game dynamics of the rabbit and the tortoise in real time; add a PushButton Control, used to perform the start game operation. After the window design is completed, save it as a .ui file, and use the PyUIC tool to convert it into a .py file.
      In the .py file, the rabbit thread class and the tortoise thread class are respectively defined by inheriting the QThread class. The implementation ideas of these two classes are the same, and the competition dynamics between the rabbit and the tortoise are mainly transmitted through custom signals. The difference is that the rabbit is at 90 meters , there will be a "rabbit is sleeping" dynamic. Then create two defined thread class objects in the main window and use the start() method to start them.

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import *    # 导入线程相关模块


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        # MainWindow.resize(367, 267)
        MainWindow.resize(367, 367)
        MainWindow.setWindowTitle("龟兔赛跑")   # 设置窗口标题
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        # 创建兔子比赛标签
        self.label=QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(40, 10, 91, 21))
        self.label.setObjectName("label")
        self.label.setText("兔子的比赛记录")
        # 创建兔子的比赛记录
        self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
        # self.textEdit.setGeometry(QtCore.QRect(10, 40, 161, 191))
        self.textEdit.setGeometry(QtCore.QRect(10, 40, 161, 291))
        self.textEdit.setObjectName("textEdit")
        # 创建乌龟比赛标签
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(220, 10, 91, 21))
        self.label_2.setObjectName("label_2")
        self.label_2.setText("乌龟的比赛记录")
        # 显示乌龟的比赛记录
        self.textEdit_2 = QtWidgets.QTextEdit(self.centralwidget)
        # self.textEdit_2.setGeometry(QtCore.QRect(190, 40, 161, 191))
        self.textEdit_2.setGeometry(QtCore.QRect(190, 40, 161, 291))
        self.textEdit_2.setObjectName("textEdit_2")
        # 创建“开始比赛”按钮
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        # self.pushButton.setGeometry(QtCore.QRect(140, 240, 75, 23))
        self.pushButton.setGeometry(QtCore.QRect(140, 340, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.pushButton.setText("开始比赛")
        MainWindow.setCentralWidget(self.centralwidget)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.r = Rabbit()        # 创建兔子线程对象
        self.r.sinOut.connect(self.rabbit)      # 将线程信号连接到槽函数
        self.t = Tortoise()  # 创建兔子线程对象
        self.t.sinOut.connect(self.tortoise)  # 将线程信号连接到槽函数
        self.pushButton.clicked.connect(self.start)     # 开始两个线程

    def start(self):
        self.r.start()    # 启动兔子线程
        self.t.start()     # 启动乌龟线程

    # 显示兔子的跑步距离
    def rabbit(self, str):
        self.textEdit.setPlainText(self.textEdit.toPlainText() + str)

    # 显示乌龟的跑步距离
    def tortoise(self, str):
        self.textEdit_2.setPlainText(self.textEdit_2.toPlainText() + str)


class Rabbit(QThread):     # 创建兔子线程类
    sinOut = pyqtSignal(str)     # 自定义信号,用来发射兔子比赛动态

    def __init__(self):
        super(Rabbit, self).__init__()

    # 重写run()方法
    def run(self):
        for i in range(1, 11):
            # 循环10次模拟赛跑的过程
            QThread.msleep(100)     # 线程休眠0.1秒,模拟兔子在跑步
            self.sinOut.emit("\n 兔子跑了" + str(i) + "0米")    # 显示兔子的跑步距离
            if i == 9:
                self.sinOut.emit("\n 兔子在睡觉")     # 当跑了90米时开始睡觉
                QThread.sleep(5)        # 休眠5秒
            if i == 10:
                self.sinOut.emit("\n 兔子到达终点")     # 显示兔子到达了终点


class Tortoise(QThread):       # 创建乌龟线程类
    sinOut = pyqtSignal(str)       # 自定义信号,用来发射乌龟比赛动态

    def __init__(self):
        super(Tortoise, self).__init__()

    # 重写run()方法
    def run(self):
        for i in range(1, 11):
            QThread.msleep(500)      # 线程休眠0.5秒。模拟乌龟在跑步
            self.sinOut.emit("\n 乌龟跑了" + str(i) + "0米")
            if i == 10:
                self.sinOut.emit("\n 乌龟到达终点")


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)    # 创建窗体对象
    MainWindow = QtWidgets.QMainWindow()    # 创建PyQt5设计的窗体对象
    ui = Ui_MainWindow()    # 调用PyQt5窗体对象进行初始化设置
    ui.setupUi(MainWindow)
    MainWindow.show()      # 显示窗体
    sys.exit(app.exec_())    # 程序关闭时退出进程

      Run the program and click the "Start Race" button. When the rabbit runs to 90 meters, it starts to sleep; when the tortoise reaches the finish line, the rabbit wakes up and runs to the finish line.
The running effect is as follows:
Please add a picture description

Guess you like

Origin blog.csdn.net/ungoing/article/details/127271810