Есть ли способ реализовать циклический индикатор ожидания с помощью PyQt?

Я пытаюсь создать приложение с использованием PyQt. Часть приложения запускает поток, выполнение которого занимает некоторое время. Как я могу добавить индикатор ожидания (желательно круглый), чтобы указать, что процесс запущен?

Я знаю, что могу использовать индикатор выполнения или, возможно, заставку. Я изучил оба, но я пытаюсь выбрать один из них только в крайнем случае. Может кто-нибудь, пожалуйста, помогите мне с этим?

Благодарю вас


person 0Nicholas    schedule 25.01.2018    source источник
comment
Вы имеете в виду что-то вроде этого или это?   -  person Arnav Borborah    schedule 25.01.2018
comment
О, круто! Спасибо @ArnavBorborah. Есть ли способ сделать то же самое в Python? Я нашел одну реализация, но, думаю, она требует некоторых мероприятие. Я не могу заставить его работать с любым другим условием, которое изменяется внутри программы. Извините, если это звучит тривиально. У меня очень хороший опыт работы с PyQt   -  person 0Nicholas    schedule 25.01.2018
comment
Если вы спрашиваете, как интегрировать QML, в Интернете есть множество руководств, таких как этот или вот этот.   -  person Arnav Borborah    schedule 25.01.2018
comment
Есть ли способ сделать это с помощью стандартной библиотеки PyQt?   -  person 0Nicholas    schedule 25.01.2018
comment
Мне жаль; Я бы не смог ответить на этот вопрос, так как я не настолько опытен. Что бы я ни говорил ранее, мне помог быстрый поиск в Google.   -  person Arnav Borborah    schedule 25.01.2018
comment
Если вы не знаете о QML, я рекомендую вам не использовать его, вы потратите много времени, пытаясь это сделать.   -  person eyllanesc    schedule 25.01.2018


Ответы (2)


Я конвертировал код из QtWaitingSpinner с C++ на PyQt4/PyQt5

from math import ceil

"""from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *"""

from PyQt4.QtCore import *
from PyQt4.QtGui import *


class QtWaitingSpinner(QWidget):
    mColor = QColor(Qt.gray)
    mRoundness = 100.0
    mMinimumTrailOpacity = 31.4159265358979323846
    mTrailFadePercentage = 50.0
    mRevolutionsPerSecond = 1.57079632679489661923
    mNumberOfLines = 20
    mLineLength = 10
    mLineWidth = 2
    mInnerRadius = 20
    mCurrentCounter = 0
    mIsSpinning = False

    def __init__(self, centerOnParent=True, disableParentWhenSpinning=True, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)
        self.mCenterOnParent = centerOnParent
        self.mDisableParentWhenSpinning = disableParentWhenSpinning
        self.initialize()

    def initialize(self):
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.rotate)
        self.updateSize()
        self.updateTimer()
        self.hide()

    @pyqtSlot()
    def rotate(self):
        self.mCurrentCounter += 1
        if self.mCurrentCounter > self.numberOfLines():
            self.mCurrentCounter = 0
        self.update()

    def updateSize(self):
        size = (self.mInnerRadius + self.mLineLength) * 2
        self.setFixedSize(size, size)

    def updateTimer(self):
        self.timer.setInterval(1000 / (self.mNumberOfLines * self.mRevolutionsPerSecond))

    def updatePosition(self):
        if self.parentWidget() and self.mCenterOnParent:
            self.move(self.parentWidget().width() / 2 - self.width() / 2,
                      self.parentWidget().height() / 2 - self.height() / 2)

    def lineCountDistanceFromPrimary(self, current, primary, totalNrOfLines):
        distance = primary - current
        if distance < 0:
            distance += totalNrOfLines
        return distance

    def currentLineColor(self, countDistance, totalNrOfLines, trailFadePerc, minOpacity, color):
        if countDistance == 0:
            return color

        minAlphaF = minOpacity / 100.0

        distanceThreshold = ceil((totalNrOfLines - 1) * trailFadePerc / 100.0)
        if countDistance > distanceThreshold:
            color.setAlphaF(minAlphaF)

        else:
            alphaDiff = self.mColor.alphaF() - minAlphaF
            gradient = alphaDiff / distanceThreshold + 1.0
            resultAlpha = color.alphaF() - gradient * countDistance
            resultAlpha = min(1.0, max(0.0, resultAlpha))
            color.setAlphaF(resultAlpha)
        return color

    def paintEvent(self, event):
        self.updatePosition()
        painter = QPainter(self)
        painter.fillRect(self.rect(), Qt.transparent)
        painter.setRenderHint(QPainter.Antialiasing, True)
        if self.mCurrentCounter > self.mNumberOfLines:
            self.mCurrentCounter = 0
        painter.setPen(Qt.NoPen)

        for i in range(self.mNumberOfLines):
            painter.save()
            painter.translate(self.mInnerRadius + self.mLineLength,
                              self.mInnerRadius + self.mLineLength)
            rotateAngle = 360.0 * i / self.mNumberOfLines
            painter.rotate(rotateAngle)
            painter.translate(self.mInnerRadius, 0)
            distance = self.lineCountDistanceFromPrimary(i, self.mCurrentCounter,
                                                         self.mNumberOfLines)
            color = self.currentLineColor(distance, self.mNumberOfLines,
                                          self.mTrailFadePercentage, self.mMinimumTrailOpacity, self.mColor)
            painter.setBrush(color)
            painter.drawRoundedRect(QRect(0, -self.mLineWidth // 2, self.mLineLength, self.mLineLength),
                                    self.mRoundness, Qt.RelativeSize)
            painter.restore()

    def start(self):
        self.updatePosition()
        self.mIsSpinning = True
        self.show()

        if self.parentWidget() and self.mDisableParentWhenSpinning:
            self.parentWidget().setEnabled(False)

        if not self.timer.isActive():
            self.timer.start()
            self.mCurrentCounter = 0

    def stop(self):
        self.mIsSpinning = False
        self.hide()

        if self.parentWidget() and self.mDisableParentWhenSpinning:
            self.parentWidget().setEnabled(True)

        if self.timer.isActive():
            self.timer.stop()
            self.mCurrentCounter = 0

    def setNumberOfLines(self, lines):
        self.mNumberOfLines = lines
        self.updateTimer()

    def setLineLength(self, length):
        self.mLineLength = length
        self.updateSize()

    def setLineWidth(self, width):
        self.mLineWidth = width
        self.updateSize()

    def setInnerRadius(self, radius):
        self.mInnerRadius = radius
        self.updateSize()

    def color(self):
        return self.mColor

    def roundness(self):
        return self.mRoundness

    def minimumTrailOpacity(self):
        return self.mMinimumTrailOpacity

    def trailFadePercentage(self):
        return self.mTrailFadePercentage

    def revolutionsPersSecond(self):
        return self.mRevolutionsPerSecond

    def numberOfLines(self):
        return self.mNumberOfLines

    def lineLength(self):
        return self.mLineLength

    def lineWidth(self):
        return self.mLineWidth

    def innerRadius(self):
        return self.mInnerRadius

    def isSpinning(self):
        return self.mIsSpinning

    def setRoundness(self, roundness):
        self.mRoundness = min(0.0, max(100, roundness))

    def setColor(self, color):
        self.mColor = color

    def setRevolutionsPerSecond(self, revolutionsPerSecond):
        self.mRevolutionsPerSecond = revolutionsPerSecond
        self.updateTimer()

    def setTrailFadePercentage(self, trail):
        self.mTrailFadePercentage = trail

    def setMinimumTrailOpacity(self, minimumTrailOpacity):
        self.mMinimumTrailOpacity = minimumTrailOpacity


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    dial = QDialog()
    w = QtWaitingSpinner(dial)
    dial.show()
    w.start()
    QTimer.singleShot(1000, w.stop)
    sys.exit(app.exec_())

По следующей ссылке вы можете найти полный пример

person eyllanesc    schedule 25.01.2018
comment
Большое спасибо, @eyllanesc. Оно работало завораживающе. QPainter выглядит великолепно. У меня просто есть причина, чтобы баловаться этим. :) - person 0Nicholas; 25.01.2018
comment
drawRoundedRect принимает два аргумента радиуса (по крайней мере, в текущей версии) — поэтому вместо self.mRoundness, Qt.RelativeSize) будет self.mRoundness, self.mRoundness, Qt.RelativeSize). - person Appleshell; 02.01.2019

В дополнение к ответу выше...

Если вы используете Qt Designer, вам нужно создать QWidget и повысить его до QtWaitingSpinner. Вы можете подписаться на это, чтобы продвижение QWidgets. В этом случае имя вашего продвигаемого класса — QtWaitingSpinner, а файл заголовка — это файл, в котором находится класс QtWaitingSpinner.

введите здесь описание изображения

Как только ваш графический интерфейс установлен, вы можете позвонить

your_QtWaitingSpinnerObject.start()
person Matheus Torquato    schedule 01.08.2020