You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止部分子QGraphicsItem随父QGraphicsItem移动?

解决QGraphicsBoxItem子项不随父项移动的问题

我来给你几个实用的方案,都是Qt图形框架里常用的思路,完美匹配你的需求:

方法一:把固定子项的父对象切换到场景

Qt里QGraphicsItem的位置是相对于父项的,所以父项移动时子项会跟着动。如果想让部分子项固定不动,最直接的办法就是把这些子项的父从GraphicsBoxItem改成你的QGraphicsScene。这样父项移动时,这些子项因为属于场景,位置就不会受父项影响了。

代码示例(在focusInEvent中创建子项时):

void GraphicsBoxItem::focusInEvent(QFocusEvent* event)
{
    QGraphicsItem::focusInEvent(event);

    // 创建需要随父项移动的子项(父设为this)
    QGraphicsImageItem* movableItem = new QGraphicsImageItem(this);
    movableItem->setPos(10, 10); // 相对于父项的位置

    // 创建需要固定的子项(父设为场景)
    QGraphicsImageItem* fixedItem = new QGraphicsImageItem();
    fixedItem->setParentItem(scene());
    // 把父项内的坐标转换成场景坐标,确保初始位置正确
    QPointF fixedScenePos = this->mapToScene(50, 10);
    fixedItem->setPos(fixedScenePos);
    // 给固定子项加个标记,方便后续focusOut时清理
    fixedItem->setData(Qt::UserRole, "FixedChildOfBox");
}

清理注意事项:

因为固定子项的父是场景,GraphicsBoxItem销毁时不会自动清理它们,所以要在focusOutEvent里额外处理:

void GraphicsBoxItem::focusOutEvent(QFocusEvent* event)
{
    QGraphicsItem::focusOutEvent(event);

    // 清理父为this的子项(随动的那些)
    for (auto item : childItems()) {
        delete item;
    }

    // 清理场景中的固定子项
    if (scene()) {
        QList<QGraphicsItem*> sceneItems = scene()->items();
        for (auto item : sceneItems) {
            if (item->data(Qt::UserRole) == "FixedChildOfBox") {
                delete item;
            }
        }
    }
}

方法二:重写子项的itemChange方法拦截位置更新

如果不想改变父对象关系,也可以给固定子项自定义一个子类,重写itemChange方法,拦截父项移动带来的位置变化,强制保持原来的场景位置。

自定义固定子项类示例:

class FixedGraphicsImageItem : public QGraphicsImageItem
{
public:
    FixedGraphicsImageItem(QGraphicsItem* parent = nullptr) 
        : QGraphicsImageItem(parent)
    {
        // 初始化时记录当前的场景位置
        m_fixedScenePos = mapToScene(pos());
    }

    QVariant itemChange(GraphicsItemChange change, const QVariant& value) override
    {
        // 当父项移动导致子项场景位置变化时,强制拉回原来的位置
        if (change == ItemScenePositionHasChanged && parentItem()) {
            // 将固定场景位置转换成父项坐标系下的位置
            QPointF localPos = mapFromScene(m_fixedScenePos);
            setPos(localPos);
            // 返回空QVariant阻止后续的位置更新逻辑
            return QVariant();
        }
        return QGraphicsImageItem::itemChange(change, value);
    }

private:
    QPointF m_fixedScenePos;
};

使用方式:

在focusInEvent中创建这个自定义类的实例,父项设为GraphicsBoxItem即可,后续focusOutEvent清理时直接遍历childItems删除就行,不用额外处理场景里的项。

这两种方法都能实现你的需求,第一种更简单直观,第二种适合不想改动父项结构的场景,你可以根据自己的代码情况选~

内容的提问来源于stack exchange,提问作者user2246120

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:14:03