python – 选择时更改对象的QGraphicsScene
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了python – 选择时更改对象的QGraphicsScene,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5681字,纯文字阅读大概需要9分钟。
内容图文
我有一个QGraphicsScene包含一些简单的对象(在这个简化的例子中为圆圈),我想在选中时将其更改为其他对象(此处为正方形).更具体地说,我希望父对象不会自己绘制,它们是由子对象绘制的,并且在各种情况下,但特别是在选择父对象时,我希望子对象集合为更改.这是我正在开发的整个应用程序的一个很好的概念框架.
所以我在PySide中实现了它,我认为它工作正常:点击它们时,圆圈会很好地变成正方形.
直到我在视图中使用RubberBandDrag选择.当橡皮筋选择到达父对象并且选择发生变化时,这会导致瞬时段错误.据推测,这是因为QT中的橡皮筋选择以某种方式保持指向儿童项目的指针,该指针在橡皮筋选择动作完成之前消失.
下面的简化代码 – 通过首先单击对象(它变化很好)然后在对象上拖动来测试它 – segfault:
from PySide import QtCore,QtGui
class SceneObject(QtGui.QGraphicsItem):
def __init__(self, scene):
QtGui.QGraphicsItem.__init__(self, scene = scene)
self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QtGui.QGraphicsItem.ItemHasNoContents, True)
self.updateContents()
def updateContents(self):
self.prepareGeometryChange()
for c in self.childItems():
self.scene().removeItem(c)
if self.isSelected():
shape_item = QtGui.QGraphicsRectItem()
else:
shape_item = QtGui.QGraphicsEllipseItem()
shape_item.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, False)
shape_item.setFlag(QtGui.QGraphicsItem.ItemStacksBehindParent,True)
shape_item.setPen(QtGui.QPen("green"))
shape_item.setRect(QtCore.QRectF(0,0,10,10))
shape_item.setParentItem(self)
def itemChange(self, change, value):
if self.scene() != None:
if change == QtGui.QGraphicsItem.ItemSelectedHasChanged:
self.updateContents()
return
return super(SceneObject,self).itemChange(change, value)
def boundingRect(self):
return self.childrenBoundingRect()
class Visualiser(QtGui.QMainWindow):
def __init__(self):
super(Visualiser,self).__init__()
self.viewer = QtGui.QGraphicsView(self)
self.viewer.setDragMode(QtGui.QGraphicsView.RubberBandDrag)
self.setCentralWidget(self.viewer)
self.viewer.setScene(QtGui.QGraphicsScene())
parent_item = SceneObject(self.viewer.scene())
parent_item.setPos(50,50)
app = QtGui.QApplication([])
mainwindow = Visualiser()
mainwindow.show()
app.exec_()
所以问题:
我刚刚犯了一个可以直接解决的错误吗?
或者是在处理ItemSelectedHasChanged事件时从场景中删除对象?
有方便的解决方法吗?或者什么是一个很好的替代方法?我可以用自定义项替换QGraphicsRectItem,可以将其绘制为方形或圆形,但不能方便地覆盖我的所有用例.我可以看到我可以做到这一点,但肯定不会那么简单.
编辑 – 解决方法:
通过暂时保留即将删除的对象可以防止这种失败.这可以通过以下方式完成:
def updateContents(self):
self.prepareGeometryChange()
self._temp_store = self.childItems()
for c in self.childItems():
self.scene().removeItem(c)
...
但是,这是丑陋的代码,增加了内存使用量,没有真正的好处.相反,我已经开始使用0700答案中建议的QGraphicsScene.selectionChanged信号.
解决方法:
我调试了它.在Lunix上转载
1 qFatal(const char *, ...) *plt 0x7f05d4e81c40
2 qt_assert qglobal.cpp 2054 0x7f05d4ea197e
3 QScopedPointer<QGraphicsItemPrivate, QScopedPointerDeleter<QGraphicsItemPrivate>>::operator-> qscopedpointer.h 112 0x7f05d2c767ec
4 QGraphicsItem::flags qgraphicsitem.cpp 1799 0x7f05d2c573b8
5 QGraphicsScene::setSelectionArea qgraphicsscene.cpp 2381 0x7f05d2c94893
6 QGraphicsView::mouseMoveEvent qgraphicsview.cpp 3257 0x7f05d2cca553
7 QGraphicsViewWrapper::mouseMoveEvent qgraphicsview_wrapper.cpp 1023 0x7f05d362be83
8 QWidget::event qwidget.cpp 8374 0x7f05d2570371
QT-比比皆是 – 开源-SRC-4.8.6 / src目录/ GUI / graphicsview / qgraphicsscene.cpp:2381
void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode,
const QTransform &deviceTransform)
{
...
// Set all items in path to selected.
foreach (QGraphicsItem *item, items(path, mode, Qt::DescendingOrder, deviceTransform)) {
if (item->flags() & QGraphicsItem::ItemIsSelectable) { // item is invalid here
if (!item->isSelected())
changed = true;
unselectItems.remove(item);
item->setSelected(true);
}
}
他们使用items()函数查找橡皮筋选择下的项目列表.但是如果处理过程中的一个项删除了某个项,则该项指针将变为无效.然后调用item-> flags()会导致崩溃.
作为替代方案,您可以使用QGraphicsScene :: selectionChanged信号.每次选择更改时只发出一次.
看起来Qt没有预料到itemChange会有一些重大变化
在这里,这是你在prepareGeometryChange()调用时遇到的常见错误.
它被设计为在更改boundingRect之前调用.当prepareGeometryChange被调用时,绑定的rect应该是旧的,并且紧接着是新的.
所以这可能发生:
在updateContents中:
self.prepareGeometryChange(); # calls boundingRect. old value returned
...
shape_item.setParentItem(self); # could call the boundingRect. but still old value returned!
添加后,它再次调用boundingRect但值意外不同.
作为解决方案,您可以添加变量
def updateContents(self):
for c in self.childItems():
self.scene().removeItem(c)
if self.isSelected():
shape_item = QtGui.QGraphicsRectItem()
else:
shape_item = QtGui.QGraphicsEllipseItem()
shape_item.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, False)
shape_item.setFlag(QtGui.QGraphicsItem.ItemStacksBehindParent,True)
shape_item.setPen(QtGui.QPen("green"))
shape_item.setRect(QtCore.QRectF(0,0,10,10))
shape_item.setParentItem(self)
self.prepareGeometryChange();
self._childRect = self.childrenBoundingRect()
def boundingRect(self):
return self._childRect
内容总结
以上是互联网集市为您收集整理的python – 选择时更改对象的QGraphicsScene全部内容,希望文章能够帮你解决python – 选择时更改对象的QGraphicsScene所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。