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!](https://i.stack.imgur.com/DAFDp.png)
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!](https://i.stack.imgur.com/wtlj6.png)
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
if
tersebut, cukup buat fungsi yang mengembalikan semua nilai dalam urutan yang benar (sehingga Anda tidak perlu melakukanlower()
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