QML/C++中常用功能整理
一、环境相关(.pro文件)
● Qt Creator中最最常用快捷键
F1 查看帮助(可直接在某个控件上)
F2 跳转到函数定义(和Ctrl+鼠标左键一样的效果)
F4 头文件和源文件之间切换
Ctrl + B 编译工程
Ctrl + R 运行工程
Ctrl + I 自动对齐
Ctrl + / 注释行,取消注释行
Ctrl + Shift + < 折叠代码块
Ctrl + Shift + > 展开代码块
Alt + 0 关闭/打开左侧显示(方便编辑)
● 多线程编译
-j16 是开启16线程编译,主要得看自己的电脑核心数,稳妥一点 -j4 一般电脑都OK的。
据我测试,加不加编译时间都一样,应该新版本的QtCreator默认已经会根据电脑的核心自动设置多线程编译,比如识别到你的电脑是16核心的就会默认设置-j16参数进行编译
● Windows下中文乱码问题
在 .pro文件中加入如下:
WindowsBuild {
QMAKE_CXXFLAGS += -execution-charset:utf-8 # 让程序执行时使用utf-8字符集
QMAKE_CXXFLAGS += -source-charset:utf-8 # 告诉vc编译器识别源文件编码类型是utf-8
}
或者:
WindowsBuild {
msvc {
QMAKE_CFLAGS += /utf-8
QMAKE_CXXFLAGS += /utf-8
}
}
重构后再编译才生效,实测有效~
● .pro 工程文件中添加常用模块
相应的功能必须添加指定的模块才能运行,如使用网络的话,必须在 .pro 中添加: QT += network
QT += \
sql \ # 数据库
svg \ # svg 图(亲测,不包含的话,手机app中将不显示svg 图)
network \ # tcp/UDP 网络
websockets \ # web 网络
xml \ # xml 文件
concurrent \ # 多线程
gui \ # Graphical User Interface (图形用户界面)
location \ # 地图定位相关
opengl \ # 三维绘图
positioning \ # 通过 QML 和 c++ 接口提供定位信息。
qml \ # 提供了使用 QML 语言创建用户界面所需的 QML 类型
quick \ # 高级用户界面技术, 默认使用 OpenGL ES, 包含 QML API 和 C++ API
quickcontrols2 \ # Qt 自带 controls 控件库,一般是几个基础控件组成的复杂控件
widgets \ # 传统桌面程序 widgets,对应于 QML
quickwidgets \ #
texttospeech \
core-private
...
● 关闭大量警告
.pro 工程文件添加:
CONFIG += warn_off
● 关闭qDebug、qWarning打印
.pro 工程文件添加:
DEFINES += QT_NO_DEBUG_OUTPUT
DEFINES += QT_NO_WARNING_OUTPUT #会编译失败....
● .pro文件中,使用$$quote(xxx),对带空格的路径进行包围
一个错误的例子如下:
INCLUDEPATH += C:/Program Files/GmSSL/include
LIBS += -LC:/Program Files/GmSSL/lib -llibcrypto
编译时,找不到头文件,因为路径C:/Program Files中带了空格,所以需要处理下,如下:
INCLUDEPATH += $$quote(C:/Program Files/GmSSL/include)
LIBS += -L$$quote(C:/Program Files/GmSSL/lib) -llibcrypto
二、小技巧
- 属性改变事件,基本都是 on+Property+Changed
- findChild 使用里面的参数,对应的是QML中的objectName,不是QML中的id
- QML对象,如果没有设置id,则使用时才初始化,如果设置了id,则一开始就初始化了,所以不要给id最好
- QML子对象可以直接使用父对象的属性,跨文件的情况同样可用
- QML定义的function可以全局使用,子对象能使用父对象的函数,父对象不能直接使用
- 不能修改JS变量给其他文件使用,每次import相对于基于js创建一个新的对象
- 可以使用Qt.binding,进行属性值的绑定
- ① QQuickView 提供了一个窗体用于显示UI
② QQuickEngine 提供QML运行环境
③ QQuickWindow 显示窗体, 以及对item对象的管理及用户交互
三、QML 中数据处理(函数相关)
可参考: QML 中常用的 JS 函数整理
● 子项的批量操作
利用 children 和 startsWith,如下,clearAllChecks() 函数可以批量操作 RowLayout 的 MyButton ,可以跳过 ColoredImage
function clearAllChecks() {
for (var i=0; i<rowLayout.children.length; i++) {
if (rowLayout.children[i].toString().startsWith("MyButton"))
rowLayout.children[i].checked = false
}
}
RowLayout {
id: rowLayout
...
//head
ColoredImage {
id: innerImage
...
}
//first Button
MyButton {
id: firstButton
text: qsTr("我是目录1")
icon.source: "/images/1"
onClicked: {
clearAllChecks()
checked = true
}
}
//second Button
MyButton {
text: qsTr("我是目录2")
icon.source: "/images/2"
onClicked: {
clearAllChecks()
checked = true
}
}
}
● 打印
//QML中打印
console.log("index is: ")
//c++中打印
qDebug() << "No Internet Access";
● 将一个数字转化成16进制字符串形式
function toHex(num){
return num<16? "0x0"+num.toString(16).toUpperCase() : "0x"+num.toString(16).toUpperCase();
}
● 小数点位数
xxx.toFixed(x),如:
property real _pi: 3.1415926
_pi.toFixed(2) //保留两位小数 3.14
● Math应用
Math.min(x, y) //取最小值
Math.max(x, y) //取最大值
Math.round(x) //返回一个数字四舍五入后接近的整数
● 数组的使用
var arr1 = [1,2,3]; // 定义数组 arr = [1,2,3]
var arr2 = new Array; // 定义数组 arr2 = []
arr2[0] = 4; // 通过下标添加元素
arr2[1] = 5;
arr2.push(6); // 往数组最末尾添加新元素
arr2.unshift(7); // 往数组最前面添加新元素
arr2.unshift(8);
var arr3 = arr1.concat(arr2); // 合并数组
console.log(arr3); // [1,2,3,8,7,4,5,6]
console.log(arr3.sort()); // 按ASCII码排序,[1,2,3,4,5,6,7,8]
console.log(arr3.reverse()); // 元素颠倒顺序,[8,7,6,5,4,3,2,1]
console.log(arr3.join("/")); // 转换成字符串,“8/7/6/5/4/3/2/1”
arr3.pop(); // 数组删除最末尾的元素
arr3.shift(); // 数组删除最前面的元素
console.log(arr3); // [7,6,5,4,3,2]
console.log(arr3.slice(1,3)); // 截取指定长度的数组,从1到3(不包括3),[6,5]
arr3.splice(1,3); // 删除指定长度的数组,从1到3(包括3)
console.log(arr3); // [7,3,2]
● 字符串转数字(Number()、parseInt() )
Number() 将不同的对象值转换为数字:
var x1 = true;
var x2 = false;
var x3 = new Date();
var x4 = "999";
var x5 = "999 888";
Number(x1) //1
Number(x2) //0
Number(x3) //1639300291930, 返回自 UTC 1970 年 1 月 1 日午夜以来的毫秒数
Number(x4) //999
Number(x5); //NaN
parseInt() 可解析一个字符串,并返回一个整数
parseInt("10") //10 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。
parseInt("10.33") //10
parseInt("34 45 66") //34 只有字符串中的第一个数字会被返回
parseInt(" 60 ") //60 开头和结尾的空格是允许的。
parseInt("40 years") //40
parseInt("He was 40") //NaN 第一个字符不能被转换为数字,那么返回 NaN。
parseInt("0x10") //16 以 "0x" 开头,解析为十六进制的整数。
parseInt("010") //10 以"0"为开始时旧的浏览器使用八进制基数。ECMAScript 5,默认的是十进制的基数。
parseInt("10",8) //8 八进制
parseInt("10",10) //10 十进制
parseInt("10",16) //16 十六进制
● 字符串子串 substr代替 substring
如下截图:
● 控件截图功能
Rectangle {
id: source
width: 100
height: 100
gradient: Gradient {
GradientStop { position: 0; color: "steelblue" }
GradientStop { position: 1; color: "black" }
}
}
...
source.grabToImage(function(result) {
result.saveToFile("something.png");
});
...
//加入时间、Android常用路径
source.grabToImage(function(result) {
var nowTime = Qt.formatDateTime(new Date(),"yyyy-MM-dd-HH:mm:ss")
var path = "/sdcard/Pictures/" + nowTime + ".png"
result.saveToFile(path);
});
}
四、QML
1. QML 地图相关
● 地图中经纬度总结
// 经纬度常用定义:
property var _coordinate: QtPositioning.coordinate(0, 0) //先纬度后经度
//定义一个简单Plugin和Map
Plugin {
id: mapPlugin
name: "osm" // "mapboxgl", "esri", ...
}
Map {
id: map
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(59.91, 10.75) // Oslo 先纬度后经度
zoomLevel: 14
}
//取地图中心经纬高的8位小数
function mapCenter() {
var coordinate = map.center
coordinate.latitude = coordinate.latitude.toFixed(8)
coordinate.longitude = coordinate.longitude.toFixed(8)
coordinate.altitude = coordinate.altitude.toFixed(8)
return coordinate
}
//取当前地图中鼠标位置的经纬高
Map {
id: map
...
MouseArea {
anchors.fill: parent
onClicked: {
var coordinate = map.toCoordinate(Qt.point(mouse.x, mouse.y), false )
coordinate.latitude = coordinate.latitude.toFixed(8)
coordinate.longitude = coordinate.longitude.toFixed(8)
coordinate.altitude = coordinate.altitude.toFixed(8) //高一般是无效的
}
}
}
● 地图中取方位角和坐标
azimuthTo、atDistanceAndAzimuth
property var changChaCoordinate: QtPositioning.coordinate(28.2, 113) //长沙
property var shangHaiCoordinate: QtPositioning.coordinate(31.2, 121.5) //上海
property var targetCoordinate: QtPositioning.coordinate(0, 0) //目标经纬度,距离长沙100km,在长沙到上海的方向上
//上海相对于长沙的方位角:
var azimuth = changChaCoordinate.azimuthTo(shangHaiCoordinate)
//计算目标经纬度,给一个距离和方位角,就可以确定另外一个经纬度:
targetCoordinate = changChaCoordinate.atDistanceAndAzimuth(1000000, azimuth)
2. 时间
property real _Time: //时间为int数字
...
function getMissionTime() {
if(isNaN(_Time)) {
return "00:00:00"
}
var t = new Date(0, 0, 0, 0, 0, Number(_Time))
return Qt.formatTime(t, 'hh:mm:ss')
}
...
Label {
text: getMissionTime()
}
五、QML 控件
● Row、Column默认宽高
经过测试,Row和Column中可以不指定宽高;
Column 中的默认宽为子控件中最宽的, 默认高为所有子控件高之和加上间隙 ;
另外width = implicitWidth height = implicitHeight;
Row中默认高为子控件中最高的,默认宽为子控件宽之和加上间隙;
另外width = implicitWidth height = implicitHeight;
● ListView 宽高与子控件一致问题
Flickable 控件或者类似与 ListView 继承于Flickable控件的,如果想宽高与子控件一致,可写成:
ListView {
width: contentItem.childrenRect.width
height: contentItem.childrenRect.height
model: xxx
delegate: xxx
}
childrenRect 为只读属性,它保存了项目的子元素的集合位置和大小
● Flickable 控件可拖动的关键
Flickable {
id: flickRoot
clip: true
contentWidth: content.width //要比width大
anchors.fill: parent
...
}
① contentWidth 文本宽的大小应该比 width 宽本身要大
② clip 裁剪使能,多余的就只能滚动显示
● 控件先确定底层大小
● 其它
Rectangle 中无色:
color: Qt.rgba(0,0,0,0)
C++未分类
● QT5 增加widgets 模块
在Qt4中,Qt提供的全部图形界面相关类都包含在Qt Gui模块中,但QT5将一些图形界面类移到了QT widgets模块中。所以在Pro文件中,需要增加一句话:
greaterThan(QT_MAJOR_VERSION, 4):QT += widgets
意思是如果Qt版本大于Qt4,则需要增加 widgets 模块。
● 浮点型判断不报警告
float f = 0
void function() {
if(f == 0.0f ) //数字0改为 0.0f
...
}
● unused parameter xxx
未使用的参数xxx告警
Q_UNUSED(xxx);
未完待续…