【问题标题】:Access nested object in QML slot by id (called from c++)通过 id 访问 QML 插槽中的嵌套对象(从 c++ 调用)
【发布时间】:2024-01-15 15:18:01
【问题描述】:

我曾经有一个窗口的这种排列方式,其中有一个文本字段,并使用从 c++ 发出的数据进行更新:

Window{
   id: root
   function qmlSlot(a){
      _textField1.text=a;
   }
   TextField{
      id: _textField1
   }
}

绑定是这样的:

QQuickWindow *window=qobject_cast<QQuickWindow*>(topLevel);
QObject::connect(src,SIGNAL(someSignal(QVariant)),window,SLOT(qmlSlot(QVariant)));

现在我在主窗口中添加了更多内容(选项卡),但事情不再那么简单了。

A:当我将qmlSlot 留在窗口范围内时,它看不到_textField1

Window{
   id: root
   function qmlSlot(a){
      _textField1.text=a;
   }
   TabView{
      Tab{
         TextField{
            id: _textField1
         }
      }
   }
}

这给了我:

qrc:/main.qml:32: ReferenceError: _textField1 is not defined

B:当我将槽本身移动到_textField1的范围内时,我不知道如何从c++中绑定到它:

Window{
   id: root
   TabView{
      Tab{
         function qmlSlot(a){
            _textField1.text=a;
         }
         TextField{
            id: _textField1
         }
      }
   }
}

导致:

QObject::connect: No such slot QQuickWindowQmlImpl_QML_21::qmlSlot(QVariant)

如何在访问嵌套项时从 c++ 调用 qmlSlot(在这种情况下为 _textField)?是否可以让我在决定更改窗口布局时不必更改绑定代码?

【问题讨论】:

    标签: c++ scope qml signals-slots qt-signals


    【解决方案1】:

    您的问题是 Tab 实际上是 Loader,因此这意味着您的 TextField 是在另一个上下文中按需创建的。当您的Tab 未激活时,没有可访问的TextField

    您可以使用 tab.item 访问您的文本字段,但它仅在加载选项卡时才有效。

    不过,您有一个更深层次的问题,从 c++ 访问 QML 对象是不好的做法,因为这意味着您的业务层必须了解您的 UI 层。如果你想重构你的 UI,那就不好了。相反,您应该做的是从 QML 中的 c++ 中提取数据。更多解释:Interacting with QML from C++.

    在您的情况下,我会创建一个带有属性或信号的QObject 子类(它是您的对象的状态还是事件?)。

    然后使用 setContextProperty 使您的对象实例之一可用于 QML 引擎。

    而在您的 QML 中,您只需这样做(如果它是一个属性):

    Window{
       id: root
       TabView{
           Tab{
               TextField{
                   text: myCppObject.textProperty
                }
            }
        }
    }
    

    【讨论】:

    • 谢谢。 (1) 那么,创建静态选项卡式界面的正确方法是什么,而不是通过加载器?我找到了(大概是旧的)TabGroup。 (2) 信号从后端发送到 QML,它是传感器接口,当数据到达时触发信号。我想找到一种更好的方法来做到这一点,但财产似乎并没有真正削减它。除非属性本身通知 QML(它知道它正在被使用)它的变化,否则它会很容易。
    • 属性确实可以通知 QML 其更改。 doc.qt.io/qt-5/…
    • 好吧,那么我明白最好的办法是拥有一个 c++ 类,例如DataHolder 保存 UI 中公开的所有数据(通过 Q_PROPERTY),并使用 view.rootContext()-&gt;setContextProperty("dataHolder", &amp;dataHolderI); 分配该实例,然后将属性设置为 root.dataHolder.x 等等,它们将自动更新。并连接信号以从其余 c++ 代码更新 DataHolder 实例。有道理,非常感谢!
    【解决方案2】:

    我以前从未使用过 QML,但 docs 建议您需要为每个对象的 id 属性分配一个值,以便您可以引用它。我认为以下应该可以工作(但尚未测试)。

    Window{
       id: root
       function qmlSlot(a){
          mytabview.mytab._textField1.text=a;
       }
       TabView{
          id: mytabview
          Tab{
             id: mytab
             TextField{
                id: _textField1
             }
          }
       }
    }
    

    【讨论】:

      最近更新 更多