ในที่สุดฉันก็ตัดสินใจว่ามันสนุกที่จะทำ :-)
สำคัญ: พิจารณาว่านี่เป็นการแฮ็กบางประเภท เนื่องจากใช้ฟังก์ชัน ส่วนตัว และไม่มีเอกสารของ Qt (ซึ่งเป็นแบบเดียวกับที่ใช้โดย QGraphicsBlurEffect) และไม่รับประกันว่าจะเป็นเช่นนั้น จะทำงานได้ทุกที่
ฉันสามารถบรรลุเป้าหมายนี้ได้ด้วยการยืมโค้ดบางส่วนจากโปรแกรมดูรายการทีวีสดที่เรียกว่า Atropine ส่วนที่น่าสนใจอยู่ใน เอฟเฟกต์ ไพแหล่งที่มา
โปรดทราบว่าเอฟเฟกต์ที่คล้ายกันอาจเกิดขึ้นได้โดยใช้ภาพวาด "นามธรรม" ของ QGraphicsScene ส่วนตัวภายใน QGraphicsEffect เอง แต่จะช้ากว่ามาก (เนื่องจากคุณจะต้องสร้าง QGraphicsPixmapItems ใหม่ในแต่ละครั้งที่เมธอด draw()
ของเอฟเฟกต์คือ เรียกว่า) และคงจะมีผลข้างเคียงบ้าง
เคล็ดลับคือการรับชื่อฟังก์ชันผ่าน 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: ฉันเรียกใช้คำสั่ง nn
เดียวกันกับไฟล์ libQtGui.so
เก่าสำหรับ Qt4 และให้ผลลัพธ์เดียวกัน
นี่คือเอฟเฟกต์นีออนที่สวยงามของคุณ...
และนี่คือโค้ด ฉันได้เพิ่มโปรแกรมตัวอย่างเพื่อทดสอบ:
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())
จากการทดสอบของฉัน การใช้ปัจจัยการเรืองแสงที่สูงกว่า 1 โดยมีรัศมีความเบลอน้อยกว่า 4 อาจส่งผลให้เกิดสิ่งประดิษฐ์บางอย่างในการวาดภาพ
นอกจากนี้ต้องใช้ความระมัดระวังกับจานสีด้วย ตัวอย่างเช่น หากคุณต้องการใช้เอฟเฟกต์กับ QLineEdit คุณอาจต้องตั้งค่า QPalette.Base
ให้โปร่งใสด้วย:
ฉันสามารถทดสอบได้สำเร็จบนเครื่อง Linux สองเครื่อง (ด้วย Qt 5.7 และ 5.12) หากใครสนใจแสดงความคิดเห็นเกี่ยวกับการทดสอบบนแพลตฟอร์มอื่น ฉันยินดีที่จะอัปเดตคำตอบนี้ตามนั้น
person
musicamante
schedule
27.03.2020
if
ทั้งหมดเหล่านั้น เพียงแค่สร้างฟังก์ชันที่คืนค่าทั้งหมดตามลำดับที่ถูกต้อง (เพื่อที่คุณจะได้ไม่ต้อง ต้องทำlower()
ทุกครั้ง) นอกจากนั้น มันดูแย่เพราะนี่ไม่ใช่สิ่งที่ QGraphicsBlurEffect ถูกสร้างขึ้นมา ดังนั้นคุณแค่สร้างองค์ประกอบที่คล้ายกับสิ่งที่คุณต้องการบรรลุ ฉันเกรงว่าทางเลือกเดียวคือสร้างคลาสย่อย QGraphicsEffect ของคุณเอง ซึ่งอาจเป็นไปตามขนาดของเอฟเฟกต์และ/หรือการเปลี่ยนสีเบลอ - person musicamante   schedule 27.03.2020