Bagaimana cara membuat efek neon yang indah?

Saya ingin membuat efek neon yang indah dan menarik dengan kemampuan mengontrol kekuatan cahaya. Untuk ini, saya membuat kode seperti itu

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_())

tapi kodenya terlalu rumit. Dan cahayanya ternyata terlalu tidak naturalistik,

masukkan deskripsi gambar di sini

terlihat sangat buruk jika Anda menunjukkan intensitas cahaya yang lemah.

Apakah ada pilihan yang lebih baik untuk membuat efek neon? atau mengapa dia terlihat begitu buruk?


person askqest    schedule 27.03.2020    source sumber
comment
Kode ini dapat sedikit ditingkatkan (tetapi ini hanya tentang keterbacaan dan kegunaan, bukan peningkatan kinerja nyata): tidak perlu melakukan semua pernyataan if tersebut, cukup buat fungsi yang mengembalikan semua nilai dalam urutan yang benar (sehingga Anda tidak perlu melakukan lower() setiap kali). Selain itu terlihat buruk karena QGraphicsBlurEffect tidak diciptakan untuk ini, jadi Anda hanya membuat komposisi yang menyerupai apa yang ingin Anda capai. Saya khawatir satu-satunya alternatif adalah membuat subkelas QGraphicsEffect Anda sendiri, mungkin berdasarkan ukuran efek dan/atau mengubah warna buram.   -  person musicamante    schedule 27.03.2020


Jawaban (2)


Yah, saya akhirnya memutuskan itu menyenangkan :-)

PENTING: Pertimbangkan bahwa ini adalah semacam peretasan, karena menggunakan fungsi Qt yang pribadi dan tidak terdokumentasi (yang sama dengan yang digunakan oleh QGraphicsBlurEffect) dan tidak dijamin akan demikian akan bekerja di mana saja.
Saya dapat mencapainya dengan meminjam beberapa kode dari penampil TV langsung yang dikenal sebagai Atropin, bagian yang menarik ada di efek. py sumber.

Perhatikan bahwa efek serupa mungkin dapat dicapai dengan menggunakan gambar "abstrak" dari QGraphicsScene pribadi di dalam QGraphicsEffect itu sendiri, tetapi akan jauh lebih lambat (karena Anda harus membuat QGraphicsPixmapItems baru setiap kali metode draw() dari efek tersebut disebut) dan mungkin akan memiliki beberapa efek samping.

Caranya adalah mendapatkan nama fungsi melalui ctypes, saya hanya bisa menemukan nama fungsi yang diekspor di Linux dan Windows (tapi saya tidak bisa mengujinya di sana):

    # 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

Saya tidak bisa melakukan pengujian untuk MacO, tapi saya berpikir baris perintahnya harus sama dengan yang ada di linux.

Perhatikan bahwa nama fungsi ini tampaknya statis pada sistem operasi dan versi Qt yang sama: Saya menjalankan perintah nn yang sama pada file libQtGui.so lama untuk Qt4 dan memberikan hasil yang sama.

Jadi, inilah efek neon cantik Anda...

efek neon yang menakjubkan!

Dan ini kodenya, saya telah menambahkan contoh program untuk mengujinya:

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())

Perhatikan bahwa, berdasarkan pengujian saya, menggunakan faktor cahaya lebih tinggi dari 1 dengan radius blur kurang dari 4 mungkin menghasilkan beberapa artefak lukisan.

Selain itu, perhatian juga harus diberikan pada palet. Jika Anda ingin, misalnya, menerapkan efek ke QLineEdit, Anda mungkin juga ingin mengatur QPalette.Base menjadi transparan:

edit garis yang bersinar!

Saya telah berhasil mengujinya pada dua mesin Linux (dengan Qt 5.7 dan 5.12), jika ada yang mau berkomentar tentang pengujian pada platform lain, saya akan dengan senang hati memperbarui jawaban ini.

person musicamante    schedule 27.03.2020
comment
Maaf untuk pertanyaan bodoh tapi apa itu import sip Saya telah mengatur pip install sip dan pip install PyQt5-sip TETAPI paython tidak menemukan modul SIP - person askqest; 28.03.2020
comment
Jika Anda memiliki PyQt, Anda seharusnya sudah menyesapnya. Mungkin periksa instalasi PyQt5 dan cari di sini di StackOverflow tentang kesalahan serupa. - person musicamante; 28.03.2020
comment
Satu-satunya hal yang saya temukan adalah pertanyaan tentang PYQT4 , tetapi di sana, sejauh yang saya pahami, mereka merekomendasikan menginstal sip secara terpisah. Dan pertanyaan ini tidak akan membantu saya. Di folder PyQt5 ada sip.cp37-win_amd64.pyd file. Apakah file ini bertanggung jawab untuk sip? - person askqest; 28.03.2020
comment
Sekarang kodenya menimbulkan kesalahan Traceback (most recent call last): File "C:\Users\user\Desktop\neon.py", line 35, in <module> _qt_blurImage = getattr(ctypes.CDLL('QtGui5.dll'), File "C:\Python37\lib\ctypes\__init__.py", line 364, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 126] The specified module was not found - person askqest; 29.03.2020
comment
Mungkin itu Qt5Gui.dll, atau Qt5Widgets.dll. Cari saja. Seperti yang sudah saya katakan, saya tidak dapat mengujinya di Windows - person musicamante; 29.03.2020
comment
Saya tidak mengerti apa yang salah dengan file-file ini (Qt5Gui.dll dan Qt5Widgets.dll) Apa yang harus saya cari di Internet? - person askqest; 29.03.2020
comment
Apa yang Anda maksud dengan apa yang salah dengan file-file ini? Apakah Anda memilikinya? Sudahkah Anda mencarinya di komputer Anda? Apakah errornya selalu sama dengan komentar Anda sebelumnya, menggunakan nama lain? Seperti yang sudah saya katakan, mohon jangan memberikan informasi sepotong-sepotong, lebih jelas. - person musicamante; 29.03.2020
comment
Saya punya file-file ini. Akan aneh bagi saya jika file-file ini tidak ada. Qt5Gui dan Qt5Widgets adalah file utama tempat program Qt berada. Maaf saya salah paham. - person askqest; 31.03.2020
comment
Saya tahu untuk apa file-file itu, tetapi karena saya tidak menggunakan Windows, saya tidak yakin dengan namanya. Dan saya tidak meminta Anda menjelaskannya, jadi, sekali lagi, dan saya harap untuk terakhir kalinya, apa masalahnya? Apakah masih tertulis modul tidak dapat ditemukan? Atau itu kesalahan lain? Anda harus menjawab semua pertanyaan yang kami ajukan!!! - person musicamante; 31.03.2020
comment
Saya menemukan apa masalahnya. skripnya mengatakan (QtGui5.dll) Dan file saya bernama (Qt5Gui.dll). Saya tidak menyadarinya karena saya sedang mencari QtGui. Namun kini kode tersebut menimbulkan masalah baru. Traceback (most recent call last):File"C:\neon.py",line36,in<module>'qt_blurImage@@YAXPAVQPainter@@AAVQImage@@N_N2H@Z')File"C:\Python37\lib\ctypes\__init__.py",line377,in__getattr__func=self.__getitem__(name)File"C:\Python37\lib\ctypes\__init__.py",line382,in__getitem__func=self._FuncPtr((name_or_ordinal,self))AttributeError:function'qt_blurImage@@YAXPAVQPainter@@AAVQImage@@N_N2H@Z' not found - person askqest; 02.04.2020
comment
?qt_blurImage@@YAXAAVQImage@@N_NH@Z dan ?qt_blurImage@@YAXPAVQPainter@@AAVQImage@@N_N2H@Z tidak berfungsi - person askqest; 02.04.2020
comment
@askqest Saya mendapatkan masalah yang sama di window10. Saya akan menyerah kalau begitu. Kode yang diberikan sangat aneh. - person Luk Aron; 11.06.2020
comment
Saya memberikan peringatan itu karena alasan tertentu: Pertimbangkan bahwa ini adalah semacam peretasan, karena menggunakan fungsi Qt yang pribadi dan tidak terdokumentasi (yang sama dengan yang digunakan oleh QGraphicsBlurEffect) dan tidak ada jaminan bahwa ini akan berfungsi di mana pun. - person musicamante; 11.06.2020
comment
WoW, saya mencari grafik yang bersinar di qtwidgets, (qml memiliki tipe Glow-nya: qt.io/blog/2017/02/07/glowing-qt-charts). Ini juga bisa digunakan pada tangga lagu, keren! - person Muhammed B. Aydemir; 02.09.2020

Saya tidak dapat berkomentar dan mengedit postingan musicamante terus memberi saya kesalahan format kode, jadi saya mempostingnya di sini.

Mengingat QGraphicsEffect diimpor dari QtWidgets bukan QtGui, jadi saya keberatan Qt5Widgets.dll dan inilah hasilnya:

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

Jadi di Windows seharusnya:

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

Berikut tangkapan layarnya:

masukkan deskripsi gambar di sini

person closer_ex    schedule 09.07.2020
comment
Pilihan ini tidak menyebabkan error, tapi sekarang kodenya kembali bertanya sip Saya masih tidak mengerti kenapa saya tidak memilikinya, saya menginstal PyQT5 beberapa kali - person askqest; 09.07.2020
comment
@askqest coba from PyQt5 import sip - person closer_ex; 09.07.2020
comment
berhasil!! Bagaimana Anda bisa memadukan putih dan biru? - person askqest; 10.07.2020
comment
@askqest Kodenya sama dengan musicamante, tetapi rendering font di windows menurut saya berbeda, yang menghasilkan efek berbeda. Pada dasarnya itu hanya label putih dengan gambar blur biru, triknya adalah membuat blur lebih pas dengan teks. - person closer_ex; 11.07.2020
comment
Saya mencoba mengubah warna di setStyleSheet('color:red') tetapi tidak mempengaruhi apa pun. Saya ingin tahu apakah mungkin untuk menambahkan NeonEffect ke dalam. dengan kata lain. Entah bagaimana membalikkan setBlurRadius() untuk membuat warna putih lebih tipis. suka di sini - person askqest; 11.07.2020
comment
@askqest mungkin membaca tentang CompositionMode untuk mempelajari bagaimana efek dipadukan dengan label. Hasilnya, dalam mode SourceIn, warna teks selalu sama dengan warna blur, mengubah ke mode DestinationIn akan mengubah warna teks dan warna blur Anda. tetapi jika yang Anda maksud adalah menggambar garis putih di dalam huruf, maka menurut saya efek blur bukanlah yang harus Anda cari. - person closer_ex; 11.07.2020