我再次使用PyQt5,这次我遇到了如何在执行方法需要更长时间时向我的gui添加类似"circular progress indicator"的东西。
为了做到这一点,我有一个(超级)简单的gui只有一个按钮。单击该按钮后,应用程序将打印15秒钟" hello world!"到控制台(这只是为了看到它实际上在做什么)。
我现在的问题是:我怎样才能覆盖"当一个方法的执行需要超过例如4秒(直到方法结束,然后进度指示器应该再次消失)?我有一个来自here的进度指示器的示例脚本。但不幸的是,当我把它添加到我的玩具示例中时,我迷失了方向。这里的任何帮助将非常感谢。
我正在使用:PyQt5.6.0
,Python3.5.2
我的代码:
design.py (gui文件)
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'design.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(300, 300)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(105, 140, 113, 32))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
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", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
main.py :(主要脚本):
from PyQt5 import QtWidgets
import time
from design import Ui_MainWindow
class ToyEx(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.gorepeat)
def gorepeat(self):
"""
print sth for 15 seconds
"""
end_time = time.time() + 15 * 1
print(end_time)
while time.time() < end_time:
print('hello world!')
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
form = ToyEx()
form.show()
app.exec_()
progress_indicator.py :(进度指示器的代码,改编自here)
"""
adapted to PyQt5 from:
Author: Jared P. Sutton <jpsutton@gmail.com>
License: LGPL
Note: I've licensed this code as LGPL because it was a complete translation of the code found here...
https://github.com/mojocorp/QProgressIndicator
sourcecode from here: https://github.com/mojocorp/QProgressIndicator
"""
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import time
class QProgressIndicator(QWidget):
m_angle = None
m_timerId = None
m_delay = None
m_displayedWhenStopped = None
m_color = None
def __init__(self, parent):
# Call parent class constructor first
super(QProgressIndicator, self).__init__(parent)
# Initialize Qt Properties
self.setProperties()
# Intialize instance variables
self.m_angle = 0
self.m_timerId = -1
self.m_delay = 40
self.m_displayedWhenStopped = False
self.m_color = Qt.black
# Set size and focus policy
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.setFocusPolicy(Qt.NoFocus)
# Show the widget
self.show()
def animationDelay(self):
return self.delay
def isAnimated(self):
return (self.m_timerId != -1)
def isDisplayedWhenStopped(self):
return self.displayedWhenStopped
def getColor(self):
return self.color
def sizeHint(self):
return QSize(20, 20)
def startAnimation(self):
self.m_angle = 0
if self.m_timerId == -1:
self.m_timerId = self.startTimer(self.m_delay)
def stopAnimation(self):
if self.m_timerId != -1:
self.killTimer(self.m_timerId)
self.m_timerId = -1
self.update()
def setAnimationDelay(self, delay):
if self.m_timerId != -1:
self.killTimer(self.m_timerId)
self.m_delay = delay
if self.m_timerId != -1:
self.m_timerId = self.startTimer(self.m_delay)
def setDisplayedWhenStopped(self, state):
self.displayedWhenStopped = state
self.update()
def setColor(self, color):
self.m_color = color
self.update()
def timerEvent(self, event):
self.m_angle = (self.m_angle + 30) % 360
self.update()
def paintEvent(self, event):
if (not self.m_displayedWhenStopped) and (not self.isAnimated()):
return
width = min(self.width(), self.height())
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
outerRadius = (width - 1) * 0.5
innerRadius = (width - 1) * 0.5 * 0.48
capsuleHeight = outerRadius - innerRadius
capsuleWidth = capsuleHeight * .23 if (width > 32) else capsuleHeight * .35
capsuleRadius = capsuleWidth / 2
for i in range(0, 12):
color = QColor(self.m_color)
if self.isAnimated():
color.setAlphaF(1.0 - (i / 12.0))
else:
color.setAlphaF(0.2)
painter.setPen(Qt.NoPen)
painter.setBrush(color)
painter.save()
painter.translate(self.rect().center())
painter.rotate(self.m_angle - (i * 30.0))
painter.drawRoundedRect(capsuleWidth * -0.5, (innerRadius + capsuleHeight) * -1, capsuleWidth,
capsuleHeight, capsuleRadius, capsuleRadius)
painter.restore()
def setProperties(self):
self.delay = pyqtProperty(int, self.animationDelay, self.setAnimationDelay)
self.displayedWhenStopped = pyqtProperty(bool, self.isDisplayedWhenStopped, self.setDisplayedWhenStopped)
self.color = pyqtProperty(QColor, self.getColor, self.setColor)
def TestProgressIndicator():
app = QApplication(sys.argv)
t_end = time.time() + 10 *1
progress = QProgressIndicator(None)
progress.setAnimationDelay(70)
progress.startAnimation()
# Execute the application
sys.exit(app.exec_())
if __name__ == "__main__":
TestProgressIndicator()
修改:
在包含进度指示器时,我使用threading
模块再次尝试了一些东西。以下是更新后的代码:
design.py (gui文件,包含进度指示器):
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'design.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(300, 300)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(105, 140, 113, 32))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
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", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
class QProgressIndicator(QtWidgets.QWidget):
m_angle = None
m_timerId = None
m_delay = None
m_displayedWhenStopped = None
m_color = None
def __init__(self, parent):
# Call parent class constructor first
super(QProgressIndicator, self).__init__(parent)
# palette = QPalette(self.palette())
# palette.setColor(palette.Background, Qt.transparent)
# self.setPalette(palette)
# Initialize Qt Properties
self.setProperties()
# Intialize instance variables
self.m_angle = 0
self.m_timerId = -1
self.m_delay = 40
self.m_displayedWhenStopped = False
#self.m_color = Qt.black
self.m_color = QtCore.Qt.transparent
# Set size and focus policy
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
self.setFocusPolicy(QtCore.Qt.NoFocus)
# Show the widget
self.show()
def animationDelay(self):
return self.delay
def isAnimated(self):
return (self.m_timerId != -1)
def isDisplayedWhenStopped(self):
return self.displayedWhenStopped
def getColor(self):
return self.color
def sizeHint(self):
return QtCore.QSize(50, 50)
def startAnimation(self):
self.m_angle = 0
if self.m_timerId == -1:
self.m_timerId = self.startTimer(self.m_delay)
def stopAnimation(self):
if self.m_timerId != -1:
self.killTimer(self.m_timerId)
self.m_timerId = -1
self.update()
def setAnimationDelay(self, delay):
if self.m_timerId != -1:
self.killTimer(self.m_timerId)
self.m_delay = delay
if self.m_timerId != -1:
self.m_timerId = self.startTimer(self.m_delay)
def setDisplayedWhenStopped(self, state):
self.displayedWhenStopped = state
self.update()
def setColor(self, color):
self.m_color = color
self.update()
def timerEvent(self, event):
self.m_angle = (self.m_angle + 30) % 360
self.update()
def paintEvent(self, event):
if (not self.m_displayedWhenStopped) and (not self.isAnimated()):
return
width = min(self.width(), self.height())
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
outerRadius = (width - 1) * 0.5
innerRadius = (width - 1) * 0.5 * 0.48
capsuleHeight = outerRadius - innerRadius
capsuleWidth = capsuleHeight * .23 if (width > 32) else capsuleHeight * .35
capsuleRadius = capsuleWidth / 2
for i in range(0, 12):
color = QtGui.QColor(self.m_color)
if self.isAnimated():
color.setAlphaF(1.0 - (i / 12.0))
else:
color.setAlphaF(0.2)
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(color)
painter.save()
painter.translate(self.rect().center())
painter.rotate(self.m_angle - (i * 30.0))
painter.drawRoundedRect(capsuleWidth * -0.5, (innerRadius + capsuleHeight) * -1, capsuleWidth,
capsuleHeight, capsuleRadius, capsuleRadius)
painter.restore()
def setProperties(self):
self.delay = QtCore.pyqtProperty(int, self.animationDelay, self.setAnimationDelay)
self.displayedWhenStopped = QtCore.pyqtProperty(bool, self.isDisplayedWhenStopped, self.setDisplayedWhenStopped)
self.color = QtCore.pyqtProperty(QtGui.QColor, self.getColor, self.setColor)
main.py (已更新):
from PyQt5 import QtWidgets
from threading import Thread, Timer
from design import Ui_MainWindow, QProgressIndicator
import time
class ToyEx(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.threadfuncts)
def threadfuncts(self):
Thread(target=gorepeat).start()
Timer(4, Thread(target=test_progressindicator).start()) # <-- THIS DOES NOT WORK!
def gorepeat():
"""
print sth for 15 seconds
"""
end_time = time.time() + 15 * 1
while time.time() < end_time:
print('hello world!')
def test_progressindicator():
progress = QProgressIndicator(None)
progress.setAnimationDelay(70)
progress.startAnimation()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
form = ToyEx()
form.show()
app.exec_()
但是当我运行此代码时,它已经在一两秒后崩溃了。方法threadfuncts()
不应该以第一个函数(gorepeat()
)被调用的方式处理线程,4秒后第二个函数(test_progressindicator()
)被调用(然后他们并行运行)?如果我将test_progressindicator()
定义为另一个简单地打印到控制台的函数,那么线程&#34;类型为&#34;工作(4秒的延迟不起作用 - 这是另一点,我不明白为什么它不起作用。)
再说一遍,如果有人能在这里帮助我,我非常感激......