PyQt изменяет размер QMovie с правильным сглаживанием

Я создал QLabel и установил его фильм на объект QMovie с анимированным gif. Затем в resizeEvent моего приложения я изменяю размер и перемещаю метку, чтобы она располагалась по центру/соответствовала макету. Это работает нормально, но в фильме много тонких линий, которые полностью искажаются при изменении размера, кажется, что сглаживание отсутствует. Так что либо я использую неправильный метод изменения размера, либо мне нужно где-то правильно настроить сглаживание? В документации QMovie или QLabel нет ничего, что бы подсказывало, как это сделать. Я читал, что QMovie унаследован от QImageReader, хотя у него тоже нет свойства сглаживания, которое я смог найти.

РЕДАКТИРОВАТЬ

Я немного заставил это работать, но это все еще не совсем правильно. Я обнаружил, что у QMovie есть метод setScaledSize, который фактически масштабирует базовый QImageViewer. Затем я просто приспосабливаю метку к своему содержимому, а именно к фильму. Используя следующий код, я могу изменить размер фильма с правильным сглаживанием, однако он довольно «дерганый» и «мерцающий» во время изменения размера, поэтому, очевидно, я делаю это не совсем «правильно». Также иногда он каким-то образом теряет соотношение сторон. Все еще ищете правильный способ сделать это ... Может быть, QLabel - неправильный путь?

Вот рабочий пример

import sys
from PyQt4 import QtGui

class MovieTest(QtGui.QDialog):
    def __init__(self):
        super(MovieTest, self).__init__()

        layout = QtGui.QVBoxLayout()
        self.setLayout(layout)

        self.loading_lbl = QtGui.QLabel()
        self.loading_lbl.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicyIgnored)
        self.loading_lbl.setScaledContents(True)
        layout.addWidget(self.loading_lbl)
        loading_movie = QtGui.QMovie("loading-radial_loop.gif") # some gif in here
        self.loading_lbl.setMovie(loading_movie)
        loading_movie.start()

        self.setGeometry(50,50,100,100)
        self.setMinimumSize(10,10)

    def resizeEvent(self, event):
        rect = self.geometry()
        size = min(rect.width(), rect.height())
        movie = self.loading_lbl.movie()
        movie.setScaledSize(QtCore.QSize(size, size))
        self.loading_lbl.adjustSize()

def main():
    app = QtGui.QApplication(sys.argv)
    ex = MovieTest()
    ex.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

person Spencer    schedule 03.05.2018    source источник
comment
предоставьте минимальный воспроизводимый пример и поделитесь своим gif-файлом   -  person eyllanesc    schedule 03.05.2018
comment
@eyllanesc Извините, вот лучший пример. Я не могу загрузить гифку прямо сейчас, но думаю, подойдет любая. Например, i.gifer. com/NtbT.gif   -  person Spencer    schedule 03.05.2018
comment
@eyllanesc Я ближе к решению. Я обнаружил, что в QMovie есть функция QMovie.setScaledSize(), которая масштабирует средство чтения изображений. Поэтому вместо масштабирования метки я масштабирую фильм, а затем вызываю QLabel.adjustSize(), чтобы подогнать метку к фильму. Это немного нервно, но это работает. Я опубликую свой код немного позже.   -  person Spencer    schedule 04.05.2018
comment
Как рекомендовано в другом посте, опубликуйте ответ и отметьте его как правильный.   -  person eyllanesc    schedule 04.05.2018
comment
@eyllanesc Это еще не совсем готово для ответа, у меня все еще есть проблемы, поэтому я не думаю, что это правильное решение.   -  person Spencer    schedule 04.05.2018


Ответы (1)


Хорошо, я понял это сейчас, всего лишь с несколькими настройками кода в моем отредактированном посте. Секрет в том, чтобы сохранить метку полного размера родительского прямоугольника (в данном случае размер всего макета), а затем масштабировать фильм в пределах метки. По сути, вы внутренне масштабируете фильм, вместо того, чтобы автоматически заполнять содержимое метки. Из того, что я могу сказать, это немного меняет порядок операций и позволяет фильму масштабироваться при рендеринге вместо рендеринга кадра, а затем масштабировать его до размера метки.

Рабочий код:

import sys
from PyQt4 import QtGui, QtCore

class MovieTest(QtGui.QDialog):
    def __init__(self):
        super(MovieTest, self).__init__()

        layout = QtGui.QVBoxLayout()
        self.setLayout(layout)

        self.loading_lbl = QtGui.QLabel()
        self.loading_lbl.setStyleSheet('border: 1px solid red') # just for illustration
        self.loading_lbl.setAlignment(QtCore.Qt.AlignCenter)
        layout.addWidget(self.loading_lbl)
        loading_movie = QtGui.QMovie("loading-radial_loop.gif")
        self.loading_lbl.setMovie(loading_movie)
        loading_movie.start()

        self.setGeometry(50,50,100,100)
        self.setMinimumSize(10,10)

    def resizeEvent(self, event):
        rect = self.geometry()
        size = QtCore.QSize(min(rect.width(), rect.height()), min(rect.width(), rect.height()))

        movie = self.loading_lbl.movie()
        movie.setScaledSize(size)

def main():
    app = QtGui.QApplication(sys.argv)
    ex = MovieTest()
    ex.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
person Spencer    schedule 04.05.2018
comment
это решение не работает, моя проблема может ли кто-нибудь дать мне ответ на этот вопрос stackoverflow.com/questions/53729463/ - person raghava; 12.12.2018
comment
@raghava Мне понадобится больше данных ... Я использую этот код некоторое время, и он определенно работает. - person Spencer; 13.12.2018
comment
@Spencer, у тебя включено HighDPIScaling для приложения? Потому что для меня масштабированный gif становится пиксельным, если я включаю HighDPIScaling: -gif-in-qt - person Boney; 07.05.2021