- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在 PySide 中使用 QGraphicsScene
创建自定义绘图应用程序 - 我希望能够绘制复杂的形状并让用户通过鼠标与它们交互。为此,我创建了一个名为 Node
的自定义 QGraphicsItem
,它通过返回一个 QPainterPath
对象来定义其形状。图形场景使用这个形状来决定鼠标何时进入对象。在对象 paint
方法中,我只是使用 QPainter
绘制路径。
import math
import sys
import weakref
from numpy import *
from PySide.QtGui import *
from PySide.QtCore import *
class Node(QGraphicsItem):
Type = QGraphicsItem.UserType+1
def __init__(self, graphWidget, line):
super(self.__class__, self).__init__()
self.line = line
self.graph = weakref.ref(graphWidget)
self.setFlag(QGraphicsItem.ItemIsMovable)
self.newPos = QPointF()
self.setZValue(-1)
def boundingRect(self):
adjust = 10.0
return QRectF(self.line[0][0]-adjust, self.line[0][1]-adjust, 2*adjust + self.line[1][0]-self.line[0][0]+100,2*adjust+self.line[1][2]-self.line[0][3]+100)
def shape(self):
(x0,y0), (xn,yn) = p0, pn = self.line
dx,dy = xn-x0, yn-y0
dV = array([dx,dy])
mag_dV = linalg.norm(dV)
radius = 10
rotation = array( [[0,-1],[1,0]])
v = dot(rotation, dV) * radius / mag_dV
startAngle = arctan2(*v) * 180/pi + 90
path = QPainterPath()
path.setFillRule(Qt.WindingFill)
path.moveTo(*p0 - v)
path.addEllipse( x0-radius, y0-radius, 2*radius, 2*radius)
path.moveTo(*p0+v)
path.lineTo( QPoint(*pn+v))
path.arcTo( xn - radius, yn-radius, 2*radius, 2*radius, startAngle+180, 180)
path.lineTo(QPoint(*p0-v))
return path.simplified()
def paint(self, painter, option, widget):
painter.setPen(QPen(Qt.black))
painter.setBrush(Qt.darkGray)
painter.drawPath(self.shape())
class GraphWidget(QGraphicsView):
def __init__(self):
super(self.__class__, self).__init__()
self.timerId = 0
scene = QGraphicsScene(self)
scene.setItemIndexMethod(QGraphicsScene.NoIndex)
scene.setSceneRect(-200,-200,400,400)
self.setScene(scene)
self.setCacheMode(QGraphicsView.CacheBackground)
self.setRenderHint(QPainter.Antialiasing)
self.centerNode = Node(self, [[-100,-100],[0,-70]])
scene.addItem(self.centerNode)
self.centerNode.setPos(0,0)
self.scale(0.8,0.8)
self.setMinimumSize(400,400)
self.setWindowTitle(self.tr("Elastic Nodes"))
if __name__ == "__main__":
app = QApplication(sys.argv)
qsrand(QTime(0,0,0).secsTo(QTime.currentTime()))
widget = GraphWidget()
widget.show()
sys.exit(app.exec_())
我遇到的问题是如何将多边形变成一个实体形状。一个示例形状是这个带有圆角末端的矩形:
当我用椭圆而不是圆弧绘制圆角时,我得到了这个:
我想要实现的是,包含在多边形形状内的路径消失了,我所拥有的只是整个形状的轮廓,用纯色填充。我也想摆脱你看到的交替填充。这表面上允许我创建任意多边形,而无需计算每个精确的角度和交点。
到目前为止我尝试了什么:
我尝试的第一件事是使用 path.setFillRule(Qt.WindingFill)
,它应该填充所有内部空间而不是交替使用颜色。然而,这似乎并没有改变结果。
我尝试的第二件事是使用“path.simplified()”,它应该完全符合我的要求。该命令的结果是:
我怎样才能克服这个问题?
最佳答案
好的,所以这个问题的解决方案实际上非常简单:以哪种方式绕过形状很重要。
上面绘制的形状基本上是一个沿线段定向的矩形,两端各有一个圆。要绘制矩形,您必须使用单独的线段。原题中,矩形轮廓是逆时针绘制的:
path.lineTo(QPointF(*p0+v))
path.lineTo(QPointF(*pn+v))
path.lineTo(QPointF(*pn-v))
path.lineTo(QPointF(*p0-v))
导致重叠的部分没有被填充:
如果我改为顺时针绘制矩形轮廓,则不会出现此问题。
path.lineTo(QPointF(*pn-v))
path.lineTo(QPointF(*pn+v))
path.lineTo(QPointF(*p0+v))
path.lineTo(QPointF(*p0-v))
结果:
就是这样。下面是我的最终代码,生成一个可点击且可操作的漂亮复合线段。
from PySide import QtGui, QtCore
import math
import sys
import weakref
from numpy import *
from PySide.QtGui import *
from PySide.QtCore import *
class Node(QGraphicsItem):
Type = QGraphicsItem.UserType+1
def __init__(self, graphWidget, line):
super(self.__class__, self).__init__()
self.line = line
self.radius = 8
if graphWidget != None:
self.graph = weakref.ref(graphWidget)
self.newPos = QPointF()
self.setCacheMode(self.DeviceCoordinateCache)
self.setZValue(-1)
def boundingRect(self):
adjust = 10.0
x,y = array(self.line).transpose()
rect = [min(x)-self.radius, min(y)-self.radius, max(x)-min(x)+2*self.radius, max(y)-min(y)+2*self.radius]
return QRectF(*rect)
def shape(self):
path = QPainterPath()
path.setFillRule(Qt.WindingFill)
radius = self.radius
rotation = array( [[0,-1],[1,0]])
points = zip(self.line[0:-1], self.line[1:])
for p0, pn in points:
(x0,y0),(xn,yn) = p0,pn
dx,dy = array(pn) - array(p0)
dV = array([dx,dy])
mag_dV = linalg.norm(dV)
v = dot(rotation, dV) * radius / mag_dV
#starting circle
path.addEllipse(QRectF(x0-radius, y0-radius, 2*radius, 2*radius))
#rectangular part
path.moveTo(QPointF(*p0-v))
path.lineTo(QPointF(*pn-v))
path.lineTo(QPointF(*pn+v))
path.lineTo(QPointF(*p0+v))
path.moveTo(QPointF(*pn))
path.addEllipse(QRectF(xn-radius, yn-radius, 2*radius, 2*radius))
return path.simplified()
def paint(self, painter, option, widget):
painter.setPen(Qt.black)
painter.setBrush(Qt.darkGray)
painter.setRenderHint(QPainter.Antialiasing)
painter.drawPath(self.shape())
def setGraph(self, graph):
self.graph = weakref.ref(graph)
class GraphWidget(QGraphicsView):
def __init__(self):
super(self.__class__, self).__init__()
self.timerId = 0
scene = QGraphicsScene(self)
scene.setItemIndexMethod(QGraphicsScene.NoIndex)
scene.setSceneRect(0,0,880,880)
self.setScene(scene)
self.setCacheMode(QGraphicsView.CacheBackground)
self.setRenderHint(QPainter.Antialiasing)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorViewCenter)
self.centerNode = Node(self, [[50,50],[200,100], [500, 100], [700,700]])
scene.addItem(self.centerNode)
self.centerNode.setPos(0,0)
self.setGeometry(100,100,900,900)
self.setWindowTitle(self.tr("Elastic Nodes"))
def addItem(self, item):
self.item = item
self.scene().addItem(item)
item.setGraph(self)
item.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
qsrand(QTime(0,0,0).secsTo(QTime.currentTime()))
widget = GraphWidget()
widget.show()
sys.exit(app.exec_())
关于python - 将 QPainterPath 简化为轮廓,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19528158/
我有 QPainterPath。我需要通过 x 找到 QPainterPath 的 y 坐标。 我在QPainterPath中找到了intersected()方法。因此,我创建了新的 QPainter
我需要“合并”两个 QPainterPath一起。问题是它们似乎总是两条不同的路径。 我需要的是,合并实际上变得与已构建单个(来自复杂的多边形或复杂的线束)相同,没有任何内部线伪影或子路径,因为它们以
我想显示一个动画箭头形状的按钮。 为了绘制它,我创建了一个类,它继承了 QGraphicsObject 并使用了 QPainterPath 类。 我在 QGraphicsScene 中绘制它并使用属性
有没有办法缩放 QPainterPath ? 例如,我的问题是我有一个 QPainterPath 400,400 的大小包含许多行,我想将其缩放到 800,800 或任何其他大小,并通过向其他坐标添加
在 Qt 5.4.2 中,我使用 QPainterPath 来呈现文本,因为文本可能会被分割成多个字符,并且每个字符都沿着一条曲线呈现。我在不同平台和打印时看到不同的结果。为了呈现文本,我尝试使用 Q
我正在处理一个图形编辑器的功能,我正在编辑圆弧,当形状是椭圆时,QPainterPath::arcTo 的行为并不像我预期的那样;当它是一个圆圈时,它按预期工作。 下面的两张图片显示了结果。在第一种情
有什么方法可以获取 QPainterPath 并将其展开,就像 Photoshop 中的“选择”>“增长...”(或“展开...”)命令一样? 我想获取从 QGraphicsItem::shape 返
我正在尝试确定命中扫描射弹的路径(基本上是一条线,但在我的示例中将其表示为 QPainterPath)与场景中的项目相交的点。我不确定是否有办法使用 QPainterPath、QLineF 等提供的函
如何获得代表沿 QPainterPath 单击的点的百分比。例如,假设我有一条线,如下图所示,用户单击 QPainterPath(由红点表示)。我想记录该点沿路径下降的百分比。在本例中,它将打印 0.
我正在实现自由格式绘图,使用鼠标按下并使用 Qpainter 移动来绘制自由路径 QPainterpath 现在我必须检测绘制的路径何时与另一条路径交叉或相交。我如何识别线何时在某个点相互交叉并向用户
我想在 Qt 中创建这样的形状: 这是一段代码(基本上是绘制一个矩形并在其上绘制一条弧线): QPainterPath groupPath; QPen pen; pen.setCosmetic(
我有一个 QPainterPath,我想裁剪一个 QPixmap 图像。此代码对我有用,但我想使用 PyQt5 内置功能像没有 numpy 的面具 # read image as RGB and ad
使用 QPen 时抚摸QPainterPath , 它在线的中心这样做。我想做的是沿着线的内部 绘制路径。我已经看过类似的问题here但它没有提供明确的解决方案或示例。 如何描边 QPainterPa
以下代码围绕 QPainterPath 绘制文本: QString text = "Short text"; QPainterPath rawPath; // fill path ... while
我正在制作的迷你游戏现在遇到了问题。问题如下:我为我的游戏创建了一个关卡编辑器,因此我必须创建自己的委托(delegate)和模型,当我尝试通过 shapeeditor(更有可能创建一个 painte
有人能告诉我如何访问 QPainterPath 下的所有像素吗? QPainterPath 的元素有一些方法,例如isLineTo(),所以我的第一个想法是创建一个具有起点和终点的线性函数。但如果路径
我正在尝试使用 QGraphicsPathItem 来表示其中有一个洞的多边形(想想 donut )。我可以让它正确绘制,并且中心是透明的。但是,启用项目选择或移动后,我可以在单击孔时与我的对象进行交
我正在 PySide 中使用 QGraphicsScene 创建自定义绘图应用程序 - 我希望能够绘制复杂的形状并让用户通过鼠标与它们交互。为此,我创建了一个名为 Node 的自定义 QGraphic
有什么方法可以编辑 QPainterPath 中单个“lineTo”元素的位置(或删除特定元素并用修改后的版本替换它们?)。我尝试使用 *.setElementPositionAt(i,x,y) 无济
我想画一个有角度的矩形。它可以工作,但是当我改变角度时,矩形的位置会在其他地方发生变化。我听不懂。有人帮我吗? 这是我的代码: QPoint point = QPoint(100,100); // h
我是一名优秀的程序员,十分优秀!