【问题标题】:Binding between C++ and QML with dynamic created tab elements使用动态创建的选项卡元素在 C++ 和 QML 之间绑定
【发布时间】:2025-12-29 09:10:06
【问题描述】:

我在main.qml 中有 TabView

TabView {
    id: tabRoot
    objectName: "tabRootObj"
}

我的应用程序在每个新的传入 TCP 连接上创建新选项卡。以下代码按需创建新标签(它基于此答案https://*.com/a/27093137/3960195)。

void addTab(QQmlApplicationEngine& engine) {
    root_tab = engine.rootObjects().first()->findChild<QQuickItem*>(QStringLiteral("tabRootObj"));

    QVariant new_tab;
    QQmlComponent component(&engine, QUrl("qrc:/MyTab.qml");
    QMetaObject::invokeMethod(root_tab, "addTab",
        Q_RETURN_ARG(QVariant, new_tab),
        Q_ARG(QVariant, QStringLiteral("Tab name")),
        Q_ARG(QVariant, QVariant::fromValue(&component)));
}

对于每个 TCP 连接,它还会创建 ConnectionManager 类的新实例,其中包含一些可通过属性访问的统计信息(例如传输字节数)。

//ConnectionManager.hpp
class ConnectionManager : public QObject
{
    Q_OBJECT
public:
    // ...
    Q_PROPERTY(QString address READ address NOTIFY ipChanged)
    Q_PROPERTY(int received READ received NOTIFY receivedChanged)
    //...
}

//MyTab.qml
Item {
    property string ip
    property int received
    ...
}

我需要将这些属性与MyTab.qml 中的属性绑定。 问题是TabView.addTab 方法自己创建了MyTab 的组件,我无法将ConnectionManager 的具体实例注入到它的上下文中。在创建新连接之前,ConnectionManager 也不存在,因此我无法通过rootContext 在应用程序开始时添加它。如何在这个新创建的对象之间创建绑定?

这是我在 QML 中的第一个项目,所以也许有更好的“QML”方式来实现它。在这种情况下,显示“正确”方式的答案也是可以接受的。

【问题讨论】:

  • 你不能将ConnectionManager 传递给QML addTab 函数吗?另外为了限制 C++ 和 QML 之间的耦合,我不会从 c++ 添加选项卡。我将公开不同连接的 c++ 模型并将其公开给 QML。然后我会使用RepeaterMyTab 作为代表。
  • QML addTab 函数只有两个参数,分别是选项卡标题和构造组件 (doc.qt.io/qt-5/qml-qtquick-controls-tabview.html#addTab-method)。中继器解决方案看起来非常棒。我不知道你可以在TabView 中使用Repeater
  • GrecKo 可能在谈论您自己的 C++- 函数:addTab(...),您可以在其中创建组件。
  • @GrecKo 我可以将它添加到我的addTab,但我仍然需要以某种方式设置新创建的标签关联ConnectionManager

标签: c++ qt qml


【解决方案1】:

正如 GrecKo 在评论中推荐的那样,我在 TabView 中使用了 Repeater 并为其定义了一个模型。

Repeater 的 TabView 如下所示:

TabView {
    id: tabRoot
    Repeater {
        model: ConnectionModel
        delegate: Tab {
            title: connection.name
            Client {
                address connection.address
                received: connection.received
            }
        }
    }
}

如何创建模型可以在 Qt 的documentation 中轻松找到。假设我有一个名为ConnectionModel 的模型类(继承自QAbstractListModel),它包含一个角色connection(用于在Repeaterdelegate 中引用ConnectionManager 的实例) .我使用QQmlApplicationEngine.rootContext()-&gt;setContextProperty() 方法将Repeater 与我的模型实例连接起来。下面的例子展示了如何建立连接:

QApplication app(argc, argv);
QQmlApplicationEngine engine;
// Create instace of ConnectionModel
ConnectionModel model;
// Assasign the model instance to the QML context property "ConnectionModel"
engine.rootContext()->setContextProperty("ConnectionModel", &model);
// ...
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

return app.exec();

对于每个新的 TCP 连接,程序都会创建一个 ConnectionManager 的新实例。之后会调用向模型中插入新记录的方法,并插入新的ConnectionManager的引用。

我希望它对必须在 QML 中创建动态选项卡的人有所帮助。

【讨论】: