在 Qt 窗口树上寻找某个窗口

Node Editor中有许多窗口,它们都是 主窗口 QMainWindow的子窗口。

  • Parameter Widget: 当点击某个节点时,会显示这个节点的信息,以及可以调整的参数。 当前选中了 Comment 节点,在 Parameter Widget上可以显示、修改它的标题。同时 Comment节点也会联动。

  • ListWidget: 节点列表。拖到 GraphicsView 时,可以动态创建一个节点。

  • Graphics View: Graphics Scene 的视口。

image.png

这些窗口的父子关系如下,每一个方块代表一个类。


窗口关系1.png

现在,需要判断 Comment 节点是否被选中。 如果选中,就根据 Comment里的属性字段,动态创建一个 QWidget ,并添加到 Parameter Widget中。

Comment节点,其实是一个 QGraphicsItem对象。判断QGraphicsItem是否被选中,非常简单,只要重写一个虚函数即可:

QVariant DmGraphicsComment::itemChange(GraphicsItemChange change, const QVariant& value)
{
    /* 如果 GraphicsItem “被选中”这个状态发生了改变... */
    if (change == QGraphicsItem::ItemSelectedChange)
    {
        if (!m_isSelected)
        {   
            m_isSelected = true;

            /* 做出相应的举动 */
            Self::OnSelected();
        }
        else
        {
            m_isSelected = false;

            Self::OnUnselected();
        }
    }

    return Super::itemChange(change, value);
}

如何根据属性动态生成不同的QWidget对象,需要反射的支持,这个我们后来再说。我们假定下面代码的dynamicUi变量是已经生成好的,那么,现在的重点变为,怎么在当前的窗口树下,找到parameterWidget,然后把dynamicUi挂在它的上面,作为一个子窗口。

void DmGraphicsComment::OnSelected()
{
    /* 要如何实现这个函数? */
    QWidget* parameterWidget = FindWindowByObjectName("ParameterWidget");
    assert(parameterWidget && "Parameter widget is nullptr");

    /* 假定这个函数已经实现 */
    QWidget* dynamicUi = GenerateDynamicUi();

    QLayout* layout = parameterWidget->layout();
    layout->addWidget(dynamicUi );
}

方法非常简单,只有三步:

  • 给各窗口设置object name,比如MainWindowobject nameMainWindowParameterWidgetobject nameParameterWidget
  • 找到名叫MainWindow的顶层窗口
  • MainWindow的子窗口里寻找名叫ParameterWidget的子窗口
QWidget* DmGraphicsComment::FindWindowByObjectName(const QString& name)
{
    /* 拿到 Graphics View 窗口 */
    QGraphicsView* graphicsView = Super::scene()->views()[0];
    assert(graphicsView && "Graphics view of the item is null");

    /* 遍历所有父窗口,直到找到名叫 MainWindow 的父窗口。 线性查找。 */
    QWidget* parentWidget = graphicsView->parentWidget();
    assert(parentWidget && "Parent widget of the graphics view is null");

    while (parentWidget && parentWidget->objectName() != "MainWindow")
    {
        parentWidget = parentWidget->parentWidget();
    }

    /* 调用 Qt Api,查找子窗口 */
    QWidget* parameterWidget = parentWidget->findChild<QWidget*>(name);

    /* 返回结果 */
    return parameterWidget;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容