qml学习总结【qt写界面】

3,704 阅读6分钟

qml的总结

经过几天的学习,简单的了解了qml的一些基础,在此记录分享。

先说下:windows下怎么安装Qt软件【这个问题,曾经搞了我一阵子,万事开头难,这就是第一步啊】

先去官网 qt下载路径下载最新或者适合你的版本(因为你开发的东西是要给别的系统使用的,需要依赖系统的支持程度,比方说,之前认为系统也许支持QWidget,愣是看了好久的QWidget相关知识以及css的相关知识,最后放弃,选择看qml。听说:现在市面上都以qml开发为主)

其中有一步最重要的就是需要关联下载mingw和perl,这个需要自己勾选【默认是不勾选的】,

然后【下一步】就可以了。

进入正题

如果你学过js的话,那么就会简单很多

如果你学过Android的话,我会从Android的角度讲讲的

学习Qt的时候一定要知道你将要开发的系统支持的qt版本是多少,否则你用了很多新的api却在对方的平台上面运行异常,这些都是要考虑的

目前最新的qt版本是5.12 ,而我安装的是5.8的,因为目前大多数的设备都支持,一旦遇到不支持的,可能需要采取兼容的方案(即采用对方可支持的版本然后再实现)

最后记得如果遇到不懂的先看帮助文档,因为我遇到了好多本可以看下帮助文档就解决,却花在百度上面好久也没有找到方案的问题。eg:

解读:

  1. qmake 的意思是需要在项目的pro文件中加入 “quick” 的意思 即(QT += quick),才可以支持这个控件。

  2. Instantiated By 和 Inherits 表示实现和继承,所有的控件都是继承自QObject的(类似java的Object,而Qt里面的Item相当于Android的View和ViewGroup,是所有控件的基类)

  3. 如果需要在C++中使用这个控件需要导入include <QQuickItem> ,这一点没有Android的IDE来的好,一键导入所有的包。在Qt里面你需要老老实实的输入导入的头文件,否则你的IDE将联想不出来相关的api,当然编译会有问题的。

以下都是基于

系统:Debian9_64 ,

qt版本:5.8

qml 的布局

如果你在qml文件中,引入import QtQuick.Layouts 1.X,你可以使用的控件可以从右侧的设计板块中看到新引入的控件,一共有四个,分别是ColumnLayout,GridLayout,RowLayout,SplitView

当然可以用拖动来绘制布局,但是建议前期,还是自己学会怎么在qml文件中,编写具体的qml代码。毕竟知道qml的代码有助于你成为一个真正的界面大神,拖拽只是一种辅助而已。

说一下:Grid和GridLayout的区别,其他的布局和控件同理

GridLayout是个一堆控件的排序规则,而Grid是一个控件,这个控件里面还可以拥有控件的控件

qml的控件

import QtQuick.Controls 1.4 如果你加入这个,你就可以看到好多控件可以使用,比方说Button,Label等

简单介绍几个常用的控件

Rectangle 矩形控件

一般可以用来绘制圆角矩形,圆形还可以用作别的控件的子控件用来填充背景颜色。

        Rectangle {
            id: rectangle2
            width: 200
            height: 200
            color: "#ffffff"
        }
MouseArea 响应鼠标点击区域控件

一般用在桌面开发的控件,响应数据点击的事件,如果想用这个控件,而不知道怎么用,那么选中这个控件,然后按F1吧,会有帮助文档的,好好理解,一点有所收获。

    MouseArea {
        id: mouseArea
        width: 100
        height: 100
        onClicked: console.log("hello world")
    }

qml之listView

如果你学过Android那么你知道listview用来展示一堆数据的,可具有上下,或者左右滚动的控件。qt里面也是这样的。

先说怎么编写这个控件,然后再说怎么填充数据。

        ListView {
            anchors.fill: parent
            model: 10
            delegate: Text {
                property var item:
                    try{
                        return modelData
                    }catch(e){
                     return   ListView.view.model.get(index);
                    }
                property int age: item || item.age
                text:age
            }
        }

其中delegate表示适配器,就是布局需要展示的模样,这里可以加入js的代码来进行一些逻辑处理。delegate后面可以跟你想要的任何控件。 其中modelData表示引用填充的数据,相当于在view中使用具体内容的方式。model表示具体填充的数据。

在js中定义一个变量是var a =1 这里面是可以定义为property var a : 1表示这个值可以通过外部进行设置。

eg:你可以通过在一个控件中声明这个变量来让外部进行赋值,相当于为一个控件增加某个属性。

// Test.qml
Rectangle {
    id :root
    property var borderColor: "blue"
    property var borderWidth: 2
    radius: width/2
    border.width: borderWidth
    border.color: borderColor
    }
    
//Main.qml
    Test{
        borderWidth: 10
    }

接下来讲怎么讲数据绑定到视图。在Android里面可以通过适配器进行设置

介绍一种姿势:其他姿势请看参考资料

ObjectModel{
    id:listModel
}
ListView {
    id: listView
    width: parent.width
    height: parent.height
    anchors.fill: parent
    model: listModel
    clip: true
}

//动态添加视图以及数据
function recvTxzSignal(cmd,param)
{
    com = Qt.createComponent("qrc:/qml/Usr.qml")
    if (com !== null)
    {
        listModel.append(com.createObject(listView,{json_data:json}))
        listView.positionViewAtEnd()
    }
}

//Usr.qml
Item {
    property var json_data: null
    Text{
        text:getText(parent.json_data["query"])
    }
}

参考资料:

QML 中的 ListView 中的隐藏秘技

qml中c++来填充数据

qml之动画

可以通过查看帮助文档进行查看,切记,帮助文档很强大的。

由图中可以看出基类Animation是所有动画的基类,实现的类有方框中的Inherited By

PropertyAnimation 是属性动画。
AnchorAnimation 是角度动画。
ParallelAnimation 是异步动画,可同时执行
SequentialAnimation 是同步动画,顺序执行

eg:

//表示顺序动画,先执行放大,在执行缩小,从而达到  小->大->小

property var oriChangeBegin: 0.9
property var oriChangeEnd: 0.3
SequentialAnimation {
    id:soundAnim
    loops: Animation.Infinite
    running: true

    NumberAnimation {
        target: roundWave
        property: "scale"
        duration: 1000
        easing.type: Easing.Linear
        from:oriChangeBegin
        to: oriChangeEnd
    }

    NumberAnimation {
        target: roundWave
        property: "scale"
        duration: 1000
        easing.type: Easing.Linear
        to:oriChangeBegin
        from: oriChangeEnd
    }
}

当然还有其他动画,记得查看帮助文档。

qml之画布

和android的画布挺像,但是qt的画布,其实就是html的画布

//画个正弦
Item {
    id:root
    visible: true
    width: Math.PI*2
    height: 2
    // 振幅
    property var amplitude: height/2
    property var borderWidth: 2
    clip:  true

    Canvas{
        id:canvas
        width: parent.width
        height: parent.height
        onPaint: {

            var ctx = getContext("2d");
            context.reset();
            ctx.lineWidth = 2;
            ctx.strokeStyle= "blue"
            var index = 0;
            while (index <= width) {
                var endY =  (Math.sin(index / width * 2.0 * Math.PI) *  amplitude + (height - amplitude)/2);
                ctx.lineTo(index, endY);
                index++;
            }
            ctx.stroke();

        }

    }
}

其中var ctx = getContext("2d"); 参数就只能是2d 然后就是画画了,画圆,画方都支持也可以支持画贝塞尔曲线。

详细文档

qml与c++交互【信号,方法】

通过发信号的方式[这里给出一种方案,其他方案看参考资料]

//main.cpp
    QQmlApplicationEngine engine;
    ActiveHelper activeHelper;
    engine.rootContext()->setContextProperty("$ActiveHelper",&activeHelper); //将引用传递过去给qml进行绑定
    engine.load(QUrl(QStringLiteral("qrc:/qml/TestFirstQml.qml")));
    
//TestFirstQml.qml
    import QtQuick 2.6
    import QtQuick.Controls 1.4
    ApplicationWindow {
        visible: true
        width: 800
        height: 800
        id:item
        Rectangle{
            color: "red"
            width: 200
            height: 200
    
            MouseArea{
                anchors.fill: parent
                onClicked: testSignal(item)
            }
            Component.onCompleted:
            {
                console.log();
                item.width =20;
                $ActiveHelper.sig_active.connect(item.testS);// 注意这里绑定信号与槽函数,c++通过发送这个信号可以调用qml中相绑定的方法
                $ActiveHelper.activeResult(item) //调用ActiveHelper中的槽函数
            }
            signal testSignal(var anObject)
        }
        function testS(){
            console.log("qml test");
        }
    }

//ActiveHelper.h
    #ifndef ACTIVEHELPER_H
    #define ACTIVEHELPER_H
    #include <QObject>
    
    class ActiveHelper : public QObject
    {
        Q_OBJECT
    public:
        explicit ActiveHelper(QObject *parent = 0);
    
        /**
         * @brief 执行激活流程
         */
        void active();
    
        /**
         * @brief 发送激活信号
         */
        void sendSigActive(){
            emit sig_active();
        }
    
    signals:
        /**
         * @brief active信号
         */
        void sig_active();
    
    public slots:
        /**
         * @brief 激活结果回来(可能成功,可能失败)
         */
        void activeResult(const QVariant &);
    };
    
    #endif // ACTIVEHELPER_H


//ActiveHelper.cpp
    #include "activehelper.h"
    #include "txz_common.h"
    
    ActiveHelper::ActiveHelper(QObject *parent) : QObject(parent){}
    
    void ActiveHelper::active()
    {
        TXZ_LOGD("active");
    }
    
    void ActiveHelper::activeResult(const QVariant &v)
    {
        TXZ_LOGD("active result");
        emit sig_active(); //发送信号
    }

参考资料 Interacting with QML Objects from C++

其他

  1. 间距不生效的问题

    在设置相对位置间距的时候,一定要设置相对应的锚边,然后才可以设置边距

    Rectangle {
        id: rectangle
        width: 200
        height: 200
        color: "#ffffff"
        anchors.right: parent.right //一定要设置这个属性,rightMargin才会生效
        anchors.rightMargin: 440
    }
    

    参考资料: qt帮助文档

  2. 加载不出来界面的问题

        //第一种方式:需要采用ApplicationWindow【window才可以展示】
        QQmlApplicationEngine engine;
        ActiveHelper activeHelper;
        engine.rootContext()->setContextProperty("$ActiveHelper",&activeHelper);
        engine.load(QUrl(QStringLiteral("qrc:/qml/TestFirstQml.qml")));
    
    //需要以Item等控件才可以展示
        QQuickView view(QUrl(QStringLiteral("qrc:/qml/Test.qml")));
        QQuickItem * item = view.rootObject();
        view.show();
    
  3. 内容自适应,好像没有找到【不知道有什么方法】

参考资料:

使用gdb进行调试

qml从入门到放弃这个文章不错