Using a Qt 5 Widget within a QML application?



  • I am writing a Qt 5 application with QML and would like to know if it is possible to integrate a Qt 5 Widget into the same UI of that application.

    1. Is it possible?
    2. If yes, how is it achieved?
    3. Are there any restrictions, caveats or problems associated with doing this?

    Thanks,

    Felix


  • Qt Champions 2016

    Hi and welcome.
    I have not huge experience with QML but i know you can expand it
    http://doc.qt.io/qt-5/qtqml-tutorials-extending-qml-example.html
    so i assume its also possible with normal widgets in some way.

    Since you can show QML inside widget application, it is possible to mix.
    http://doc.qt.io/qt-4.8/qml-integration.html

    So yes, I think with some research its possible.


  • Moderators

    sorry thats not officially supported by Qt.
    The problem is that QML uses SceneGraph for painting, where QWidgets use a raster engine for painting. So they unfortunately dont play very well together.
    But not impossible, but but far not efficient. You would need to render the widget as a texture on every paint event. Additionally you would need to forward the events to the widget.


  • Moderators

    @Lucan1d
    you made me curious, and so i played around a bit.
    This example renders the widget and forwards mouse- and key-events to the widget (i used a QTextEdit in this case).
    But it also points out the problems very well:

    • you can't use widgets with popup windows (e.g. combobox)
    • cursor blinking and text-selection isn't painted (may be fixed somehow - didn't investigate further)
    • correct focus handling might be pretty tricky to implement
    • correct state handling is essential for visual appearance

    But i think it might be a good starting point. It still needs a lot of work to behave as someone would expect it to behave.

    qmlRegisterType<MyQmlWidget>("com.test.qml", 1, 0, "MyQmlWidget");
    QQuickView *qmlView = new QQuickView;
    qmlView->setSource(QUrl::fromLocalFile("test.qml"));
    qmlView->show();
    

    test.qml

    import QtQuick 2.0
    import com.test.qml 1.0
    
    MyQmlWidget {
        focus: true
    }
    

    h

    class MyQmlWidget : public QQuickPaintedItem
    {
        Q_OBJECT
    
    public:
        MyQmlWidget( QWidget* widget = new QTextEdit );
    
        virtual bool eventFilter(QObject *, QEvent *);
        virtual void paint(QPainter * painter);
    
        virtual bool event(QEvent * e);
    
    protected:
        void setWidget( QWidget* widget );
    
        QWidget*    m_Widget;
    };
    

    cpp

    MyQmlWidget::MyQmlWidget( QWidget* widget )
        : QQuickPaintedItem()
    {
        this->setWidget( widget );
        this->setAcceptedMouseButtons(Qt::AllButtons);
    }
    
    bool MyQmlWidget::eventFilter(QObject * watched, QEvent * event)
    {
        if( watched == m_Widget )
        {
            switch( event->type() )
            {
                case QEvent::Paint:
                case QEvent::UpdateRequest:
                    this->update();
                break;
            }
        }
        return QQuickPaintedItem::eventFilter(watched, event);
    }
    
    void MyQmlWidget::paint(QPainter *painter)
    {
        if( !m_Widget )
            return;
    
        m_Widget->render( painter );
    }
    
    bool MyQmlWidget::event(QEvent *event)
    {
        switch( event->type() )
        {
            case QEvent::MouseButtonPress:
            case QEvent::MouseButtonRelease:
            case QEvent::MouseButtonDblClick:
            case QEvent::KeyPress:
            case QEvent::KeyRelease:
            {
                qDebug() << "SEND EVENT:" << event;
                QApplication::sendEvent( m_Widget, event );
                return true;
            }
            break;
            case QEvent::FocusIn:
                this->forceActiveFocus();
            break;
        }
        return QQuickPaintedItem::event(event);
    }
    
    void MyQmlWidget::setWidget(QWidget *widget)
    {
        m_Widget = widget;
        m_Widget->installEventFilter( this );
    
        const QSizeF sh = m_Widget->sizeHint();
        this->setImplicitSize( sh.width(), sh.height() );
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.