我想在用户每次按下按钮时显示一个加载屏幕(运行过程需要几秒钟)。
我想要这样的东西
QSplashScreen
对我没有帮助,因为它仅在打开应用程序之前使用,而QDialog
对我没有用,因为我希望通过拖动窗口来使应用程序随消息一起移动...
我必须使用什么?
答案 0 :(得分:0)
请检查Qt :: WindowFlags。 Qt :: SplashScreen标志将在不使用QSplashScreen的情况下为您提供闪屏体验(您可以将其与所有小部件一起使用,如图所示),或者更好地,将QDialog与该标志一起使用。 对于移动,可能没有好的解决方案,但是您可以仅使用父级moveEvent发出信号。例如: 主视窗: moveEvent->信号已移动 对话: 信号移动->重新居中窗口。 它看起来并不难。
顺便说一句,我认为在应用程序运行期间阻止所有GUI并不是最好的解决方案。您认为使用QProgressBar吗?
答案 1 :(得分:0)
您可以使用以下插槽:void QWidget::raise()
。
将这个小部件提升到父小部件堆栈的顶部。
调用后,小部件将在任何重叠的同级小部件之前出现在视觉上。
答案 2 :(得分:0)
实现此目的的唯一(安全)方法是添加子窗口小部件,而无需将其添加到任何布局管理器。
您唯一需要关心的是,小部件始终在显示后始终https://www.youtube.com/watch?v=KcC8KZ_Ga2M,并且几何图形始终会更新为父小部件(或者最好是顶层窗口)。
这是一个稍微高级的示例,但是它的好处是您可以对 any 小部件进行子类化,将LoadingWidget
类添加到基类中以实现加载机制。
from random import randrange
from PyQt5 import QtCore, QtGui, QtWidgets
class Loader(QtWidgets.QWidget):
def __init__(self, parent):
super().__init__(parent)
self.gradient = QtGui.QConicalGradient(.5, .5, 0)
self.gradient.setCoordinateMode(self.gradient.ObjectBoundingMode)
self.gradient.setColorAt(.25, QtCore.Qt.transparent)
self.gradient.setColorAt(.75, QtCore.Qt.transparent)
self.animation = QtCore.QVariantAnimation(
startValue=0., endValue=1.,
duration=1000, loopCount=-1,
valueChanged=self.updateGradient
)
self.stopTimer = QtCore.QTimer(singleShot=True, timeout=self.stop)
self.focusWidget = None
self.hide()
parent.installEventFilter(self)
def start(self, timeout=None):
self.show()
self.raise_()
self.focusWidget = QtWidgets.QApplication.focusWidget()
self.setFocus()
if timeout:
self.stopTimer.start(timeout)
else:
self.stopTimer.setInterval(0)
def stop(self):
self.hide()
self.stopTimer.stop()
if self.focusWidget:
self.focusWidget.setFocus()
self.focusWidget = None
def updateGradient(self, value):
self.gradient.setAngle(-value * 360)
self.update()
def eventFilter(self, source, event):
# ensure that we always cover the whole parent area
if event.type() == QtCore.QEvent.Resize:
self.setGeometry(source.rect())
return super().eventFilter(source, event)
def showEvent(self, event):
self.setGeometry(self.parent().rect())
self.animation.start()
def hideEvent(self, event):
# stop the animation when hidden, just for performance
self.animation.stop()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setRenderHints(qp.Antialiasing)
color = self.palette().window().color()
color.setAlpha(max(color.alpha() * .5, 128))
qp.fillRect(self.rect(), color)
text = 'Loading...'
interval = self.stopTimer.interval()
if interval:
remaining = int(max(0, interval - self.stopTimer.remainingTime()) / interval * 100)
textWidth = self.fontMetrics().width(text + ' 000%')
text += ' {}%'.format(remaining)
else:
textWidth = self.fontMetrics().width(text)
textHeight = self.fontMetrics().height()
# ensure that there's enough space for the text
if textWidth > self.width() or textHeight * 3 > self.height():
drawText = False
size = max(0, min(self.width(), self.height()) - textHeight * 2)
else:
size = size = min(self.height() / 3, max(textWidth, textHeight))
drawText = True
circleRect = QtCore.QRect(0, 0, size, size)
circleRect.moveCenter(self.rect().center())
if drawText:
# text is going to be drawn, move the circle rect higher
circleRect.moveTop(circleRect.top() - textHeight)
middle = circleRect.center().x()
qp.drawText(
middle - textWidth / 2, circleRect.bottom() + textHeight,
textWidth, textHeight,
QtCore.Qt.AlignCenter, text)
self.gradient.setColorAt(.5, self.palette().windowText().color())
qp.setPen(QtGui.QPen(self.gradient, textHeight))
qp.drawEllipse(circleRect)
class LoadingExtension(object):
# a base class to extend any QWidget subclass's top level window with a loader
def startLoading(self, timeout=0):
window = self.window()
if not hasattr(window, '_loader'):
window._loader = Loader(window)
window._loader.start(timeout)
# this is just for testing purposes
if not timeout:
QtCore.QTimer.singleShot(randrange(1000, 5000), window._loader.stop)
def loadingFinished(self):
if hasattr(self.window(), '_loader'):
self.window()._loader.stop()
class Test(QtWidgets.QWidget, LoadingExtension):
def __init__(self):
super().__init__()
layout = QtWidgets.QGridLayout(self)
# just a test widget
textEdit = QtWidgets.QTextEdit()
layout.addWidget(textEdit, 0, 0, 1, 2)
textEdit.setMinimumHeight(20)
layout.addWidget(QtWidgets.QLabel('Timeout:'))
self.timeoutSpin = QtWidgets.QSpinBox(maximum=5000, singleStep=250, specialValueText='Random')
layout.addWidget(self.timeoutSpin, 1, 1)
self.timeoutSpin.setValue(2000)
btn = QtWidgets.QPushButton('Start loading...')
layout.addWidget(btn, 2, 0, 1, 2)
btn.clicked.connect(lambda: self.startLoading(self.timeoutSpin.value()))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = Test()
test.show()
sys.exit(app.exec_())