【问题标题】:How do I update the progress bar on my Pyside2 GUI?如何更新 Pyside2 GUI 上的进度条?
【发布时间】:2021-07-30 16:21:46
【问题描述】:

我一直在尝试更新我的 GUI 上的进度条,但我不知道该怎么做...我提供的代码显示了进度更新 - 我只需要该值来更新进度条在我的图形用户界面上!这是来自 Qt Creator 的 QML 文件。

main.py

import os
import sys
import time

from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType
from PySide2.QtCore import QObject, Slot, Signal, QTimer, QUrl, QThread
from pathlib import Path

from multiprocessing.pool import ThreadPool

class MainWindow(QObject):
    def __init__(self):
        QObject.__init__(self)

    @Slot()
    def thread_progress(self):
        print("Worker")
        self.worker = Worker()
        self.thread = QThread()
        self.worker.moveToThread(self.thread)
        self.thread.start()
        self.worker.run()
        

class Worker(QObject):
    progress_value = Signal(float)

    @Slot()
    def run(self):
        self.progress = 0
        self.total = 100
        for i in range(0, self.total):
            self.update_progress()

    def update_progress(self):
        print(f"{self.progress} / {self.total}")
        self.progress += 1
        self.progress_value.emit(self.progress)
        time.sleep(1)

if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    # Get Context
    main = MainWindow()
    engine.rootContext().setContextProperty("backend", main)
    # Set App Extra Info
    app.setOrganizationName("zardoss")
    app.setOrganizationDomain("N/A")

    engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

main.py 文件与 main.qml 文件连接。 GUI 有一个按钮、进度条和一个文本输入元素。我只关心按下生成按钮后进度条会填满。 按下生成按钮后,您可以从控制台看到正在填充 1-100 的值,但它没有填充进度条,因为我不确定如何。

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import QtQuick.Shapes 1.15

Window {
    id: mainWindow
    width: 750
    height: 500
    visible: true
    color: "#00000000"

    // Remove title bar
    flags: Qt.Window | Qt.FramelessWindowHint

    // Properties
    property int windowStatus: 0
    property int windowMargin: 10

    title: qsTr("Progress Bar")
    Rectangle {
        id: bg
        color: "#2c313c"
        border.color: "#f12c313c"
        border.width: 1
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: parent.top
        anchors.bottom: parent.bottom
        anchors.rightMargin: windowMargin
        anchors.leftMargin: windowMargin
        anchors.bottomMargin: windowMargin
        anchors.topMargin: windowMargin
        z:1

        Rectangle {
            id: appContainer
            height: 480
            color: "#00000000"
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            anchors.rightMargin: 1
            anchors.leftMargin: 1
            anchors.bottomMargin: 1
            anchors.topMargin: 1

            Rectangle {
                id: content
                color: "#00000000"
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.top: topBar.bottom
                anchors.bottom: parent.bottom
                anchors.topMargin: 0

                Button {
                    id: btnGenerate
                    x: 265
                    y: 44
                    width: 200
                    height: 50
                    text: "Generate"
                    anchors.verticalCenter: parent.verticalCenter
                    anchors.right: parent.right
                    anchors.horizontalCenterOffset: 0
                    anchors.horizontalCenter: parent.horizontalCenter
                    anchors.verticalCenterOffset: 165
//                    colorPressed: "#1e5425"
//                    colorMouseOver: "#42b852"
                    font.pointSize: 14
                    display: AbstractButton.TextBesideIcon
                    font.bold: false
//                    colorDefault: "#328a3f"
                    anchors.rightMargin: 250
                    onPressed: {
                        // backend.generate()
                        backend.thread_progress()
                    }
                }

                ProgressBar{
                    id: progressBar
                    x: 239
                    y: 64
                    visible: true
                    width: 661
                    height: 250
//                    text: "%"
                    anchors.verticalCenter: parent.verticalCenter
                    value: 0
                    //bgColor: "#00000/*000"
                    //dropShadowColor: "#20000000"
                    //samples: 16
                    anchors.verticalCenterOffset: -15
                    anchors.horizontalCenter: parent.horizontalCenter
                    
                }
            }
        }
    }
    DropShadow{
        anchors.fill: bg
        horizontalOffset: 0
        verticalOffset: 0
        radius: 10
        samples: 16
        color: "#80000000"
        source:bg
        z: 0
    }

    Connections{
        target: backend

        function onLinkValid(valid)  {
            if(valid === true)    {
                textField.textColor = "#00FF00"
            } else {
                textField.textColor = "#FF00FF"
            }
        }
    }
}

【问题讨论】:

  • 请提供minimal reproducible example,而不是外部链接
  • 有很多文件可以使用 - 包含在 repo 中。每个人都更容易克隆 repo 并运行它,而不是手动复制+粘贴和下载必要的文件。
  • SO 的目的不是帮助用户实施他们的项目,而是解决特定问题,以便其他用户可以将其作为未来问题的参考。因此,帖子必须是独立的,也就是说,它们不能依赖于外部资源,因为例如,将来可能会断开链接使帖子无法使用。
  • 如果您的项目很小,那么它将是 MRE 的一个很好的候选者,但如果不是,那么您将不得不努力做到这一点:要么删除与当前问题无关的文件,要么复制您帖子中的所有代码,或创建一个新代码。项目只关注功能并复制您帖子中的代码。另请阅读How to Ask 并查看tour
  • @zardoss 抱歉,这是您的观点。在什么基础上,安全方面,我们可以克隆并运行一些我们一无所知的随机存储库?无论如何,我们当然不能通过“大量文件”让您找到与您的问题相关的特定点,这是您的工作。请仔细阅读给定的链接,并遵循他们的建议。

标签: python multithreading multiprocessing qml pyside2


【解决方案1】:

您的问题是具有进度值的信号未连接到 GUI 的任何元素。

在这种情况下,必须在暴露给 QML 的与 ProgressBar 连接的类中创建一个信号,并且该信号必须从 Worker 的信号中接收信息。另一方面,您不应直接调用“run()”方法,因为它将在调用它的线程中执行,在您的情况下是主线程,因此它将阻塞 GUI,而您必须调用它间接使用信号或使用 QTimer。

import os
import sys
import time
from pathlib import Path

from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtCore import QObject, Slot, Signal, QTimer, QUrl, QThread


class Backend(QObject):
    progress_changed = Signal(float, name="progressChanged")

    def __init__(self, parent=None):
        super().__init__(parent)

        self.worker = Worker()
        self.worker.progress_changed.connect(self.progress_changed)
        self.worker_thread = QThread()
        self.worker.moveToThread(self.worker_thread)
        self.worker_thread.start()

    @Slot()
    def start_worker(self):
        QTimer.singleShot(0, self.worker.run)


class Worker(QObject):
    progress_changed = Signal(float)

    @Slot()
    def run(self):
        self.progress = 0
        self.total = 100
        for i in range(0, self.total):
            self.update_progress()

    def update_progress(self):
        print(f"{self.progress} / {self.total}")
        self.progress += 1
        self.progress_changed.emit(self.progress)
        time.sleep(1)


if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    backend = Backend()
    engine.rootContext().setContextProperty("backend", backend)
 
    engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
    if not engine.rootObjects():
        sys.exit(-1)
    ret = app.exec_()
    # backend.worker_thread.quit()
    # backend.worker_thread.wait()
    sys.exit(ret)
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15

Window {
    id: mainWindow

    width: 750
    height: 500
    visible: true
    color: "#00000000"
    title: qsTr("Progress Bar")

    Row {
        spacing: 10
        anchors.centerIn: parent

        Button {
            id: btnGenerate

            text: "start"
            onClicked: backend.start_worker()
        }

        ProgressBar {
            id: progressBar
            from: 0
            to: 100.0
        }

    }

    Connections {
        target: backend

        function onProgressChanged(progress) {
            progressBar.value = progress;
        }

    }

}

【讨论】:

  • 这很好用,谢谢@eyllanesc。由于我正在努力学习 qml 和 py 文件之间的通信方面,我在哪里可以了解更多信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-06
  • 2016-08-17
  • 2019-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-08
相关资源
最近更新 更多