目录
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 参考链接
(177条消息) qwidget嵌入qml最完整代码_qml嵌入widget,qml嵌入qwidget-C++文档类资源-
(177条消息) 如何获取指定objectName的QObject_qyvlik的博客
pengguanjun/UseQtWidgetInQML: 在qt widget中使用qml很容易,那怎么在qml中使用qt widget控件呢 (github.com)
(175条消息) QWidget嵌入QML窗口中_Eosin_Sky的博客-
(175条消息) 将Qt Widgets嵌入到QML界面中的一种示范_Eosin_Sky的博客
(176条消息) 在Qt中将QWindow或者QWidget嵌入到别的进程中的窗口中(windows)_Eosin_Sky的博客