Qml基础教程

Qt Creator的安装和Qml项目的创建


什么是Qt


Qt是一个跨平台的C++图形用户界面应用程序框架。它为应用程序开发者提供建立图形界面所需的所有功能。它是完全面向对象的,很容易扩展,并且允许真正的组件编程。

下载安装包


官网下载

下载好后先别急着点开

安装


如果不想注册,点开之前先断网

  1. 如果没注册Qt账号的先注册
  2. 填写好账号密码点击右下角Next

image-20240708135517308

  1. 如果有公司可以填,也可以不填,勾选这两项包快的,点击右下角Next

image-20240708140040299

  1. 这里直接下一步,点击右下角Next

image-20240708140359052

5.如果不想把自己的隐私透露出去,选第二个,点击右下角Next

image-20240708140431990

  1. 第一个框:选择安装路径,建议不选C盘

    第二个框:自定义安装,其实如果你不想那么麻烦,就全选了吧

    点击右下角Next

image-20240708140603691

  1. 如果选择了Custom Installation,那就看自己需求选,点击右下角Next

image-20240708141424960

  1. 勾选后点击右下角Next

image-20240708141549926

  1. 设置开始菜单快捷方式,直接点击右下角Next
  2. 查看自己的空间足部足够,然后点击右下角install,记得联网
  3. 等他下载完后就Finish可以启动了

创建项目


打开Qt Creator后就这个界面,左边创建项目就行了,右边就是打开过的项目

image-20240708142027874

点击创建项目,选额Application(Qt)→Qt Quick Application

image-20240708142135781

输入项目名称和路径

image-20240708142242756

然后一直下一步就行了,这就是Qml项目的项目结构,只用看有锤子图标的demoQmlApp部分里的main.qml,Source Files是装C++文件的,先不用看

打开main.qml,可以先把这里删了

image-20240708143035101

输入以下内容,然后点击左下角的绿色三角箭头运行,你就得到了第一个由qml创建的页面了

Window{
    width: 800
    height: 400
    visible: true
}

Window组件


写qml就像再写css一样,但是里面又有js的写法,所以编写qml非常的方便和快捷

如果我们需要一个窗口,就需要用到Window组件

基本的属性


属性 说明
width number 窗口宽度*
height number 窗口高度*
visible boolean 窗口是否显示*
title QString 窗口标题
x/y number 窗口位置
minimumWidth/minimumHeight number 窗口最小宽度/高度
maximumWidth/maximumHeight number 窗口最大宽度/高度

而编写成以下代码,就你创建出一个简单的窗口

import QtQuick

Window{
    width: 800
    height: 400
    visible: true
}

添加标题

import QtQuick

Window{
    width: 800
    height: 400
    visible: true
    title:qsTr("DemoTitle")//窗口标题
}

设置窗口固定大小

import QtQuick

Window{
    width: 800
    height: 400
    visible: true
    title:qsTr("DemoTitle")//窗口标题
        //设置窗口大小最大最小值
    minimumWidth: 800
    minimumHeight: 400
    maximumWidth: 800
    maximumHeight: 400
}

当然,还可以设置窗口透明度,添加以下代码就行

opacity: 0.5

在Qt中会有信号和槽函数这一说法,而QML中定义信号,就会有相应的槽函数

//定义一个信号
    signal aSigaal()
    //槽函数
    onASigaal: {
        
    }

而在Window组件中,也已经定义了多种槽函数,只要输入on,就你看到提示中有很多槽函数

image-20240708154005201

而如果我们定义一个变量值,它也会自动生成一个函数,来检测值的改变

//如果定义了一个变量值,它会自动生成一个槽函数
    property int aValue: 1
    //如:
    onAValueChanged: {

    }

通过onWidthChanged这个去举例,引出槽函数,然后在里面打印它存在的变量,运行后,拉伸窗口宽度,可以看到打印了qml: width: 600类似的输出

	onWidthChanged: {
        console.log("width:", width)
    }

Rectangle组件


Rectangle是用Item组件引申出来的组件,Item组件有的,它都有

其实了解了窗口的属性,其他的属性也都是差不多的,id是为了方便获取组件中的属性值

	Rectangle{
        id:rect//每个组件都可以有id,但是不能重复
        x:120
        y:120
        color: "#545454"
        width: 100
        height: 50
    }

z属性就如css中的z-index一样

//常用组件,相当于Widget,继承Item
    Rectangle{
        x:100
        y:100
        z:1//调整层数,越大越优先
        //而越下面创建的组件,显示层数越高,但是默认z都是1
        color: "#131313"
        width: 100
        height: 50
    }

锚点定位[anchors]


一般是这种形式

anchors.属性: 组件/组件属性/数值

fill 填充完父组件


	Rectangle{
        //这个就是将这个组件填充满父组件
        anchors.fill: parent
        color: "#131313"
    }

left/top/right/bottom 锚点定位


rect2放在里rect1方块的右边,并且在同一条水平线,且离rect1距离20

	Rectangle{
        id:rect1
        x:100
        y:200
        width: 80
        height: 40
        color: "#131313"
    }	
	Rectangle{
        id:rect2
        width: 80
        height: 40
        anchors.left: rect1.right//放在rect1的右边
        anchors.top: rect1.top//与rect1的top对齐
        anchors.leftMargin: 20//其实就是相对于当前组件,左边+20而已
        color: "#131313"
    }

后面加个Margin代表该Rectangle外边距

居中定位


三种,水平居中,垂直居中,水平垂直居中

	Rectangle{
        height: 50
        width: 50
        anchors.centerIn: parent//相对于父组件的中间位置
        color: "#434321"
    }

    Rectangle{
        height: 50
        width: 50
        anchors.horizontalCenter: parent.horizontalCenter//相对于父组件的水平中间位置
        color: "#434321"
    }

    Rectangle{
        height: 50
        width: 50
        anchors.verticalCenter: parent.verticalCenter//相对于父组件的垂直中间位置
        color: "#434321"
    }

旋转与缩放


通过添加rotationscale属性来旋转和缩放

	Rectangle{
        width: 80
        height: 40
        x:50
        y:250
        color: "#325314"
        rotation: 60//旋转度数*
        scale:1.5//缩放倍数*
    }

Item与Rectangle


而相比于Item,Rectangle多了以下属性

	Rectangle{
        width: 80
        height: 40
        x:200
        y:300
        //多的属性
        antialiasing: true//抗锯齿,默认true
        border.color: "#847203"//边框颜色
        border.width: 3//边框粗细
        color: "#691274"//背景颜色
        radius: 10//圆角
        //gradient: 详细看下一个组件
    }

渐变


	Rectangle{
        width: 80
        height: 40
        x:300
        y:300
        gradient: Gradient{//渐变,从上到下
            GradientStop{position: 0.0;color: "#634543"}//起点及颜色
            GradientStop{position: 1.0;color: "#217342"}//终点及颜色
        }
    }

事件


qml中,我们可以通过引入QtQuick.Controls去使用Button组件

以下创建了两个按钮,按键盘的左右方向键可以切换这两个按钮的样式

	Button{
        id:btn1 //访问这个组件,用他的id就行了
        objectName: "btn1ON"//不设置也行,在获取按钮名可能就会出现组件名(地址)的情况
        width: 80
        height: 40
        x:100
        y:50
        focus:true
        //设置背景,包括边框
        background: Rectangle{
            //输入btn1.什么,可以获取按钮状态,然后使用三重表达式去切换颜色
            color: btn1.focus ? "#131313" : "#f1f1f1"
            border.color: "#888"
        }
        onClicked: {
            console.log("按钮1")
        }
        //这里的按键事件,必须要按钮处于聚焦才能触发
        Keys.onRightPressed: {
            btn2.focus = true
        }
    }	
Button{
        id:btn2
        objectName: "btn2ON"
        width: 80
        height: 40
        x:200
        y:50
        focus:false
        background: Rectangle{
            //灵活应用可以设置多种触发改变按钮的样式
            color: btn2.focus ? "#131313" : btn2.hovered ? "#888" : "#f1f1f1"
            border.color: "#888"
        }
        onClicked: {
            console.log("按钮2")
        }
        Keys.onLeftPressed: {
            btn1.focus = true
        }
    }

获取正在被聚焦的组件,及信息

	onActiveFocusItemChanged: {
        //记得设置ObjectName,不然只会出现组件名(地址),可以通过activeFocusItem获取objectName
        console.log("当前活动Item:",activeFocusItem,"objectName:",activeFocusItem.objectName)
    }

MouseArea


这个组件为了能让Rectangle等没有点击事件的组件设计而成

主要的方法如下

方法 说明
onClicked 点击事件,点击区域触发
onDoubleClicked 双击事件,快速双击区域触发
onPressed 按下事件,点击按下区域触发
onReleased 松开事件,点击松开区域触发
onPressAndHold 长按事件,长按区域触发
onCanceled 取消点击事件,目前测出点击区域,然后且换窗口会触发
onEntered 点击进入事件,如果鼠标点击区域或点击离开区域再次进入区域会触发
onExited 点击离开事件,如果鼠标点击区域后松开或离开区域会触发
	Rectangle{
        x:100
        y:100
        color: "#131313"
        width: 100
        height: 50
    //这种组件的鼠标点击事件如下
        MouseArea{
            anchors.fill: parent
            onClicked: {
                console.log("点击了黑块")
            }
        }
    }

或者

MouseArea{
        x:100
        y:100
        width: 100
        height: 50
        Rectangle{
            anchors.fill: parent
            color: "#131313"
        }
        onClicked: {
            console.log("点击了黑块")
        }
    }

只是看谁嵌套进去而已

如何右键


很简单,在MouseArea里加这一行就行了,每添加一个按键,前面要加个|

acceptedButtons: Qt.LeftButton | Qt.RightButton

如果你想添加其他的鼠标按键,下面的按键,任你挑选,只要把::换成.就行了

XButton为侧键,1是后侧键,2是前侧键 [我的鼠标是这样的]

image-20240709154258990

怎么区分是哪个按键


可以通过按键事件的方法中的一个属性pressedButtons,来获取当前按下的按键的值,但是这个值不是普通的值,所有要判断,就需要通过pressedButtons == Qt.什么什么来判断

	onPressed: {
                console.log(pressedButtons == Qt.LeftButton)
            }

至于为什么在onClicked中的pressedButtons值是0的问题,因为只有按钮按下的才会出现这个值,当松开后,按下的按键的值就会清零

动画

普通动画


通过PropertyAnimation可以创建一个属性的动画,并且能够绑定在某个或多个组件中

PropertyAnimation需要以下属性,*为必要

属性 说明
id 同上 设置id,以便可以访问里面的方法
target 组件id 绑定到组件,可以绑定多个格式为[组件1,组件2]*
properties 属性 将动画运用到哪个属性上*
from 属性值 动画开始状态,空位当前状态
to 属性值 动画结束状态*
duration num 动画事件,可省略,默认250,即0.25秒
easing.什么什么 属性值 设计动画曲线

例如:

	Rectangle{
        id:block
        width: 75
        height: 75
        color: "#131313"
// 特殊值动画,给特殊值属性添加动画,其实也可以用在数值属性上
        PropertyAnimation{
            id:toRed
            target:block
            properties: "color"
            to:"darkRed"
            duration: 2000//时间可省略
        }
        MouseArea{
            anchors.fill: parent
            onClicked: {
                toRed.start()
            }
        }
    }

当引用动画的id,可以设置动画的开始和暂停

其实除了PropertyAnimation外,还有NumberAnimationColorAnimationColorAnimation就少了properties属性,因为他只用设置颜色数值就行了,而NumberAnimation只能设置数值属性的动画,例如:

	Rectangle{
        id:block
        width: 75
        height: 75
        color: "#131313"
// 数值动画,给数值属性添加动画
        NumberAnimation{
            id:opacityshade
            target: block
            properties: "opacity"
            from: 0
            to:1
            duration: 1000
        }
        MouseArea{
            anchors.fill: parent
            onClicked: {
                opacityshade.start()
            }
        }
    }

自动触发动画


只要在PropertyAnimation或[NumberAnimationColorAnimation]后面加on 属性就行了

	Rectangle{
        id:block1
        width: 75
        height: 75
        y:100
        color: "black"
        PropertyAnimation on x {
            to: 100
            duration: 1000
        }
        PropertyAnimation on width {
            to:150
        }
    }

队列动画


通过SequentialAnimation可以创建出队列动画

Rectangle{
        id:block2
        width: 75
        height:75
        y:200
        color:"black"
        //SequentialAnimation也可以跟第二种一样直接执行
        SequentialAnimation{
            id:toRedThenMoveX100
            PropertyAnimation{
                target:block2
                properties: "color"
                to:"darkRed"
            }
            PropertyAnimation{
                target:block2
                properties: "x"
                to:100
            }
        }
        MouseArea{
            anchors.fill: parent
            onClicked: {
                toRedThenMoveX100.start()
            }
        }
    }

states动画


states可以设置当前组件的属性多个状态,可以改变这个state的值来设置不同的状态,PropertyChanges记得绑定组件id

然后通过按钮事件去更改state的值,让组件处于其他state

Rectangle{
        id: block3
        width: 75
        height: 75
        x: 200
        color: "#131313"

        state: "block3Released"
        states: [
            State {
                name: "block3Pressed"
                PropertyChanges {
                    target: block3
                    color: "#666"
                }
            },
            State {
                name: "block3Released"
                PropertyChanges {
                    target: block3
                    color: "#131313"
                }
            }
        ]
        MouseArea{
            anchors.fill: parent
            onPressed: block3.state = "block3Pressed"
            onReleased: block3.state = "block3Released"
        }
    }

然后在组件内通过transitions属性和Transition组件来创建动画,我在动画中使用了两种不同的动画创建方法,都一样的,在Transition中,要设置好to属性,from可以省略,默认当前状态

	transitions: [
            Transition {
                from: "block3Pressed"//设置从什么状态
                to: "block3Released"//到什么状态的动画
                ColorAnimation{
                    target: block3
                }
            },
            Transition {
                to: "block3Pressed"
                PropertyAnimation{
                    target: block3
                    properties: "color"
                    duration: 1000
                }
            }
        ]

行为动画


就是设置一个只要这个属性改变,就会有动画

形式就是Behavior on 属性{}

如果想引用已经设置好的行为动画可通过animation: 动画id来设置

以下代码就是方块x或y坐标改变,会有弹性的动画:

    Rectangle{
        id: block5
        width: 75
        height: 75
        x: 300
        y:100
        color: "#131313"
//可以在里面设置动画
        Behavior on x{
            PropertyAnimation{
                id:bounce
                easing{//设计动画曲线
                    type: Easing.OutElastic
                    amplitude: 1
                    period: 0.5
                }
            }
        }
//也可以应用外面的动画
        Behavior on y{
            animation: bounce
        }
//只有x或y改变,就会有相应的动画
        MouseArea{
            anchors.fill: parent
            onClicked: {
                block5.x += 10
                block5.y += 10
            }
        }
    }

Component和Loader


对于用Component包裹的组件,他不会立即将该组件生成到窗口

	Component{
        id:comp1
        Rectangle{
            width: 100
            height: 100
            y:100
            color: "#131313"
        }
    }

而要将Component里的组件显示出来需要Loader组件

	Loader{
        id:loader1   //Loader也可以有id
        asynchronous: true    //是否异步加载
        sourceComponent: comp1
    }

可以通过事件,改变Loader组件加载的Component

	onClicked: {
            //当把sourceComponent设为空,及不加载任何组件
            // loader1.sourceComponent = null
        }

如果用Loader的id去修改Component内的值,则需要通过loader1.item.属性设置

	onClicked: {

            //因为当我们把sourceComponent设置为空后,组件销毁,系统就会找不到这个组件
            //但是loader中的item可以获取loader中的组件,所有可以用item设置loader加载组件的属性值
            // loader1.com1.height = 50//这个不行,可以自己尝试下
            loader1.item.height = 50
        }

图片组件

通过Image组件可以将资源里的图片文件加载出来,source就是资源的目标地址

如果图片的宽高都设置的话,可能会出现变形

		Image {
            id: img1
            x: 200
            //加载图片可以通过source
            source: "oak.png"
            //可设置图片宽高,但是会变形
            width: 200
            height: 100
        }

动图加载

如果通过Image加载动图,那图片是不会动的,可以通过组件来加载动图,而且可以设置动图的一下状态

	AnimatedImage{
        id:img2
        x:200
        source: "test.gif"
        playing: true   //是否播放
        paused: false   //是否停止
        speed: 2   //动图加速
    }
	Button{
        width: 80
        height: 40
        x:parent.width-80
        onClicked: {
            img2.playing = !img2.playing	//切换动图的播放和停止
     }	
posted @ 2024-09-02 21:40  TuringICE  阅读(122)  评论(0编辑  收藏  举报