QT5.在QML中嵌入QWidget对象

eat*_*ens 31 qwidget qml 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下工作吗?

seb*_*sgo 30

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

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

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

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

  • 更新:自发布此答案以来,纯QML小部件即组件已经成熟了很多. (4认同)
  • -1:“不可能”将常规 QWidget 嵌入到 Qt Quick 2 场景中是完全错误的。这不仅是可能的,而且效果也很好。我在我的应用程序中这样做,并且性能非常好。请参阅[此](/sf/answers/954187251/)和[此](/sf/answers/3004481441/)答案和此[存储库](https://github .com/mosolovsa/qmlplot)为例。 (2认同)

小智 8

根据 Julien 的回答,实现此目的的一个简单方法是使用 QQuickWidget 显示 QML 场景,然后添加常规 QWidget 作为 QQuickWidget 的子级。您还可以添加一个简单的中间 QObject 将 QWidget 锚定到场景中的某个项目。

例如:

在 main.qml 中:

Item {

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

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

    ... // more layouts, extra items, etc.
}
Run Code Online (Sandbox Code Playgroud)

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());
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

在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();
}
Run Code Online (Sandbox Code Playgroud)

该文档指出,使用 QQuickWidget 比 QQuickView 和 QWidget::createWindowContainer 有优势,例如对堆叠顺序没有限制,但有“轻微的性能影响”。

希望有帮助。


小智 7

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

  • 究竟.但这种方法需要有创造力和大胆的个人. (7认同)

Jul*_*ian 5

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

  • -1:即使我同意你的观点,这也不能回答问题。问题是关于将 QWidget 嵌入到 QML 场景中。虽然确实通常最好保持应用程序基于 QWidget,但您可能仍然希望在 QML 视图中嵌入 QWidget(例如,我的应用程序就是这种情况)。 (2认同)

Mos*_*gey 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的固有属性。提供绘画方法,该方法只渲染QtWidget,并提供鼠标和其他事件(从QQuickPaintedItem的继承传递到嵌入QtWidget)。

也有QSG(Qt场景图API),但是我在这方面的经验并不顺利。我相信多线程的线索(在不同的线程中执行渲染(不是Qt GUI线程,但是在Windows上是不正确的,并且所有操作都在主GUI线程中完成)。

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