Issue
A little Context
I'm trying to make a QSplashScreen
with a custom animation. I've tried many different approaches, with each failures. Mostly, my main technique was to create a new Class which inherits from QSplashScreen
and then plan with the paintEvent()
. It worked... ish. The animation is not the problem, It is really the QPaintDevice which seems corrupted.
Because I was calling the super(classname, self).__init__(args)
only way after in my init and passing it arguments that I modified in the init, I always had corrupted pixels; The image was in weird tones and had lines of colorful pixels in the background. Sometimes it is patterns sometimes it is completely random.
I have tried changing every line of code and the only thing that removed those lines was calling the super()
at the beginning of the __init__
. Unfortunately, I was making a frame that I was passing to the init. Now that this isn't possible, I would like to modify the size of the QPaintDevice
on which my QSplashScreen
initializes, because my animation is displayed beyond that frame. I won't post all the code since the custom animation is quite heavy.
Minimal Working Exemple
from PyQt5.QtWidgets import QApplication, QSplashScreen, QMainWindow
from PyQt5.QtCore import Qt, QSize, pyqtSignal, QPoint
from PyQt5.QtGui import QPixmap, QPainter, QIcon, QBrush
import time, sys
class FakeAnimatedSplash(QSplashScreen):
def __init__(self, image):
self.image = image
self.newFrame = QPixmap(self.image.size()+QSize(0, 20))
super(FakeAnimatedSplash, self).__init__(self.newFrame, Qt.WindowStaysOnTopHint)
def showEvent(self, event):
self.update()
def paintEvent(self, event):
painter = QPainter(self)
painter.fillRect(self.rect(), Qt.transparent)
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setPen(Qt.NoPen)
painter.drawPixmap(self.image.rect(), self.image)
painter.drawEllipse(QPoint(0, 110), 8, 8)
class App(QApplication):
def __init__(self, sys_argv):
super(App, self).__init__(sys_argv)
self.main = QMainWindow()
self.setAttribute(Qt.AA_EnableHighDpiScaling)
self.newSplash()
self.main.show()
def newSplash(self):
pixmap = QPixmap("yourImage.png")
smallerPixmap = pixmap.scaled(100, 100, Qt.KeepAspectRatio, Qt.SmoothTransformation)
splash = FakeAnimatedSplash(smallerPixmap)
splash.setEnabled(False)
splash.show()
start = time.time()
while time.time() < start + 10:
self.processEvents()
def main():
app = App(sys.argv)
app.setWindowIcon(QIcon("ABB_icon.png"))
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Potential Solution
Changing the super()
to the beginning makes it work but reduces the QPaintDevice window which hides my animation. I would like to expand it, but there are no methods which can do it after the initialization.
def __init__(self, image):
super(LoadingDotsSplash, self).__init__(image, QtCore.Qt.WindowStaysOnTopHint)
self.image = image
# here a function or method that changes the size of the QPaintDevice
Solution
The problem is that newFrame is an uninitialized QPixmap and for efficiency reasons the pixels are not modified so they have random values, and that is because the size of the FakeAnimatedSplash is larger than the QPixmap that is painted. The solution is to set the value of the newFrame pixels to transparent:
class FakeAnimatedSplash(QSplashScreen):
def __init__(self, image):
self.image = image
pix = QPixmap(self.image.size() + QSize(0, 20))
pix.fill(Qt.transparent)
super(FakeAnimatedSplash, self).__init__(pix, Qt.WindowStaysOnTopHint)
def paintEvent(self, event):
painter = QPainter(self)
painter.fillRect(self.rect(), Qt.transparent)
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setPen(Qt.NoPen)
painter.drawPixmap(self.image.rect(), self.image)
painter.drawEllipse(QPoint(0, 110), 8, 8)
Answered By - eyllanesc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.