[Feelings & Sharing] 经常看到V23更新日志说QML重构,那么QML是啥?
Tofloor
poster avatar
流浪的加菲
deepin
2024-06-04 14:27
Author

QML 是一种基* 的声明式语言。在 Qt 5 中,QML 有了长足进步,并且同 C++ 并列成为 Qt 的首选编程语言。也就是说,使用 Qt 5,我们不仅可以使用 C++ 开发 Qt 程序,而且可以使用 QML。虽然 QML 是解释型语言,性能要比 C++ 低一些,但是新版 QML 使用 V8,Qt 5.2 又引入了专为 QML 优化的 V4 引擎,使得其性能不再有明显降低。

  • QtDesigner可以设计出ui界面文件,但是不支持和Qt原生C++代码的交互。
  • QtScript可以和Qt原生代码进行交互,但是有一个缺点,如果要在脚本中创建一个继承于QObject的图形对象非常不方便,只能在Qt代码中创建图形对象,然后从QtScript中进行访问。

QML可以在脚本里创建图形对象,并且支持各种图形特效,以及状态机等,同时又能跟Qt写的C++代码进行方便的交互,使用起来非常方便。

QML实际上是Qt Quick (Qt4.7.0中的新特性)核心组件之一,Qt Quick 就是使用 QML 构建的一套类库。

QML 属性

QML 将用户界面分解成一块块小的元素,每一元素都由很多组件构成。QML 定义了用户界面元素的外观和行为;更复杂的逻辑则可以结* 脚本实现。这有点类似于 HTML * 的关系,前者用来显示界面,后者用来定义行为。

QML 基本元素可以分为可视元素和不可视元素两类。

  • 可视元素(例如Rectangle)具有几何坐标,会在屏幕上占据一块显示区域。
  • 不可视元素(例如Timer)通常提供一种功能,这些功能可以作用于可视元素。

可视元素

QML最基本的可视元素:Item、MouseArea、Rectangle、Text、Image

Item

Item是所有可视元素中最基本的一个。它是所有其它可视元素的父元素,可以说是所有其它可视元素都继承Item。Item本身不具有特定的可视化外观,而是用作容器(例如放置Rectangle、Image、Text等元素)或布局控制器,它的作用是定义所有可视元素的通用属性,例如控制元素的位置、大小、可见性、透明度等:

image.png

Item它还具有事件处理能力,可以处理鼠标、键盘和触摸事件。Item是QML中的基本元素类型,用于创建用户界面并控制元素的外观和行为。

几何属性x和y:指定元素相对于其父元素的位置坐标。

z是定义堆叠顺序。

width和height:指定元素的宽度和高度。

rotation:指定元素的旋转角度。

enabled:指定元素是否启用。设置为true时启用,设置为false时禁用。

anchors:用于指定元素相对于其父元素或其他元素的定位方式。

Item {
    width: 200
    height: 200  //属性将元素的宽度和高度设置为200。
    x: 100
    y: 100 //属性将元素的位置坐标设置为(100, 100),相对于其父元素的位置
    rotation: 45 //属性将元素以45度的角度旋转。
    opacity: 0.8 //属性将元素的透明度设置为0.8。
    visible: true //属性将元素设置为可见状态
    enabled: true //属性将元素设置为启用状态。
    scale: 1.5    //属性将元素的缩放比例设置为1.5。
    clip: true    //属性将元素的内容剪裁,确保不超出元素的边界。
  
    Rectangle { 
        width: 100
        height: 100
        color: "red"
        anchors.centerIn: parent //anchors.centerIn属性将其居中于父元素。
    }
}
Item {
    width: 400
    height: 200
  
    RowLayout { //水平方向上排列
        anchors.fill: parent //以填充整个父元素的空间
        spacing: 10 //spacing属性为10,以在两个子元素之间创建一些间距。
  
        Rectangle {
            width: 100
            height: 100
            color: "red"
        }
        Rectangle {
            width: 100
            height: 100
            color: "blue"
        }
    }
}

MouseArea 鼠标区域

MouseArea是 Qt Quick 的重要组成部分,用于处理鼠标交互事件。它允许你在QML界面中捕获和响应鼠标的移动、点击和释放等事件。MouseArea 属性描述键盘事件onPressed、onReleased、onEntered、onExited等,可以根据需要选择相应的事件进行处理。鼠标事件hoverEnabled、drag.target等,可以用于控制鼠标事件的交互行为,例如启用悬停效果或启用拖拽操作。

onEntered:在鼠标进入MouseArea元素时触发。

onExited:在鼠标离开MouseArea元素时触发。

onPressed:在鼠标按下时触发。

onReleased:在鼠标释放时触发。

onClicked:在鼠标点击时触发。

onPositionChanged:在鼠标位置发生变化时触发。

示例:

MouseArea {
    anchors.fill: parent
    onClicked: {
        Qt.quit();
    }
}

MouseArea {
    anchors.fill: parent  // 使其覆盖整个父元素的区域。
    onClicked: { //使用onClicked信号处理器捕获鼠标点击事件。当鼠标在MouseArea元素上被点击时,onClicked信号被触发,并执行相关的操作。
        console.log("Mouse clicked at (" + mouseX + ", " + mouseY + ")"); //console.log输出到控制台。
    }
}
Rectangle {
        width: 200
        height: 200
        MouseArea {
            anchors.fill: parent
            onEntered: {
                console.log("Mouse entered");
                // 在鼠标进入时执行的操作
                // 例如改变元素的颜色或显示提示信息
            }
            onExited: {
                console.log("Mouse exited");
                // 在鼠标离开时执行的操作
                // 例如恢复元素的颜色或隐藏提示信息
            }
            onPressed: {
                console.log("Mouse pressed");
                // 在鼠标按下时执行的操作
                // 例如改变元素的外观或记录点击的位置
            }
            onReleased: {
                console.log("Mouse released");
                // 在鼠标释放时执行的操作
                // 例如执行特定的操作或响应点击事件
            }
            onClicked: {
                console.log("Mouse clicked");
                // 在鼠标点击时执行的操作
                // 例如触发特定的行为或进行导航
            }
            onPositionChanged: {
                console.log("Mouse position changed: (" + mouseX + ", " + mouseY + ")");
                // 在鼠标位置发生变化时执行的操作
                // 例如实时更新元素的位置或响应鼠标拖动事件
            }
        }
    }

Rectangle 矩形

RectangleRectangle是QML中的一个基本可视元素,用于绘制矩形形状的图形对象Rectangle 属性描述

x、y:矩形的左上角相对于其父元素的坐标。

width、height:矩形的宽度和高度。

color:矩形的背景颜色。

border.width、border.color:矩形的边框宽度和颜色。r

adius:矩形的圆角半径。

visible:矩形的可见性。

opacity:矩形的不透明度。

示例

Rectangle {  //矩形
    width: 100
    height: 100
    color: "red"  
    border.width: 10      //矩形的边框宽度为10像素。
    border.color: "black" //矩形的边框颜色为黑色。
    radius: 10    //圆角
    rotation: 45  //旋转
}

Rectangle {
        id: backgroud
        width: 100
        height: 100
        color: "grey"  //grey
        Rectangle {
            id: greenlight
            width: 60
            height: 60
            x: 20
            y: 20
            color: "green"
            radius: 30
            Component .onCompleted: flick.start()
            SequentialAnimation{
                  id: flick
                  ColorAnimation { target: greenlight; properties: "color"; to: "black"; duration: 1000 }
                  ColorAnimation { target: greenlight; properties: "color"; to: "green"; duration: 1000 }
                  ColorAnimation { target: greenlight; properties: "color"; to: "black"; duration: 1000 }
                  ColorAnimation { target: greenlight; properties: "color"; to: "green"; duration: 1000 }
                  ColorAnimation { target: greenlight; properties: "color"; to: "black"; duration: 1000 }
            }
        }
}

示例2:定义一个宽 100 像素、高 150 像素,浅金属蓝填充,红色 4 像素的边框的矩形:

Rectangle {
    id: rect
    width: 100
    height: 150
    color: "lightsteelblue"
    border {
        color: "#FF0000"
        width: 4
    }
    radius: 8
}

Text

Text 类型可以用于在Rectangle中增加文字信息,Text 属性描述:

Text {
    text: "Hello World"
    color: "#303030"
    font.family: "Century"
    font.pixelSize: 28
}

上述示例:

text: 显示的文本内容为"Hello, World!"。

color: 文本颜色为 #303030

font.family: 字体族名称,文本字体为“Century”。

font.pixelSize: 字体大小为18像素。

更多属性如下:

font.bold: 是否使用粗体字体。

font.italic: 是否使用斜体字体。

font.underline: 是否使用下划线。

font.strikeout: 是否使用删除线。

font.capitalization: 文本的大小写转换方式。

horizontalAlignment: 文本在水平方向上的对齐方式。

verticalAlignment: 文本在垂直方向上的对齐方式。

wrapMode: 文本的换行方式。

示例

Text {
    text: "Hello, World!"  //显示的文本内容为"Hello, World!"。
    font.pixelSize: 16     //字体大小为16像素。
    color: "black"         //文本颜色为黑色。
}

Text {
    text: "Welcome!"
    font.family: "Arial"
    font.bold: true
    color: "blue"
    horizontalAlignment: Text.AlignHCenter  //水平方向上居中对齐
    verticalAlignment: Text.AlignVCenter    //垂直方向上居中对齐
    wrapMode: Text.WordWrap       //文本的自动换行
}

Image

用于显示图像。目前 QML 支持的图像格式有 PNG、JPG、GIF 和 BMP 等,相关属性解释如下:

fillMode: 图像的填充模式,用于控制图像如何适应元素的大小。

sourceSize: 指定图像的原始大小,用于进行缩放或裁剪。

asynchronous: 是否异步加载图像文件。

smooth: 是否对图像进行平滑处理。

visible: 图像的可见性。

source: 图像的源文件路径为"image.jpg"。这里假设当前目录下存在名为"image.jpg"的图像文件。

Image {
    source: "image.jpg"
    width: 200
    height: 200
}
//--------------------------------------------------------------------
图像裁剪:
Image {
    source: "image.jpg"
    width: 200
    height: 200    //通过设置width和height属性来指定显示图像的实际大小,可以实现图像的裁剪效果。
    sourceSize.width: 400   //sourceSize属性来指定图像的原始大小,
    sourceSize.height: 300 
}
//--------------------------------------------------------------------
动态改变图像源:
Image {
    id: myImage
    width: 200
    height: 200
    source: imageSource // 可以是一个表达式或变量
}

// 动态改变图像源
Button {
    text: "Load Image"
    onClicked: {
        myImage.source = "new_image.jpg";
    }
}

图像缩放和平滑处理:
Image {
    source: "image.jpg"
    width: 400
    height: 300
    smooth: true // 启用平滑处理
}

除此之外,我们也可以直接给 source属性一个 URL 来自动从网络加载图片,也可以通过 fillMode属性设置改变大小的行为。例如下面代码片段:

Image {
    x: 12;
    y: 12
    // width: 48
    // height: 118
    source: "assets/rocket.png"
}
 
Image {
    x: 112;
    y: 12
    width: 48
    height: 118/2
    source: "assets/rocket.png"
    fillMode: Image.PreserveAspectCrop
    clip: true
}

对于较大的图像文件或远程图像,你可以使用异步加载来避免界面的阻塞。
通过将asynchronous属性设置为true,可以在图像加载时将其作为后台任务,不会阻塞主线程。

Image {
    source: "large_image.jpg"
    width: 800
    height: 600
    asynchronous: true // 启用异步加载
}

通过将asynchronous属性设置为true,可以在图像加载时将其作为后台任务,不会阻塞主线程。


上面内容都是摘录的,对Qt和QML学习感兴趣的同学可以查阅:Qt学习之路

Reply Favorite View the author
All Replies
wlly-lzh
deepin
2024-06-04 14:31
#1

qml是解释型语言?

很明显qml是声明式标记语言吧。

Reply View the author
流浪的加菲
deepin
2024-06-04 14:42
#2
wlly-lzh

qml是解释型语言?

很明显qml是声明式标记语言吧。

开篇第一句“QML 是一种基* 的声明式语言。”

Reply View the author
乾豫恒益
deepin
2024-06-04 14:46
#3

收藏了,认真学习一下

Reply View the author
wlly-lzh
deepin
2024-06-04 14:55
#4
流浪的加菲

开篇第一句“QML 是一种基* 的声明式语言。”

然而文中依然提到了“虽然 QML 是解释型语言”。

私以为这样的话很容易引起误解,如果此处的“解释型语言”有特殊的含义,还请专门指出。

Reply View the author
流浪的加菲
deepin
2024-06-04 15:02
#5
wlly-lzh

然而文中依然提到了“虽然 QML 是解释型语言”。

私以为这样的话很容易引起误解,如果此处的“解释型语言”有特殊的含义,还请专门指出。

哈哈,我也是原文摘录,刚才百度搜索了下“声明式语言”和“解释型语言”,感觉我俩要被别人当傻子围观了,哈哈😂

Reply View the author
yicold
deepin product team
2024-06-04 15:02
#6

like

qml的视觉效果,未来社区版可期

Reply View the author
WangZhongyun
deepin
2024-06-04 17:11
#7

学习

Reply View the author
caoyuUU
deepin
2024-06-04 17:49
#8

我会js,相当于我会QML?

Reply View the author
兆兆嘟嘟嘟
deepin
2024-06-04 19:17
#9
流浪的加菲

哈哈,我也是原文摘录,刚才百度搜索了下“声明式语言”和“解释型语言”,感觉我俩要被别人当傻子围观了,哈哈😂

凡是以ml结尾的都是标记语言(markup language)。

Reply View the author
PurestAsh
deepin
2024-06-06 09:55
#10

一直对qml不太熟。他是那种响应式的语言吗?

命令式:

比如我有一个Text组件和一个Button组件,我想更改这个Text组件的文字,

我就要在Button拿到这个Text的id,然后.text='hello world'这种吗?

还是我可以这样:

响应式:

  1. 定义一个模型:MyData{ id : myData, myText : 'old hello' }
  2. 然后Text{ text : myData.myText } //监听模型
  3. 然后Button{ onclick: myData.myText = 'new hello' } //使用模型

但是我之前学习的时候又看到有‘model’这种类似的词汇。

所以一直不太理解qml到底是响应式的,还是命令式的。😭

Reply View the author