QT5。在QML中嵌入QWidget对象

时间:2012-10-22 15:14:17

标签: qml qwidget qt5

我正在使用Qt5 beta并尝试将基于QWidget的对象嵌入到QML中。目标是尽可能多地使用QML,并且只使用QML不能满足我需要的QWidget对象。我找到了一个解释如何为Qt4.7执行此操作的链接,但我没有找到任何解释如何在Qt5中执行此操作的信息。

http://doc.qt.digia.com/4.7/declarative-cppextensions-qwidgets.html

同样的例子也可以在Qt5示例文件夹中找到:

实例\ qtquick1 \声明\ cppextensions \ qwidgets

不幸的是,这个例子使用QtQuick 1而不是QtQuick 2,我想使用Qt5的新功能。我实际上想嵌入一个qwt小部件,但作为第一步,我很乐意嵌入任何简单的基于QWidget的对象。

有人能帮助我在Qt5 / QtQuick 2下工作吗?

6 个答案:

答案 0 :(得分:30)

Qt Quick 2使用场景图在GPU上进行高效渲染。不幸的是,这使得无法将经典小部件嵌入到场景中。在QGraphicsProxyWidget的帮助下嵌入此类小部件的旧方法仅适用于Qt Quick 1,因为在内部它使用QGraphicsView进行所有繁重的工作,QGraphicsProxyWidget意味着与它

截至目前,还没有计划将经典QWidgets嵌入到我所知道的场景图中。我认为这不太可能改变,因为QPainter的概念,用于经典小部件的绘画框架和新的场景图形彼此不能很好地发挥作用。

有一些努力开发专门针对QML需求量身定制的新小部件集,但它们都没有像经典小部件那样强大和成熟。最突出的是QML Quick Controls,自5.1版以来与Qt捆绑在一起。

如果你真的依赖QWT,我的建议是坚持使用Qt Quick 1.1。它仍然与Qt 5捆绑在一起,可能适用于像你这样的情况。这样你就不会利用新的场景图。

答案 1 :(得分:7)

可以做的是将小部件渲染为图像并上传为纹理。对于交互,有人需要从sceneGraph转发事件,如mouseClick或keyPressed,转换为小部件坐标,再次传递,渲染和上传纹理。只是一个想法:)

答案 2 :(得分:5)

推荐的方法是使用基于QWidget的应用程序并使用QWidget :: createWindowContainer嵌入QML部分。

答案 3 :(得分:5)

您可以使用QQuickPaintedItem类将QWidget嵌入到QML中: http://doc.qt.io/qt-5/qquickpainteditem.html

Qt5有一个例子: http://doc.qt.io/qt-5/qtquick-customitems-painteditem-example.html

您应该使用要嵌入的私有窗口小部件属性来实现QQuickPaintedItem的固有内容。提供paint方法,只需渲染QtWidget,并提供从QQuickPaintedItem继承传输的鼠标和其他事件,以嵌入QtWidget。

还有QSG(Qt场景图API),但我对这件事的经验并不顺利。我相信多线程的线索(在不同的线程中执行渲染(不是在Qt GUI线程中执行渲染,但在Windows上并非如此,并且所有操作都在主GUI线程中完成)。

我已经实现了QCustomPlot的嵌入,这里是链接:github.com/mosolovsa/qmlplot

答案 4 :(得分:0)

除了Julien的答案之外 - 实现这一点的一个简单方法是使用QQuickWidget来显示QML场景,然后添加常规QWidget作为QQuickWidget的子节点。您还可以添加一个简单的中间QObject来将QWidget锚定到场景中的项目。

E.g:

在main.qml中:

Item {

    ... // layouts, extra items, what have you

        Item
        {
            objectName: "layoutItem"
            anchors.fill: parent
        }

    ... // more layouts, extra items, etc.
}

widgetanchor.h:

class WidgetAnchor: public QObject
{
    ptr<QWidget> _pWidget;
    QPointer<QQuickItem> _pQuickItem;
public:
    WidgetAnchor(QWidget* pWidget, QQuickItem* pItem)
        : QObject(pWidget), _pWidget(pWidget), _pQuickItem(pItem)
    {
        connect(_pQuickItem, &QQuickItem::xChanged, this, &WidgetAnchor::updateGeometry);
        connect(_pQuickItem, &QQuickItem::yChanged, this, &WidgetAnchor::updateGeometry);
        connect(_pQuickItem, &QQuickItem::widthChanged, this, &WidgetAnchor::updateGeometry);
        connect(_pQuickItem, &QQuickItem::heightChanged, this, &WidgetAnchor::updateGeometry);
        updateGeometry();
    }
private:
    void updateGeometry()
    {
        if (_pQuickItem)
        {
            QRectF r = _pQuickItem->mapRectToItem(0, QRectF(_pQuickItem->x(), _pQuickItem->y(), _pQuickItem->width(), _pQuickItem->height()));
            _pWidget->setGeometry(r.toRect());
        }
    }
};

在main.cpp中:

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    auto pqw = new QQuickWidget;
    pqw->setSource(QUrl::fromLocalFile("main.qml"));
    pqw->setResizeMode(QQuickWidget::SizeRootObjectToView);
    pqw->setAttribute(Qt::WA_DeleteOnClose);
    auto pOwt = new MyWidget(pqw);
    if (auto pOverlayItem = pqw->rootObject()->findChild<QQuickItem*>("overlayItem"))
        new WidgetAnchor(pOwt, pOverlayItem);
    pqw->show();

    return app.exec();
}

该文档指出,使用QQuickWidget优于QQuickView和QWidget :: createWindowContainer,例如对堆叠顺序没有限制,但是“性能损失很小”。

希望有所帮助。

答案 5 :(得分:0)

Here解释了如何在基于QML的布局上添加QComboBox。认为这将是您案件的好榜样。 (在Qt 5.9中实现了原生的ComboBox QML控件)。