I am using Qt5 beta and trying to embed a QWidget-based object into QML. The goal is to use QML as much as possible, and only use QWidget objects where QML does not do what I need. I found a link explaining how to do this for Qt4.7, but I have not found any information explaining how to do this in Qt5.
我正在使用Qt5 beta,并试图将一个基于qwidget的对象嵌入到QML中。我们的目标是尽可能地使用QML,并且只在QML不满足我需要的情况下使用QWidget对象。我找到了一个链接,解释了如何在Qt4.7中实现这个功能,但是我没有找到任何关于Qt5中如何做到这一点的信息。
http://doc.qt.digia.com/4.7/declarative-cppextensions-qwidgets.html
http://doc.qt.digia.com/4.7/declarative-cppextensions-qwidgets.html
The same example is also available in the Qt5 examples folder under:
在Qt5示例文件夹中也有相同的示例:
examples\qtquick1\declarative\cppextensions\qwidgets
例子\ qtquick1 \声明\ cppextensions \ qwidgets
Unfortunately, this example uses QtQuick 1, rather than QtQuick 2, and I would like to use the new features of Qt5. I actually want to embed a qwt widget, but as a first step I would be happy to embed any simple QWidget-based object.
不幸的是,这个例子使用QtQuick 1,而不是QtQuick 2,我想使用Qt5的新特性。实际上,我想要嵌入一个qwt小部件,但是作为第一步,我很乐意嵌入任何简单的基于qwidget的对象。
Can anybody help me get the example working under Qt5 / QtQuick 2 ?
有人能帮我得到Qt5 / QtQuick 2下的例子吗?
6 个解决方案
#1
32
Qt Quick 2 uses a scene graph for efficient rendering on the GPU. Unfortunately this makes it impossible to embed classic widgets into the scene. The old approach to embed such widgets with the help of QGraphicsProxyWidget
works only with Qt Quick 1, because internally it uses a QGraphicsView
for all the heavy lifting and QGraphicsProxyWidget
is meant to be used with it.
Qt Quick 2使用场景图来高效地渲染GPU。不幸的是,这使得将经典小部件嵌入场景变得不可能。旧的方法将这些小部件嵌入到QGraphicsProxyWidget的帮助下,只适用于Qt Quick 1,因为在内部它使用QGraphicsView来处理所有的重载,QGraphicsProxyWidget应该与它一起使用。
As of now there are no plans to enable embedding classic QWidgets into the scene graph I know of. I think this is rather unlikely to change, because the concepts of QPainter, the painting framework used for the classic widgets, and the new scene graph doesn't play well with each other.
到目前为止,还没有计划将经典的QWidgets嵌入到我所知道的场景图中。我认为这是不太可能改变的,因为QPainter的概念,用于经典小部件的绘画框架,新的场景图不能很好地相互作用。
There some efforts to develop new widgets sets specifically tailored for the needs of QML, but none of them are as powerful and mature as the classic widgets. The most prominent ones are the QML Quick Controls, bundled with Qt since version 5.1.
有一些开发新部件的努力,专门为QML的需求定制,但是没有一个像经典的小部件一样强大和成熟。最突出的是QML快速控件,它与Qt绑定,自5.1版本以来。
If you really depend on QWT my advice would be to stick with Qt Quick 1.1 for now. It's still bundled with Qt 5, probably for cases like yours. That way you won't take advantage of the new scene graph, though.
如果你真的依赖QWT,我的建议是现在就坚持Qt快1.1。它仍然与Qt 5捆绑在一起,可能是针对像你这样的情况。这样你就不会利用新的场景图了。
#2
6
What could be done is to render the widget to an image and upload as texture.For interaction someone needs to forward events like mouseClick or keyPressed from the sceneGraph, translate to widget coordinates, pass on, render and upload texture again. Just an idea :)
可以做的是将小部件呈现为图像,并上传为纹理。对于交互来说,需要将mouseClick或keyPressed之类的事件转发到sceneGraph中,转换到小部件坐标,再传递、渲染和上传纹理。只是一个想法:)
#3
6
The recommended approach is to stay with a QWidget based application and embed the QML parts using QWidget::createWindowContainer.
推荐的方法是使用基于QWidget的应用程序,并使用QWidget::createWindowContainer嵌入QML部件。
#4
2
You can embed QWidget to QML by using QQuickPaintedItem class: http://doc.qt.io/qt-5/qquickpainteditem.html
通过使用QQuickPaintedItem类,您可以将QWidget嵌入到QML中:http://doc.qt.io/qt-5/qquickpainteditem.html。
Qt5 has an example: http://doc.qt.io/qt-5/qtquick-customitems-painteditem-example.html
Qt5有一个例子:http://doc.qt.io/qt-5/qtquick-customitems-painteditem-example.html。
You should implement an inherent of QQuickPaintedItem with private widget attribute, that you want to embed. Provide paint method, that just render the QtWidget and provide mouse and other event transmitting from inherit of QQuickPaintedItem to embed QtWidget.
您应该使用私有小部件属性实现QQuickPaintedItem的固有特性,您想要嵌入。提供绘制方法,它只提供QtWidget,并提供鼠标和其他从继承QQuickPaintedItem到嵌入QtWidget的事件。
There's also QSG (Qt scene graph API), but my experience with that thing wasn't smooth. I believe the clue in multithreading (performing rendering in the different thread (not the Qt GUI thread one, however on Windows that's not true and all is done in main GUI thread).
也有QSG (Qt scene graph API),但我的经历并不顺利。我相信多线程的线索(在不同的线程中执行呈现(不是Qt GUI线程1,但是在Windows上不是真的,所有的都是在主GUI线程中完成的)。
I've implemented embedding of QCustomPlot, here's link: github.com/mosolovsa/qmlplot
我已经实现了QCustomPlot的嵌入,这里有链接:github.com/mosolovsa/qmlplot。
#5
0
Further to Julien's answer - a simple way to achieve this is to use QQuickWidget to display the QML scene, and then add a regular QWidget as a child of the QQuickWidget. You can also add a simple intermediate QObject to anchor the QWidget to an item in the scene.
进一步到Julien的答案——实现这一目标的简单方法是使用QQuickWidget来显示QML场景,然后作为QQuickWidget的子元素添加一个常规的QWidget。您还可以添加一个简单的中间QObject来将QWidget锚定到场景中的一个项目。
E.g.:
例如:
In main.qml:
在main.qml:
Item {
... // layouts, extra items, what have you
Item
{
objectName: "layoutItem"
anchors.fill: parent
}
... // more layouts, extra items, etc.
}
widgetanchor.h:
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());
}
}
};
In main.cpp:
在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();
}
The documentation states that using QQuickWidget has advantages over QQuickView and QWidget::createWindowContainer, such as no restrictions on stacking order, but has a 'minor performance hit'.
文档说明,使用QQuickWidget优于QQuickView和QWidget::createWindowContainer,比如对堆码顺序没有限制,但有“轻微的性能影响”。
Hope that helps.
希望有帮助。
#6
0
Here explained how to add QComboBox on QML based layout. Think that will good example for your case. (In Qt 5.9 implemented native ComboBox QML control).
这里解释了如何在基于QML的布局中添加QComboBox。这将为你的案例提供一个很好的例子。(Qt 5.9实现了本机ComboBox QML控制)。
#1
32
Qt Quick 2 uses a scene graph for efficient rendering on the GPU. Unfortunately this makes it impossible to embed classic widgets into the scene. The old approach to embed such widgets with the help of QGraphicsProxyWidget
works only with Qt Quick 1, because internally it uses a QGraphicsView
for all the heavy lifting and QGraphicsProxyWidget
is meant to be used with it.
Qt Quick 2使用场景图来高效地渲染GPU。不幸的是,这使得将经典小部件嵌入场景变得不可能。旧的方法将这些小部件嵌入到QGraphicsProxyWidget的帮助下,只适用于Qt Quick 1,因为在内部它使用QGraphicsView来处理所有的重载,QGraphicsProxyWidget应该与它一起使用。
As of now there are no plans to enable embedding classic QWidgets into the scene graph I know of. I think this is rather unlikely to change, because the concepts of QPainter, the painting framework used for the classic widgets, and the new scene graph doesn't play well with each other.
到目前为止,还没有计划将经典的QWidgets嵌入到我所知道的场景图中。我认为这是不太可能改变的,因为QPainter的概念,用于经典小部件的绘画框架,新的场景图不能很好地相互作用。
There some efforts to develop new widgets sets specifically tailored for the needs of QML, but none of them are as powerful and mature as the classic widgets. The most prominent ones are the QML Quick Controls, bundled with Qt since version 5.1.
有一些开发新部件的努力,专门为QML的需求定制,但是没有一个像经典的小部件一样强大和成熟。最突出的是QML快速控件,它与Qt绑定,自5.1版本以来。
If you really depend on QWT my advice would be to stick with Qt Quick 1.1 for now. It's still bundled with Qt 5, probably for cases like yours. That way you won't take advantage of the new scene graph, though.
如果你真的依赖QWT,我的建议是现在就坚持Qt快1.1。它仍然与Qt 5捆绑在一起,可能是针对像你这样的情况。这样你就不会利用新的场景图了。
#2
6
What could be done is to render the widget to an image and upload as texture.For interaction someone needs to forward events like mouseClick or keyPressed from the sceneGraph, translate to widget coordinates, pass on, render and upload texture again. Just an idea :)
可以做的是将小部件呈现为图像,并上传为纹理。对于交互来说,需要将mouseClick或keyPressed之类的事件转发到sceneGraph中,转换到小部件坐标,再传递、渲染和上传纹理。只是一个想法:)
#3
6
The recommended approach is to stay with a QWidget based application and embed the QML parts using QWidget::createWindowContainer.
推荐的方法是使用基于QWidget的应用程序,并使用QWidget::createWindowContainer嵌入QML部件。
#4
2
You can embed QWidget to QML by using QQuickPaintedItem class: http://doc.qt.io/qt-5/qquickpainteditem.html
通过使用QQuickPaintedItem类,您可以将QWidget嵌入到QML中:http://doc.qt.io/qt-5/qquickpainteditem.html。
Qt5 has an example: http://doc.qt.io/qt-5/qtquick-customitems-painteditem-example.html
Qt5有一个例子:http://doc.qt.io/qt-5/qtquick-customitems-painteditem-example.html。
You should implement an inherent of QQuickPaintedItem with private widget attribute, that you want to embed. Provide paint method, that just render the QtWidget and provide mouse and other event transmitting from inherit of QQuickPaintedItem to embed QtWidget.
您应该使用私有小部件属性实现QQuickPaintedItem的固有特性,您想要嵌入。提供绘制方法,它只提供QtWidget,并提供鼠标和其他从继承QQuickPaintedItem到嵌入QtWidget的事件。
There's also QSG (Qt scene graph API), but my experience with that thing wasn't smooth. I believe the clue in multithreading (performing rendering in the different thread (not the Qt GUI thread one, however on Windows that's not true and all is done in main GUI thread).
也有QSG (Qt scene graph API),但我的经历并不顺利。我相信多线程的线索(在不同的线程中执行呈现(不是Qt GUI线程1,但是在Windows上不是真的,所有的都是在主GUI线程中完成的)。
I've implemented embedding of QCustomPlot, here's link: github.com/mosolovsa/qmlplot
我已经实现了QCustomPlot的嵌入,这里有链接:github.com/mosolovsa/qmlplot。
#5
0
Further to Julien's answer - a simple way to achieve this is to use QQuickWidget to display the QML scene, and then add a regular QWidget as a child of the QQuickWidget. You can also add a simple intermediate QObject to anchor the QWidget to an item in the scene.
进一步到Julien的答案——实现这一目标的简单方法是使用QQuickWidget来显示QML场景,然后作为QQuickWidget的子元素添加一个常规的QWidget。您还可以添加一个简单的中间QObject来将QWidget锚定到场景中的一个项目。
E.g.:
例如:
In main.qml:
在main.qml:
Item {
... // layouts, extra items, what have you
Item
{
objectName: "layoutItem"
anchors.fill: parent
}
... // more layouts, extra items, etc.
}
widgetanchor.h:
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());
}
}
};
In main.cpp:
在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();
}
The documentation states that using QQuickWidget has advantages over QQuickView and QWidget::createWindowContainer, such as no restrictions on stacking order, but has a 'minor performance hit'.
文档说明,使用QQuickWidget优于QQuickView和QWidget::createWindowContainer,比如对堆码顺序没有限制,但有“轻微的性能影响”。
Hope that helps.
希望有帮助。
#6
0
Here explained how to add QComboBox on QML based layout. Think that will good example for your case. (In Qt 5.9 implemented native ComboBox QML control).
这里解释了如何在基于QML的布局中添加QComboBox。这将为你的案例提供一个很好的例子。(Qt 5.9实现了本机ComboBox QML控制)。