一、QML文件的创建
选择qt--->QML File------>选择
二、Window 基础属性
X,Y是以窗口左上角为原点,具体位置是相对于父控件
x:在窗口中的横向位置
y:在窗口中的纵向位置
width:宽
height:高
visible:可见性
注意:Window需要设置可见性为true,否则不显示窗口
title:标题
opacity: 透明度
minimumHeight:最小高
maximumHeight:最大高
minimumWidth:最小宽
maximumWidth:最大宽
implicitWidth:默认宽度
implicitHeight: 默认高度
radius: 设置圆角
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.5 //qml调用控件需要该头文件
Window {
width: 500 //宽
height: 500 //高
visible: true //可见性
title: qsTr("Hello World") //标题
//位置
x:50
y:50
opacity: 0.5 //透明度
minimumHeight: 400 //最小高
maximumHeight: 400 //最大高
minimumWidth: 400 //最小宽
maximumWidth: 600 //最大宽
implicitWidth:100//默认宽度
implicitHeight:40// 默认高度
radius: 10 // 设置圆角
}
三、声明与定义——property
property既可以声明数值类型也可以声明组件类型
property int myTopMar: 0
property int mybotMar: 0
property string mystring: "asd"
property color mycolor: "red"
property url myurl: "qrc:/1.jpg"
property var myvar: value//相当于auto
property Component myComponent
只读:readonly
readonly property int name: value//只读
必须赋值:required
required property type name: value//必须赋值才能进行
起别名: alias
property alias newname: oldname
四、矩形——Rectangle
Rectangle
是一个基本的图形元素,用来绘制矩形。它通常被用作UI组件的背景或作为其它图形元素的容器。
Rectangle {
width: 100
height: 50
color: "blue"//颜色
border { //边框
width: 2
color: "red"
}
radius: 10 // 设置圆角
}
注意:在Rectangel中添加一个子Rectangel时,子控件会显示在父控件之上,子控件也会随着父控件的显示与隐藏来显示与隐藏自己,但popup是个例外
五、组件——Component
Compon或者开发者封装好的、只暴露必要接口的QML类型ent是Qt框架,可以重复使用。
Component本身并不可见,可以通过添加矩形Rectangle的方式使其变得可见。
Component.onCompleted:{
console.log("界面创建")//界面创建时触发信号onCompleted
}
Component.onDestruction: {
console.log("界面销毁")//界面销毁时调用onDestruction
}
//自定义Component
Component {
id: itemCompont //设置组件id
Rectangle { //矩形
id: compontRect //设置矩形id
color: 'blue' //设置矩形颜色
visible:true //设置能见度可见
implicitWidth: 200 //默认宽度
implicitHeight: 50 //默认高度
Text { //文本
id: interText //设置文本id
anchors.left: parent.left //使文本的左边与文本所在父控件的左边对齐
anchors.leftMargin: 10 //设置左侧锚点的外边距为10个像素单位。
anchors.verticalCenter: parent.verticalCenter//元素相对于父元素垂直居中
text: qsTr("text")
}
Button {
anchors.margins: 5 //设置所有锚点的外边距为5个像素单位。
anchors.top: parent.top //元素的顶部边缘将与父元素的顶部边缘对齐。
anchors.bottom: parent.bottom//元素的底部边缘将与父元素的底部边缘对齐。
anchors.right: parent.right //元素的右边缘将与父元素的右边缘对齐。
text: '删除'
}
}
}
//调用component,使其生效
Loader{//Component无法自己加载需要通过loader加载
id:load
// source: "/MyRectangel.qml"
sourceComponent: itemCompont //加载Component
//status状态
onStatusChanged: {
console.log("status",status)//staus默认为1
}
}
Button{
id:btn
width: 50
height: 50
x:100
y:100
onClicked: {
//load.sourceComponent=null
load.item.width=100//在component直接用矩形的id改变属性是不可用的,需要使用item调用
load.item.height=100
}
}
Component有两个比较重要的信号
- Completed:该信号会在界面创建时发出
- Destruction:该信号会在界面销毁时发出
Component在使用时无法自己加载需要通过Loader加载
六、加载——Loader
装载资源与组件
Loader{//Component无法自己加载需要通过loader加载
id:load
source: "/MyRectangel.qml" //资源地址
sourceComponent: itemCompont//组件ID
onStatusChanged: {
console.log("status",status)//staus默认为1
}
}
6.1、状态-status
Loader有四种状态分别为
- Loader.Null——非活动状态或未设置QML源时的状态——0
- Loader.Ready——就绪,QML源已加载——1
- Loader.Loading——加载,QML源当前正在加载——2
- Loader.Error——错误,QML源加载时出现错误——3
6.2、属性
1、item
使用Loader加载后如果想要调整组件的属性可以用item
load.item.width=100
2、asynchronous
异步操作,当加载大型资源时可以使用asynchronous
asynchronous: true
6.3、加载图片
//图片
Component
{
id:com
Image {//静态图
id: tp1
source: "/3.gif"
width:200
height:200
}
AnimatedImage{//动态图
id:aim
source: "/3.gif"
speed: 2//动态的速度
}
}
Loader{
id:load
sourceComponent: com
}
Button{
width: 50
height: 50
x:200
onClicked: {
load.item.paused = !load.item.paused//动态取反,暂停
}
}
注:所有控件都可以用过component封装,然后通过loader动态加载
七、鼠标——MouseArea
MouseArea{
id:mousearea
width:200
height: 200
enabled: true
Rectangle{
anchors.fill: parent//填充并匹配其父元素的大小和位置
color: "blue"
}
Rectangle{
width:200
height: 200
color: "yellow"
MouseArea
{
anchors.fill: parent
onClicked:
{
console.log("yellow")
}
}
Rectangle{
width: 100
height: 100
color: "red"
MouseArea{
anchors.fill: parent
propagateComposedEvents: true//当设置为true时,它允许一个组件处理事件后
//继续将该事件传播给其他组件
onClicked: {
console.log("red")
mouse.accepted=false//在鼠标事件处理函数中使用,用来指示该事件没有被
//完全处理,并且应该继续传播给可能对处理此事件感兴趣的其他项目
}
}
}
}
pressAndHoldInterval: 3000//设置长按触发时间
onPressAndHold: {//长按默认800ms
console.log("onPressAndHold")
}
acceptedButtons: Qt.LeftButton|Qt.RightButton//鼠标左键右键
onClicked: {//点击
console.log("clieck")
}
onPressed: {//按下
var ret=pressedButtons&Qt.LeftButton
var ret2=pressedButtons&Qt.RightButton
console.log(ret?"left":ret2?"right":"other")
console.log("pressed")
}
onReleased: {//松开
console.log("reless")
}
hoverEnabled: true//鼠标悬停
onHoveredChanged: {
console.log("onHoveredChanged")
}
onContainsMouseChanged: {//用于判断鼠标是否在元素范围内
console.log("onContainsMouseChanged")
}
onContainsPressChanged: {//用于判断当前元素是否正在被鼠标按压
console.log("onContainsPressChanged")
}
onMouseXChanged: {
console.log("x:",mouseX)
}
onMouseYChanged: {
console.log("y",mouseY)
}
cursorShape://改变光标
Qt.CrossCursor
}
7.1、常用信号
- Clieck:点击
onClicked: {//点击
console.log("clieck")
}
- Pressed:按下
onPressed: {//按下
console.log("pressed")
}
- Released:松开
onReleased: {//松开
console.log("reless")
}
7.2、属性
1、acceptedButtons:此属性包含鼠标区域对其作出反应的鼠标按钮。
acceptedButtons: Qt.LeftButton|Qt.RightButton
2、containsMouse与containsPress:用于判断当前鼠标在不在范围内
如果hoverEnabled为false则只有按下才会触发containsMouse
onContainsMouseChanged: {
console.log("onContainsMouseChanged",containsMouse)
}
onContainsPressChanged: {
console.log("onContainsPressChanged",containsPress)
}
3、hoverEnabled:用于启用鼠标悬停事件的处理。
默认为false
hoverEnabled: true
4、cursorShape:控制光标样式
cursorShape: Qt.CrossCursor
5、Drag:实现鼠标控制拖拽
Rectangle{
width: 1000
height: 1000
id :rec
color: "green"
Rectangle{
id:rect
width: 50
height: 50
color: "red"
opacity: (600-rect.x)/600//不透明度
MouseArea{
anchors.fill: parent
drag.target: rect//设置在哪里拖动
drag.axis:Drag.XAxis|Drag.YAxis//控制在X轴移动还是Y轴移动
drag.minimumX: 0//最小移动位置
drag.maximumX: rec.width-rect.width//最大移动位置
}
}
}
filterChildren:如果为true,则子控件的MouseArea依然有效但子控件同样继承了父控件的拖动事件
Rectangle {
width: 480
height: 320
Rectangle {
x: 30; y: 30
width: 300; height: 240
color: "lightsteelblue"
MouseArea {
anchors.fill: parent
drag.target: parent;
drag.axis: "XAxis"
drag.minimumX: 30
drag.maximumX: 150
drag.filterChildren: true
Rectangle {
color: "yellow"
x: 50; y : 50
width: 100; height: 100
MouseArea {
anchors.fill: parent
onClicked: console.log("Clicked")
}
}
}
}
}
6、enabled:当前MouseArea是否是使能的,默认true
enabled:false
7、mouseX与mouseY:获取鼠标位置
如果hoverEnabled为true,光标悬停依然触发
onMouseXChanged: {
console.log("x:",mouseX)
}
onMouseYChanged: {
console.log("y",mouseY)
}
8、pressAndHoldInterval:设置长按触发时间
pressAndHoldInterval: 3000//设置长按触发时间
9、propagateComposedEvents :允许复合事件在被一个元素处理后继续传播给其他元素
Rectangle {
color: "yellow"
width: 100; height: 100
MouseArea {
anchors.fill: parent
onClicked: console.log("clicked yellow")
}
Rectangle {
color: "blue"
width: 50; height: 50
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onClicked: {
console.log("clicked blue")
mouse.accepted = false
}
}
}
}
八、按钮——Button
Button{
id:btn
width: 50
height: 50
autoExclusive: true //实现按钮互斥
checkable: true
}
Button{
id:btn1
x:60
width: 50
height: 50
autoExclusive: true
checkable: true
}
Button{
id:btn2
x:120
width: 50
height: 50
autoExclusive: true
checkable: true
}
Button{
id:btn
x:120
width: 50
height: 50
autoRepeat: true//不断触发信号
autoRepeatDelay: 3000 //第一次按下到信号发生的时间
autoRepeatInterval: 1000//不断的触发信号的间隔
onDownChanged: {//如果鼠标按下便为true,如果松开或移开则为false
console.log("down",down,"press",pressed)
}
onClicked:
{
console.log("clicked")
}
onPressed: {
console.log("pressed")
}
onReleased: {
console.log("release")
}
icon.source: "/1.jpg"
icon.color: "red"
indicator: Image {
id: im
source: "/1.jpg"
}
text: "1234"//文本
background: Rectangle{
anchors.fill: btn
color: {
if(btn.pressed)
{
return "green"
}
else
{
return "blue"
}
}
border.width: 5//边框
border.color: {
if(btn.pressed)
{
return "red"
}
else
{
return "black"
}
}
}
}
8.1、属性
1、flat:不绘制背景色,点击显示
flat:true
2、highlighted:背景颜色置为黑色,按下后变为灰色
highlighted: true
3、checkable:使得一些UI元素具有可选中和不可选中的状态。
如果checked状态设为true则checkable会被强制设为true
Button{
id:btn
width: 50
height: 50
checkable: true
}
4、autoExclusive:实现互斥
Button{
id:btn
width: 50
height: 50
autoExclusive: true //实现按钮互斥
checkable: true
}
Button{
id:btn1
x:60
width: 50
height: 50
autoExclusive: true
checkable: true
}
5、autoRepeat:不断触发信号
autoRepeat: true//不断触发信号
6、autoRepeatInterval:第一次按下到信号发生的时间
autoRepeatDelay: 3000 //第一次按下到信号发生的时间
7、autoRepeatInterval:不断的触发信号的间隔
autoRepeatInterval: 1000//不断的触发信号的间隔
8、down:如果鼠标按下便为true,如果松开或移开则为false
onDownChanged: {//如果鼠标按下便为true,如果松开或移开则为false
console.log("down",down,"press",pressed)
}
9、icon:用于给用户界面元素(如按钮、菜单项等)添加图标
icon.source: "/1.jpg"//加载路径
icon.color: "red" //修改颜色
10、indicator:用于指代一个视觉元素
indicator: Image { //
id: im
source: "/1.jpg"
}
11、text:文本
text: "1234"//文本
12、background:用于指定一个控件的背景元素
Button{
id:btn
x:120
width: 50
height: 50
background: Rectangle{
anchors.fill: btn
color: {
if(btn.pressed)
{
return "green"
}
else
{
return "blue"
}
}
border.width: 5//边框
border.color: {
if(btn.pressed)
{
return "red"
}
else
{
return "black"
}
}
}
}
8.2、自定义按钮
由于普通按钮无法满足需求所以需要进行按钮自定义
- background重绘
Button{
id:btn
width: 50
height: 50
background: Rectangle{
anchors.fill: parent
color: btn.checked|btn.down?"blue":"black"
}
- contentItem对内容做重绘
例:想要文本
contentItem: Text {
text: btn.text
font.pixelSize: 18//字体大小
font.bold: true//粗体
}
例:想要图片
//文本+图片
text: qsTr("button")
contentItem: Rectangle{
Text {
id: text
text: btn.text
font.pixelSize: 18//字体大小
font.bold: true//粗体
}
Image {
id: img
source: "/1.jpg"
width: btn.width
height: btn.height
anchors.right: btn.right
}
}
九、复选框——chekBox
ButtonGroup{
id:childbutton
exclusive: true
//互斥方法1
// buttons: col.children
}
Column{
id:col
CheckBox{
checked: true
text: qsTr("文本1")
//互斥方法2
ButtonGroup.group: childbutton
}
CheckBox{
checked: true
text: qsTr("文本2")
ButtonGroup.group: childbutton
}
CheckBox{
checked: true
text: qsTr("文本3")
ButtonGroup.group: childbutton
}
}
CheckBox{
checked: true
nextCheckState: function(){
if(checkState==Qt.Unchecked)
{
return Qt.Checked
}
else if(checkState==Qt.Checked)
{
return Qt.PartiallyChecked
}
else
{
return Qt.Unchecked
}
}
}
9.1、属性
1、tristate:控制checkBox是否具有三态
三态:
- unchecked:未选中
- partiallyChecked:部分选中
- checked:选中
CheckBox{
checked: true
tristate:true
text: qsTr("文本1")
}
2、checkState
Column {
ButtonGroup {
id: childGroup
exclusive: false//非排他
checkState: parentBox.checkState
}
CheckBox {
id: parentBox
text: qsTr("Parent")
checkState: childGroup.checkState
}
CheckBox {
checked: true
text: qsTr("Child 1")
leftPadding: indicator.width
ButtonGroup.group: childGroup
}
CheckBox {
text: qsTr("Child 2")
leftPadding: indicator.width
ButtonGroup.group: childGroup
}
}
3、nextCheckState: function():回调函数
CheckBox{
checked: true
nextCheckState: function(){
if(checkState===Qt.Unchecked)
{
return Qt.Checked
}
else if(checkState===Qt.Checked)
{
return Qt.PartiallyChecked
}
else
{
return Qt.Unchecked
}
}
}
9.2、互斥
方法一:
ButtonGroup{
id:childbutton
exclusive: true
buttons: col.children
}
Column{
id:col
CheckBox{
checked: true
text: qsTr("文本1")
}
CheckBox{
checked: true
text: qsTr("文本2")
}
CheckBox{
checked: true
text: qsTr("文本3")
}
}
方法二:
ButtonGroup{
id:childbutton
exclusive: true
}
Column{
id:col
CheckBox{
checked: true
text: qsTr("文本1")
ButtonGroup.group: childbutton
}
CheckBox{
checked: true
text: qsTr("文本2")
ButtonGroup.group: childbutton
}
CheckBox{
checked: true
text: qsTr("文本3")
ButtonGroup.group: childbutton
}
}
十、按下后进度条——DelayButton
DelayButton{
width: 100
height: 50
delay: 3000//设置时间
onPressedChanged: {
console.log(progress)//当前进度
}
}
设置时间:delay
delay: 3000//设置时间
十一、单选按钮——RadioButton
Column {
RadioButton {
checked: true
text: qsTr("First")
}
RadioButton {
text: qsTr("Second")
}
RadioButton {
text: qsTr("Third")
}
}
十二、开关——Switch
Column{
Switch{
text: "1"
LayoutMirroring.enabled: true//翻转
onPositionChanged: {
console.log("pos",position)//从右往左数
}
onVisualPositionChanged: {
console.log("vis",visualPosition)//从左往右
}
}
Switch
{
text: "2"
}
}
互斥:
ButtonGroup{
id:btg
exclusive: true
buttons: col.children
}
Column{
id:col
Switch{
text: "1"
LayoutMirroring.enabled: true//翻转
onPositionChanged: {
console.log("pos",position)//从右往左数
}
onVisualPositionChanged: {
console.log("vis",visualPosition)//从左往右
}
}
Switch
{
text: "2"
}
}
12.1、属性
1、Position:从右向左的进度
onPositionChanged: {
console.log("pos",position)//从右往左数
}
2、VisualPosition:从左往右的进度
onVisualPositionChanged: {
console.log("vis",visualPosition)//从左往右
}
十三、标签按钮——TabButton
TabBar{
TabButton{
text: qsTr("1")
}
TabButton{
text: qsTr("2")
}
TabButton{
text: qsTr("3")
}
}
十四、圆形按钮——RoundButton
RoundButton{
text: "111"
}
十五、组合按钮——ToolButton
ToolBar {
Row {
anchors.fill: parent
ToolButton {
text: qsTr("‹")
onClicked: stack.pop()//回收
}
Label {
text: "Title"
elide: Label.ElideRight//当label中的内容超出范围时变为省略号
horizontalAlignment: Qt.AlignHCenter//水平居中对齐
verticalAlignment: Qt.AlignVCenter//垂直居中对齐
}
ToolButton {
text: qsTr("⋮")
onClicked: menu.open()//展开
}
}
}
elide:指定了文本内容超出可显示区域时,文本应如何被省略
Label.ElideRight:当label中的内容超出范围时右侧被剪切并且在后面添加省略号
horizontalAlignment: 控制文本在水平方向上的对齐位置
verticalAlignment: 控制文本在垂直方向上的对齐位置
Qt.AlignHCenter:水平方向上居中对齐
Qt.AlignVCenter:垂直居中对齐
十六、文本——text
16.1属性
1、color:设置文本颜色
Text {
color: "#00FF00"
text: "green text"
}
2、contentHeight:文本高度
Text {
id: txt
text: qsTr("text")
Component.onCompleted: {
console.log(contentHeight)
}
}
3、contentWidth:文本宽度
Text {
id: txt
text: qsTr("text")
Component.onCompleted: {
console.log(contentWidth)
}
}
4、elide:省略
Rectangle{
width: 50
height: 50
anchors.centerIn: parent
border.color: "black"
Text {
id: txt
width: 50
text: qsTr("2222222222222222222222")
anchors.fill: parent
elide: Text.ElideRight//只显示一部分文本,后续加省略号来使得文本不会越过父控件的范围
}
}
5、font
font.bold: true//粗体
font.family: "courier New"//字体
font.italic: true//斜体
font.letterSpacing: 20//字体之间的距离
font.pixelSize: 36//字体像素为单位
font.pointSize: 36//字体磅为单位
font.underline: true//下划线
6、lineCount:当前文本行数
Component.onCompleted: {
console.log(lineCount)//lineCount当前文本行数
}
7、lineHeight:文本间隔高度
lineHeight:1.5
Component.onCompleted: {
console.log(lineHeight)//lineHeight文本间隔高度
}
8、textFormat:文本格式
Column{
Text {
font.pointSize: 24
text: "<b>Hello</b> <i>world!</i>"//html
}
Text {
font.pointSize: 24
textFormat:Text.RichText//富文本形式
text: "<b>Hello</b> <i>world!</i>"
}
Text {
font.pointSize: 24
textFormat:Text.PlainText//纯文本
text: "<b>Hello</b> <i>world!</i>"
}
Text {
font.pointSize: 24
textFormat:Text.MarkdownText//Markdown语法**加粗*斜体
text: "**Hello** *world*"
}
}
9、wrapMode:换行
WordWrap:通过单词换行
Rectangle{
id:rect
width: 150
height:150
border.color: "black"//边框
Text {
id: txt
text: qsTr("text text text texttext text text text")
anchors.fill: parent
wrapMode: Text.WordWrap//通过单词判断当每行填满后换行输出
elide: Text.ElideRight
}
}
10、超链接
Text{
text: "See the <a href=\"http://qt-project.org\">Qt Project wedsite</a>."
onLinkActivated:{
console.log(link+" link activated")
}
onLinkHovered: {
console.log("hover",link)
}
onHoveredLinkChanged: {
console.log("hover link changed",hoveredLink)
}
}
}
LinkActivated信号:在点击超链接时触发
LinkHovered信号:在鼠标移到超链接上时触发,从超链接上一开始也触发
HoveredLinkChanged信号:在鼠标移到超链接上时触发
手指针样式:
cursorShape: Qt.PointingHandCursor
MouseArea{
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
Qt.openUrlExternally("http://qt-project.org")
}
}
十七、弹出窗口——popup
popup默认visible为false
popup的打开或关闭:
1、手动设置visible属性为true
2、通过open()或者close()
17.1、pupup的两个例外
1、qml中子控件是否显示都受到父控件的影响,但popup是个例外
Rectangle{
width: 200
height: 200
color: "red"
visible:false
Rectangle{
width: 150
height: 150
color: "black"
visible: true
}
Popup{
width: 50
height: 50
visible: true
}
}
2、popup的z顺序是一个例外,popup的z顺序只影响其他popup,而对于其他控件popup的z轴优先级最高,在z轴最上层
Rectangle{
width: 200
height: 200
color: "red"
}
Rectangle{
width: 100
height: 100
color: "blue"
}
Popup{
width: 50
height: 50
visible: true
z:-1
background: Rectangle{
color: "black"
}
}
Popup{
width: 20
height: 20
visible: true
z:1
background: Rectangle{
color: "white"
}
}
17.2、属性
1、closePolicy:关闭策略
默认带两个关闭策略:Popup.CloseOnEscape与Popup.CloseOnPressOutside点击外部与点击esc
不关闭可以使用Popup.NoAutoClose此时只能通过close进行关闭或将属性设置为隐藏
closePolicy: Popup.CloseOnEscape|Popup.CloseOnPressOutside
closePolicy: Popup.NoAutoClose
2、modal模态对话框
模态对话框:只有关闭当前对话框才能进行其他界面的操作
非模态对话框:不关闭当前对话框也可以对其他界面进行操作
modal:true//打开模态对话框
modal:false//打开非模态对话框
3、dim:控制除popup以外的背景颜色
如果是模态对话框则默认为深灰色,如果为非模态对话框则默认不显示,如果dim设置为true则可以看到背景色为浅灰色
dim:true
4、enter:设置打开逻辑
enter: Transition {
NumberAnimation{
property: "opacity"
from:0.0
to:1.0
duration: 1000
}
}
5、exit:设置关闭逻辑
exit:Transition {
NumberAnimation{
property:"opacity"//不透明度
from: 1.0
to:0.0
duration: 1000//1s
}
6、contentItem:popup的绘制
可根据想要的效果进行定制
contentItem: Rectangle{
anchors.fill: parent
Text {
id: txt
text: qsTr("Message Box area!!!")
font.pixelSize: 26
wrapMode: Text.WordWrap
}
Button{
anchors.bottom: parent.bottom
anchors.bottomMargin: 30
anchors.right: parent.right
anchors.rightMargin: 30
text: "ok"
}
Button{
anchors.bottom: parent.bottom
anchors.bottomMargin: 30
anchors.right: parent.right
anchors.rightMargin: 230
text: "close"
}
}
7、Overlay:附加属性
Overlay.modal:对应模态对话对话框
Overlay.modal: Rectangle{
anchors.fill: parent
color: "blue"
}
控制除模态对话框以外区域的背景色为蓝色
Overlay.modeless:对应非模态对话框
Overlay.modalless: Rectangle{
anchors.fill: parent
color: "blue"
}
控制除非模态对话框以外区域的背景色为蓝色
设置颜色
Overlay.modeless: Rectangle{
anchors.fill: parent
color: "red" //英语设置
color: "#FF0000"//十六进制
color: "#33000000" //RGBA
}
十八、重复组件——Repeater,ListView
18.1、属性
1、model:
如果是数字,表示有几个模型
Repeater{
//循环几次
model: 3//模型 数字的话表示有几个模型/控件
Button{
y:index*50
width:100;height:40
}
如果是数组形式,则表示可以通过modelData获取model中的数据
Repeater{
model: ["Button","Rectangel","MouseArea"]
Button{
y:index*50
width:100;height:40
text: modelData
}
listmodel:
Repeater{
id:rep
model: ListModel{
}
Button{
width: 100
height:50
text: name
}
}
将listmodel置为空,可以使用insert向listmodel中添加项,实现动态添加
Button{
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.bottomMargin: 20
onClicked: {
rep.model.insert(0,{"name":rep.model.count})
}
}
insert第一个参数为要添加的位置,第二个参数为listmodel需要的ListElement的类型
2、index:表示当前是第几个模型
3、count:表示总共有多少模型
4、delegate:控制每一项数据是如何绘制的
ListView{
width:180;height:200
model:3 //数字 控制了所有的数据
//model: ["Button","Rectangel","MouseArea"]
spacing:10//间隔
delegate: Button{//控制每一项数据是如何绘制的
text:modelData
}
}
4、ListModel:封装元素给delegate使用
model: ListModel{
ListElement{//list元素
name:"Bill Smith"
number:"555 3246"
myvalue:222
}
ListElement{
name:"john brown"
number:"555 8426"
myvalue:222
}
ListElement{
name:"sam wise"
number:"555 0475"
myvalue:222
}
}
spacing:10//间隔
delegate: Button{//控制每一项数据是如何绘制的
text:name+number+myvalue
}
5、highlight:高亮显示
model: ListModel{
ListElement{//list元素
name:"Bill Smith"
number:"555 3246"
myvalue:222
}
ListElement{
name:"john brown"
number:"555 8426"
myvalue:222
}
ListElement{
name:"sam wise"
number:"555 0475"
myvalue:222
}
}
spacing:10//间隔
highlight: Rectangle{
color: "lightblue"
radius: 5
}
delegate:Rectangle{
color: "transparent"//默认白色需要改为透明
width:list.width
height:50
Text {
id: txt
text: name
}
MouseArea{
anchors.fill: parent
onClicked:{
currentIndex=index
}
}
}
6、currentIndex:保存了当前项的值
7、flickableDirection:滑动回弹效果
默认是Flickable.AutoFlickDirection
- Flickable.HorizontalFlick——允许水平轻弹
- Flickable.VerticalFlick——允许垂直轻弹
- Flickable.HorizontalAndVerticalFlick——允许在两个方向上轻弹
- Flickable.AutoFlickDirection——如果contentHeight不等于Flickable的高度,则允许垂直轻弹。如果contentWidth不等于Flickable的宽度,则允许水平轻弹。
- Flickable.AutoFlickIfNeeded——如果contentHeight大于Flickable的高度,则允许垂直轻弹。如果contentWidth大于Flickable的宽度,则允许水平轻弹。
flickableDirection:Flickable.horizontalFilck
8、header与footer
如果想要在listview的上方与下方添加元素但不能影响listview时可以使用header与footer
Rectangle{
width: 300
height:200
border.color: "black"
ListView{
id:list
width:180;height:200
//model:3 //数字 控制了所有的数据
//model: ["Button","Rectangel","MouseArea"]
y:20
model: ListModel{
ListElement{//list元素
name:"Bill Smith"
number:"555 3246"
myvalue:222
}
ListElement{
name:"john brown"
number:"555 8426"
myvalue:222
}
ListElement{
name:"sam wise"
number:"555 0475"
myvalue:222
}
}
spacing:5//间隔
flickableDirection:Flickable.horizontalFilck
// delegate: Button{//控制每一项数据是如何绘制的
// text:name+number+myvalue
// }
highlight: Rectangle{
color: "lightblue"
radius: 5
}
delegate:Rectangle{
color: "transparent"//默认白色需要改为透明
width:list.width
height:50
Text {
id: txt
text: name
}
MouseArea{
anchors.fill: parent
onClicked:{
currentIndex=index
}
}
}
header: Rectangle{
width: 300
height:20
color: "red"
}
footer:Rectangle{
width: 300
height:20
color: "blue"
}
}
}
9、section:排列
Rectangle{
width: 300
height:200
border.color: "black"
Component {
id: sectionHeading
Rectangle {
width: container.width
height: childrenRect.height
color: "lightsteelblue"
required property string section
Text {
text: parent.section
font.bold: true
font.pixelSize: 20
}
}
}
ListView{
id:list
width:180;height:200
//model:3 //数字 控制了所有的数据
//model: ["Button","Rectangel","MouseArea"]
y:20
model: ListModel{
ListElement{//list元素
name:"Bill Smith"
number:"555 3246"
myvalue:1
}
ListElement{
name:"john brown"
number:"555 8426"
myvalue:2
}
ListElement{
name:"sam wise"
number:"555 0475"
myvalue:3
}
}
spacing:5//间隔
flickableDirection:Flickable.horizontalFilck
// delegate: Button{//控制每一项数据是如何绘制的
// text:name+number+myvalue
// }
highlight: Rectangle{
color: "lightblue"
radius: 5
}
delegate:Rectangle{
color: "transparent"//默认白色需要改为透明
width:list.width
height:50
Text {
id: txt
text: name
}
MouseArea{
anchors.fill: parent
onClicked:{
currentIndex=index
}
}
}
section.property: "myvalue"//根据哪个属性进行排列
section.criteria: ViewSection.FullString//FullString完整显示
//FirstCharacter只显示第一个字符
section.delegate: sectionHeading//控制每一个每一个标题行如何数值
}
}
- property: 根据哪个属性进行排列
- criteria:设置标题怎么显示
ViewSection.FullString完整显示
ViewSection.FirstCharacter只显示第一个字符
- delegate:控制每一个每一个标题行如何绘制
18.2、如何访问复杂组件的子控件
复杂组件内部控件的id是不能直接访问的
- Repeater
1、可以通过item的索引获取
Repeater{
id:rep
model:3
Button{
id:dtn
y:index*60
text: "button"+index
}
}
Button{
id:bt2
x:200
text:"click"
onClicked: {
for(var i=0;i<rep.count;i++)
{
console.log(rep.itemAt(i).text)
}
}
}
2、在布局当中可以直接通过子项的id来访问子项的属性
Column{
id:col
Button{
id:btn
text:"btn"
}
Text {
id: txt
text: qsTr("text")
}
Rectangle{
id:rec
width: 50
height: 50
color: "black"
}
}
Button{
id:btn2
x:100
onClicked: {
console.log(btn.text,txt.text,rec.height)
}
}
3、通过children+ instanceof +控件类型来访问子项
Column{
id:col
Repeater{
id:rep
model:3
Button{
id:dtn
text: "button"+index
}
}
Text {
id: txt
text: qsTr("text")
}
Rectangle{
id:rec
width: 50
height: 50
color: "black"
}
}
Button{
id:btn2
x:100
text:"bt2"
onClicked: {
//console.log(btn.text,txt.text,rec.height)
for(var i=0;i<col.children.length;i++)
{
if(col.children[i] instanceof Button)
{
console.log(col.children[i].text)
}
}
}
}
- ListView
ListView{
id:list
width: 100
height: 300
model: ["zhangsan","lisi","wangwu"]
delegate: Column{//绘制显示单个项
Text{
id:txt
text: modelData+"text"
}
Button{
id:btn
text: modelData+"btn"
}
}
}
Button{
id:btn2
x:100
text:"bt2"
onClicked: {
for(var i=0;i<list.contentItem.children.length;i++)
{
var col=list.contentItem.children[i]
for(var j=0;j<col.children.length;j++)
{
console.log(col.children[j])
}
}
}
}
当listview中delegate的是布局,那整个结构将会非常复杂,需要通过contentItem先获取listview的全部项,子项如果是布局将需要再通过children获取相应的子项
十九、下拉菜单——combobox
19.1、属性
1、model
如果是数字,表示有几个选项,如果是数组,则选项为数组内容
ComboBox{
model: 3
//model: ['asd','asf','qwer']
}
2、count:model的长度,表示有几个选项
3、editable:使当前控件可编辑
默认为false
editable: true
4、editText:当前文本
text:editText
5、currentText与currentValue:当前文本与值
onCurrentTextChanged: {
console.log("text",currentText)
}
onCurrentValueChanged: {
console.log("value",currentValue)
}
6、textRole与ValueRole:
对应了当前currentText与currentValue的值,可以手动对其进行修改
ComboBox{
textRole: "value"
valueRole: "name"
model: [
{value:100,text:qsTr("No modifier"),name:"zhangsan"},
{value:200,text:qsTr("Shift"),name:"lisi"},
{value:300,text:qsTr("Control"),name:"wangwu"}
]
}
7、displayText
控制combobox最上面显示的文本
displayText: currentText+" "+currentValue
8、validator:控制当前输入的上下限
top:控制当前输入上限
bottom:控制当前输入的下限
ComboBox{
model:10
editable: true
validator: IntValidator{
top: 20
bottom: 0
//regExp:/[0-9A-F]+[.][0-9]/
}
onAcceptableInputChanged: {
console.log(acceptableInput)
}
19.2、信号
1、Accepted:
按下回车键后触发
ComboBox{
editable: true
model: ListModel{
id:model
ListElement{
text:"111"
}
ListElement{
text:"222"
}
ListElement{
text:"333"
}
}
onAccepted: {
if(find(editText)===-1)
{
model.append({text:editText})
}
}
}
2、CurrentTextChanged与CurrentValueChanged
onCurrentTextChanged: {
console.log("text",currentText)
}
onCurrentValueChanged: {
console.log("value",currentValue)
}
3、acceptableInput
超出上下限会返回false,未超出返回true
onAcceptableInputChanged: {
console.log(acceptableInput)
}
19.3、补充
19.3.1、滑动窗体——SwipeView
可以添加多个页面,实现滑动效果
SwipeView {
id: view
currentIndex: 1
anchors.fill: parent
Item {
id: firstPage
Rectangle{
anchors.fill: parent
color: "blue"
}
}
Item {
id: secondPage
Rectangle{
anchors.fill: parent
color: "red"
}
}
Item {
id: thirdPage
Rectangle{
anchors.fill: parent
color: "green"
}
}
}
注意:SwipeView存在缺陷,如果不使用anchors.fill: parent填满父控件,那SwipeView便不可使用。为了解决该问题,可以使用lastView与ObjectModel实现该功能。
19.3.2、ObjectModel:
ObjectModel{
id:mymode
Rectangle{
width:400
height:500
color: "blue"
}
Rectangle{
width:400
height:500
color: "red"
}
Rectangle{
width:400
height:500
color: "green"
}
}
ListView{
anchors.left: btn.right
anchors.right: parent.right
height:500
model:mymode
orientation: ListView.Horizontal
snapMode: ListView.SnapOneItem
clip: true
//clip: false
}
Button{
id:btn
width: 200
height: 500
}
头文件:
import QtQml.Models 2.15
objectmodel默认是上下滑动
如果想要左右滑动可以使用
orientation: ListView.Horizontal
如果想要一次性滑动一个控件可以使用snapMode
snapMode: ListView.SnapOneItem
如果当子控件超出父控件,是否显示可以使用clip设置
clip: true//超出不绘制
clip: false//超出绘制
19.3.3、XmlListModel
1、创建一个xml文件
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
...
<channel>
<item>
<title>A blog post</title>
<pubDate>Sat, 07 Sep 2010 10:00:01 GMT</pubDate>
</item>
<item>
<title>Another blog post</title>
<pubDate>Sat, 07 Sep 2010 15:35:01 GMT</pubDate>
</item>
</channel>
</rss>
头文件
import QtQuick.XmlListModel 2.0
XmlListModel {
id: xmlModel
source: "/myXml.xml"//文件地址
query: "/rss/channel/item"//xml节点地址
XmlRole { //类似于listEmelents
name: "title";
query: "title/string()" }
XmlRole { name: "pubDate"; query: "pubDate/string()" }
}
ListView{
width:200
height: 500
model: xmlModel
delegate: Text {
text: title+":"+pubDate
}
}
19.3.4、FolderListModel
用于管理文件夹
头文件
mport Qt.labs.folderlistmodel 2.15
ListView {
width: 200; height: 400
FolderListModel {//能够检查某一路径下的文件
id: folderModel
nameFilters: ["*qml"]
folder: "file:///D:\\360\\qml"//直接设置文件夹地址时前面必须加上file:///
showDirs: false//默认为true,默认输出文件夹
}
//数据与绘制
model: folderModel//model负责数据
delegate: Text{//delegate负责绘制
text: fileName
}
}
19.3.4.1属性
1、caseSensitive:是否匹配大小写
2、count:输出个数
3、folder:设置想要看哪一个文件夹下的文件,注意直接设置文件夹地址时前面必须加上file:///
4、showDirs: false//默认为true,默认输出显示文件夹,并且nameFilters无法guolv
5、nameFilters:过滤
6、parentFolder:显示父文件
7、showDirsFirst:先显示文件夹
8、showFiles:默认显示文件,如果改为false就只显示文件夹
9、showHidden:显示隐藏文件
10、showOnlyReadable:显示只读文件
11、sortCaseSensitive:根据大小写排序
19.4自定义combobox
ComboBox {
id: control
model: ["First", "Second", "Third"] // 数据模型,定义了下拉列表中的选项
// 自定义每一个下拉项的外观和行为
delegate: ItemDelegate { // 针对model中每一项的具体绘制
width: control.width // 委托项的宽度与ComboBox的宽度一致
contentItem: Text {
text: modelData // 显示模型数据(即选项文本)
color: "red" // 文本颜色设置为红色
font: control.font // 使用ComboBox的字体设置
elide: Text.ElideRight // 文本过长时在右侧显示省略号
verticalAlignment: Text.AlignVCenter // 文本垂直居中对齐
}
highlighted: control.highlightedIndex === index // 如果当前项被高亮,则为true
}
// 定义ComboBox控件主体的内容
contentItem: Text {
leftPadding: 0 // 设置元素内部内容相对于其左边界的内边距
rightPadding: control.indicator.width + control.spacing // 设置元素内部内容相对于其右边界的内边距,留出空间给指示器
text: control.displayText // 显示当前选中的文本
font: control.font // 字体使用ComboBox的设置
color: control.pressed ? "#17a81a" : "#21be2b" // 根据是否被按下改变文本颜色
verticalAlignment: Text.AlignVCenter // 垂直居中对齐文本
elide: Text.ElideRight // 文本过长时在右侧显示省略号
}
// ComboBox背景设置
background: Rectangle {
implicitWidth: 120 // 默认宽度
implicitHeight: 40 // 默认高度
border.color: control.pressed ? "#17a81a" : "#21be2b" // 根据是否被按下改变边框颜色
border.width: control.visualFocus ? 2 : 1 // 当ComboBox获得视觉焦点时边框宽度加粗
radius: 2 // 边框圆角半径
}
// 定义弹出的下拉列表
popup: Popup { // 与delegate的区别在于,delegate绘制单个项,而popup绘制整个下拉列表
y: control.height - 1 // 下拉列表的位置,紧贴ComboBox底部
width: control.width // 下拉列表的宽度与ComboBox一致
implicitHeight: contentItem.implicitHeight // 高度根据内容自动调整
padding: 1 // 内边距
contentItem: ListView {
clip: true // 裁剪超出ListView边界的内容
implicitHeight: contentHeight // 高度根据内容自动调整
model: control.popup.visible ? control.delegateModel : null // 只有当popup可见时才设置模型
currentIndex: control.highlightedIndex // 设置当前高亮的项
interactive: true // 允许通过鼠标进行交互
boundsBehavior: Flickable.StopAtBounds // 拖动到边界时停止
ScrollBar.vertical: ScrollBar { // 垂直滚动条
policy: ScrollBar.AlwaysOn // 滚动条始终显示
}
}
background: Rectangle {
border.color: "#21be2b" // 边框颜色
radius: 2 // 边框圆角半径
layer.enabled: true // 启用图层效果,以显示阴影
layer.effect: DropShadow{//设置下拉列表中的阴影效果
horizontalOffset: 2
verticalOffset: 3//控制纵向偏移
radius: 8.0 //模糊效果
samples: 17 //控制具体点的绘制数量
color: "#80000000"
}
}
}
}
二十、焦点——focus
20.1、FocusScope
在QML中是一个非常有用的组件,它定义了一个焦点区域,可以控制键盘焦点在其内部的子元素之间如何传递
作用:
-
焦点管理:FocusScope允许你创建一个界面区域,在该区域内部,焦点可以自由移动,但不会移出到其他焦点区域。这对于创建模块化UI组件非常有用,每个组件有自己的焦点管理逻辑。
-
键盘导航:在使用键盘输入的应用程序中,如桌面应用,FocusScope可以改善用户的键盘导航体验,使用户可以通过键盘如Tab键在特定区域内的元素间切换焦点。
-
模态对话框和表单:在模态对话框或表单中,使用FocusScope可以确保用户的焦点仅限于该对话框或表单内的元素,提升用户体验。
注:后构造完成的获取焦点,下方代码构造时先构造rect1再构造rect
FocusScope{
id:rect
width: 200
height: 100
focus: true
Button{
id:btn1
focusPolicy:"NoFocus"
anchors.fill: parent
background: Rectangle{
anchors.fill: parent
color: btn1.activeFocus?"red":"blue"
}
onClicked: {
btn1.forceActiveFocus()//获取焦点
}
}
}
FocusScope{
id:rect1
y:200
width: 200
height: 100
Text {
id: txt1
focus: true
text: qsTr("rect2 focus "+txt1.focus+" activeFoucs "+txt1.activeFocus)
}
Button{
id:btn2
anchors.fill: parent
focusPolicy:"NoFocus"
background: Rectangle{
anchors.fill: parent
color: btn2.activeFocus?"red":"blue"
}
onClicked: {
btn2.forceActiveFocus()
}
}
}
focus: true:指定一个元素应该获得焦点
通过focus: true可以使得两个不同的控件都能获取焦点,但实际活动焦点activeFocus只有一个在后构造的控件上,可以使用focusPolicy:"NoFocus"设置不获取焦点,当需要获取焦点时可以通过forceActiveFocus()获取
20.2、ActiveFocusItem:
可以通过ActiveFocusItem查看当前获取焦点的控件
onActiveFocusChanged: {
console.log("activeFocus",activeFocusItem)
}
二十一、信号与槽
qml端
21.1、自定义信号
//发送信号
signal testSig(string s,int value)//自定义一个信号
Button{
width: 50
height:50
onClicked: {
testSig("zhangsan: ","1")//按钮按下后触发信号
}
}
//接收信号
//方法1——不常用
function func(ss,ii){//自定义一个函数
console.log(ss,ii)
}
Component.onCompleted: {
testSig.connect(func)//func不可以带括号,使用connect调用信号触发后调用的函数
}
//方法2——不常用
Connections{//使用自带的Connections
target:window
onTestSig:{//on后面的信号名首字母必须大写
console.log(s,value)
}
}
//方法3
Connections{
target:window
function onTestSig(str,iValue)//on后面的信号名首字母必须大写
{
console.log(str,iValue)
}
}
21.2、自定义组件与信号槽的使用
main.qml
Component{
id:com
Button{
id:btn
background: Rectangle{
anchors.fill: parent
border.color: btn.activeFocus?"red":"blue"
}
signal leftBtnPressed()
Keys.onLeftPressed: {//键盘左键
leftBtnPressed()
}
}
}
MyComponent{//调用新建的qml文件
com1: com
com2: com
}
创建一个组件,自定义一个信号leftBtnPressed(),当按下键盘左键时触发
MyComponent.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.5
Rectangle{
width: 400
height: 300
property Component com1
property Component com2
border.color: "red"
Loader{
id:load1
sourceComponent: com1
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.right: parent.right
anchors.rightMargin: 20
Connections{
target: load1.item
ignoreUnknownSignals: true//确保只有信号槽而没有信号时不会报错
function onLeftBtnPressed(){
load2.item.focus=true
load2.item.forceActiveFocus()
}
}
Component.onCompleted: {
load1.item.focus=true
load1.item.forceActiveFocus()
}
}
Loader{
id:load2
sourceComponent: com2
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.right: parent.right
anchors.rightMargin: 150
Connections{
target: load2.item
ignoreUnknownSignals: true
function onBtnSig(value)
{
console.log(value)
}
function onLeftBtnPressed(){
load2.item.focus=true
}
}
}
}
通过connections接受信号,当信号接收后焦点转移
二十二、QML与C++交互
22.1、QML与C++交互基础
MVC设计结构:是一种软件架构模式,旨在分离应用程序的数据层(Model)、用户界面层(View)和业务逻辑层(Controller),以实现关注点分离。这种分离使得应用程序的开发、维护和扩展变得更加容易和高效。MVC模式主要用于Web应用程序和桌面GUI应用程序的开发中。
22.1.1、全局对象——engine
main.cpp
#include <QQmlContext>
#include <QScreen>
//全局对象,所有qml中都可使用
QQmlApplicationEngine engine;
QQmlContext *context=engine.rootContext();
//获取当前窗口的大小
QScreen *screen=QGuiApplication::primaryScreen();
QRect rect=screen->virtualGeometry();
context->setContextProperty("SCREEN_WIDTH",rect.width());//SCREEN_WIDTH便是值为
//rect.width()的全局对象
main.qml
Window {
id:window
width: SCREEN_WIDTH //宽,使用全局变量设置宽度
height: 500 //高
visible: true //可见性
title: qsTr("Hello World") //标题
}
22.1.2、QtObject
1、qml:
main.qml
MyRectangel{
Component.onCompleted: {
attr.myvalue=200
console.log("22 "+attr.myvalue)
}
}
MyRectangel.qml
Rectangle{
width: 200
height:100
property alias attr:attributes//起别名
QtObject{//私有化
id:attributes
property int myvalue:0
}
Component.onCompleted: {
console.log("11 "+attributes.myvalue)
}
}
2、自定义一个Object
创建一个继承自QObject的c++类
添加头文件
include <QtQml>
在Q_OBJECT下方添加宏QML_ELEMENT,用于声明为qml可以访问的元素
myqobject.h
class MyQObject : public QObject
{
Q_OBJECT
QML_ELEMENT
public:
}
此时可以将需要与qml访问设置的值做定义
例:
myqobject.h
int value;
QString mystring;
定义完成后按下ALT+回车选择第一个
此时将会自动生成一系列用于返回数据的函数并添加了一个宏
myqobject.h
Q_PROPERTY(int value READ getValue WRITE setValue NOTIFY valueChanged FINAL)
- int value:定义名
- READ 设置通过哪个函数读值
- WRITE 设置通过哪个函数修改值
- NOTIFY 数值改变时发出信号
通过static创建类的对象
myqobject.h
static MyQObject* getInstance();
myqobject.cpp
MyQObject *MyQObject::getInstance()
{
static MyQObject *obj=new MyQObject;
return obj;
}
使用qmlRegisterType方法
main.cpp
qmlRegisterType<MyQObject>("MyObj",1,0,"MyQObject");
MyObj:名称
1:主版本号
0:子版本号
MyQObject:模块名
main.qml
import MyObj 1.0
MyQObject{
id:myobj
value: 10
mystring:"aaa";
}
22.2、QML 端与C++端的信号传输
22.2.1、在qml端直接调用c++端的函数
在函数名前使用宏Q_INVOKABLE
myqobject.h
Q_INVOKABLE void functext();
myqobject.cpp
void MyQObject::functext()
{
qDebug()<<"111";
}
main.qml
Button{
onClicked: {
myobj.functext()
}
}
22.2.2、信号与槽
22.2.2.1、qml端发送信号,C++端接收
- 在qml端绑定
main.qml
signal qmlSig(QVariant i,QVariant s)//在qml端定义信号
Button{
onClicked: {
qmlSig(10,"zhangsan")//按下按钮后发送信号
}
}
myqobject.h
public slots:
void cppSlot(QVariant i,QVariant s);
myqobject.cpp
void MyQObject::cppSlot(QVariant i, QVariant s)
{
qDebug()<<i<<" "<<s;
}
qml端绑定有两种方法
方法一:
main.qml
Connections{
target: window
function onQmlSig(i,s)
{
myobj.cppSlot(i,s)
}
}
方法二:
main.qml
Component.onCompleted: {
qmlSig.connect(myobj.cppSlot)
}
- 在C++端绑定
1、一定在engin加载完成以后,使用rootObjects返回qml文件的所有对象
main.cpp
#include <QObject>
//engine加载完后,load以后
auto list=engine.rootObjects();
auto obname=list.first();
//通过QObject的connect
QObject::connect(obname,SIGNAL(qmlSig(QVariant,QVariant))
,MyQObject::getInstance(),SLOT(cppSlot(QVariant,QVariant)));
// auto obname=list.first()->findChild<QObject *>("mybtn");
// qDebug()<<obname;
22.2.2.2、C++端发送信号,qml端接收
在qml中设置一个函数
main.qml
function qmlSlot(i,s)//参数类型对应CPP端的都是QVariant类型
{
console.log("qml ",i,s)
}
定义一个信号
myqobject.h
void cppSig(int,QString);
链接信号
- 在qml端绑定
main.qml
Button{
objectName: "mybtn"
onClicked: {
myobj.cppSig(99,"lisi")
}
}
Connections{
target: myobj
function onCppSig(i,s)
{
qmlSlot(i,s)
}
}
- 在C++端绑定
注: 上述代码中的关于myqobject的示例可以不用单独创建,可以使用qmlRegisterSingletonInstance
qmlRegisterSingletonInstance("MyObj",1,0,"MyQObject",MyQObject::getInstance());
后续中可以使用"MyQObject"直接调用c++中的函数而不需要特意声明定义
Button{
objectName: "mybtn"
onClicked: {
MyQObject.functext()//直接使用MyQObject调用函数
}
}
//MyQObject{//不需要此步骤
// id:myobj
//}
补充:
在c++端直接调用qml中的函数
在qml文件中定义一个函数
main.qml
function qmlFunc(i , s){
return "success"
}
通过QMetaObject::invokeMethod调用
QVariant res;
QVariant arg1=123;
QVariant arg2="zhangsan";
QMetaObject::invokeMethod(obname,//调用的对象
"qmlFunc",//调用的函数名称
Q_RETURN_ARG(QVariant,res),//通过Q_RETURN_ARG将返回值存在res中
Q_ARG(QVariant,arg1),//参数1
Q_ARG(QVariant,arg2));//参数二
qDebug()<<"res="<<res;
二十三、布局——Layout
23.1、纵向——Column
Column {
id:col
spacing: 10
Repeater{
id:rep
model: ListModel{
}
Button{
width: 100
height:50
text: name
}
}
add:Transition {
NumberAnimation{properties: "x,y";easing.type: Easing.OutBounce}
}
move:Transition {
NumberAnimation{properties: "x,y";easing.type: Easing.OutBounce}
}
populate:Transition {
NumberAnimation{properties: "x,y";from:200;duration: 100;easing.type: Easing.OutBounce}
}
}
Button{
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.bottomMargin: 20
onClicked: {
rep.model.insert(0,{"name":rep.model.count})
}
}
23.1.1、属性
- add:Transition:用于指定当有新的元素添加到视图或组件中时应该播放的动画
add:Transition {
NumberAnimation{properties: "x,y";easing.type: Easing.OutBounce}
}
- move:Transition:用于定义当元素在视图中移动时的动画效果
move:Transition {
NumberAnimation{properties: "x,y";easing.type: Easing.OutBounce}
}
- populate:Transition:用于定义当一个视图或组件被“填充”时的动画效果。
populate:Transition {
NumberAnimation{properties: "x,y";from:200;duration: 100;easing.type: Easing.OutBounce}
}
- spacing:控件之间的间隔
- 以下为控制绘制的控件与布局元素(如column)的距离
- Leftpadding:左
- bottomPadding:下
- rightPadding:右
- topPadding:上
23.2、横向——Row
23.2.1、属性
除effecticeLayoutDirection与layoutDirection外其余与column相同
- effecticeLayoutDirection:获取layoutDirection控制的方向
0:从左往右
1:从右往左
- layoutDirection:控制绘制方向
layoutDirection: Qt.RightToLeft//从右往左
layoutDirection: Qt.LeftToRight//从左往右(默认)
23.3、自动换行——Flow
Rectangle{
width:200
height:300
Flow {
anchors.fill: parent
anchors.margins: 4
spacing: 10
Text { text: "Text"; font.pixelSize: 40 }
Text { text: "items"; font.pixelSize: 40 }
Text { text: "flowing"; font.pixelSize: 40 }
Text { text: "inside"; font.pixelSize: 40 }
Text { text: "a"; font.pixelSize: 40 }
Text { text: "Flow"; font.pixelSize: 40 }
Text { text: "item"; font.pixelSize: 40 }
}
}
23.3.1、属性
属性与前面基本相同,唯一多了flow
- flow:控制绘制方向
flow: Flow.TopToBottom//从上到下
flow: Flow.LeftToRight//从左往右
二十四、手动控制的行列——Grid
Grid {
columns: 1//默认值为4
spacing: 2
Rectangle { color: "red"; width: 50; height: 50 }
Rectangle { color: "green"; width: 20; height: 50 }
Rectangle { color: "blue"; width: 50; height: 20 }
Rectangle { color: "cyan"; width: 50; height: 50 }
Rectangle { color: "magenta"; width: 10; height: 10 }
}
24.1、属性
除了rows与columns,其余与上面相同
- rows:网格中的行数,如果网格中没有足够的项目来填充指定的行数,则某些行的宽度将为零。
- columns:网格中的列数,如果网格中没有足够的项目来填充指定数量的列,则某些列的宽度将为零。
columns: 3
rows: 5
24.2、自定义Grid与OpacityMask
Grid{
id:grid
x:100
y:100
width: 15
height: 200
columns: 3
Repeater{
model:grid.width/5*grid.height/5
Rectangle{
width: 5
height: 5
color:index%2?"black":"white"
}
}
}
此时如果需要将整体边框设置为圆角直接通过radius会使绘制的所有矩形都为圆角不符合要求,所以需要使用OpacityMask
导入文件
import QtGraphicalEffects 1.15
功能:OpacityMask可以实现按照A的形状添加B的内容
Rectangle{
id:maskrect
x:200
y:100
width: grid.width
height:grid.height
radius: 10
visible: false
border.color: "red"
}
OpacityMask{//按照maskrect的形状绘制grid的内容
source: grid
maskSource: maskrect
anchors.fill: maskrect
}
maskrect只需要它的形状,实际是通过OpacityMask绘制
添加圆角边框可以将OpacityMask放在一个rectangel中
Grid{
id:grid
x:100
y:100
width: 15
height: 200
columns: 3
visible: false
Repeater{
model:grid.width/5*200/5
Rectangle{
width: 5
height: 5
color:index%2?"black":"white"
}
}
}
Rectangle{
id:maskrect
x:200
y:100
width: grid.width
height:grid.height
radius: 10
visible: false
border.color: "red"
}
Button{
width: 50
height: 50
x:50
y:50
onClicked: {
grid.height-=10
}
}
Rectangle{
width: grid.width+4
height: grid.height+4
radius: 10
border.color: "red"
border.width: 3
anchors.bottom: parent.botton
anchors.horizontalCenter: parent.horizontalCenter
OpacityMask{
// width: maskrect.width
// height: maskrect.height
source: grid
maskSource: maskrect
anchors.fill: parent
anchors.margins: 2
}
}
OpacityMask显示在rectangel上层,而且无法通过z更改顺序,通过调整像素大小可以实现边框显示
二十五、计时器——Timer
property int time: 0
Timer{//默认不启动
id:tim
interval: 1000//1s
running: true//启动
repeat: true//不断触发
triggeredOnStart: true//使计时器在开始计时时触发一次
onTriggered: {
time+=1
}
}
Text {
id: txt
text: time
font.pixelSize: 68//字体大小
anchors.centerIn: parent//置于屏幕中间
}
Button{
id:btn
onClicked: {
// tim.start()//停止计时器
// tim.stop()//开启计时器,已开启便没有效果
tim.restart()//重启计时器,假设1秒,当1s没有到达时点击,便重新计时,但已经跑完的不会重置
}
}
25.1、属性
1、interval:设置触发间隔
interval: 1000//1s
2、running:启动计时器
默认为fasle,需要手动启动
running: true//启动
3、repeat:设置不断触发计时
默认为fasle
repeat: true//不断触发
4、triggeredOnStart:使计时器在开始计时时触发一次
默认为true
triggeredOnStart: true//使计时器在开始计时时触发一次
25.2、函数
- restart
重启计时器,假设1秒,当1s没有到达时点击,便重新计时,但已经跑完的不会重置
tim.restart()
- start
开启计时器,已开启便没有效果
tim.start()
- stop
停止计时器
tim.stop()
二十六、自定义Model
由于repeater、listview、tableview需要设置model但直接使用数字、数组、listmodel一般无法满足动态更改等需求所以需要自定义的Model
新建
这里以listmodel为例
在QAbstractListModel中将virtual QHash<int,QByteArray> roleNames() const;复制出来重写
需要重写这三个函数来实现model的自定义
int MyListModel::rowCount(const QModelIndex &parent) const
作用:返回数据的个数
QHash<int, QByteArray> MyListModel::roleNames() const
int:映射当前需要显示的数据的枚举类型
QByteArray:在qml端使用的名
作用:映射
QVariant MyListModel::data(const QModelIndex &index, int role) const
创建实例
MyListModel.h
static MyListModel* getInstance();
MyListModel.cpp
MyListModel *MyListModel::getInstance()
{
static MyListModel *obj=new MyListModel;
return obj;
}
定义
MyListView.h
enum MyRoleName{
Name=Qt::DisplayRole+1,//Qt::DisplayRole为qt默认的枚举
Value
};
class MyData{
public:
MyData(QString s,int v):m_string(s),m_value(v){};
QString m_string;
int m_value;
};
QList<MyData> m_data
MyListView.cpp
//添加数据
m_data.append(MyData("zhangsan",111));
m_data.append(MyData("lisi",222));
m_data.append(MyData("wangwu",333));
m_data.append(MyData("maliu",444));
创建哈希的类型并
MyListView.cpp
QHash<int, QByteArray> MyListModel::roleNames() const
{
QHash<int,QByteArray>roles;
roles.insert(MyRoleName::Name,"name");//字符串是qml端用
roles.insert(MyRoleName::Value,"value");//枚举是c++端来判断
return roles;
}
判断
MyListView.cpp
QVariant MyListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if(role==MyRoleName::Name)
{
return m_data[index.row()].m_string;
}
else if(role==MyRoleName::Value)
{
return m_data[index.row()].m_value;
}
return QVariant();
}
注册
main.cpp
//在QUrl加载之前
qmlRegisterSingletonInstance("MyModel",1,0,"MyListModel",MyListModel::getInstance());
使用该自定义的model
main.qml
import MyModel 1.0
ListView{
width: 200
height: 300
model: MyListModel
delegate: Text {
id: txt
text: name+" "+value
}
}
二十七、图表视图——chartView
导入文件
import QtCharts 2.15
27.1、饼状图——PieSeries
创建图表
例:创建饼状图
Button{
width: 50
height: 50
z:1
onClicked: {
var slice=chart.createSeries(ChartView.SeriesTypePie,"mypie")
slice.append("pie",50)
slice.append("pi2",100)
}
}
createSeries:创建图表,具有四个参数
参数1:绘制图表类型,如饼状图
参数2:名称
参数3:X坐标系
参数4:Y坐标系
ChartView {
id: chart
title: "Top-5 car brand shares in Finland"
anchors.fill: parent
legend.alignment: Qt.AlignBottom
antialiasing: true//抗锯齿
PieSeries {
id: pieSeries
PieSlice { label: "Volkswagen"; value: 13.5 }
PieSlice { label: "Toyota"; value: 10.9 }
PieSlice { label: "Ford"; value: 8.6 }
PieSlice { label: "Skoda"; value: 8.2 }
PieSlice { label: "Volvo"; value: 6.8 }
}
}
legand:显示图表的图标
antialiasing: 抗锯齿,默认为fasle
PieSeries:绘制饼状图的主控件
PieSlice:绘制的线条
label:默认不显示,可以通过labelVisible设置为true使其显示出来
27.1.1、PieSlice属性
1、angleSpan——当前绘制饼状图所占角度
2、border:边框
borderColor: "red"//颜色
borderWidth: 2//空隙,默认为1
3、exploded:远离当前的饼状图,默认为false
4、explodeDistanceFactor:远离的距离
5、labelArmLengthFactor:控制label距离饼状图的距离
6、labelPosition:控制label在饼状图中的位置,默认为LabelOutside
- labelPosition: PieSlice.LabelOutside//饼状图外侧
- labelPosition: PieSlice.LabelInsideHorizontal//横向内置在饼状图中
- labelPosition: PieSlice.LabelInsideTangential//竖向内置在饼状图中
- labelPosition: PieSlice.LabelInsideNormal//内置在饼状图中但位置会自动调整
7、startAngel:起始角度,默认为360度,只读
8、value:设置value值,根据value值自动计算比例,总和占比是100%,如果不额外设置,总和的角度为360度
27.1.2、PieSeries属性
1、count:饼状图中PieSlice的个数
2、size:放缩,默认为0.7倍
3、startAngel:设置起始位置
4、endAngel:设置结束位置
5、horizontalPosition:饼状图的具体位置,默认是0.5
6、sum:整个图表的value值的总和
7、append:添加图表,有两个参数
参数1:label
参数2:value值
Button{
width: 50
height: 50
z:1
onClicked: {
var slice=pieSeries.append("mySlice",50)
slice.labelVisible=true
slice.borderColor="blue"
}
}
8、at:访问某个PieSlice
pieSeries.at(0).exploded=true
9、clear:清空
27.2、折线图——LineSeries
动态创建折线图
property var linePoints: [[0,0,10,10,20,20,30,30,40,40,50,50],[0,0,10,40,20,25,40,50,50,10]]
Button{
width: 50
height: 50
z:1
onClicked: {
for(var j=0;j<linePoints.length;j++)
{
var line=chart.createSeries(ChartView.SeriesTypeLine,"mypline",xAxis,yAxis)
var points=linePoints[j]
for(var i=0;i<points.length;i+=2)
{
line.append(points[i],points[i+1])
}
}
}
}
ChartView {
id: chart
title: "Line"
anchors.fill: parent
antialiasing: true
ValueAxis{
id: xAxis
min:0
max:50
}
ValueAxis{
id: yAxis
min:0
max:50
minorTickCount: 5//间隔虚线数量
}
}
在LineSeries中append的两个参数分别为X轴坐标点的位置与y轴坐标点的位置
ValueAxis:用于设置横轴与纵轴的长度
注意:可以通过ChartView.SeriesTypeSpline绘制曲线,数据添加方法与折线图一致
27.2.1、属性
1、count:点的数量
2、width:线条的宽度
3、style:风格
line.style=Qt.DotLine
27.3、填充型图表——AreaSeries
ChartView {
id:chartview
title: "Line"
anchors.fill: parent
antialiasing: true
LineSeries {
id:line1
color: "blue"
name: "LineSeries"
XYPoint { x: 0; y: 0 }
XYPoint { x: 1.1; y: 2.1 }
XYPoint { x: 1.9; y: 3.3 }
XYPoint { x: 2.1; y: 2.1 }
XYPoint { x: 2.9; y: 4.9 }
XYPoint { x: 3.4; y: 3.0 }
XYPoint { x: 4.1; y: 3.3 }
}
LineSeries {
id:line2
color: "red"
name: "LineSeries"
XYPoint { x: 0; y: 0 }
XYPoint { x: 1.1; y: 1.1 }
XYPoint { x: 1.9; y: 2.3 }
XYPoint { x: 2.1; y: 1.1 }
XYPoint { x: 2.9; y: 3.9 }
XYPoint { x: 3.4; y: 2.0 }
XYPoint { x: 4.1; y: 2.3 }
}
}
Component.onCompleted: {
var area=chartview.createSeries(ChartView.SeriesTypeArea,"seri")
area.upperSeries=line1//上限
area.lowerSeries=line2//下限
area.opacity=0.3
area.color="yellow"
}
ChartView.SeriesTypeArea:绘制填充型图表
注意上下限并不是严格意义上的上下限,而是指定两个线条,AreaSeries会在两个线条之间进行填充
27.4、柱形图——BarSeries
Component.onCompleted: {
var barseries=chartview.createSeries(ChartView.SeriesTypeBar,"myBar",barX,barY)
barseries.append("mybar",[0,0.1,0.2,0.3,0.4,0.5])
}
ChartView {
id:chartview
title: "Bar series"
anchors.fill: parent
legend.alignment: Qt.AlignBottom
antialiasing: true
BarCategoryAxis{
id:barX
categories: ["2007", "2008", "2009", "2010", "2011" ]
}
ValueAxis{
id:barY
min: 0
max: 2
}
}
ChartView.SeriesTypeBar:用与绘制柱形图
二十八、动画效果Glow与发射器Emitter
28.1、 Glow
头文件
import QtGraphicalEffects 1.15
color: "grey"
Text {
id: txt
text: qsTr("Watting")
font.pixelSize: 70
anchors.centerIn: parent
}
Glow {
id:glow
anchors.fill: txt
radius: 10
samples: 17
color: "white"
source: txt//设置要执行动画的资源
SequentialAnimation{//队列的动画效果
running: true//运行动画
loops: Animation.Infinite//无限运行动画
NumberAnimation{
target: glow
property: "spread"
to:0
duration: 1000//持续时间1s
}
NumberAnimation{
target: glow
property: "spread"
to:0.5
duration: 1000
}
}
}
上述代码可以看到字体外围闪动效果
28.2、Emitter
头文件
import QtQuick.Particles 2.15
ParticleSystem{//粒子效果的系统
id:part
}
Emitter{//发射器,需要指定系统
id:emit
anchors.centerIn: parent
width: 300
height: 300
system: part//指定系统
emitRate: 10//发射粒子的速度
lifeSpan: 600//发射粒子的生命周期
lifeSpanVariation: 400//每个粒子的间隔时间
size: 60//大小
velocity: PointDirection{//控制粒子移动的方向
x:45
}
}
ImageParticle{
id:img
source: "/1.jpeg"
system: part
color: Qt.rgba(153/255,217/255,234/255,1.0)
colorVariation: 0.3//根据color随机修改颜色
}
Attractor:控制当前特效的控件
ParticleSystem{//粒子效果的系统
id:part
}
Emitter{//发射器,需要指定系统
id:emit
anchors.centerIn: parent
width: 300
height: 300
system: part//指定系统
emitRate: 10//发射粒子的速度
lifeSpan: 600//发射粒子的生命周期
lifeSpanVariation: 400//每个粒子的间隔时间
size: 60//大小
velocity: PointDirection{//控制粒子移动的方向
x:45
}
}
ImageParticle{
id:img
source: "/1.jpeg"
system: part
color: Qt.rgba(153/255,217/255,234/255,1.0)
colorVariation: 0.3//根据color随机修改颜色
}
MouseArea{
id:mouse
anchors.fill: parent
hoverEnabled: true
}
Attractor{//
anchors.fill: parent
enabled: true
system:part
pointX: mouse.mouseX
pointY: mouse.mouseY
strength: -10000000//粒子被吸引的强度,正值为吸引,负值为排斥
affectedParameter: Attractor.Position//效果
proportionalToDistance: Attractor.InverseQuadratic//有弧度的弹飞效果
}
二十九、Settings
头文件
import Qt.labs.settings 1.0
main.cpp
app.setOrganizationName("myApp");
使用settings需要通过setOrganizationName为QApplication app设置一个名称
Settings{
id:settings
//设置配置文件地址
fileName: "D:\\360\\qml\\setting.ini"
//注意:不能够使用qml类型,只能用下面的类型
property int iData: 0
property double iDouble: 1.23
property string istring: "my string"
property var iVar: [1,2,3,4,5,"text"]
category: "other"//新建分组
}
Text {
id: txt
text: settings.iData
font.pixelSize: 40
}
Button{
x:100
onClicked: {
// console.log(settings.value("iData",0))//通过value进行值的访问
settings.setValue("myvalue",4)//添加项与值
}
}
fileName:设置配置文件地址
category:新建分组
value:通过value进行值的访问
setValue:项配置文件中添加项与值
三十、states与transitions动画效果制作
30.1、states
类似于switch,可以使用state通过name调用不同的状态
Rectangle{
id:root
height: 100
width: 100
color: "blue"
state: "normal"
states: [
State {
name: "normal"
PropertyChanges {
target:root;
color: "black"}
},
State {
name: "state1"
PropertyChanges {
target:root;color: "red";
width:200
}
},
State {
name: "state2"
PropertyChanges {
target:root;color: "blue";
height:200
}
}
]
MouseArea {//鼠标
anchors.fill:parent
onPressed: {//鼠标按下
root.state="state1"
}
onReleased: {//鼠标送开
root.state="state2"
}
}
}
30.2、Animation and Transition动画效果
- 方法一:通过动作手动开启动画
Rectangle{
id:ant
width:100
height: 100
color: "blue"
opacity: 1.0//不透明度
MouseArea{
anchors.fill: parent
onClicked: {
animateColor.start()//start为开启动画
animateOpacity.start()
animatewidth.start()
}
}
PropertyAnimation{//属性动画
id:animateColor
target: ant
properties: "color"
to:"green"
duration: 1000//持续时间
}
NumberAnimation{//数值动画
id:animateOpacity
target: ant
//使透明度从0.1在两秒时间内变成1.0
properties: "opacity"
from:0.1
to:1.0
duration: 2000
}
NumberAnimation{
id:animatewidth
target: ant
properties: "width"
from:100
to:200
duration: 2000
}
}
start:开启动画
PropertyAnimation:属性动画
NumberAnimation:数值动画
- 方法二:通过PropertyAnimation on+属性值,直接修改属性
Rectangle{
id:rect
width:100
height:100
color: "red"
PropertyAnimation on x{
to:100
duration: 1000
}
PropertyAnimation on y{
to:100
duration: 1000
}
//控制颜色
ColorAnimation on color {
to: "black"
duration: 2000
}
//队列顺序执行动画
SequentialAnimation on color {
ColorAnimation {
to: "yellow"
duration: 1000
}
ColorAnimation {
to: "blue"
duration: 1000
}
}
}
on会导致立即触发动画
SequentialAnimation:可以顺序的执行动画
- 方法三:通过states与transitions实现过渡动画效果
如果没有transitions,将会直接出现颜色变化,加入transitions后,添加过渡动画效果
Rectangle{
id:rect
width: 100
height: 100
state: "state1"
MouseArea{
anchors.fill: parent
onPressed: rect.state="state1"
onReleased: rect.state="state2"
}
states: [
State {
name: "name"
PropertyChanges {
target: object
}
},
State {
name: "state1"
PropertyChanges {
target: rect;
color:"lightblue"
}
},
State {
name: "state2"
PropertyChanges {
target: rect;
color:"lightsteelblue"
}
}
]
transitions: [
Transition {
from: "state1"
to: "state2"
ColorAnimation {
target: rect
duration: 2000
}
},
Transition {
from: "state2"
to: "state1"
ColorAnimation {
target: rect
duration: 2000
}
}
]
}
- 方法四:Behavior行为动画
Rectangle{
id:rect
width: 75
height: 75
radius:width
color: "red"
MouseArea{
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button == Qt.RightButton)
{
rect.x +=50;
rect.y +=40;
}
else
{
rect.x -=50;
rect.y -=40;
}
}
}
Behavior on x{
NumberAnimation{
id:beha
easing{
type:Easing.OutElastic
amplitude:1.0
period:0.5
}
}
}
Behavior on y{
animation: beha
}
Behavior{
ColorAnimation {
target: rect
duration: 200
}
}
}