我参考http://zetcode.com/gui/qt5/introduction/ 这个链接入坑,使用 macOS。网上看起来是 Windows 和 Linux 的教程居多,这个链接里的教程初看起来应该也是基于 Linux 的。谁让 Mac 的市场占有率低呢。
First Try
Show version
首先是从官网下载了 GUI 形式的安装器安装的 Qt,Qt 的默认安装位置是~/Qt
。安装的 Qt 版本是 5.13.1。首先参照教程熟悉一下编译过程。教程链接里给出的例子是:
1 2 3 4 5 6 7 #include <QtCore> #include <iostream> int main () { std ::cout << "Qt version: " << qVersion() << std ::endl ; }
编译的命令是
1 g++ -o version version.cpp -I/usr/local/qt5/include/QtCore -I/usr/local/qt5/include -L/usr/local/qt5/lib -lQt5Core -fPIC
不过这个编译命令在 Mac 上无法成功。我使用的是如下命令:
1 2 3 4 5 6 7 8 9 10 11 g++ -o version version.cpp \ # Include path,需要指向包含QtCore的头文件的位置 -Ipath/to/qt/5.13.1/clang_64/lib/QtCore.framework/Headers \ # -F指定framework的路径,-framework则用来指明使用的framework的名字 -F/Users/lena/qt/5.13.1/clang_64/lib -framework QtCore # 在mac上g++其实也是调用的clang,这里加上这个避免一些warning -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.13.sdk \ -mmacosx-version-min=10.12 \ # rpath是程序在运行的时候载入动态库(即QtCore.framework)的位置 -Wl,-rpath,/path/to/5.13.1/clang_64/lib -pipe -stdlib=libc++ -O2 -std=gnu++11 -Wall -W -fPIC
编译成功后调用./version
就可以看到运行成功并输出 Qt 版本了。
First GUI
下面我们来测试一个简单的 GUI 例子。首先新建一个文件如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <QApplication> #include <QWidget> int main (int argc, char *argv[]) { QApplication app (argc, argv) ; QWidget window; window.resize(250 , 150 ); window.setWindowTitle("Simple example" ); window.show(); return app.exec(); }
然后使用qmake
工具,运行
这个命令会创建一个项目文件simple.pro
。文件的内容应该类似于:
1 2 3 4 5 6 7 8 9 10 11 12 ###################################################################### # Automatically generated by qmake (3.0) Fri Oct 30 17:11:00 2015 ###################################################################### TEMPLATE = app TARGET = simple INCLUDEPATH += . # Input SOURCES += simple.cpp QT += widgets
注意最后一行,需要我们手动添加 QtWidget 模块。然后运行qmake
命令,生成编译使用的 Makefile。然后就可以编译了:
程序运行后会弹出一个空的窗口。
Strings
Qt 引入了QString
来加强字符串处理的能力。
QtString
表示一个 Unicode 字符串,其存储字符串为 16 比特的QChars
。每个QChar
代表一个 Unicode 4.0 字符。不同于很多其他的变成语言,QtString
可以被修改。
这里主要是了解QtString
的能力,汇总记录就可以了,没有必要编译运行。
初始化
有多种初始化方法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <QTextStream> int main (void ) { QTextStream out (stdout ) ; QString str1 = "The night train" ; out << str1 << endl ; QString str2 ("A yellow rose" ) ; out << str2 << endl ; std ::string s1 = "A blue sky" ; QString str3 = s1.c_str(); out << str3 << endl ; std ::string s2 = "A thick fog" ; QString str4 = QString::fromLatin1(s2.data(), s2.size()); out << str4 << endl ; char s3[] = "A deep forest" ; QString str5 (s3) ; out << str5 << endl ; return 0 ; }
访问字符串元素
如前文所述,QString
由QChar
组成,我们可以使用[]
操作符或者at()
函数来访问元素:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <QTextStream> int main (void ) { QTextStream out (stdout ) ; QString a = "Eagle" ; out << a[0 ] << endl ; out << a[4 ] << endl ; out << a.at(0 ) << endl ; if (a.at(5 ).isNull()) { out << "Outside the range of the string" << endl ; } return 0 ; }
字符串长度
与字符串长度相关的函数有三个: size()
, count()
和length
。三个函数的作用是一样的。
字符串构建
参考如下的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <QTextStream> int main () { QTextStream out (stdout ) ; QString s1 = "There are %1 white roses" ; int n = 12 ; out << s1.args(n) << endl ; QString s2 = "The tree is %1 m high" ; double h = 5.65 ; out << s2.args(h) << endl ; QString s3 = "We have %1 lemons and %2 oranges" ; int ln = 12 ; int on = 4 ; out << s3.arg(ln).arg(on) << endl ; return 0 ; }
待被替换的占位符用%
开头,后面借数字。需要注意的是多个占位符需要替换时,需要多次调用args()
函数,而非为args()
函数传递多个参数。
子字符串(Substring)
这里涉及left()
,mid()
,right()
三个函数,分别代表从左侧开始的 Substring,中间一段的 Substring,右侧开始的 Substring。见下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <QTextStream> int main (void ) { QTextStream out (stdout ) ; QString str = "The night train" ; out << str.right(5 ) << endl ; out << str.left(9 ) << endl ; out << str.mid(4 , 5 ) << endl ; QString str2 ("The big apple" ) ; QStringRef sub (&str2, 0 , 7 ) ; out << sub.toString() << endl ; return 0 ; }
遍历字符串
QString
遵循了 C++的通常做法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <QTextStream> int main (void ) { QTextStream out (stdout ) ; QString str = "There are many stars." ; foreach (QChar qc, str) { out << qc << " " ; } out << endl ; for (QChar *it=str.begin(); it!=str.end(); ++it) { out << *it << " " ; } out << endl ; for (int i = 0 ; i < str.size(); ++i) { out << str.at(i) << " " ; } out << endl ; return 0 ; }
字符串比较
QString::compare()
函数用来比较两个字符串。该函数返回一个整型数。如果返回值小于 0,那么第一个字符串小于第二个字符串;如果返回 0,两个字符串相等;如果返回值大于 0,那么第一个字符串大于第二个字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <QTextStream> #define STR_EQUAL 0 int main (void ) { QTextStream out (stdout ) ; QString a = "Rain" ; QString b = "rain" ; QString c = "rain\n" ; if (QString::compare(a, b) == STR_EQUAL) { out << "a, b are equal" << endl ; } else { out << "a, b are not equal" << endl ; } out << "In case insensitive comparison:" << endl ; if (QString::compare(a, b, Qt::CaseInsensitive) == STR_EQUAL) { out << "a, b are equal" << endl ; } else { out << "a, b are not equal" << endl ; } if (QString::compare(b, c) == STR_EQUAL) { out << "b, c are equal" << endl ; } else { out << "b, c are not equal" << endl ; } c.chop(1 ); out << "After removing the new line character" << endl ; if (QString::compare(b, c) == STR_EQUAL) { out << "b, c are equal" << endl ; } else { out << "b, c are not equal" << endl ; } return 0 ; }
其中Qt::CaseInsensitive
表示无视大小写的比较。
字符串解析
这里指将字符串解析为数字类型。这里涉及toInt()
, toFloat()
, toLong()
等函数。反过来,setNum()
函数可以将数字类型转化成字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <QTextStream> int main (void ) { QTextStream out (stdout ) ; QString s1 = "12" ; QString s2 = "15" ; QString s3, s4; out << s1.toInt() + s2.toInt() << endl ; int n1 = 30 ; int n2 = 40 ; out << s3.setNum(n1) + s4.setNum(n2) << endl ; return 0 ; }
字符类型
QChar
类型可以肥尾数字,祖母,空格以及标点符号,QChar
提供了识别这些类型的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <QTextStream> int main (void ) { QTextStream out (stdout ) ; int digits = 0 ; int letters = 0 ; int spaces = 0 ; int puncts = 0 ; QString str = "7 white, 3 red roses." ; foreach(QChar s, str) { if (s.isDigit()) { digits++; } else if (s.isLetter()) { letters++; } else if (s.isSpace()) { spaces++; } else if (s.isPunct()) { puncts++; } } out << QString("There are %1 characters" ).arg(str.count()) << endl ; out << QString("There are %1 letters" ).arg(letters) << endl ; out << QString("There are %1 digits" ).arg(digits) << endl ; out << QString("There are %1 spaces" ).arg(spaces) << endl ; out << QString("There are %1 punctuation characters" ).arg(puncts) << endl ; return 0 ; }
修改字符串
修改字符串的函数可以分为两类,一类返回一个修改后的副本,原字符串保持不变(如toLower()
);另一类是直接原地修改原字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <QTextStream> int main (void ) { QTextStream out (stdout ) ; QString str = "Lovely" ; str.append(" season" ); out << str << endl ; str.remove(10 , 3 ); out << str << endl ; str.replace(7 , 3 , "girl" ); out << str << endl ; str.clear(); if (str.isEmpty()) { out << "The string is empty" << endl ; } return 0 ; }
字符串对齐
这里指输出格式调整,将输出的内容左对齐(leftJustified()
)或者右对齐(rightJustified()
)。如下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <QTextStream> int main (void ) { QTextStream out (stdout ) ; QString field1 = "Name: " ; QString field2 = "Occupation: " ; QString field3 = "Residence: " ; QString field4 = "Marital status: " ; int width = field4.size(); out << field1.rightJustified(width, ' ' ) << "Robert\n" ; out << field2.rightJustified(width, ' ' ) << "programmer\n" ; out << field3.rightJustified(width, ' ' ) << "New York\n" ; out << field4.rightJustified(width, ' ' ) << "single\n" ; return 0 ; }
输出为
1 2 3 4 Name: Robert Occupation: programmer Residence: New York Marital status: single
Escaping
Qt5 提供了 toHtmlEscapted()
方法,将字符串中涉及的 html 下特殊的字符,如<, >, &, "
等,替换成 HTML 下的编码。如
处理文件
1 2 3 4 5 6 7 8 #include <stdio.h> int main(void) { for (int i=1; i<=10; i++) { printf("Bottle %d\n", i); } }
使用如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <QTextStream> #include <QFile> int main (void ) { QTextStream out (stdout ) ; QFile file ("cprog.c" ) ; if (!file.open(QIODevice::ReadOnly)) { qWarning("Cannot open file for reading" ); return 1 ; } QTextStream in (&file) ; QString allText = in.readAll(); out << allText.toHtmlEscaped() << endl ; file.close(); return 0 ; }
输出内容如下:
1 2 3 4 5 6 7 8 9 $ ./html_escape # include <stdio.h> int main(void) { for (int i=1; i<=10; i++) { printf("Bottle %d\n", i); } }
Date and Time
这个部分还是继续讲 Qt 扩展的数据类型。本次涉及QDate
,QTime
和 QDateTime
三个类。
QDate
用于管理格里高利历的日历。QTime
处理时钟,QDateTime
则是二者的结合。
初始化 日期&时间对象
日期和时间对象的初始化有两种基本方法:要么用构造函数直接复制,要么构造一个空的对象后续赋值。参见下面的粒子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <QTextStream> #include <QDate> #include <QTime> int main (void ) { QTextStream out (stdout ) ; QDate dt1 (2015 , 4 , 12 ) ; out << "The date is " << dt1.toString() << endl ; QDate dt2; dt2.setDate(2015 , 3 , 3 ); out << "The date is " << dt2.toString() << endl ; QTime tm1 (17 , 30 , 12 , 55 ) ; out << "The time is " << tm1.toString("hh:mm:ss.zzz" ) << endl ; QTime tm2; tm2.setHMS(13 , 52 , 45 , 155 ); out << "The time is " << tm2.toString("hh:mm:ss.zzz" ) << endl ; }
当前时间
见下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <QTextStream> #include <QTime> #include <QDate> int main (void ) { QTextStream out (stdout ) ; QDate cd = QDate::currentDate(); QTime ct = QTime::currentTime(); out << "Current date is: " << cd.toString() << endl ; out << "Current time is: " << ct.toString() << endl ; }
注意,源文件不能叫time.cpp
。
1 QDate cd = QDate::currentDate();
返回的当前的日期。
1 QTime ct = QTime::currentTime();
返回当前的时间。toString()
函数则将的日期和时间对象转化成字符串。
比较日期
关系操作符和用来比较日期(在日历上的位置)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <QTextStream> #include <QDate> int main (void ) { QTextStream out (stdout ) ; QDate dt1 (2015 , 4 , 5 ) ; QDate dt2 (2014 , 4 , 5 ) ; if (dt1 < dt2) { out << dt1.toString() << " comes before " << dt2.toString() << endl ; } else { out << dt1.toString() << " comes after " << dt2.toString() << endl ; } }
闰年
使用QDate::isLeapYear()
函数来判断
日期/时间 格式
预定义日期格式
Qt 有一些内建的日期格式。QDate
的 toString()
函数可以接收一个日期格式描述对象作为参数。默认的参数是Qt::TextDate
。一些其他的格式见下面的粒子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <QTextStream> #include <QDate> int main (void ) { QTextStream out (stdout ) ; QDate cd = QDate::currentDate(); out << "Today is " << cd.toString(Qt::TextDate) << endl ; out << "Today is " << cd.toString(Qt::ISODate) << endl ; out << "Today is " << cd.toString(Qt::SystemLocaleShortDate) << endl ; out << "Today is " << cd.toString(Qt::SystemLocaleLongDate) << endl ; out << "Today is " << cd.toString(Qt::DefaultLocaleShortDate) << endl ; out << "Today is " << cd.toString(Qt::DefaultLocaleLongDate) << endl ; out << "Today is " << cd.toString(Qt::SystemLocaleDate) << endl ; out << "Today is " << cd.toString(Qt::LocaleDate) << endl ; }
1 2 3 4 5 6 7 8 Today is Sat Oct 31 2015 Today is 2015-10-31 Today is 10/31/15 Today is Saturday, October 31, 2015 Today is 10/31/15 Today is Saturday, October 31, 2015 Today is 10/31/15 Today is 10/31/15
自定义日期格式
如下表:
预定义时间格式
和日期的类似,时钟对象的toString()
也接收格式描述对象参数。默认的是Qt::TextDate
。其他格式如下例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <QTextStream> #include <QTime> int main (void ) { QTextStream out (stdout ) ; QTime ct = QTime::currentTime(); out << "The time is " << ct.toString(Qt::TextDate) << endl ; out << "The time is " << ct.toString(Qt::ISODate) << endl ; out << "The time is " << ct.toString(Qt::SystemLocaleShortDate) << endl ; out << "The time is " << ct.toString(Qt::SystemLocaleLongDate) << endl ; out << "The time is " << ct.toString(Qt::DefaultLocaleShortDate) << endl ; out << "The time is " << ct.toString(Qt::DefaultLocaleLongDate) << endl ; out << "The time is " << ct.toString(Qt::SystemLocaleDate) << endl ; out << "The time is " << ct.toString(Qt::LocaleDate) << endl ; }
输出为
1 2 3 4 5 6 7 8 The time is 15:58:26 The time is 15:58:26 The time is 3:58 PM The time is 3:58:26 PM CET The time is 3:58 PM The time is 3:58:26 PM CET The time is 3:58 PM The time is 3:58 PM
自定义时间格式
其他工具函数
daysOfWeek()
: 周几,1 表示周一,7 表示周日;
daysInMonth()
: 在月中的第几天;
daysInYear():
: 在年中的第几天;
isValid()
: 验证日期是否有效;
daysTo()
,daysFrom
:计算日期的间距;
QDateTime
类
QDateTime
类是日期和时间的组合,其接口也非常类似。