web-dev-qa-db-de.com

Qt5. Einbetten des QWidget-Objekts in QML

Ich verwende Qt5 Beta und versuche, ein QWidget-basiertes Objekt in QML einzubetten. Das Ziel ist, QML so weit wie möglich zu verwenden und nur QWidget-Objekte zu verwenden, bei denen QML nicht das tut, was ich brauche. Ich habe einen Link gefunden, der erklärt, wie dies für Qt4.7 ausgeführt wird, aber ich habe keine Informationen gefunden, die dies in Qt5 erläutern.

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

Das gleiche Beispiel finden Sie auch im Qt5-Ordner "Beispiele" unter:

beispiele\qtquick1\deklarativ\cppextensions\qwidgets

Leider verwendet dieses Beispiel QtQuick 1 anstelle von QtQuick 2, und ich möchte die neuen Funktionen von Qt5 verwenden. Ich möchte eigentlich ein qwt-Widget einbetten, aber als ersten Schritt würde ich gerne jedes einfache QWidget-basierte Objekt einbetten.

Kann mir jemand helfen, das Beispiel unter Qt5/QtQuick 2 zum Laufen zu bringen?

28
eatyourgreens

Qt Quick 2 verwendet ein Szenendiagramm für effizientes Rendern auf der GPU. Leider ist es unmöglich, klassische Widgets in die Szene einzubetten. Der alte Ansatz, solche Widgets mit Hilfe von QGraphicsProxyWidget einzubetten, funktioniert nur mit Qt Quick 1, da intern eine QGraphicsView für all das schwere Heben verwendet wird und QGraphicsProxyWidget damit verwendet werden soll.

Derzeit ist nicht geplant, klassische QWidgets in das mir bekannte Szenendiagramm einzubetten. Ich denke, dass sich dies wahrscheinlich nicht ändern wird, da die Konzepte von QPainter, der Malrahmen für die klassischen Widgets und der neue Szenegraph nicht gut miteinander harmonieren.

Es gibt einige Bemühungen, neue Widgets zu entwickeln, die speziell auf die Bedürfnisse von QML zugeschnitten sind, aber keines davon ist so leistungsfähig und ausgereift wie die klassischen Widgets. Die bekanntesten sind die QML Quick Controls , die seit Version 5.1 im Lieferumfang von Qt enthalten sind.

Wenn Sie wirklich auf QWT angewiesen sind, würde ich Ihnen raten, Qt Quick 1.1 beizubehalten. Es ist immer noch im Lieferumfang von Qt 5 enthalten, wahrscheinlich für Fälle wie Ihres. Auf diese Weise können Sie das neue Szenendiagramm jedoch nicht nutzen.

31
sebasgo

Was getan werden könnte, ist, das Widget in ein Bild zu rendern und als Textur hochzuladen. Für die Interaktion muss jemand Ereignisse wie mouseClick oder keyPressed vom sceneGraph weiterleiten, in Widget-Koordinaten übersetzen, weitergeben, wiedergeben und Textur erneut hochladen. Nur eine Idee :)

7
Sebastian

Der empfohlene Ansatz besteht darin, bei einer QWidget-basierten Anwendung zu bleiben und die QML-Teile mit QWidget :: createWindowContainer einzubetten.

5
Julian

Sie können QWidget mithilfe der Klasse QQuickPaintedItem in QML einbetten: http://doc.qt.io/qt-5/qquickpainteditem.html

Qt5 hat ein Beispiel: http://doc.qt.io/qt-5/qtquick-customitems-painteditem-example.html

Sie sollten ein inhärentes QQuickPaintedItem mit dem privaten Widgetattribut implementieren, das Sie einbetten möchten. Stellen Sie eine Paint-Methode bereit, die nur das QtWidget rendert und die Übertragung von Maus und anderen Ereignissen vom Erben von QQuickPaintedItem zum Einbetten von QtWidget ermöglicht.

Es gibt auch QSG (Qt Scene Graph API), aber meine Erfahrungen mit diesem Ding waren nicht glatt. Ich glaube, der Hinweis auf Multithreading (Rendering in den verschiedenen Threads (nicht der Qt-GUI-Thread, jedoch unter Windows ist dies nicht der Fall und alles wird im Haupt-GUI-Thread ausgeführt).

Ich habe die Einbettung von QCustomPlot implementiert. Hier ist der Link: github.com/mosolovsa/qmlplot

4
Mosolov Sergey

Weiter zu Juliens Antwort - eine einfache Möglichkeit, dies zu erreichen, besteht darin, die QML-Szene mit QQuickWidget anzuzeigen und dann ein reguläres QWidget als untergeordnetes Element des QQuickWidget hinzuzufügen. Sie können auch ein einfaches Zwischen-QObject hinzufügen, um das QWidget mit einem Element in der Szene zu verankern. 

Z.B.:

In 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());
        }
    }
};

In 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();
}

Die Dokumentation besagt, dass die Verwendung von QQuickWidget Vorteile gegenüber QQuickView und QWidget :: createWindowContainer bietet, z. B. keine Einschränkung der Stapelreihenfolge, jedoch ein geringer Performance-Treffer.

Hoffentlich hilft das.

0
NickD2039

Hier wurde erklärt, wie QComboBox in einem QML-basierten Layout hinzugefügt wird. Denken Sie, dass dies ein gutes Beispiel für Ihren Fall ist. (In Qt 5.9 wurde eine native ComboBox-QML-Steuerung implementiert.).

0
stanislav888