【问题标题】:Is there a way to put shadow just behind QSplashScreen?有没有办法在 QSplashScreen 后面放置阴影?
【发布时间】:2020-10-17 21:14:28
【问题描述】:

我正在尝试制作一个项目,我想在我的 QSplashScreen 后面放置阴影。有什么办法吗?

我搜索了,QGraphicsDropShadowEffect 不起作用。

【问题讨论】:

    标签: python pyqt shadow qsplashscreen


    【解决方案1】:

    阴影效果通常是操作系统的职责。

    对于那些效果不可用的系统,您可以创建“虚拟”光栅化阴影,但有一些缺点:

    • 如果系统确实支持阴影效果,结果会很丑,因为系统阴影将与自定义阴影一起绘制;
    • 阴影效果应用于整个“根”窗口的外观,因此如果在显示启动画面时某些内容发生变化,这些变化将不会反映在阴影效果中;
    • 如果系统不支持不透明的移动事件(意味着moveEvent() 仅在移动完成时发送),阴影效果会显示一些伪影;

    这是对显示阴影效果的 QSplashScreen 的可能重新实现。诀窍是创建一个临时的 QGraphicsScene 并添加一个应用了 QGraphicsDropShadowEffect 的 QGraphicsRectItem。

    class SplashTest(QtWidgets.QSplashScreen):
        _shadowSize = 8
        shadowCache = None
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.setWindowFlags(QtCore.Qt.SplashScreen)
            self.desktopPixmap = QtWidgets.QApplication.primaryScreen().grabWindow(0)
    
        @QtCore.pyqtProperty(int)
        def shadowSize(self):
            return self._shadowSize
    
        @shadowSize.setter
        def shadowSize(self, shadowSize):
            if shadowSize == self._shadowSize:
                return
            self._shadowSize = shadowSize
            if self.shadowCache is None:
                self.shadowCache = {}
            else:
                self.shadowCache.clear()
            self.repaint()
    
        def setShadowSize(self, shadowSize):
            self.shadowSize = shadowSize
    
        def setPixmap(self, pixmap):
            self.shadowCache.clear()
            super().setPixmap(pixmap)
            size = QtCore.QSize(pixmap.width() + self.shadowSize, pixmap.height() + self.shadowSize)
            self.setFixedSize(size)
            if self.isVisible():
                self.repaint()
    
        def drawShadow(self, event):
            if not self.pixmap() or self.pixmap().isNull():
                return
            shadowCache = self.shadowCache.get((self.width(), self.height()))
            if not shadowCache:
                # create the shadow effect if it's not cached yet
                self.shadowCache[(self.width(), self.height())] = shadowCache = QtGui.QPixmap(self.size())
                shadowCache.fill(QtCore.Qt.transparent)
    
                # create a virtual QGraphicsScene to paint onto
                scene = QtWidgets.QGraphicsScene()
                scene.setSceneRect(QtCore.QRectF(self.desktopPixmap.rect()))
                # add a QGraphicsRectItem to the scene that will be used for the shadow
                pmItem = scene.addRect(QtCore.QRectF(self.pixmap().rect()).translated(self.geometry().topLeft()))
                pmItem.setPen(QtGui.QPen(QtCore.Qt.NoPen))
                pmItem.setBrush(QtGui.QBrush(QtCore.Qt.white))
                offset = QtCore.QPoint(self.shadowSize / 2, self.shadowSize / 2)
                effect = QtWidgets.QGraphicsDropShadowEffect(blurRadius=self.shadowSize, offset=offset)
                pmItem.setGraphicsEffect(effect)
    
                pmPainter = QtGui.QPainter(shadowCache)
                pmPainter.setRenderHints(pmPainter.Antialiasing)
                scene.render(pmPainter, QtCore.QRectF(self.rect()), pmItem.sceneBoundingRect().adjusted(0, 0, self.shadowSize, self.shadowSize))
                pmPainter.end()
    
            qp = QtGui.QPainter(self)
            # draw the background taken from the root window
            qp.drawPixmap(event.rect(), self.desktopPixmap, event.rect().translated(self.pos()))
            # draw the shadow
            qp.drawPixmap(0, 0, shadowCache)
    
        def event(self, event):
            if event.type() == QtCore.QEvent.Paint:
                # intercept the Paint event in order to draw the shadow
                self.drawShadow(event)
            return super().event(event)
    
        def moveEvent(self, event):
            self.repaint()
    
    
    def updateSplash():
        # remember: globals should *ALWAYS* be avoided unless you *really* know how to
        # use them; this is just for the purpose of this example
        global loadingStatus
        loadingStatus += 1
        splashTest.showMessage('Loading: {}%'.format(loadingStatus))
        if loadingStatus >= 100:
            timer.stop()
            QtCore.QTimer.singleShot(1000, lambda: splashTest.showMessage('Completed'))
            QtCore.QTimer.singleShot(5000, splashTest.close)
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        splashTest = SplashTest(shadowSize=16)
        splashTest.setPixmap(QtGui.QPixmap('splash.png'))
        loadingStatus = 0
        timer = QtCore.QTimer(interval=50, timeout=updateSplash)
        timer.start()
        splashTest.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 多么棒的工作!!!谢谢,这正是我正在寻找的^^
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2021-12-30
    • 2020-09-04
    • 2021-02-09
    • 1970-01-01
    • 2016-09-26
    相关资源
    最近更新 更多