PySide6 GUI 编程(46): 基于QThread构造常驻后台的线程

2024-09-17 09:00:37 浏览数 (3)

QRunnable与QThread的使用区别

在 PySide6 中,QRunnableQThread 都可以用来在后台执行任务,但它们的使用场景和设计目的有所不同。

使用 QRunnable

QRunnable 是一个轻量级的便利类,用于封装一个可以在线程池中执行的任务。它通常用于以下情况:

  1. 任务是短暂的QRunnable 适用于执行一些快速的、独立的任务。因为它们是在线程池中运行的,所以可以有效地重用线程,避免了频繁创建和销毁线程的开销。
  2. 大量的、小型的任务:如果你的应用程序需要处理大量的小任务,使用 QRunnable 可以避免操作系统线程数量的限制,因为线程池会管理这些线程的生命周期,并根据需要重用它们。
  3. 不需要详细控制线程行为QRunnable 提供的控制相对较少,主要关注任务的执行。如果你不需要管理线程的暂停、恢复或其他复杂的线程管理操作,QRunnable 是一个好选择。

使用 QThread

QThread 是 Qt 的线程类,它提供了完整的线程功能,包括线程的生命周期管理、信号槽机制等。它适用于以下情况:

  1. 长时间运行的任务:如果你有一个需要长时间运行的后台任务,比如持续监控或处理数据流,使用 QThread 可以给你更多的控制和灵活性。
  2. 需要复杂交互的线程QThread 支持 Qt 的信号和槽机制,这使得线程之间的通信变得简单。如果你的线程需要与其他线程或主线程频繁交互,QThread 提供的功能会更加合适。
  3. 需要精细控制线程的行为:如果你需要对线程进行详细的控制,比如调整优先级、暂停、恢复或其他特定的线程管理操作,QThread 提供了这些能力。

总结

  • 选择 QRunnable:当你需要处理许多短暂的、独立的任务,并且希望通过线程池来优化性能和资源使用。
  • 选择 QThread:当你的任务需要长时间运行,或者需要复杂的线程管理和线程间通信。

使用QThread 构造常驻后台的线程

示例代码

代码语言:python代码运行次数:0复制
from __future__ import annotations
import sys
from datetime import datetime

from PySide6.QtCore import QThread, Signal, Slot
from PySide6.QtWidgets import QApplication, QLabel, QMainWindow, QPushButton, QVBoxLayout, QWidget

class CounterThread(QThread):
    update_count = Signal(str)  # 发送带时间戳的计数信息

    def __init__(self):
        super().__init__()
        self.running = False
        self.paused = False

    def run(self):
        count = 0
        self.running = True
        while self.running:
            if not self.paused:
                timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                message = f"{timestamp} - Count: {count}"
                self.update_count.emit(message)
                count  = 1
                self.sleep(1)

    def pause_or_resume(self):
        self.paused = not self.paused

    def stop(self):
        self.running = False
        self.paused = False


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.counter_thread = CounterThread()
        self.start_button = QPushButton("Start", self)
        self.toggle_pause_button = QPushButton("Pause", self)
        self.stop_button = QPushButton("Stop", self)
        self.count_label = QLabel("Counter not started", self)
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("Thread Control Example")

        self.start_button.clicked.connect(self.start_thread)
        self.toggle_pause_button.clicked.connect(self.toggle_pause)
        self.stop_button.clicked.connect(self.stop_thread)

        self.toggle_pause_button.setEnabled(False)  # 初始时Pause按钮不可用

        layout = QVBoxLayout()
        layout.addWidget(self.start_button)
        layout.addWidget(self.toggle_pause_button)
        layout.addWidget(self.stop_button)
        layout.addWidget(self.count_label)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.counter_thread.update_count.connect(self.handle_count_update)

    @Slot(str)
    def handle_count_update(self, message):
        self.count_label.setText(message)

    def start_thread(self):
        if not self.counter_thread.isRunning():
            self.counter_thread.start()
            self.toggle_pause_button.setText("Pause")
            self.toggle_pause_button.setEnabled(True)  # 启动后Pause按钮可用

    def toggle_pause(self):
        self.counter_thread.pause_or_resume()
        if self.counter_thread.paused:
            self.toggle_pause_button.setText("Resume")
        else:
            self.toggle_pause_button.setText("Pause")

    def stop_thread(self):
        self.counter_thread.stop()
        self.counter_thread.wait()  # 等待线程安全结束
        self.count_label.setText("Counter stopped")
        self.toggle_pause_button.setEnabled(False)  # 停止后Pause按钮不可用


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

运行效果

控制常驻后台的 QThread 线程控制常驻后台的 QThread 线程

0 人点赞