web-dev-qa-db-fra.com

Qt5. Incorporer l'objet QWidget dans QML

J'utilise Qt5 beta et tente d'incorporer un objet basé sur QWidget dans QML. L'objectif est d'utiliser QML autant que possible et d'utiliser uniquement les objets QWidget où QML ne fait pas ce dont j'ai besoin. J'ai trouvé un lien expliquant comment faire cela pour Qt4.7, mais je n'ai trouvé aucune information expliquant comment faire cela avec Qt5.

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

Le même exemple est également disponible dans le dossier Exemples Qt5 sous:

exemples\qtquick1\declarative\cppextensions\qwidgets

Malheureusement, cet exemple utilise QtQuick 1, plutôt que QtQuick 2, et j'aimerais utiliser les nouvelles fonctionnalités de Qt5. En fait, je souhaite intégrer un widget QWT, mais dans un premier temps, je serais heureux d'intégrer un objet simple basé sur QWidget.

Est-ce que quelqu'un peut m'aider à obtenir l'exemple en travaillant sous Qt5/QtQuick 2?

28
eatyourgreens

Qt Quick 2 utilise un graphique de scène pour un rendu efficace sur le GPU. Malheureusement, cela rend impossible l'intégration de widgets classiques dans la scène. L'ancienne approche consistant à intégrer de tels widgets à l'aide de QGraphicsProxyWidget fonctionne uniquement avec Qt Quick 1, car elle utilise en interne QGraphicsView pour tout le travail de levage et QGraphicsProxyWidget pour pouvoir être utilisée avec.

Pour l'instant, il n'est pas prévu d'activer l'intégration de QWidgets classiques dans le graphe de scène que je connais. Je pense que cela ne devrait pas changer, car les concepts de QPainter, le cadre de peinture utilisé pour les widgets classiques et le nouveau graphique de scène ne fonctionnent pas bien entre eux.

Certains efforts ont été faits pour développer de nouveaux ensembles de widgets spécialement adaptés aux besoins de QML, mais aucun d’eux n’est aussi puissant et aussi mature que les widgets classiques. Les plus importants sont les QML Quick Controls , fournis avec Qt depuis la version 5.1.

Si vous comptez vraiment sur QWT, je vous conseillerais de vous en tenir à Qt Quick 1.1 pour le moment. Il est toujours fourni avec Qt 5, probablement pour des cas comme le vôtre. De cette façon, vous ne profiterez pas du nouveau graphe de scène.

31
sebasgo

Ce qui pourrait être fait est de rendre le widget en une image et de le télécharger en tant que texture. Juste une idée :)

7
Sebastian

L'approche recommandée consiste à rester avec une application basée sur QWidget et à incorporer les parties QML à l'aide de QWidget :: createWindowContainer.

5
Julian

Vous pouvez intégrer QWidget à QML en utilisant la classe QQuickPaintedItem: http://doc.qt.io/qt-5/qquickpainteditem.html

Qt5 a un exemple: http://doc.qt.io/qt-5/qtquick-customitems-painteditem-example.html

Vous devez implémenter un attribut inhérent à QQuickPaintedItem avec un widget privé, que vous souhaitez intégrer. Fournissez la méthode Paint, qui ne fait que restituer QtWidget et fournit à la souris et à tout autre événement transmis à partir de hériter de QQuickPaintedItem l’intégration de QtWidget.

Il y a aussi QSG (API de graphique de scène Qt), mais mon expérience avec cette chose n'a pas été fluide. Je crois que la clé du multithreading (effectuer un rendu dans un autre thread (pas le premier thread de Qt GUI, mais sous Windows ce n'est pas vrai et tout est fait dans le principal thread).

J'ai implémenté l'incorporation de QCustomPlot, voici le lien: github.com/mosolovsa/qmlplot

4
Mosolov Sergey

Pour compléter la réponse de Julien, un moyen simple d'y parvenir consiste à utiliser QQuickWidget pour afficher la scène QML, puis à ajouter un QWidget normal en tant qu'enfant de QQuickWidget. Vous pouvez également ajouter un QObject intermédiaire simple pour ancrer le QWidget à un élément de la scène. 

Par exemple.:

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

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

La documentation indique que l'utilisation de QQuickWidget présente des avantages par rapport à QQuickView et QWidget :: createWindowContainer, tels que l'absence de restrictions sur l'ordre de superposition, mais qu'elle a un impact négatif sur les performances.

J'espère que cela pourra aider.

0
NickD2039

Ici a expliqué comment ajouter QComboBox sur une présentation basée sur QML. Pensez que ce sera un bon exemple pour votre cas. (Dans Qt 5.9, le contrôle ComboBox QML natif est implémenté).

0
stanislav888