Qt5ベータ版を使用しており、QWidgetベースのオブジェクトをQMLに埋め込もうとしています。目標は、できるだけQMLを使用することであり、QWidgetオブジェクトは、QMLが私が必要とすることを実行しない場合にのみ使用します。 Qt4.7でこれを行う方法を説明するリンクを見つけましたが、Qt5でこれを行う方法を説明する情報は見つかりませんでした。
http://doc.qt.digia.com/4.7/declarative-cppextensions-qwidgets.html
同じ例は、Qt5のサンプルフォルダーにもあります。
examples\qtquick1\declarative\cppextensions\qwidgets
残念ながら、この例ではQtQuick 2ではなくQtQuick 1を使用しています。Qt5の新機能を使用したいと思います。実際にはqwtウィジェットを埋め込みたいのですが、最初のステップとして、簡単なQWidgetベースのオブジェクトを埋め込みたいと思います。
Qt5/QtQuick 2でサンプルを動作させるのを手伝ってくれる人はいますか?
Qt Quick 2は、GPUで効率的にレンダリングするためにシーングラフを使用します。残念ながら、これにより、クラシックウィジェットをシーンに埋め込むことができなくなります。 QGraphicsProxyWidget
を使用してこのようなウィジェットを埋め込む古いアプローチは、Qt Quick 1でのみ機能します。これは、内部でQGraphicsView
を使用してすべての負荷が大きく、QGraphicsProxyWidget
がそれと一緒に使用されます。
現在のところ、私が知っているシーングラフにクラシックQWidgetを埋め込むことを可能にする計画はありません。 QPainterの概念、クラシックウィジェットに使用されるペインティングフレームワーク、および新しいシーングラフは互いにうまく機能しないため、これが変更される可能性はかなり低いと思います。
QMLのニーズに合わせて特別に調整された新しいウィジェットセットを開発するためのいくつかの取り組みがありますが、それらのどれも、クラシックウィジェットほど強力で成熟したものではありません。最も有名なものは QML Quick Controls で、バージョン5.1以降、Qtにバンドルされています。
あなたが本当にQWTに依存しているなら、私のアドバイスは今のところQt Quick 1.1に固執することです。それはおそらくあなたのような場合のためにQt 5にまだバンドルされています。そうすれば、新しいシーングラフを利用できなくなります。
実行できることは、ウィジェットを画像にレンダリングしてテクスチャとしてアップロードすることです。インタラクションのために、誰かがmouseGraphやkeyPressedなどのイベントをsceneGraphから転送し、ウィジェット座標に変換し、テクスチャを渡し、再度レンダリングしてアップロードする必要があります。ただのアイデア:)
推奨されるアプローチは、QWidgetベースのアプリケーションにとどまり、QWidget :: createWindowContainerを使用してQMLパーツを埋め込むことです。
QWidgetをQMLに埋め込むには、QQuickPaintedItemクラスを使用します。 http://doc.qt.io/qt-5/qquickpainteditem.html
Qt5には例があります: http://doc.qt.io/qt-5/qtquick-customitems-painteditem-example.html
埋め込みたいQQuickPaintedItemの固有のウィジェット属性を実装する必要があります。 QtWidgetをレンダリングするだけのPaintメソッドを提供し、QQuickPaintedItemの継承からQtWidgetを埋め込むためにマウスやその他のイベントを送信できるようにします。
QSG(QtシーングラフAPI)もありますが、私の経験はスムーズではありませんでした。マルチスレッド(Qt GUIスレッドではなく、別のスレッドでレンダリングを実行する際の手掛かりと思いますが、Windowsでは正しくないため、すべてメインGUIスレッドで行われます)。
QCustomPlotの埋め込みを実装しました。ここにリンクがあります:github.com/mosolovsa/qmlplot
ジュリアンの答えに加えて-これを達成する簡単な方法は、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.
}
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よりも優れていると記載されています。たとえば、スタックの順序に制限はありませんが、「わずかなパフォーマンスヒット」があります。
お役に立てば幸いです。
ここ QMLベースのレイアウトにQComboBoxを追加する方法を説明しました。それはあなたのケースの良い例になると思います。 (Qt 5.9では、ネイティブのComboBox QMLコントロールが実装されました)。