C++生成QML代码与QML里面集成QWidget

Posted yantuguiguziPGJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++生成QML代码与QML里面集成QWidget相关的知识,希望对你有一定的参考价值。

目录

1  QML代码生成

2  注册机制的含义

3   QWidgetInQml  QML里面集成widget

4 QML_OSR_EXP  将Qt Widgets嵌入到QML界面中的一种示范

5  参考链接


1  QML代码生成

/******************************************************************************
 * QSkinny - Copyright (C) 2016 Uwe Rathmann
 * This file may be used under the terms of the 3-clause BSD License
 *****************************************************************************/

#pragma once

#include "GridAccessor.h"
#include <QQuickWidget>

class QGraphicsGridLayout;

class GridQuick : public QQuickWidget, public GridAccessor

  public:
    GridQuick( QWidget* parent = nullptr );
    ~GridQuick() override;

    void insert( const QByteArray& colorName,
        int row, int column, int rowSpan, int columnSpan ) override;

    void setSpacing( Qt::Orientations, int spacing ) override;

    void setStretchFactor( int pos, Qt::Orientation, int stretch ) override;
    void setSizeHint( int pos, Qt::Orientation, Qt::SizeHint, int hint ) override;

    void setSizeHintAt( int index, Qt::Orientation, Qt::SizeHint, int hint ) override;
    void setSizePolicyAt( int index, Qt::Orientation, int policy ) override;
    void setAlignmentAt( int index, Qt::Alignment ) override;
    void setRetainSizeWhenHiddenAt( int index, bool on ) override;
    void setVisibleAt( int index, bool on ) override;

    QSize preferredSize() const override;

  protected:
    void resizeEvent( QResizeEvent* ) override;

  private:
    QQuickItem* m_grid;
;

/******************************************************************************
 * QSkinny - Copyright (C) 2016 Uwe Rathmann
 * This file may be used under the terms of the 3-clause BSD License
 *****************************************************************************/

#include "GridQuick.h"
#include <QQuickItem>
#include <QtQml>
#include <QDebug>

static QQuickItem* createQml( const char* qmlCode )

    QQmlEngine engine( nullptr );

    QQmlComponent component( &engine );
    component.setData( qmlCode, QUrl() );

    if ( component.status() != QQmlComponent::Ready )
        qWarning() << component.errorString();

    return qobject_cast< QQuickItem* >( component.create() );


static QQuickItem* itemAt( const QQuickItem* grid, int index )

    const auto children = grid->childItems();
    if ( ( index >= 0 ) && ( index < children.count() ) )
        return children.at( index );

    return nullptr;


static QObject* attachedProperties( const QQuickItem* item )

    for ( auto child : item->children() )
    
        if ( child->inherits( "QQuickLayoutAttached" ) )
            return child;
    

    return nullptr;


static QObject* attachedPropertiesAt( const QQuickItem* grid, int index )

    if ( auto item = itemAt( grid, index ) )
        return attachedProperties( item );

    return nullptr;


GridQuick::GridQuick( QWidget* parent )
    : QQuickWidget( parent )

    setContentsMargins( QMargins() );
    setResizeMode( QQuickWidget::SizeRootObjectToView );

    auto contentItem =
        createQml( "import QtQuick 2.0\\nimport QtQuick.Layouts 1.1\\nItem  GridLayout  " );
    setContent( QUrl(), nullptr, contentItem );

    m_grid = contentItem->childItems().constFirst();
    m_grid->setProperty( "rowSpacing", 5 );
    m_grid->setProperty( "columnSpacing", 5 );


GridQuick::~GridQuick()



void GridQuick::insert( const QByteArray& colorName,
    int row, int column, int rowSpan, int columnSpan )

    /*
        We need to create a temporary layout in QML, so that the
        object for the attachedProperties is created early
     */
    auto layout = createQml( "import QtQuick 2.0\\nimport QtQuick.Layouts 1.15\\nGridLayout  Rectangle  " );

    auto rectangle = layout->childItems().constFirst();
    rectangle->setParent( nullptr );

    delete layout;

    rectangle->setParent( m_grid );
    rectangle->setParentItem( m_grid );

    rectangle->setImplicitWidth( 50 );
    rectangle->setImplicitHeight( 50 );
    rectangle->setProperty( "color", QColor( colorName.constData() ) );

    if ( auto props = attachedProperties( rectangle ) )
    
        props->setProperty( "row", row );
        props->setProperty( "column", column );
        props->setProperty( "rowSpan", rowSpan );
        props->setProperty( "columnSpan", columnSpan );
        props->setProperty( "fillWidth", true );
        props->setProperty( "fillHeight", true );
    


void GridQuick::setSpacing( Qt::Orientations orientations, int spacing )

    if ( orientations & Qt::Vertical )
        m_grid->setProperty( "rowSpacing", spacing );

    if ( orientations & Qt::Horizontal )
        m_grid->setProperty( "columnSpacing", spacing );


void GridQuick::setSizeHint( int, Qt::Orientation, Qt::SizeHint, int )

    qWarning() << "setSizeHint is not supported by Quick Layouts.";


void GridQuick::setStretchFactor( int, Qt::Orientation, int )

    qWarning() << "setStretchFactor is not supported by Quick Layouts.";


void GridQuick::setSizeHintAt( int index, Qt::Orientation orientation,
    Qt::SizeHint which, int hint )

    if ( auto props = attachedPropertiesAt( m_grid, index ) )
    
        const qreal size = hint;

        switch( static_cast< int >( which ) )
        
            case Qt::MinimumSize:
            
                if ( orientation == Qt::Horizontal )
                    props->setProperty( "minimumWidth", size );
                else
                    props->setProperty( "minimumHeight", size );

                break;
            
            case Qt::PreferredSize:
            
                if ( orientation == Qt::Horizontal )
                    props->setProperty( "preferredWidth", size );
                else
                    props->setProperty( "preferredHeight", size );

                break;
            
            case Qt::MaximumSize:
            
                if ( orientation == Qt::Horizontal )
                    props->setProperty( "maximumWidth", size );
                else
                    props->setProperty( "maximumHeight", size );

                break;
            
        
    


void GridQuick::setSizePolicyAt(
    int index, Qt::Orientation orientation, int policy )

    const auto qPolicy = static_cast< QSizePolicy::Policy >( policy & 0xF );

#if 0
    const bool isConstrained = policy & ( 1 << 4 );
#endif

    const bool doFill = ( qPolicy & QSizePolicy::GrowFlag )
        || ( qPolicy & QSizePolicy::ExpandFlag );

    if ( auto props = attachedPropertiesAt( m_grid, index ) )
    
        if ( orientation == Qt::Horizontal )
            props->setProperty( "fillWidth", doFill );
        else
            props->setProperty( "fillHeight", doFill );
    


void GridQuick::setAlignmentAt( int index, Qt::Alignment alignment )

    if ( auto props = attachedPropertiesAt( m_grid, index ) )
        props->setProperty( "alignment", QVariant::fromValue( alignment ) );


void GridQuick::setRetainSizeWhenHiddenAt( int, bool )

    qWarning() << "setRetainSizeWhenHidden is not supported by Quick Layouts.";


void GridQuick::setVisibleAt( int index, bool on )

    if ( auto item = itemAt( m_grid, index ) )
        item->setVisible( on );


static const qreal margin = 10.0;

QSize GridQuick::preferredSize() const

    return QSize(
        m_grid->implicitWidth() + 2 * margin,
        m_grid->implicitHeight() + 2 * margin );


void GridQuick::resizeEvent( QResizeEvent* event )

    QQuickWidget::resizeEvent( event );

    m_grid->setX( margin );
    m_grid->setY( margin );
    m_grid->setWidth( width() - 2 * margin );
    m_grid->setHeight( height() - 2 * margin );


2  注册机制的含义


#include "QskQuickItem.h"
#include "QskQuickItemPrivate.h"
#include "QskQuick.h"
#include "QskEvent.h"
#include "QskSetup.h"
#include "QskSkin.h"
#include "QskDirtyItemFilter.h"

#include <qglobalstatic.h>
#include <qquickwindow.h>

#if defined( QT_DEBUG )

QSK_QT_PRIVATE_BEGIN

#if QT_VERSION >= QT_VERSION_CHECK( 6, 2, 0 )
    #ifndef emit
        #define emit
        #include <private/qabstractanimation_p.h>
        #undef emit
    #endif
#endif

#include <private/qquickpositioners_p.h>

QSK_QT_PRIVATE_END

#endif

#include <unordered_set>

static inline void qskSendEventTo( QObject* object, QEvent::Type type )

    QEvent event( type );
    QCoreApplication::sendEvent( object, &event );


static inline void qskApplyUpdateFlags(
    QskQuickItem::UpdateFlags flags, QskQuickItem* item )

    auto d = static_cast< QskQuickItemPrivate* >( QskQuickItemPrivate::get( item ) );
    d->applyUpdateFlags( flags );


static inline void qskFilterWindow( QQuickWindow* window )

    if ( window == nullptr )
        return;

    static QskDirtyItemFilter itemFilter;
    itemFilter.addWindow( window );


namespace

    class QskQuickItemRegistry
    
      public:
        QskQuickItemRegistry()
        
            /*
                Its faster and saves some memory to have this registry instead
                of setting up direct connections between qskSetup and each control
             */
            QObject::connect( qskSetup, &QskSetup::itemUpdateFlagsChanged,
                qskSetup, [ this ]  updateControlFlags();  );

            /*
                We would also need to send QEvent::StyleChange, when
                a window has a new skin. TODO ...
             */
            QObject::connect( qskSetup, &QskSetup::skinChanged,
                qskSetup, [ this ]  updateSkin();  );
        

        inline void insert( QskQuickItem* item )
        
            m_items.insert( item );
        

        inline void remove( QskQuickItem* item )
        
            m_items.erase( item );
        

        void updateControlFlags()
        
            const auto flags = qskSetup->itemUpdateFlags();

            for ( auto item : m_items )
                qskApplyUpdateFlags( flags, item );
        

        void updateSkin()
        
            QEvent event( QEvent::StyleChange );

            for ( auto item : m_items )
            
                event.setAccepted( true );
                QCoreApplication::sendEvent( item, &event );
            
        

      private:
        std::unordered_set< QskQuickItem* > m_items;
    ;


namespace

    /*
        A helper class to store the released window to be able to
        put it later into the WindowChange event.
     */
    class QskWindowStore
    
      public:
        QskWindowStore()
            : m_refCount( 0 )
            , m_window( nullptr )
        
        

        void setWindow( QQuickWindow* window )
        
            if ( m_window != window )
            
                m_window = window;
                m_refCount = 0;
            

            if ( m_window )
                m_refCount++;
        

        QQuickWindow* window()
        
            QQuickWindow* w = m_window;

            if ( m_window )
            
                if ( --m_refCount == 0 )
                    m_window = nullptr;
            

            return w;
        

      private:
        int m_refCount;
        QQuickWindow* m_window;
    ;


Q_GLOBAL_STATIC( QskQuickItemRegistry, qskRegistry )
Q_GLOBAL_STATIC( QskWindowStore, qskReleasedWindowCounter )

QskQuickItem::QskQuickItem( QskQuickItemPrivate& dd, QQuickItem* parent )
    : QQuickItem( dd, parent )

    setFlag( QQuickItem::ItemHasContents, true );

    if ( dd.updateFlags & QskQuickItem::DeferredUpdate )
        qskFilterWindow( window() );

    qskRegistry->insert( this );


QskQuickItem::~QskQuickItem()

    /*
        We set componentComplete to false, so that operations
        that are triggered by detaching the item from its parent
        can be aware of the about-to-delete state.
     */
    d_func()->componentComplete = false;

    if ( qskRegistry )
        qskRegistry->remove( this );


const char* QskQuickItem::className() const

    return metaObject()->className();


void QskQuickItem::classBegin()

    Inherited::classBegin();

3   QWidgetInQml  QML里面集成widget


bool QMLInteract::initUI()

    m_engin.rootContext()->setContextProperty("QMLInteractObj", this);
    m_engin.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
    if (m_engin.rootObjects().isEmpty())
    
        return false;
    

    QObject* obj = m_engin.rootObjects().at(0);
    basewindowobj.setWndBaseInfo(obj);
    basewindowobj.setWndSplitType();

    m_engin.load(QUrl(QStringLiteral("qrc:/qml/CalibTwoPage.qml")));

    QObject* obj1 = m_engin.rootObjects().at(1);

    return true;






void BaseWindowContainer::setWndBaseInfo(QObject* obj)

    QWindow * mainWindow = qobject_cast<QWindow*>(obj);

    if (obj)
    
        WId proc2Window_HWND = mainWindow->winId();

        m_widget->setProperty("_q_embedded_native_parent_handle", QVariant(proc2Window_HWND));
        m_widget->setWindowFlags(Qt::Widget|Qt::FramelessWindowHint);
        m_widget->winId();
        m_widget->setStyleSheet("background-color: rgb(46,138,201)");
        m_widget->windowHandle()->setParent(mainWindow);

        m_delegateObj = obj;
    

4 QML_OSR_EXP  将Qt Widgets嵌入到QML界面中的一种示范


bool WidgetOSRItem::sendEventToOSRWidget(QEvent *e)

    QWindow* wHandle = mOSRWidget->windowHandle();
    bool res = false;
    if(wHandle)
    
        res = qApp->sendEvent(wHandle, e);
    

    return res;


#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))

bool WidgetOSRItem::eventFilter(QObject *obj, QEvent *e)

    QWindow* pw = (QWindow*)(window());
    bool res = QQuickPaintedItem::eventFilter(obj, e);
    if(obj == mOSRWidget)
    
        switch(e->type())
        
        case QEvent::Paint: //当OsrWidget paint的时候也触发自己paint
        
            QPaintEvent* pe = (QPaintEvent*)e;
            this->update(pe->rect());
        
            break;
        
    
    else if(obj == pw)
    

        //* 如果是鼠标等(有鼠标坐标信息的事件。)的话我们得计算一下偏移量并修正一下,这里就只处理QMouseEvent和QWheelEvent作为示例
        //* 如果有其他类似的也需要修正,不然可能坐标偏移
        switch(e->type())
        
        case QEvent::MouseButtonDblClick  :
        case QEvent::MouseButtonPress	  :
        case QEvent::MouseButtonRelease	  :
        case QEvent::MouseMove	          :
        case QEvent::MouseTrackingChange  :
        case QEvent::Move	              :
        
            QMouseEvent *me = (QMouseEvent*)e;
            QEvent::Type type = me->type();
            QPointF localPosF(QPointF(0,0));
//          QPointF localPosF = me->position();
            Qt::MouseButton mouseButton = me->button();
            Qt::MouseButtons mouseButtons = me->buttons();
            Qt::KeyboardModifiers modifiers = me->modifiers();

            //修正一下localpos
            QPointF offsetF = mapToScene(QPoint(0,0));
            QPointF diffPosF = localPosF - offsetF;

            QMouseEvent tme(type, diffPosF, mouseButton, mouseButtons, modifiers);
            sendEventToOSRWidget(&tme);
        
            break;
        case QEvent::Wheel:
        
            QWheelEvent *we = (QWheelEvent*)e;
            QPointF localPosF = we->position();
            QPointF gloabalPosF = we->globalPosition();
            QPoint  pixelDelta = we->pixelDelta();
            QPoint  angleDelta = we->angleDelta();

            Qt::MouseButtons mouseButtons = we->buttons();
            Qt::KeyboardModifiers modifiers = we->modifiers();

            //修正一下localpos
            QPointF offsetF = mapToScene(QPoint(0,0));
            QPointF diffPosF = localPosF - offsetF;

            QWheelEvent twe(diffPosF, gloabalPosF, pixelDelta, angleDelta,
                               mouseButtons, modifiers, Qt::ScrollBegin, false);

            sendEventToOSRWidget(&twe);
        

            break;
        default:
        
            sendEventToOSRWidget(e);
        
            break;
        
    

    return res;



void WidgetOSRItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)

    QQuickPaintedItem::geometryChange(newGeometry, oldGeometry);

    if(mOSRWidget)
    
        mOSRWidget->setGeometry(newGeometry.toRect());
    


#else


bool WidgetOSRItem::eventFilter(QObject *obj, QEvent *e)

    QWindow* pw = (QWindow*)(window());
    bool res = QQuickPaintedItem::eventFilter(obj, e);
    if(obj == mOSRWidget)
    
        switch(e->type())
        
        case QEvent::Paint: //当OsrWidget paint的时候也触发自己paint
        
            QPaintEvent* pe = (QPaintEvent*)e;
            this->update(pe->rect());
        
            break;
        
    
    else if(obj == pw)
    

        //* 如果是鼠标等(有鼠标坐标信息的事件。)的话我们得计算一下偏移量并修正一下,这里就只处理QMouseEvent和QWheelEvent作为示例
        //* 如果有其他类似的也需要修正,不然可能坐标偏移
        switch(e->type())
        
        case QEvent::MouseButtonDblClick  :
        case QEvent::MouseButtonPress	  :
        case QEvent::MouseButtonRelease	  :
        case QEvent::MouseMove	          :
        case QEvent::MouseTrackingChange  :
        case QEvent::Move	              :
        
            QMouseEvent *me = (QMouseEvent*)e;
            QEvent::Type type = me->type();
            QPointF localPosF = me->localPos();
            Qt::MouseButton mouseButton = me->button();
            Qt::MouseButtons mouseButtons = me->buttons();
            Qt::KeyboardModifiers modifiers = me->modifiers();

            //修正一下localpos
            QPointF offsetF = mapToScene(QPoint(0,0));
            QPointF diffPosF = localPosF - offsetF;

            QMouseEvent tme(type, diffPosF, mouseButton, mouseButtons, modifiers);
            sendEventToOSRWidget(&tme);
        
            break;
        case QEvent::Wheel:
        
            QWheelEvent *we = (QWheelEvent*)e;
            QPointF localPosF = we->posF();
            QPointF gloabalPosF = we->globalPosF();
            QPoint  pixelDelta = we->pixelDelta();
            QPoint  angleDelta = we->angleDelta();
            int qt4Delta = we->delta();
            Qt::Orientation orientation = we->orientation();
            Qt::MouseButtons mouseButtons = we->buttons();
            Qt::KeyboardModifiers modifiers = we->modifiers();

            //修正一下localpos
            QPointF offsetF = mapToScene(QPoint(0,0));
            QPointF diffPosF = localPosF - offsetF;

            QWheelEvent twe(diffPosF, gloabalPosF, pixelDelta, angleDelta, qt4Delta, orientation, mouseButtons, modifiers);
            sendEventToOSRWidget(&twe);
        
            break;
        default:
        
            sendEventToOSRWidget(e);
        
            break;
        
    

    return res;



void WidgetOSRItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)

    QQuickPaintedItem::geometryChanged(newGeometry, oldGeometry);

    if(mOSRWidget)
    
        mOSRWidget->setGeometry(newGeometry.toRect());
    


#endif

5  参考链接

uwerat/qskinny: A lightweight framework on top of the Qt scene graph and only few classes from Qt/Quick. It is usable from C++ and/or QML. (github.com)

Skycoder42/QtMvvm: A mvvm oriented library for Qt, to create Projects for Widgets and Quick in parallel (github.com)

(177条消息) qwidget嵌入qml最完整代码_qml嵌入widget,qml嵌入qwidget-C++文档类资源-CSDN文库

(177条消息) 如何获取指定objectName的QObject_qyvlik的博客-CSDN博客

pengguanjun/UseQtWidgetInQML: 在qt widget中使用qml很容易,那怎么在qml中使用qt widget控件呢 (github.com)

(175条消息) QWidget嵌入QML窗口中_Eosin_Sky的博客-CSDN博客_qwidget放到qml

(175条消息) 将Qt Widgets嵌入到QML界面中的一种示范_Eosin_Sky的博客-CSDN博客_widgetosritem

(176条消息) 在Qt中将QWindow或者QWidget嵌入到别的进程中的窗口中(windows)_Eosin_Sky的博客-CSDN博客_qwindow

以上是关于C++生成QML代码与QML里面集成QWidget的主要内容,如果未能解决你的问题,请参考以下文章

刚学QT,想问下学了QML是否就不需要用QWidget那种方式写程序了,两者之间的区别和优劣,复制的就不要回了

将 Qt Widgets 和 QML 与 QWidget::createWindowContainer() 结合起来

QML QWidget 容器

qml systemtrayicon 没有 qwidget/qapplication?

QWidget 中的 QML 小部件

Qt Quick - 如何仅通过 c++ 代码与 qml 属性交互