- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
虽然 Qt 提供了 QGraphicsDropShadowEffect,但没有可用的“Neumorphism”效果:
在 css 中有 box-shadow
属性(上图中就是这样做的),它可以有多种颜色,但 Qt 缺乏对该属性的支持,并且一次应用多个图形效果是不可能的。
这能做到吗?
最佳答案
解决方案是创建 QGraphicsEffect 的自定义子类并使用渐变。
起初我想遵循用于 CSS 的相同概念,继承 QGraphicsDropShadowEffect 并在内部使用另一个来绘制“另一个”阴影,但我不喜欢结果:在某些情况下(通常是半径和对比度太大时)它只是不起作用:
如果仔细观察,您会发现结果与阴影太相似,就像对象在 float ,而应该是“挤出”。
我发现的唯一有效解决方案是手动绘制所有内容,使用边界的线性渐变和角的复合渐变。虽然第一个非常合乎逻辑,但第二个需要一些使用 QPainter 复合模式的独创性:Qt 只有径向和锥形渐变,但它们之间没有“混合”。
然后的技巧是为“浅”色创建径向渐变,中心为全色,边框为 0 alpha 的相同颜色,然后为“暗”色(带有“暗”色)叠加锥形渐变开始时的颜色和 90° 处的“光”),将使用第一个渐变的 alpha 分量进行绘制。
然后只需创建函数来更新每个属性:距离(效果的范围)、颜色(用于渐变,默认为应用程序的 QPalette.Window 颜色角色)、原点(用作光源的“源”)和圆形边框的可选 clipRadius。
一些重要的注意事项:
length
返回一个值。属性(property); clipRadius
属性允许圆角边框剪裁,但并不完美,因为QPainter的剪裁不支持抗锯齿;我会看看我将来是否可以解决这个问题; border-radius
属性,而我的设置为
clipRadius
):
class NeumorphismEffect(QtWidgets.QGraphicsEffect):
originChanged = QtCore.pyqtSignal(QtCore.Qt.Corner)
distanceChanged = QtCore.pyqtSignal(float)
colorChanged = QtCore.pyqtSignal(QtGui.QColor)
clipRadiusChanged = QtCore.pyqtSignal(int)
_cornerShift = (QtCore.Qt.TopLeftCorner, QtCore.Qt.TopRightCorner,
QtCore.Qt.BottomRightCorner, QtCore.Qt.BottomLeftCorner)
def __init__(self, distance=4, color=None, origin=QtCore.Qt.TopLeftCorner, clipRadius=0):
super().__init__()
self._leftGradient = QtGui.QLinearGradient(1, 0, 0, 0)
self._leftGradient.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode)
self._topGradient = QtGui.QLinearGradient(0, 1, 0, 0)
self._topGradient.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode)
self._rightGradient = QtGui.QLinearGradient(0, 0, 1, 0)
self._rightGradient.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode)
self._bottomGradient = QtGui.QLinearGradient(0, 0, 0, 1)
self._bottomGradient.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode)
self._radial = QtGui.QRadialGradient(.5, .5, .5)
self._radial.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode)
self._conical = QtGui.QConicalGradient(.5, .5, 0)
self._conical.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode)
self._origin = origin
distance = max(0, distance)
self._clipRadius = min(distance, max(0, clipRadius))
self._setColor(color or QtWidgets.QApplication.palette().color(QtGui.QPalette.Window))
self._setDistance(distance)
def color(self):
return self._color
@QtCore.pyqtSlot(QtGui.QColor)
@QtCore.pyqtSlot(QtCore.Qt.GlobalColor)
def setColor(self, color):
if isinstance(color, QtCore.Qt.GlobalColor):
color = QtGui.QColor(color)
if color == self._color:
return
self._setColor(color)
self._setDistance(self._distance)
self.update()
self.colorChanged.emit(self._color)
def _setColor(self, color):
self._color = color
self._baseStart = color.lighter(125)
self._baseStop = QtGui.QColor(self._baseStart)
self._baseStop.setAlpha(0)
self._shadowStart = self._baseStart.darker(125)
self._shadowStop = QtGui.QColor(self._shadowStart)
self._shadowStop.setAlpha(0)
self.lightSideStops = [(0, self._baseStart), (1, self._baseStop)]
self.shadowSideStops = [(0, self._shadowStart), (1, self._shadowStop)]
self.cornerStops = [(0, self._shadowStart), (.25, self._shadowStop),
(.75, self._shadowStop), (1, self._shadowStart)]
self._setOrigin(self._origin)
def distance(self):
return self._distance
def setDistance(self, distance):
if distance == self._distance:
return
oldRadius = self._clipRadius
self._setDistance(distance)
self.updateBoundingRect()
self.distanceChanged.emit(self._distance)
if oldRadius != self._clipRadius:
self.clipRadiusChanged.emit(self._clipRadius)
def _getCornerPixmap(self, rect, grad1, grad2=None):
pm = QtGui.QPixmap(self._distance + self._clipRadius, self._distance + self._clipRadius)
pm.fill(QtCore.Qt.transparent)
qp = QtGui.QPainter(pm)
if self._clipRadius > 1:
path = QtGui.QPainterPath()
path.addRect(rect)
size = self._clipRadius * 2 - 1
mask = QtCore.QRectF(0, 0, size, size)
mask.moveCenter(rect.center())
path.addEllipse(mask)
qp.setClipPath(path)
qp.fillRect(rect, grad1)
if grad2:
qp.setCompositionMode(qp.CompositionMode_SourceAtop)
qp.fillRect(rect, grad2)
qp.end()
return pm
def _setDistance(self, distance):
distance = max(1, distance)
self._distance = distance
if self._clipRadius > distance:
self._clipRadius = distance
distance += self._clipRadius
r = QtCore.QRectF(0, 0, distance * 2, distance * 2)
lightSideStops = self.lightSideStops[:]
shadowSideStops = self.shadowSideStops[:]
if self._clipRadius:
gradStart = self._clipRadius / (self._distance + self._clipRadius)
lightSideStops[0] = (gradStart, lightSideStops[0][1])
shadowSideStops[0] = (gradStart, shadowSideStops[0][1])
# create the 4 corners as if the light source was top-left
self._radial.setStops(lightSideStops)
topLeft = self._getCornerPixmap(r, self._radial)
self._conical.setAngle(359.9)
self._conical.setStops(self.cornerStops)
topRight = self._getCornerPixmap(r.translated(-distance, 0), self._radial, self._conical)
self._conical.setAngle(270)
self._conical.setStops(self.cornerStops)
bottomLeft = self._getCornerPixmap(r.translated(0, -distance), self._radial, self._conical)
self._radial.setStops(shadowSideStops)
bottomRight = self._getCornerPixmap(r.translated(-distance, -distance), self._radial)
# rotate the images according to the actual light source
images = topLeft, topRight, bottomRight, bottomLeft
shift = self._cornerShift.index(self._origin)
if shift:
transform = QtGui.QTransform().rotate(shift * 90)
for img in images:
img.swap(img.transformed(transform, QtCore.Qt.SmoothTransformation))
# and reorder them if required
self.topLeft, self.topRight, self.bottomRight, self.bottomLeft = images[-shift:] + images[:-shift]
def origin(self):
return self._origin
@QtCore.pyqtSlot(QtCore.Qt.Corner)
def setOrigin(self, origin):
origin = QtCore.Qt.Corner(origin)
if origin == self._origin:
return
self._setOrigin(origin)
self._setDistance(self._distance)
self.update()
self.originChanged.emit(self._origin)
def _setOrigin(self, origin):
self._origin = origin
gradients = self._leftGradient, self._topGradient, self._rightGradient, self._bottomGradient
stops = self.lightSideStops, self.lightSideStops, self.shadowSideStops, self.shadowSideStops
# assign color stops to gradients based on the light source position
shift = self._cornerShift.index(self._origin)
for grad, stops in zip(gradients, stops[-shift:] + stops[:-shift]):
grad.setStops(stops)
def clipRadius(self):
return self._clipRadius
@QtCore.pyqtSlot(int)
@QtCore.pyqtSlot(float)
def setClipRadius(self, radius):
if radius == self._clipRadius:
return
oldRadius = self._clipRadius
self._setClipRadius(radius)
self.update()
if oldRadius != self._clipRadius:
self.clipRadiusChanged.emit(self._clipRadius)
def _setClipRadius(self, radius):
radius = min(self._distance, max(0, int(radius)))
self._clipRadius = radius
self._setDistance(self._distance)
def boundingRectFor(self, rect):
d = self._distance + 1
return rect.adjusted(-d, -d, d, d)
def draw(self, qp):
restoreTransform = qp.worldTransform()
qp.setPen(QtCore.Qt.NoPen)
x, y, width, height = self.sourceBoundingRect(QtCore.Qt.DeviceCoordinates).getRect()
right = x + width
bottom = y + height
clip = self._clipRadius
doubleClip = clip * 2
qp.setWorldTransform(QtGui.QTransform())
leftRect = QtCore.QRectF(x - self._distance, y + clip, self._distance, height - doubleClip)
qp.setBrush(self._leftGradient)
qp.drawRect(leftRect)
topRect = QtCore.QRectF(x + clip, y - self._distance, width - doubleClip, self._distance)
qp.setBrush(self._topGradient)
qp.drawRect(topRect)
rightRect = QtCore.QRectF(right, y + clip, self._distance, height - doubleClip)
qp.setBrush(self._rightGradient)
qp.drawRect(rightRect)
bottomRect = QtCore.QRectF(x + clip, bottom, width - doubleClip, self._distance)
qp.setBrush(self._bottomGradient)
qp.drawRect(bottomRect)
qp.drawPixmap(x - self._distance, y - self._distance, self.topLeft)
qp.drawPixmap(right - clip, y - self._distance, self.topRight)
qp.drawPixmap(right - clip, bottom - clip, self.bottomRight)
qp.drawPixmap(x - self._distance, bottom - clip, self.bottomLeft)
qp.setWorldTransform(restoreTransform)
if self._clipRadius:
path = QtGui.QPainterPath()
source, offset = self.sourcePixmap(QtCore.Qt.DeviceCoordinates)
sourceBoundingRect = self.sourceBoundingRect(QtCore.Qt.DeviceCoordinates)
qp.save()
qp.setTransform(QtGui.QTransform())
path.addRoundedRect(sourceBoundingRect, self._clipRadius, self._clipRadius)
qp.setClipPath(path)
qp.drawPixmap(source.rect().translated(offset), source)
qp.restore()
else:
self.drawSource(qp)
关于pyqt - 我可以将 Neumorphism 效果应用于 QWidget 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60626717/
我可以使用 javascript 和其他所有东西,但在重新发明轮子之前,我想知道是否已经有一个类似的 jquery 插件,因为我想使用那个框架而不是 mootools。 我没有钱的问题,特别是 5 欧
我正在 React 应用程序中处理动画。我需要动画在悬停 后开始工作。我尝试了 :hover:after css 但不起作用。将鼠标悬停在图像上后动画可以工作,但我需要在悬停后开始。将鼠标悬停在图像上
我正在使用 jQuery 在按钮单击时实现 slider 效果。我的代码是: $(document).ready(function() { $("#mybutton").click(functio
我需要一个div标签在屏幕右侧滑出,如何使用jQuery获得这种效果?我一直在看这里:http://api.jquery.com/category/effects/sliding/而且这似乎不是我要找
我正在使用此代码实现页面 curl 效果......它在模拟器和设备中工作正常......但它不是(setType:@“pageCurl”)苹果记录的api,这导致它被iPhone拒绝App Stor
我见过各种关于 WPF 效果的引用,但它们似乎是针对位图的,而不是针对文本的。是否可以将除模糊或投影以外的效果应用于XAML中的TextBlock对象? 我想要做的示例可能是轮廓笔划,或斜角/浮雕效果
我见过各种关于 WPF 效果的引用,但它们似乎是针对位图的,而不是针对文本的。是否可以将除模糊或投影以外的效果应用于XAML中的TextBlock对象? 我想要做的示例可能是轮廓笔划,或斜角/浮雕效果
我正在尝试模拟这种效果:http://meyerweb.com/eric/css/edge/complexspiral/demo.html在我的博客上:http://segment6.blogspot
我尝试将样式应用到 Accordion Pane ,但遇到了问题。 这行不通。 accordion.setEffect(new DropShadow(BlurType.ONE_PASS_BOX, Co
关于 Datatables website 的教程足够清楚了: 在我告诉 Datatables 我正在谈论哪一列后,我只需将切换按钮放入: column.visible( ! column.visib
我正在寻找 scratchOut 效果,随便叫它什么。 这是从前景中删除图像的效果,因此背景图像变得可见。 我曾尝试使用 jquery 插件重新创建此效果,但它并不像我希望的那样流畅。 有没有人有这种
本文实例讲述了android实现文字和图片混排(文字环绕图片)效果。分享给大家供大家参考,具体如下: 在平时我们做项目中,或许有要对一张图片或者某一个东西进行文字和图片说明,这时候要求排版美观,所
本文实例讲述了Javafx简单实现【我的电脑资源管理器】效果。分享给大家供大家参考。具体如下: 1. java代码: ?
我是 ngrx 的新手,正在尝试让我的 ngrx 商店的 @Effect 函数正常工作。下面的代码显示了如果我没有使用 ngrx 商店,服务是如何工作的。我首先调用 http.get 来获取列表,然后
基本上我搜索了很多,解决方案建议应用一些 PNG 掩码或不提供所需的解决方案。 我发现了什么。 ffmpeg -i main.mkv -i facecloseup.mkv -filter_compl
有关使用从商店中选择的状态的效果的 Ngrx 文档状态(没有双关语意) Note: For performance reasons, use a flattening operator like co
我有一个数据网格控件,我在其中使用名为 FastShadow 的自定义效果,它就像一个光晕。 我希望效果在其边界之外发光,这样很好,但是当我在顶部绘制另一个形状时,我不希望这个形状受到影响。在本例中,
除了子 div.exception 中的所有内容,我想将 div.main 中的所有文本设为灰色。 div.exception 应该看起来好像类 main 从未添加到父 div。 这可能吗?如果是这样
我有一个 PDF 文件,我想重现此包页面中的页面 curl 效果: https://pub.flutter-io.cn/packages/page_turn 我试过用这个 page_turn插件,它需
我想测试一个效果如下: 如果调度了 LoadEntriesSucces 操作,则效果开始 等待 5 秒 5 秒后发送 http 请求 当响应到达时,将分派(dispatch)新的操作(取决于响应是成功
我是一名优秀的程序员,十分优秀!