如何制作漂亮的霓虹灯效果?

时间:2020-03-27 17:35:32

标签: python qt pyqt5 qtstylesheets

我想通过控制光的力量来制作出美丽多汁的霓虹灯效果。为此,我构建了这样的代码

import sys
from PyQt5.QtWidgets import (QRadioButton, QHBoxLayout, QButtonGroup, 
    QApplication, QGraphicsScene,QGraphicsView, QGraphicsLinearLayout, QGraphicsWidget, QWidget, QLabel)
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtCore import QSize, QPoint,Qt
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *



from PyQt5.QtGui import QPainter


class Window(QWidget):
    def __init__(self):
        super().__init__()

        self.resize(800, 800)

        self.setStyleSheet('background:black;')


        mainLayout = QtWidgets.QVBoxLayout(self)
        mainLayout.setContentsMargins(0, 0, 0, 0)

        color_1 = '162, 162, 162,'
        color_2 = '255, 255, 255,'
        color_3 = '0, 255, 255,'

        d_ = 1

        power = int(255/100*d_)

        for x in range(6):
            label = QLabel(self)


            color_L = color_1
            glass_L = 255
            size_L = 60
            blut_L = 0


            label.raise_()

            if x < 1 :
                color_L = color_1
            elif x < 2 :
                color_L = color_3
                glass_L = power
            elif x < 3 :
                color_L = color_2
                blut_L = 6
                glass_L = power
            elif x < 4:
                color_L = color_2
                blut_L = 40
                glass_L = power
            elif x < 5 :
                label.lower()
                color_L = color_3
                blut_L = 40
                size_L = 70
                glass_L = power
            elif x < 6 :
                label.lower()
                color_L = color_3
                blut_L = 150
                size_L = 70
                glass_L = power

            label.setText('test')
            label.setStyleSheet('background:rgba(0, 0, 0, 0);color:rgba({} {}); font-size:{}px;'.format(color_L, glass_L,size_L))
            label.resize(self.width(), self.height())
            label.setAlignment(Qt.AlignCenter)

            self.effect = QtWidgets.QGraphicsBlurEffect(blurRadius=blut_L)
            label.setGraphicsEffect(self.effect)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

但是代码太麻烦了。结果发现光线太不自然了,

enter image description here

如果您指示弱的光强度,则看起来特别糟糕。

有没有更好的选择可以产生霓虹灯效果?还是为什么他看起来这么糟糕?

2 个答案:

答案 0 :(得分:3)

嗯,我最终认为这样做很有趣:-)

重要:考虑到这是某种黑客行为,因为它使用了Qt的 private 和未记录的功能(与QGraphicsBlurEffect相同),并且无法保证它将在任何地方都可以使用。
我已经能够通过从实时电视查看器中借用一些称为Atropine的代码来实现这一点,有趣的部分位于effects.py来源中。

请注意,可以通过在QGraphicsEffect自身内部使用私有QGraphicsScene的“抽象”绘图来实现类似的效果,但是这样做会慢得多(因为每次{{1时,您都必须创建新的QGraphicsPixmapItems }}这种效果的方法称为),并且可能会有一些副作用。

诀窍是通过ctypes获得函数名称,我只能在Linux和Windows中找到导出的函数名称(但是我无法在那里进行测试):

    # Linux:
    $ nm -D /usr/lib/libQt5Widgets.so |grep qt_blurImage
    004adc30 T _Z12qt_blurImageP8QPainterR6QImagedbbi
    004ae0e0 T _Z12qt_blurImageR6QImagedbi

    # Windows (through Mingw):
    > objdump -p /QtGui4.dll |grep blurImage
        [8695] ?qt_blurImage@@YAXAAVQImage@@N_NH@Z
        [8696] ?qt_blurImage@@YAXPAVQPainter@@AAVQImage@@N_N2H@Z

我无法对MacO进行测试,但我认为它应该与Linux上的命令行相同。

请注意,这些函数名在相同的操作系统 Qt版本上似乎是静态的:我在旧的draw()文件上为Qt4运行相同的nn命令并给出了相同的结果。

所以,这是您的美丽的霓虹灯效果 ...

a wonderful neon effect!

这是代码,我添加了一个示例程序对其进行测试:

libQtGui.so

请注意,根据我的测试,使用大于1的辉光因数且模糊半径小于4的辉光因数可能会导致某些绘画瑕疵。

此外,必须谨慎对待调色板。例如,如果要将效果应用于QLineEdit,则可能还需要将import sys import sip import ctypes from PyQt5 import QtCore, QtGui, QtWidgets if sys.platform == 'win32': # the exported function name has illegal characters on Windows, let's use # getattr to access it _qt_blurImage = getattr(ctypes.CDLL('QtGui5.dll'), '?qt_blurImage@@YAXPAVQPainter@@AAVQImage@@N_N2H@Z') else: try: qtgui = ctypes.CDLL('libQt5Widgets.so') except: qtgui = ctypes.CDLL('libQt5Widgets.so.5') _qt_blurImage = qtgui._Z12qt_blurImageP8QPainterR6QImagedbbi class NeonEffect(QtWidgets.QGraphicsColorizeEffect): _blurRadius = 5. _glow = 2 def glow(self): return self._glow @QtCore.pyqtSlot(int) def setGlow(self, glow): if glow == self._glow: return self._glow = max(1, min(glow, 10)) self.update() def blurRadius(self): return self._blurRadius @QtCore.pyqtSlot(int) @QtCore.pyqtSlot(float) def setBlurRadius(self, radius): if radius == self._blurRadius: return self._blurRadius = max(1., float(radius)) self.update() def applyBlurEffect(self, blurImage, radius, quality, alphaOnly, transposed=0, qp=None): blurImage = ctypes.c_void_p(sip.unwrapinstance(blurImage)) radius = ctypes.c_double(radius) quality = ctypes.c_bool(quality) alphaOnly = ctypes.c_bool(alphaOnly) transposed = ctypes.c_int(transposed) if qp: qp = ctypes.c_void_p(sip.unwrapinstance(qp)) _qt_blurImage(qp, blurImage, radius, quality, alphaOnly, transposed) def draw(self, qp): pm, offset = self.sourcePixmap(QtCore.Qt.LogicalCoordinates, self.PadToEffectiveBoundingRect) if pm.isNull(): return # use a double sized image to increase the blur factor scaledSize = QtCore.QSize(pm.width() * 2, pm.height() * 2) blurImage = QtGui.QImage(scaledSize, QtGui.QImage.Format_ARGB32_Premultiplied) blurImage.fill(0) blurPainter = QtGui.QPainter(blurImage) blurPainter.drawPixmap(0, 0, pm.scaled(scaledSize, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)) blurPainter.end() # apply the blurred effect on the image self.applyBlurEffect(blurImage, 1 * self._blurRadius, True, False) # start the painter that will use the previous image as alpha tmpPainter = QtGui.QPainter(blurImage) # using SourceIn composition mode we use the existing alpha values # to paint over tmpPainter.setCompositionMode(tmpPainter.CompositionMode_SourceIn) color = QtGui.QColor(self.color()) color.setAlpha(color.alpha() * self.strength()) # fill using the color tmpPainter.fillRect(pm.rect(), color) tmpPainter.end() # repeat the effect which will make it more "glowing" for g in range(self._glow): qp.drawImage(0, 0, blurImage.scaled(pm.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)) super().draw(qp) class NeonTest(QtWidgets.QWidget): def __init__(self): super().__init__() layout = QtWidgets.QGridLayout(self) palette = self.palette() palette.setColor(palette.Window, QtCore.Qt.black) palette.setColor(palette.WindowText, QtCore.Qt.white) self.setPalette(palette) self.label = QtWidgets.QLabel('NEON EFFECT') layout.addWidget(self.label, 0, 0, 1, 2) self.label.setPalette(QtWidgets.QApplication.palette()) self.label.setContentsMargins(20, 20, 20, 20) f = self.font() f.setPointSizeF(48) f.setBold(True) self.label.setFont(f) self.effect = NeonEffect(color=QtGui.QColor(152, 255, 250)) self.label.setGraphicsEffect(self.effect) self.effect.setBlurRadius(40) layout.addWidget(QtWidgets.QLabel('blur radius')) radiusSpin = QtWidgets.QDoubleSpinBox(minimum=1, maximum=100, singleStep=5) layout.addWidget(radiusSpin, 1, 1) radiusSpin.setValue(self.effect.blurRadius()) radiusSpin.valueChanged.connect(self.effect.setBlurRadius) layout.addWidget(QtWidgets.QLabel('glow factor')) glowSpin = QtWidgets.QSpinBox(minimum=1, maximum=10) layout.addWidget(glowSpin, 2, 1) glowSpin.setValue(self.effect.glow()) glowSpin.valueChanged.connect(self.effect.setGlow) layout.addWidget(QtWidgets.QLabel('color strength')) strengthSpin = QtWidgets.QDoubleSpinBox(minimum=0, maximum=1, singleStep=.05) strengthSpin.setValue(1) layout.addWidget(strengthSpin, 3, 1) strengthSpin.valueChanged.connect(self.effect.setStrength) colorBtn = QtWidgets.QPushButton('color') layout.addWidget(colorBtn, 4, 0) colorBtn.clicked.connect(self.setColor) self.aniBtn = QtWidgets.QPushButton('play animation') layout.addWidget(self.aniBtn, 4, 1) self.aniBtn.setCheckable(True) self.glowAni = QtCore.QVariantAnimation(duration=250) self.glowAni.setStartValue(1) self.glowAni.setEndValue(5) self.glowAni.setEasingCurve(QtCore.QEasingCurve.InQuad) self.glowAni.valueChanged.connect(glowSpin.setValue) self.glowAni.finished.connect(self.animationFinished) self.aniBtn.toggled.connect(self.glowAni.start) def animationFinished(self): if self.aniBtn.isChecked(): self.glowAni.setDirection(not self.glowAni.direction()) self.glowAni.start() def setColor(self): d = QtWidgets.QColorDialog(self.effect.color(), self) if d.exec_(): self.effect.setColor(d.currentColor()) 设置为透明:

a glowing line edit!

如果有人愿意评论在其他平台上进行测试,我已经能够在两台Linux机器(Qt 5.7和5.12)上成功地对其进行测试,我将很乐意相应地更新此答案。

答案 1 :(得分:1)

我无法评论和编辑musicamante的帖子,不断给我代码格式错误,所以我将其发布在这里。

考虑到QGraphicsEffect是从QtWidgets而不是QtGui导入的,所以我将Qt5Widgets.dll objdump了,结果如下:

.\objdump.exe -p /Qt5Widgets.dll | findstr "blurImage"
        [5154] ?qt_blurImage@@YAXAEAVQImage@@N_NH@Z
        [5155] ?qt_blurImage@@YAXPEAVQPainter@@AEAVQImage@@N_N2H@Z

因此在Windows上应该是:

_qt_blurImage = getattr(ctypes.CDLL('Qt5Widgets.dll'),
        '?qt_blurImage@@YAXPEAVQPainter@@AEAVQImage@@N_N2H@Z')

这是屏幕截图:

enter image description here

相关问题