我参考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
类是日期和时间的组合,其接口也非常类似。