如何更新 Pyside2 GUI 上的进度条?
How do I update the progress bar on my Pyside2 GUI?
我一直在尝试更新我的 GUI 上的进度条,但我不知道该怎么做...我提供的代码显示了进度更新 - 我只需要该值来更新我的 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"
}
}
}
}
您的问题是具有进度值的信号未连接到 GUI 的任何元素。
在这种情况下,必须在 class 暴露给与 ProgressBar 连接的 QML 中创建一个信号,并且该信号必须从 Worker 的信号中接收信息。另一方面,您不应该直接调用“运行()”方法,因为它将在调用它的线程中执行,在您的情况下是主线程,因此它会阻塞 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;
}
}
}
我一直在尝试更新我的 GUI 上的进度条,但我不知道该怎么做...我提供的代码显示了进度更新 - 我只需要该值来更新我的 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"
}
}
}
}
您的问题是具有进度值的信号未连接到 GUI 的任何元素。
在这种情况下,必须在 class 暴露给与 ProgressBar 连接的 QML 中创建一个信号,并且该信号必须从 Worker 的信号中接收信息。另一方面,您不应该直接调用“运行()”方法,因为它将在调用它的线程中执行,在您的情况下是主线程,因此它会阻塞 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;
}
}
}