У меня есть GraphicsBoxItem, который содержит список GraphicsImageItem (какие-то плавающие кнопки вокруг коробки). Я создаю их на лету в focusInEvent() и уничтожаю в focusOutEvent().
Некоторые из GraphicsImageItem должны перемещаться вместе с родителем при щелчке, некоторые из них должны оставаться на том же месте при щелчке, пока поле не получит focusOut, щелкнув за пределами любых графических элементов.
Есть ли способ предотвратить перемещение дочернего 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();
};





Положение дочернего элемента всегда относительно его родителя, если родитель перемещается, то абсолютное положение дочернего элемента также изменяется.
Если вы хотите создать иллюзию того, что этого не происходит, вам придется вручную переместить ребенка в противоположном направлении, чтобы он мог оставаться в том же абсолютном положении.
Другой вариант - вообще не иметь элементы как дочерние элементы.
Может быть, вам следует создать невидимый элемент, а затем сделать его родительским для подвижного объекта, а также для его неподвижных дочерних элементов, а для подвижных дочерних элементов - для этого подвижного объекта. Затем вы просто перемещаете только подвижный элемент - его дочерние элементы перемещаются, его братья и сестры остаются в том же положении, поскольку их родительский элемент не перемещается.
@ user2246120 Inside that function I can't know Да, вы можете, просто передайте параметр, чтобы указать источник.
Я имел в виду focusInEvent(QFocusEvent*) от Qt. Изначально неподвижный элемент находится в верхнем левом углу поля, когда он получает фокус. Затем предмет остается, пока ящик перемещается. при нажатии за пределами сцены и повторном выборе поля неподвижный элемент теперь снова должен быть помещен рядом с ящиком. Если вы не потеряете фокус при щелчке по неподвижному объекту, это решит проблему ... Возможно ли это?
Для дочерних элементов, которые вы не хотите перемещать, попробуйте установить этот флаг:
setFlag(QGraphicsItem::ItemIgnoresTransformations);
Похоже, в данном случае это не работает. В документации сказано: «его позиция по-прежнему привязана к своему родителю» ...
Если вы можете создать подкласс своих дочерних элементов, вы можете переопределить метод itemChange () и следить за:
ItemScenePositionHasChanged
The item's scene position has changed. This notification is sent if the ItemSendsScenePositionChanges flag is enabled, and after the item's scene position has changed (i.e., the position or transformation of the item itself or the position or transformation of any ancestor has changed). The value argument is the new scene position (the same as scenePos()), and QGraphicsItem ignores the return value for this notification (i.e., a read-only notification).
Затем верните последний scenePos () дочернего элемента, который вам нужно будет сохранить как член, и обновите каждое изменение положения сцены.
Не забудьте установить флаг:
ItemSendsGeometryChanges
в ctor вашего дочернего подкласса.
Я пробовал подход с использованием другого родителя для подвижных элементов. Однако этот подход не сработал, потому что я воссоздаю все элементы в
focusIn(). Внутри этой функции я не могу знать, попал ли я туда из-за щелчка по кнопке (кнопка должна оставаться в том же положении) или из-за того, что я щелкнул вне каких-либо элементов. После следующего щелчка по окну мне нужно будет разместить неподвижную кнопку рядом с окном. Есть ли способ запретить ящику получать событие focusOut () при нажатии кнопкиGraphicsImageItem?