如何防止子 QGraphicsItem 与父级一起移动?
Posted
技术标签:
【中文标题】如何防止子 QGraphicsItem 与父级一起移动?【英文标题】:How to prevent child QGraphicsItem from being moved with parent? 【发布时间】:2018-03-12 15:41:24 【问题描述】:我有一个GraphicsBoxItem
包含GraphicsImageItem
的列表(框周围的某种浮动按钮)。我在focusInEvent()
中即时创建它们,并在focusOutEvent()
中销毁它们。
一些GraphicsImageItem
在单击时应与父级一起移动,其中一些应在单击时保持在同一位置,直到通过单击任何图形项外部框获得焦点。
有没有办法防止子 QGraphicsItem 与父级一起移动?
class GraphicsBoxItem : public QObject, public QGraphicsItem
Q_OBJECT
private:
QColor mColor;
QVector<GraphicsImageItem*> mItemList;
public:
GraphicsBoxItem(QGraphicsItem *parent = NULL)
:QGraphicsItem(parent)
mColor = Qt::lightGray;
setFlag(QGraphicsItem::ItemIsSelectable);
setFlag(QGraphicsItem::ItemIsFocusable);
QRectF boundingRect() const return QRectF(50, 20, 100, 60);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
painter->setBrush(mColor);
painter->drawRect(boundingRect());
virtual void focusOutEvent(QFocusEvent * event)
foreach(GraphicsImageItem *item1, mItemList)
item1->deleteLater();
item1 = NULL;
mItemList.clear();
mColor = Qt::lightGray;
QGraphicsItem::focusOutEvent(event);
virtual void focusInEvent(QFocusEvent * event)
GraphicsImageItem *movableItem = new GraphicsImageItem(this);
movableItem->setPos(150, 20);
mItemList.push_back(movableItem);
movableItem->installSceneEventFilter(this);
connect(movableItem, SIGNAL(SignalClicked()), this, SLOT(SlotButtonClicked()));
GraphicsImageItem *nonMovableItem = new GraphicsImageItem(this);
nonMovableItem->setPos(20, 20);
mItemList.push_back(nonMovableItem);
nonMovableItem->installSceneEventFilter(this);
connect(nonMovableItem, SIGNAL(SignalClicked()), this, SLOT(SlotButtonClicked()));
mColor = Qt::blue;
QGraphicsItem::focusInEvent(event);
bool sceneEventFilter(QGraphicsItem* target, QEvent* event)
if(event->type() == QEvent::GraphicsSceneMousePress || event->type() == QEvent::GraphicsSceneMouseDoubleClick)
GraphicsImageItem* item = dynamic_cast<GraphicsImageItem*>(target);
if(item)
item->SignalClicked();
qDebug() << "image button was clicked: Need to set the focus back to the box";
setFocus();
return true;
return QGraphicsItem::sceneEventFilter(target, event);
public slots:
void SlotButtonClicked()
setPos(pos().x() + 10, pos().y()+10);
;
SignalClicked()
将 GraphicsBoxItem
移动 10 个像素。一些GraphicsImageItem
留在原地,一些与GraphicsBoxItem
一起移动:
class GraphicsImageItem : public QGraphicsSvgItem
Q_OBJECT
public:
GraphicsImageItem::GraphicsImageItem(QGraphicsItem *parent = NULL)
: QGraphicsSvgItem(QString(":/images/icon.svg"), parent)
setFlag(QGraphicsItem::ItemIsSelectable);
QRectF boundingRect() const return QRectF(0, 0, 30, 30);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
painter->setBrush(Qt::lightGray);
painter->drawRect(boundingRect());
renderer()->render(painter, boundingRect().adjusted(3, 3, -3, -3));
Q_SIGNALS:
void SignalClicked();
;
【问题讨论】:
【参考方案1】:孩子的位置总是相对于它的父母,如果父母移动,那么孩子的绝对位置也会改变。
如果您想制造这种情况不会发生的错觉,则必须手动将孩子朝相反的方向移动,以便它可以保持在相同的绝对位置。
另一种选择是首先不将这些项目作为子项。
也许您应该创建一个不可见的项目,然后将可移动项目以及不可移动的子项添加到它的父项,以及可移动的子项 - 在可移动项下。然后您只需移动可移动项目 - 它的子项移动,其兄弟项保持在同一位置,因为它们的父项不移动。
【讨论】:
我尝试了为可移动项目使用不同父级的方法。但是这种方法不起作用,因为我重新创建了focusIn()
中的所有项目。在该功能中,我不知道我是因为单击按钮(按钮应保持在同一位置)还是因为我单击了任何项目之外而到达那里。在下一次单击框后,我需要将不可移动按钮放置在框旁边。有没有办法在按下GraphicsImageItem
按钮时防止框获得focusOut() 事件?
@user2246120 Inside that function I can't know
可以,只需传递一个参数来指示来源。
我的意思是 focusInEvent(QFocusEvent*)
来自 Qt。最初,当框获得焦点时,不可移动项位于框的左上角。然后该项目在盒子移动时保持不变。当在场景外按下并再次选择框时,不可移动的项目现在应该再次放置在框旁边。在单击不可移动项目时不会失去对框的关注将解决问题......这可能吗?【参考方案2】:
对于您不想移动的子项,请尝试设置此标志:
setFlag(QGraphicsItem::ItemIgnoresTransformations);
【讨论】:
这在这种情况下似乎不起作用。文档说:“它的位置仍然锚定到它的父级”......【参考方案3】:如果您可以子类化您的子项,那么您可以重写 itemChange() 方法并注意:
ItemScenePositionHasChanged
该项目的场景位置已更改。发送此通知,如果 ItemSendsScenePositionChanges 标志已启用,并且在 项目的场景位置已更改(即位置或 项目本身的变换或位置或变换 任何祖先都改变了)。 value 参数是新场景 位置(与 scenePos() 相同),并且 QGraphicsItem 忽略 此通知的返回值(即只读通知)。
然后返回子项的最后一个 scenePos(),您必须将其存储为成员并更新每个场景位置更改。
记得设置标志:
ItemSendsGeometryChanges
在您的子类的 ctor 中。
【讨论】:
以上是关于如何防止子 QGraphicsItem 与父级一起移动?的主要内容,如果未能解决你的问题,请参考以下文章