注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

沙漠里de烟雨

原创分享,禁止转载

 
 
 

日志

 
 

如何将QWidget等QtGui写成qml来调用 之 二  

2017-09-08 02:44:33|  分类: QT5.x与QML |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
前面已经简单讨论了将qtgui做成qml来调用的方法,现在我们以另一种方式来实现,虽比第一种复杂些,但形式更接近qml的编写形式.下面就以从曾经的一个项目中提取出的工程代码来细观这种更优雅的实现方式,不多说了,贴代码先:

如何将QWidget等QtGui写成qml来调用 之 二 - 漠雨 - 沙漠里de烟雨
 新建的调用工程为QtGui2Qml,里面的文件(夹)如上图所示, 其中Gui2Qml则为自己写的库.本文主要要讲的也是这里面的内容.
先来看一下效果图: 
如何将QWidget等QtGui写成qml来调用 之 二 - 漠雨 - 沙漠里de烟雨
 

QtGui2Qml.pro ==>如下:

QT += core gui widgets qml

TARGET = QtGui2Qml
TEMPLATE = app

DESTDIR = $$PWD/bin64
include($$PWD/Gui2Qml/QtGui2Qml.pri)

SOURCES += main.cpp

/////////////////////////////////////

main.cpp ==>如下:

#include <QApplication>

#include <QQmlApplicationEngine>
#include <QtQml>

#include "registerqmltypes.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    RegisterQmlTypes::registered();

    QDir dir(QApplication::applicationDirPath());
    QQmlApplicationEngine engine;
    engine.load(QUrl::fromLocalFile(dir.absoluteFilePath("qmls/main.qml")));

    return a.exec();
}

////////////////////////////////////

bin64文件夹下有一文件夹qmls, 里面的文件为main.qml ==> 如下:
import GUI 2.0
import "."

Window
{
    id: root

    width: 800
    height: 600
    visible: true

    MouseArea
    {
        id: ma;

        hoverEnable: true
        pressEnable: true

        onEnteredChanged: console.log("enter");
        onLeavedChanged: console.log("leave");
        onMovedChanged: console.log("move");
        onPressedChanged: console.log("pressed");
        onReleasedChanged: console.log("released");
    }

    Widget
    {
        x:0; y:0
        width: root.width
        height: 50
        visible: true
    }

    Splitter
    {
        id: mainSp

        x: 0; y: 60
        width: root.width/2
        height: root.height-60
        handleWidth: 1
        handleColor: "gray"
        visible: true
        layout: Qt.Vertical

        Splitter
        {
            id: topSplitter

            width: mainSp.width
            height: mainSp.height/2
            opaqueResize: false;
            handleWidth: 1
            handleColor: "gray"
            visible: true
            layout: Qt.Horizontal

            Splitter
            {
                id: leftSplitter

                width: topSplitter.width/2
                height: topSplitter.height
                opaqueResize: true;
                handleWidth: 1
                handleColor: "gray"
                visible: true
                layout: Qt.Vertical

                Widget
                {
                    width: leftSplitter.width
                    height: leftSplitter.height/2
                    visible: true
                }

                Widget
                {
                    width: leftSplitter.width
                    height: leftSplitter.height/2
                    visible: true
                }
            }

            Widget
            {
                width: topSplitter.width/2
                height: topSplitter.height
                visible: true
            }
        }

        Widget
        {
            width: mainSp.width
            height: mainSp.height/2
            visible: true
        }
    }


    DockWindow
    {
        id: dockWindowId

        x: root.width/2; y: 60
        width: root.width/2
        height: root.height - 60
        visible: true
        dockOptions:DockWindow.AllowTabbedDocks|DockWindow.AllowNestedDocks|DockWindow.AnimatedDocks
        windowFlags:Qt.Widget
        centerWidget: CenterWidget{
            id: centerId
        }

        DockWidget
        {
            id: dock1
            windowTitle: "dock1"
            dockWidgetArea: Qt.LeftDockWidgetArea
            allowedAreas: Qt.AllDockWidgetAreas
        }

        DockWidget
        {
            id: dock2
            windowTitle: "dock2"
            dockWidgetArea: Qt.RightDockWidgetArea
            allowedAreas: Qt.AllDockWidgetAreas
        }

        DockWidget
        {
            id: dock3;
            windowTitle: "dock3"
            dockWidgetArea: Qt.BottomDockWidgetArea
            allowedAreas: Qt.AllDockWidgetAreas
        }
    }
}

////////////////////////////////////
//////////////////////////////////

下面就来看看 Gui2Qml文件夹下的代码:

如何将QWidget等QtGui写成qml来调用 之 二 - 漠雨 - 沙漠里de烟雨
 
QtGui2Qml.pri ==> 如下: 

INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD

CONFIG += c++11 console

SOURCES += $$PWD/qmlobject.cpp \
    $$PWD/qmlwidget.cpp \
    $$PWD/qmlwindow.cpp \
    $$PWD/widget.cpp \
    $$PWD/qmlmousearea.cpp \
    $$PWD/qmlsplitter.cpp \
    $$PWD/dockwindow.cpp \
    $$PWD/qmldockwindow.cpp \
    $$PWD/qmldockwidget.cpp \
    $$PWD/dockwidget.cpp \
    $$PWD/centerwidget.cpp


HEADERS += $$PWD/registerqmltypes.h \
    $$PWD/qmlobject.h \
    $$PWD/qmlwidget.h \
    $$PWD/qmlwindow.h \
    $$PWD/widget.h \
    $$PWD/qmlmousearea.h \
    $$PWD/qmlsplitter.h \
    $$PWD/dockwindow.h \
    $$PWD/qmldockwindow.h \
    $$PWD/qmldockwidget.h \
    $$PWD/dockwidget.h \
    $$PWD/centerwidget.h

//////////////////////////////////////////////

registerqmltypes.h ==> 如下: 
#include "qmlobject.h"
#include "qmlmousearea.h"
#include "qmlwidget.h"
#include "qmlwindow.h"
#include "qmlsplitter.h"
#include "qmldockwindow.h"
#include "qmldockwidget.h"
#include "centerwidget.h"

#ifndef REGISTERQMLTYPES_H
#define REGISTERQMLTYPES_H

class RegisterQmlTypes
{
public:
    static void registered()
    {
        qmlRegisterType<QmlWidget>("GUI", 2, 0, "Widget");
        qmlRegisterType<QmlWindow>("GUI", 2, 0, "Window");
        qmlRegisterType<QmlMouseArea>("GUI",2,0,"MouseArea");
        qmlRegisterType<QmlSplitter>("GUI",2,0,"Splitter");
        qmlRegisterType<QmlDockWindow>("GUI",2,0,"DockWindow");
        qmlRegisterType<QmlDockWidget>("GUI",2,0,"DockWidget");
        qmlRegisterType<CenterWidget>("GUI",2,0,"CenterWidget");
    }
};

#endif // REGISTERQMLTYPES_H

////////////////////////////////////////////////
关键类: QmlObject (qmlobject.h, qmlobject.cpp)

qmlobject.h ==> 如下: 

#ifndef QMLOBJECT_H
#define QMLOBJECT_H

#include <QObject>
#include <QQmlListProperty>

class QmlObject : public QObject
{
    Q_OBJECT
    Q_CLASSINFO("DefaultProperty", "childrenList")
    Q_PROPERTY(QQmlListProperty<QObject> childrenList READ childrenList)
public:
    explicit QmlObject(QObject *parent = 0);

signals:
    void componentBegined();
    void componentCompleted();
    void parentSetCompleted(QmlObject* parent);

public:
    QObject* object();
    void setObject(QObject* object);

protected:
    virtual void componentBegin(){emit componentBegined();}
    virtual void componentComplete(){emit componentBegined();}
    virtual void parentSetComplete(QmlObject* parent){emit parentSetCompleted(parent);}

private:
    QQmlListProperty<QObject> childrenList();
    static void appendData(QQmlListProperty<QObject> *list, QObject *obj);
    static int dataCount(QQmlListProperty<QObject> *list);
    static QObject *dataAt(QQmlListProperty<QObject> *list, int index);
    static void clearData(QQmlListProperty<QObject> *list);

private:
    QObject*    m_object;
};

#endif // QMLOBJECT_H

/////----------------

qmlobject.cpp  ==> 如下:

#include "qmlobject.h"
#include <QWidget>

QmlObject::QmlObject(QObject *parent) : QObject(parent)
{
    m_object = Q_NULLPTR;
}

QObject *QmlObject::object()
{
    return m_object;
}

void QmlObject::setObject(QObject *object)
{
    m_object = object;
}

QQmlListProperty<QObject> QmlObject::childrenList()
{
    return QQmlListProperty<QObject>(this, 0,
                                     QmlObject::appendData,
                                     QmlObject::dataCount,
                                     QmlObject::dataAt,
                                     QmlObject::clearData);
}

void QmlObject::appendData(QQmlListProperty<QObject> *list, QObject *obj)
{

    if(!list || !obj || !qobject_cast<QmlObject*>(obj))
        return ;

    QmlObject* child = qobject_cast<QmlObject*>(obj);
    QmlObject* parent = qobject_cast<QmlObject*>(list->object);


    ///设置父子关系:
    child->setParent(parent);//parent也可以为NULL;

    ///下面设置child(QmlObject类型)下挂着的m_object与
    /// parent(QmlObject)下挂着的m_object之间的父子关系:

    //!1) parent为空时,表明此child对象为程序最外层的对象;
    if(!parent)
    {
        //此时如果child下的m_object为窗体类型,则应设置其为window类型窗体,即主窗体;
        QObject* window = child->object();
        if(window)
            window->setParent(0);
        child->parentSetComplete(0);
        return ;
    }

    //!2) parent不为空时:
    QObject* childObj = child->object();
    QObject* parentObj = parent->object();

    if(childObj && childObj->isWidgetType() &&
       parentObj && parentObj->isWidgetType())
    {
        QWidget* childWdt = qobject_cast<QWidget*>(childObj);
        QWidget* parentWdt = qobject_cast<QWidget*>(parentObj);
        childWdt->setParent(parentWdt);
        childWdt->show();
    }
    else
    {
        if(childObj)
        {
            childObj->setParent(parentObj);
            if(childObj->isWidgetType())
                qobject_cast<QWidget*>(childObj)->hide();
        }
    }

    child->parentSetComplete(parent);
}

int QmlObject::dataCount(QQmlListProperty<QObject> *list)
{
    if(!list)
        return 0;

    QmlObject *self = static_cast<QmlObject*>(list->object);
    if(!self)
        return 0;

    const QObjectList &childlist = self->children();
    return childlist.size();
}

QObject *QmlObject::dataAt(QQmlListProperty<QObject> *list, int index)
{
    if(!list)
        return 0;

    if(index<0)
        return 0;

    QmlObject *self = static_cast<QmlObject*>(list->object);
    if(!self)
        return 0;

    const QObjectList &childlist = self->children();
    return childlist.at(index);
}

void QmlObject::clearData(QQmlListProperty<QObject> *list)
{
    if(!list)
        return ;

    QmlObject * self = qobject_cast<QmlObject*>(list->object);
    if(!self)
        return ;

    for(QObject* const child : self->children())
        child->setParent(0);
}

////////////////////////////////////

qmlmousearea.h =>如下: 

#ifndef QMLMOUSEAREA_H
#define QMLMOUSEAREA_H

#include "qmlobject.h"

class QEvent;
class QMouseEvent;
class QmlMouseArea : public QmlObject
{
    Q_OBJECT
    Q_PROPERTY(bool hoverEnable READ hoverEnable WRITE setHoverEnable)
    Q_PROPERTY(bool pressEnable READ pressEnable WRITE setPressEnable)
    Q_PROPERTY(bool hovered READ hovered)
    Q_PROPERTY(bool pressed READ pressed)
    Q_PROPERTY(bool released READ released)
    Q_PROPERTY(bool moved READ moved)
    Q_PROPERTY(bool entered READ entered)
    Q_PROPERTY(bool leaved READ leaved)
public:
    explicit QmlMouseArea(QObject *parent = 0);

protected:
    void parentSetComplete(QmlObject* parent);

signals:
    void hoveredChanged(bool hovered,int mouseX,int mouseY);
    void pressedChanged(bool pressed,int mouseX,int mouseY);
    void releasedChanged(bool released,int mouseX,int mouseY);
    void movedChanged(bool moved,int mouseX,int mouseY);
    void enteredChanged(bool entered,int mouseX,int mouseY);
    void leavedChanged(bool leaved,int mouseX,int mouseY);
    void hoverEnableChanged(bool enable);

public slots:
    void enterEvent(QEvent* event);
    void leaveEvent(QEvent* event);
    void mouseMoveEvent(QMouseEvent* event);
    void mousePressEvent(QMouseEvent* event);
    void mouseReleaseEvent(QMouseEvent* event);

public:
    bool    hoverEnable() const;
    void    setHoverEnable(bool enable);
    bool    pressEnable()const;
    void    setPressEnable(bool enable);
    bool    hovered()const;
    bool    pressed()const;
    bool    released()const;
    bool    moved()const;
    bool    entered()const;
    bool    leaved()const;

private:
    bool    m_hoverEnable;
    bool    m_pressEnable;
    bool    m_hovered;
    bool    m_pressed;
    bool    m_released;
    bool    m_moved;
    bool    m_entered;
    bool    m_leaved;
};

#endif // QMLMOUSEAREA_H

/////--------------------

qmlmousearea.cpp ==>如下:

#include "qmlmousearea.h"
#include <QMouseEvent>
#include <QDebug>

QmlMouseArea::QmlMouseArea(QObject *parent) : QmlObject(parent)
{
    m_hoverEnable = false;
    m_pressEnable = false;
    m_hovered = false;
    m_pressed = false;
    m_released = false;
    m_moved = false;
    m_entered = false;
    m_leaved = false;

    this->setObject(new QObject);
}

void QmlMouseArea::parentSetComplete(QmlObject *parent)
{
    if(parent)
    {
        if(parent->object() && parent->object()->isWidgetType())
        {
            connect(parent,SIGNAL(enter(QEvent*)),this,SLOT(enterEvent(QEvent*)));
            connect(parent,SIGNAL(leave(QEvent*)),this,SLOT(leaveEvent(QEvent*)));
            connect(parent,SIGNAL(mouseMove(QMouseEvent*)),this,SLOT(mouseMoveEvent(QMouseEvent*)));
            connect(parent,SIGNAL(mousePress(QMouseEvent*)),this,SLOT(mousePressEvent(QMouseEvent*)));
            connect(parent,SIGNAL(mouseRelease(QMouseEvent*)),this,SLOT(mouseReleaseEvent(QMouseEvent*)));
            connect(this,SIGNAL(hoverEnableChanged(bool)),parent,SIGNAL(hoverEnableChanged(bool)));
            emit hoverEnableChanged(m_hoverEnable);
        }
    }
}

void QmlMouseArea::enterEvent(QEvent *event)
{
    if(m_hoverEnable)
    {
        m_hovered = true;
        QMouseEvent* me = (QMouseEvent*)event;
        emit enteredChanged(m_hovered,me->x(),me->y());
    }
}

void QmlMouseArea::leaveEvent(QEvent *event)
{
    m_hovered = false;
    m_moved = false;
    if(m_hoverEnable)
    {
        QMouseEvent* me = (QMouseEvent*)event;
        emit enteredChanged(m_hovered,me->x(),me->y());
    }
}

void QmlMouseArea::mouseMoveEvent(QMouseEvent *event)
{
    m_moved = true;
    if(m_hoverEnable)
    {
        emit movedChanged(m_moved,event->x(),event->y());
    }
}

void QmlMouseArea::mousePressEvent(QMouseEvent *event)
{
    if(m_pressEnable)
    {
        m_pressed = true;
        emit pressedChanged(m_pressed,event->x(),event->y());
    }
}

void QmlMouseArea::mouseReleaseEvent(QMouseEvent *event)
{
    m_pressed = false;
    if(m_pressEnable)
    {
        emit pressedChanged(m_pressed,event->x(),event->y());
    }
}

bool QmlMouseArea::hoverEnable() const
{
    return m_hoverEnable;
}

void QmlMouseArea::setHoverEnable(bool enable)
{
    m_hoverEnable = enable;
    emit hoverEnableChanged(enable);
}

bool QmlMouseArea::pressEnable() const
{
    return m_pressEnable;
}

void QmlMouseArea::setPressEnable(bool enable)
{
    m_pressEnable = enable;
}

bool QmlMouseArea::hovered() const
{
    return m_hovered;
}

bool QmlMouseArea::pressed() const
{
    return m_pressed;
}

bool QmlMouseArea::released() const
{
    return m_released;
}

bool QmlMouseArea::moved() const
{
    return m_moved;
}

bool QmlMouseArea::entered() const
{
    return m_entered;
}

bool QmlMouseArea::leaved() const
{
    return m_leaved;
}

////////////////////////////////////////////
qmlwidget.h ==> 如下:

#ifndef QMLWIDGET_H
#define QMLWIDGET_H

#include "qmlobject.h"
#include "widget.h"

class QEvent;
class QMouseEvent;
class QmlWidget : public QmlObject
{
    Q_OBJECT
    Q_PROPERTY(Widget* widget READ widget)
    Q_PROPERTY(int x READ x WRITE setX NOTIFY xChanged)
    Q_PROPERTY(int y READ y WRITE setY NOTIFY yChanged)
    Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
    Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)
    Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
    Q_PROPERTY(Qt::WindowFlags windowFlags READ windowFlags WRITE setWindowFlags NOTIFY windowFlagsChanged)
public:
    explicit QmlWidget(QObject *parent = 0);
    explicit QmlWidget(Widget* widget,QObject *parent = 0);

private:
    void initConnections();

protected:
    virtual void parentSetComplete(QmlObject* parent);

///for MouseArea;
signals:
    void enter(QEvent *event);
    void leave(QEvent* event);
    void mouseMove(QMouseEvent* event);
    void mousePress(QMouseEvent* event);
    void mouseRelease(QMouseEvent *event);
    void hoverEnableChanged(bool enable);
///-
signals://as a parent to send;
    void xChanged(int x);
    void yChanged(int y);
    void widthChanged(int width);
    void heightChanged(int height);
    void visibleChanged(bool visible);
    void windowFlagsChanged(Qt::WindowFlags windowFlags);

public:
    Widget *widget();

    int x() const;
    void setX(int x);
    int y() const;
    void setY(int y);

    int width();
    void setWidth(int width);
    int height();
    void setHeight(int height);

    bool visible() const;
    virtual void setVisible(bool visible);

    Qt::WindowFlags windowFlags() const;
    void setWindowFlags(Qt::WindowFlags windowFlags);

protected: //setparent之后,(x,y),visible,windowFlags均会改变,且会clearFocus;
    int             m_x;
    int             m_y;
    bool            m_visible;
    bool            m_bParentSet;
    Qt::WindowFlags m_windowFlags;

};

#endif // QMLWIDGET_H

////---------------------------

qmlwidget.cpp ==>如下:

#include "qmlwidget.h"

QmlWidget::QmlWidget(QObject *parent) : QmlObject(parent)
{
    m_x = m_y = 0;
    m_visible = false;
    m_bParentSet = false;

    Widget* widget = new Widget;
    widget->setVisible(false);
    this->setObject(widget);
    if(widget)
        m_windowFlags = widget->windowFlags();

    initConnections();
}

QmlWidget::QmlWidget(Widget *widget, QObject *parent) : QmlObject(parent)
{
    m_x = m_y = 0;
    m_visible = false;
    m_bParentSet = false;

    widget->setVisible(false);
    this->setObject(widget); //widget现在还不能设置parent;
    if(widget)
        m_windowFlags = widget->windowFlags();

    initConnections();
}

void QmlWidget::initConnections()
{
    ///for MouseArea;
    if(widget())
    {
        QObject* wdt = object();
        connect(wdt,SIGNAL(enter(QEvent*)),this,SIGNAL(enter(QEvent*)));
        connect(wdt,SIGNAL(leave(QEvent*)),this,SIGNAL(leave(QEvent*)));
        connect(wdt,SIGNAL(mouseMove(QMouseEvent*)),this,SIGNAL(mouseMove(QMouseEvent*)));
        connect(wdt,SIGNAL(mousePress(QMouseEvent*)),this,SIGNAL(mousePress(QMouseEvent*)));
        connect(wdt,SIGNAL(mouseRelease(QMouseEvent*)),this,SIGNAL(mouseRelease(QMouseEvent*)));
        connect(this,SIGNAL(hoverEnableChanged(bool)),wdt,SLOT(hoverEnableChanged(bool)));
    }
}

void QmlWidget::parentSetComplete(QmlObject *parent)
{
    if(widget()
        && parent
        && parent->object()
        && parent->object()->isWidgetType())
    {
        m_bParentSet = true;
        widget()->move(m_x,m_y);
        widget()->setVisible(m_visible);
//        widget()->setWindowFlags(m_windowFlags);
    }
}

Widget *QmlWidget::widget()
{
    if(object() && object()->isWidgetType())
        return qobject_cast<Widget*>(object());
    return Q_NULLPTR;
}

int QmlWidget::x() const
{
    return m_x;
}

void QmlWidget::setX(int x)
{
    Q_ASSERT(widget());
    m_x = x;
    widget()->move(x,y());
    if(m_bParentSet)
        emit xChanged(x);
}

int QmlWidget::y() const
{
    return m_y;
}

void QmlWidget::setY(int y)
{
    Q_ASSERT(widget());
    m_y = y;
    widget()->move(x(),y);
    if(m_bParentSet)
        emit yChanged(y);
}

int QmlWidget::width()
{
    Q_ASSERT(widget());
    return widget()->width();
}

void QmlWidget::setWidth(int width)
{
    Q_ASSERT(widget());
    widget()->resize(width,height());
    emit widthChanged(width);
}

int QmlWidget::height()
{
    Q_ASSERT(widget());
    return widget()->height();
}

void QmlWidget::setHeight(int height)
{
    Q_ASSERT(widget());
    widget()->resize(width(),height);
    emit heightChanged(height);
}

bool QmlWidget::visible() const
{
    return m_visible;
}

void QmlWidget::setVisible(bool visible)
{
    Q_ASSERT(widget());
    m_visible = visible;
    QmlObject* parentObj = qobject_cast<QmlObject*>(parent()); //parentSetComplete()之前为空,之后方有值;
    if(parentObj && parentObj->object()->isWidgetType())
    {
        widget()->setVisible(visible);
        emit visibleChanged(visible);
    }
}

Qt::WindowFlags QmlWidget::windowFlags() const
{
    return m_windowFlags;
}

void QmlWidget::setWindowFlags(Qt::WindowFlags windowFlags)
{
    Q_ASSERT(widget());
    m_windowFlags = windowFlags;
    widget()->setWindowFlags(windowFlags);
    emit windowFlagsChanged(windowFlags);
}

//////////////////////////////////

widget.h ==>如下: 

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class QEvent;
class QMouseEvent;
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget();

signals:
    void enter(QEvent *event);
    void leave(QEvent* event);
    void mouseMove(QMouseEvent* event);
    void mousePress(QMouseEvent* event);
    void mouseRelease(QMouseEvent *event);

protected:
    void paintEvent(QPaintEvent* event);
    void enterEvent(QEvent *event);
    void leaveEvent(QEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

public slots:
    void hoverEnableChanged(bool enable);
};

#endif // WIDGET_H

////----------------------

widget.cpp ==> 如下: 

#include "widget.h"

#include <QPaintEvent>
#include <QPainter>
#include <QDebug>

Widget::Widget() : QWidget(0)
{
    this->setVisible(false);
//    this->setMinimumWidth(120);
    this->setMinimumSize(120,20);
}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    ///for test...
    painter.setPen(QColor(Qt::blue));
    painter.setBrush(QBrush(Qt::lightGray));
    painter.drawRect(0,0,width()-1,height()-1);
    ///---tested...

    QWidget::paintEvent(event);
}

void Widget::enterEvent(QEvent *event)
{
    emit enter(event);
    QWidget::enterEvent(event);
}

void Widget::leaveEvent(QEvent *event)
{
    emit leave(event);
    QWidget::leaveEvent(event);
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    emit mouseMove(event);
    QWidget::mouseMoveEvent(event);
}

void Widget::mousePressEvent(QMouseEvent *event)
{
    emit mousePress(event);
    QWidget::mousePressEvent(event);
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    emit mouseRelease(event);
    QWidget::mouseReleaseEvent(event);
}

void Widget::hoverEnableChanged(bool enable)
{
    this->setMouseTracking(enable);
}

/////////////////////////////////////////

qmlwindow.h ==>如下:

#ifndef QMLWINDOW_H
#define QMLWINDOW_H

#include "qmlwidget.h"

class QmlWindow : public QmlWidget
{
    Q_OBJECT
public:
    explicit QmlWindow(QObject *parent = 0);

public: //overwrite;
    void setVisible(bool visible);

};

#endif // QMLWINDOW_H

////------------------

qmlwindow.cpp ==>如下: 

#include "qmlwindow.h"
#include "widget.h"

QmlWindow::QmlWindow(QObject *parent) : QmlWidget(parent)
{

}

void QmlWindow::setVisible(bool visible)
{
    Q_ASSERT(widget());
    m_visible = visible;

    if(widget() && parent()==Q_NULLPTR) //无父窗体,为主窗体window;
    {
        widget()->setVisible(visible);
        emit visibleChanged(visible);
    }
}


//////////////////////////////////////////////

qmlsplitter.h ==>如下: 

#ifndef QMLSPLITTER_H
#define QMLSPLITTER_H

#include "qmlobject.h"

class QSplitter;
class QmlSplitter : public QmlObject
{
    Q_OBJECT
    Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
    Q_PROPERTY(int x READ x WRITE setX  NOTIFY xChanged)
    Q_PROPERTY(int y READ y WRITE setY  NOTIFY yChanged)
    Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
    Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)
    Q_PROPERTY(bool opaqueResize READ opaqueResize WRITE setOpaqueResize)
    Q_PROPERTY(Qt::Orientation layout READ layout WRITE setLayout)
    Q_PROPERTY(int handleWidth READ handleWidth WRITE setHandleWidth)
    Q_PROPERTY(QString handleColor READ handleColor WRITE setHandleColor)
public:
    explicit QmlSplitter(QObject *parent = 0);

protected:
    QSplitter* splitter();
    virtual void parentSetComplete(QmlObject* parent);

signals://as a parent to send;
    void visibleChanged(bool visible);
    void xChanged(int x);
    void yChanged(int y);
    void widthChanged(int width);
    void heightChanged(int height);

public:
    bool visible() const;
    void setVisible(bool visible);


    int x() const;
    void setX(int x);
    int y() const;
    void setY(int y);

    int width();
    void setWidth(int width);
    int height();
    void setHeight(int height);

    bool opaqueResize();
    void setOpaqueResize(bool opaqueResize);

    Qt::Orientation layout();
    void setLayout(Qt::Orientation layout);

    int handleWidth();
    void setHandleWidth(int width);

    QString handleColor();
    void setHandleColor(const QString& color);

private:
    int             m_x;
    int             m_y;
    bool            m_visible;
    bool            m_bParentSet;
    QString         m_handleColor;
    QStringList     m_stretchFactor;
};

#endif // QMLSPLITTER_H

/////----------------------

qmlsplitter.cpp ==>如下: 

#include "qmlsplitter.h"
#include <QSplitter>

QmlSplitter::QmlSplitter(QObject *parent) : QmlObject(parent)
{
    m_x = m_y = 0;
    m_visible = false;
    m_bParentSet = false;
    m_handleColor = "gray";

    QSplitter * splitter = new QSplitter(Qt::Horizontal);
//    splitter->setVisible(false);
    splitter->hide();
    this->setObject(splitter);
}

QSplitter *QmlSplitter::splitter()
{
    if(object() && object()->isWidgetType())
        return qobject_cast<QSplitter*>(object());
    return Q_NULLPTR;
}

void QmlSplitter::parentSetComplete(QmlObject *parent)
{
    Q_ASSERT(splitter());
    if(splitter())
    {
        m_bParentSet = true;
        splitter()->move(m_x,m_y);
        splitter()->setVisible(m_visible);
    }
}

bool QmlSplitter::visible() const
{
    return m_visible;
}

void QmlSplitter::setVisible(bool visible)
{
    Q_ASSERT(splitter());
    m_visible = visible;
    QmlObject* p = qobject_cast<QmlObject*>(parent());
    if(p && p->object() && p->object()->isWidgetType())
    {
        splitter()->setVisible(visible);
        emit visibleChanged(visible);
    }
}

int QmlSplitter::x() const
{
    return m_x;
}

void QmlSplitter::setX(int x)
{
    Q_ASSERT(splitter());
    m_x = x;
    splitter()->move(x,y());
    if(m_bParentSet)
        emit xChanged(x);
}

int QmlSplitter::y() const
{
    return m_y;
}

void QmlSplitter::setY(int y)
{
    Q_ASSERT(splitter());
    m_y = y;
    splitter()->move(x(),y);
    if(m_bParentSet)
        emit yChanged(y);
}

int QmlSplitter::width()
{
    Q_ASSERT(splitter());
    return splitter()->width();
}

void QmlSplitter::setWidth(int width)
{
    Q_ASSERT(splitter());
    splitter()->resize(width,height());
    emit widthChanged(width);
}

int QmlSplitter::height()
{
    Q_ASSERT(splitter());
    return splitter()->height();
}

void QmlSplitter::setHeight(int height)
{
    Q_ASSERT(splitter());
    splitter()->resize(width(),height);
    emit heightChanged(height);
}

bool QmlSplitter::opaqueResize()
{
    Q_ASSERT(splitter());
    return splitter()->opaqueResize();
}

void QmlSplitter::setOpaqueResize(bool opaqueResize)
{
    Q_ASSERT(splitter());
    splitter()->setOpaqueResize(opaqueResize);
}

Qt::Orientation QmlSplitter::layout()
{
    Q_ASSERT(splitter());
    return splitter()->orientation();
}

void QmlSplitter::setLayout(Qt::Orientation layout)
{
    Q_ASSERT(splitter());
    splitter()->setOrientation(layout);
}

int QmlSplitter::handleWidth()
{
    Q_ASSERT(splitter());
    return splitter()->handleWidth();
}

void QmlSplitter::setHandleWidth(int width)
{
    Q_ASSERT(splitter());
    splitter()->setHandleWidth(width);
}

QString QmlSplitter::handleColor()
{
    Q_ASSERT(splitter());
    return m_handleColor;
}

void QmlSplitter::setHandleColor(const QString &color)
{
    Q_ASSERT(splitter());
    QString style = "QSplitter::handle{background-color:"+color+"}";
    splitter()->setStyleSheet(style);
}

///////////////////////////////////

qmldockwindow.h ==> 如下: 

#ifndef QMLDOCKWINDOW_H
#define QMLDOCKWINDOW_H

#include "qmlobject.h"

class QmlDockWidget;
class CenterWidget;
class DockWindow;
class QmlDockWindow : public QmlObject
{
    Q_OBJECT
    Q_PROPERTY(CenterWidget* centerWidget READ centerWidget WRITE setCenterWidget)
    Q_PROPERTY(int x READ x WRITE setX  NOTIFY xChanged)
    Q_PROPERTY(int y READ y WRITE setY  NOTIFY yChanged)
    Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
    Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)
    Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
    Q_PROPERTY(DockOption dockOptions READ dockOptions WRITE setDockOptions)
    Q_PROPERTY(Qt::WindowFlags windowFlags READ windowFlags WRITE setWindowFlags)
public:
    explicit QmlDockWindow(QObject *parent = nullptr);

public:
    DockWindow* dockWindow();

public:
    CenterWidget* centerWidget();
    void setCenterWidget(CenterWidget* centerWidget);

public:
    enum DockOption
    {
        AnimatedDocks = 0x01,
        AllowNestedDocks = 0x02,
        AllowTabbedDocks = 0x04,
        ForceTabbedDocks = 0x08,  // implies AllowTabbedDocks, !AllowNestedDocks
        VerticalTabs = 0x10,      // implies AllowTabbedDocks
        GroupedDragging = 0x20    // implies AllowTabbedDocks
    };
    Q_ENUM(DockOption)


protected:
    virtual void parentSetComplete(QmlObject* parent);

signals://as a parent to send;
    void xChanged(int x);
    void yChanged(int y);
    void widthChanged(int width);
    void heightChanged(int height);
    void visibleChanged(bool visible);

public:
    int x()const;
    void setX(int x);
    int y()const;
    void setY(int y);
    int width();
    void setWidth(int width);
    int height();
    void setHeight(int height);
    bool visible()const;
    void setVisible(bool visible);
    DockOption dockOptions() const;
    void setDockOptions(DockOption options);
    Qt::WindowFlags windowFlags() const;
    void setWindowFlags(Qt::WindowFlags windowFlags);
private:
    int     m_x;
    int     m_y;
    bool    m_visible;
    bool    m_bParentSet;
    DockOption m_dockOptions;
    Qt::WindowFlags m_windowFlags;
};

#endif // QMLDOCKWINDOW_H

///----------------------

qmldockwindow.cpp ==>如下: 

#include "qmldockwindow.h"
#include "dockwindow.h"
#include "centerwidget.h"
#include "qmldockwidget.h"
#include "dockwidget.h"
QmlDockWindow::QmlDockWindow(QObject *parent) : QmlObject(parent)
{
    m_x = m_y = 0;
    m_visible = false;
    m_bParentSet = false;

    this->setObject(new DockWindow);
}

DockWindow *QmlDockWindow::dockWindow()
{
    if(object() && object()->isWidgetType())
        return qobject_cast<DockWindow*>(object());
    return Q_NULLPTR;
}

CenterWidget *QmlDockWindow::centerWidget()
{
    Q_ASSERT(dockWindow());
    return dockWindow()->centerWidget();
}

void QmlDockWindow::setCenterWidget(CenterWidget *centerWidget)
{
    Q_ASSERT(dockWindow());
    dockWindow()->setCenterWidget(centerWidget);
    dockWindow()->setCentralWidget(centerWidget->widget());
}

void QmlDockWindow::parentSetComplete(QmlObject *parent)
{
    Q_ASSERT(dockWindow());
    m_bParentSet = true;
    dockWindow()->move(m_x,m_y);
    dockWindow()->setVisible(m_visible);

    ///?????/
//    dockWindow()->setWindowFlags(Qt::Widget);
//    dockWindow()->setDockOptions(QMainWindow::AllowNestedDocks | QMainWindow::AnimatedDocks);
    dockWindow()->setWindowFlags(m_windowFlags);
    dockWindow()->setDockOptions((QMainWindow::DockOptions)m_dockOptions);
}

int QmlDockWindow::x() const
{
    return m_x;
}

void QmlDockWindow::setX(int x)
{
    Q_ASSERT(dockWindow());
    m_x = x;
    dockWindow()->move(x,y());
    if(m_bParentSet)
        emit xChanged(x);
}

int QmlDockWindow::y() const
{
    return m_y;
}

void QmlDockWindow::setY(int y)
{
    Q_ASSERT(dockWindow());
    m_y = y;
    dockWindow()->move(x(),y);
    if(m_bParentSet)
        emit yChanged(y);
}

int QmlDockWindow::width()
{
    Q_ASSERT(dockWindow());
    return dockWindow()->width();
}

void QmlDockWindow::setWidth(int width)
{
    Q_ASSERT(dockWindow());
    dockWindow()->resize(width,height());
    emit widthChanged(width);
}

int QmlDockWindow::height()
{
    Q_ASSERT(dockWindow());
    return dockWindow()->height();
}

void QmlDockWindow::setHeight(int height)
{
    Q_ASSERT(dockWindow());
    dockWindow()->resize(width(),height);
    emit heightChanged(height);
}
bool QmlDockWindow::visible() const
{
    return m_visible;
}

void QmlDockWindow::setVisible(bool visible)
{
    Q_ASSERT(dockWindow());
    m_visible = visible;
    QmlObject* p = qobject_cast<QmlObject*>(parent());
    if(p && p->object()->isWidgetType())
    {
        dockWindow()->setVisible(visible);
        emit visibleChanged(visible);
    }
}

QmlDockWindow::DockOption QmlDockWindow::dockOptions() const
{
    return m_dockOptions;
}

void QmlDockWindow::setDockOptions(QmlDockWindow::DockOption options)
{
    Q_ASSERT(dockWindow());
    m_dockOptions = options;
    dockWindow()->setDockOptions((QMainWindow::DockOptions)options);
}

Qt::WindowFlags QmlDockWindow::windowFlags() const
{
    return m_windowFlags;
}

void QmlDockWindow::setWindowFlags(Qt::WindowFlags windowFlags)
{
    Q_ASSERT(dockWindow());
    m_windowFlags = windowFlags;
    dockWindow()->setWindowFlags(windowFlags);
}

/////////////////////////////////////
qmldockwidget.h ==>如下: 

#ifndef QMLDOCKWIDGET_H
#define QMLDOCKWIDGET_H

#include "qmlobject.h"

class DockWidget;
class QmlDockWidget : public QmlObject
{
    Q_OBJECT
    Q_PROPERTY(Qt::DockWidgetAreas allowedAreas READ allowedAreas WRITE setAllowedAreas)
    Q_PROPERTY(Qt::DockWidgetArea dockWidgetArea READ dockWidgetArea WRITE setDockWidgetArea)
    Q_PROPERTY(QString windowTitle READ windowTitle WRITE setWindowTitle)
public:
    explicit QmlDockWidget(QObject *parent = 0);

protected:
    virtual void parentSetComplete(QmlObject *parent);

public:
    DockWidget* dockWidget();

public:
    Qt::DockWidgetAreas allowedAreas();
    void setAllowedAreas(Qt::DockWidgetAreas area);
    Qt::DockWidgetArea dockWidgetArea();
    void setDockWidgetArea(Qt::DockWidgetArea area);
    QString windowTitle();
    void setWindowTitle(const QString& title);
};

#endif // QMLDOCKWIDGET_H

////-------------

qmldockwidget.cpp ==> 如下: 

#include "qmldockwidget.h"
#include <QMainWindow>
#include "dockwidget.h"
QmlDockWidget::QmlDockWidget(QObject *parent) : QmlObject(parent)
{
    this->setObject(new DockWidget);
}

void QmlDockWidget::parentSetComplete(QmlObject *parent)
{
    if(parent && parent->object() &&  parent->object()->isWidgetType())
    {
        dockWidget()->setAllowedAreas(allowedAreas());
        QMainWindow* p = qobject_cast<QMainWindow*>(parent->object());
        p->addDockWidget(dockWidgetArea(),dockWidget());
    }
}

DockWidget *QmlDockWidget::dockWidget()
{
    if(object())
        return qobject_cast<DockWidget*>(object());
    return 0;
}

Qt::DockWidgetAreas QmlDockWidget::allowedAreas()
{
    Q_ASSERT(dockWidget());
    return dockWidget()->allowedAreas();
}

void QmlDockWidget::setAllowedAreas(Qt::DockWidgetAreas area)
{
    Q_ASSERT(dockWidget());
    dockWidget()->setAllowedAreas(area);
}

Qt::DockWidgetArea QmlDockWidget::dockWidgetArea()
{
    Q_ASSERT(dockWidget());
    return dockWidget()->dockWidgetArea();
}

void QmlDockWidget::setDockWidgetArea(Qt::DockWidgetArea area)
{
    Q_ASSERT(dockWidget());
    dockWidget()->setDockWidgetArea(area);
}

QString QmlDockWidget::windowTitle()
{
    Q_ASSERT(dockWidget());
    return dockWidget()->windowTitle();
}

void QmlDockWidget::setWindowTitle(const QString &title)
{
    Q_ASSERT(dockWidget());
    dockWidget()->setWindowTitle(title);
}

////////////////////////////////

dockwindow.h ==> 如下: 

#ifndef DOCKWINDOW_H
#define DOCKWINDOW_H

#include <QMainWindow>

class CenterWidget;
class DockWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit DockWindow(QWidget *parent = nullptr);

public:
    CenterWidget* centerWidget();
    void setCenterWidget(CenterWidget* center);

private:
    CenterWidget*    m_centerWidget;
};

#endif // DOCKWINDOW_H

////-------------------------------

dockwindow.cpp ==> 如下: 

#include "dockwindow.h"
#include "centerwidget.h"
DockWindow::DockWindow(QWidget *parent) : QMainWindow(parent)
{
    m_centerWidget = 0;
    this->setWindowFlags(Qt::Widget);
    this->setDockOptions(QMainWindow::AllowNestedDocks | QMainWindow::AnimatedDocks);
}

CenterWidget *DockWindow::centerWidget()
{
    return m_centerWidget;
}

void DockWindow::setCenterWidget(CenterWidget *center)
{
    m_centerWidget = center;
}


//////////////////////////////////

dockwidget.h ==>如下:

#ifndef DOCKWIDGET_H
#define DOCKWIDGET_H

#include <QDockWidget>

class DockWidget : public QDockWidget
{
    Q_OBJECT
    Q_PROPERTY(Qt::DockWidgetArea dockWidgetArea READ dockWidgetArea WRITE setDockWidgetArea)
public:
    explicit DockWidget(QWidget *parent = 0);

protected:
    void resizeEvent(QResizeEvent* event);
    void paintEvent(QPaintEvent *event);

public:
    Qt::DockWidgetArea dockWidgetArea() const;
    void setDockWidgetArea(Qt::DockWidgetArea dockArea);

private:
    Qt::DockWidgetArea  m_dockArea;
};

#endif // DOCKVIEW_H

//////--------------

dockwidget.cpp ==> 如下:

#include "dockwidget.h"
#include <QPainter>

DockWidget::DockWidget(QWidget *parent) : QDockWidget(parent)
{

}

void DockWidget::resizeEvent(QResizeEvent *event)
{
    update();
    QDockWidget::resizeEvent(event);
}

void DockWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    painter.save();

    ///for test...
    painter.setPen(QColor(Qt::blue));
    painter.setBrush(QBrush(Qt::red));
    painter.drawRect(0,0,width()-1,height()-1);
    ///---tested...

    painter.restore();

    QDockWidget::paintEvent(event);
}

Qt::DockWidgetArea DockWidget::dockWidgetArea() const
{
    return m_dockArea;
}

void DockWidget::setDockWidgetArea(Qt::DockWidgetArea dockArea)
{
    m_dockArea = dockArea;
}


///////////////////////////////////////////////

centerwidget.h ==>如下: 

#ifndef CENTERWIDGET_H
#define CENTERWIDGET_H

#include <QWidget>

class CenterWdt : public QWidget
{
    Q_OBJECT
public:
    explicit CenterWdt(QWidget *parent = nullptr);

protected:
    void paintEvent(QPaintEvent* event);
    void resizeEvent(QResizeEvent *event);

public:
    void setWidget(QWidget* childWdt);
private:
    QWidget*    m_childWdt;
};

class CenterWidget : public QObject
{
    Q_OBJECT
public:
    explicit CenterWidget(QObject *parent = nullptr);
    void setWidget(QWidget* childWdt);
    CenterWdt* widget() const;
private:
    CenterWdt* m_centerWdt;
};

#endif // CENTERWIDGET_H

////-----------------

#include "centerwidget.h"
#include <QPainter>
CenterWdt::CenterWdt(QWidget *parent) : QWidget(parent)
{
    m_childWdt = 0;
}

void CenterWdt::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    ///for test...
    painter.setPen(QColor(Qt::blue));
    painter.setBrush(QBrush(Qt::yellow));
    painter.drawRect(0,0,width()-1,height()-1);
    ///---tested...

    QWidget::paintEvent(event);
}

void CenterWdt::resizeEvent(QResizeEvent *event)
{
    if(m_childWdt)
        m_childWdt->setGeometry(0,0,width(),height());
    QWidget::resizeEvent(event);
}

void CenterWdt::setWidget(QWidget *childWdt)
{
    if(childWdt)
    {
        m_childWdt = childWdt;
        m_childWdt->setParent(this);
        m_childWdt->show();
        resize(width()-1,height());
        resize(width()+1,height());
    }
}
 /////
CenterWidget::CenterWidget(QObject *parent) : QObject(parent)
{
    m_centerWdt = new CenterWdt;
}

void CenterWidget::setWidget(QWidget *childWdt)
{
    m_centerWdt->setWidget(childWdt);
}

CenterWdt *CenterWidget::widget() const
{
    return m_centerWdt;
}


代码都贴完,这里只要你按照上面的代码,即可实现上图所示.
这个库还不够完善,只实现了基本的widget, splitter, dockwidget这几个窗体控件,感兴趣的读者,可以在此基础上完成layout, listview等相关的控件.

其原理其实很简单 , 由于qml中不能有Widget,只能有Object, 所以 为实现Widget的qml形式, 只能在QObject下挂接一个QWidget成员变量, 通过对两个QObject下的QWidget进行setparent处理,实现窗体的父子关系.由于前面博文中讲到setparent会破坏parent的链,其position, windowflags, visible等相关参数会发生变化,所以要格外注意.
  评论这张
 
阅读(3)| 评论(0)
推荐

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017