Qt 是一个C++ GUI应用框架,Qt 具有良好的可移植性支持大多数桌面和移动操作系统并常用于嵌入式开发。
Qt的发行版分为商业版和开源版,提供了Qt Creator作为轻量级IDE。
Hello World!
Qt应用的UI界面设计支持xml或者Qt Designer进行可视化设计,也可以通过C++代码建立视图。
Qt中的大多数类继承自QObject(没有继承QObject的类在开发中造成了很大麻烦),QtGui编程中各种可视化组件均继承自QWidget。
每个Qt GUI应用有且只有一个顶级组件,它可以是QWidget ,QMainWindow窗口应用,QDialog (对话框)。
上述 Qt 工程包括:
-
.pro 文件 qmake配置文件
-
dialog.h头文件 声明界面方法等
-
diaglog.cpp 事件监听及相应代码
-
main.cpp 入口和主程序逻辑
除了使用Qt Designer或编辑.ui文件外,Qt可以使用C++代码控制ui组件。这里我们完全使用代码创建一个与效果相同的工程,并解释它的机制。
mainwindow. h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
//防止重复包含的哨兵,C/C++惯用
#include <QMainWindow>
//包含组件
namespace Ui { //定义namespace
class MainWindow;
}
//顶级组件MainWindow的类声明
class MainWindow : public QMainWindow
{
Q_OBJECT
//Q_OBJECT宏提供了信号槽机制、国际化机制和不基于C++ RTTI的反射能力
//建议均包含此宏
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
//构造函数与析构函数
private:
Ui::MainWindow *ui; //定义了ui作为访问接口
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
包含mainwindow类的实现以及事件的响应代码(当然这里没有...)
注意构造函数使用了初始化列表(这种缩进容易让人晕掉...)
main.cpp:
#include "mainwindow.h"
#include <QApplication>
#include <QLabel>
#include <QPushButton>
//头文件包含
int main(int argc, char *argv[]) //main函数
{
QApplication a(argc, argv);//定义应用对象,从参数看它是支持命令行的
MainWindow w; //定义mainwindow顶级组件
QLabel *label = new QLabel("Hello World!", &w); //自定义Label组件
QPushButton *button = new QPushButton("Disp", &w);//自定义PushButton组件
w.show(); //绘制主窗口w
button -> show(); //绘制按钮
QObject::connect(button,SIGNAL(clicked()),label,SLOT(show()));
/*重点来了:信号槽
* 信号槽是Qt实现事件响应的机制,当某一组件的某事件发生时将会发出相应的信号(SIGNAL)
* 与此信号相关的槽(SLOT)将会收到该信号并响应事件
*
* connect函数则可以将信号和槽关联起来
* QObject::connect(Object *sender,Func signal,Object* reciver,Func slot)
* 信号和槽本质上都是函数,信号由组件定义,槽则由程序员定义
*/
return a.exec();
/* 运行消息循环
* 应用等待事件的发生并进行响应
*/
}
组件与布局
布局管理
与很多GUI框架一样,Qt 提供了布局(layout) 作为空间的容器 以自动地管理组件的位置。
Qt Desinger可以方便地设置布局,Qt 同样允许以C++代码创建布局:
示例1:
#include <QApplication>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *w = new QWidget;
QLabel *label = new QLabel("Hello World!");
QPushButton *button = new QPushButton("Clear");
QHBoxLayout *layout = new QHBoxLayout;
layout ->addWidget(label);
layout ->addWidget(button);
w->setLayout(layout);
w->show();
QObject::connect(button,SIGNAL(clicked()),label,SLOT(clear()));
return a.exec();
}
示例2:
#include <QApplication>
#include <QWidget>
#include <QSpinBox>
#include <QSlider>
#include <QHBoxLayout>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *window = new QWidget;
window->setWindowTitle("Enter your age");
QSpinBox *spinBox = new QSpinBox;
QSlider *slider = new QSlider(Qt::Horizontal);
spinBox->setRange(0, 130);
slider->setRange(0, 130);
QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int)));
QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)));
spinBox->setValue(35);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(spinBox);
layout->addWidget(slider);
window->setLayout(layout);
window->show();
return app.exec();
}
以Qwidget或QDialog为顶级组件的应用可以使用上述代码创建布局,以QMainWindow为顶级组件的应用无法用这种方式来创建布局。
其它常用组件请参考Qt API文档...
组件介绍
QTimer 计时器
QTimer *timer = new QTimer(QObject *);
它可以使用start(int msec)方法来开始计时timer->start(1000);
start()函数同时还是一个槽函数。
当计时结束,timer组件将发出timeout()信号,然后开始下一轮计时。
timer -> stop();
方法将阻止继续计时。
static void QTimer::singleShot(int msec, QObject receiver, SLOT());
该方法只会在第一次时间到后定向发出timeout()信号,不再继续计时。这是一个静态方法无需建立QTimer对象即可使用。
若QTimer的计时时间设为0,则当事件队列为空时发出timeout()信号。
请不要这一机制而使用多线程机制代替。
当然,QWidget子类的timerEvent()方法可以更方便的实现计时。
QWidget::startTimer(interval)
实例方法用来启动计时器,每隔interval毫秒发出执行一次QWidget::timerEvent(event)
方法。
菜单(QMenuBar)、工具(QToolBar)与状态栏(QStatusBar)
示例:
#include "mainwindow.h"
#include <QApplication>
#include <QMenu>
#include <QMenuBar>
#include <QToolBar>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow *w = new MainWindow;
QAction *openAction = new QAction(w);
openAction ->setIconText("Open");//设置QACtion组件显示的文字
openAction -> setStatusTip("Open a File");
//设置状态栏信息,当鼠标指针指向该组件时信息会一直显示
QMenu *fileMenu = w->menuBar()->addMenu("File");//新键菜单
fileMenu -> addAction(openAction); //新键菜单项
QToolBar *toolBar = w->addToolBar("F");//新建工具栏
toolBar->addAction(openAction);//添加工具
//QStatusBar *status = w -> statusBar();
//与QMenuBar类似的函数可以获得状态栏指针
w -> show();
return a.exec();
}
标准对话框
Qt 提供了消息、打开文件、保存文件、选择颜色等标准对话框,它们可以实例化也可以通过静态函数进行调用。
- QMessageBox 消息框
- QFileDialog 文件对话框(获取路径而已)
- QColorDialog 颜色对话框
- QInputDialog 输入框
- QPrintDialog 打印对话框
下面以QMessageBox为例说明:
通过静态函数使用对话框:
void QMessageBox::about(QWidget * parent, const QString & title, const QString & text)
显示关于对话框,其标题是 title、内容是 text、父窗口是 parent,对话框只有一个 OK 按钮。
void QMessageBox::aboutQt(QWidget * parent, const QString & title = QString())
显示关于 Qt 对话框。
StandardButton QMessageBox::critical(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton)
显示严重错误对话框。这个对话框将显示一个红色的错误符号。我们可以通过 buttons 参数指明其显示的按钮。默认情况下只有一个 Ok 按钮,我们可以使用StandardButtons类型指定多种按钮。
StandardButton QMessageBox::information(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton)
QMessageBox::information()函数与QMessageBox::critical()类似,不同之处在于这个对话框提供一个普通信息图标。
StandardButton QMessageBox::question(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = StandardButtons( Yes | No ), StandardButton defaultButton = NoButton)
QMessageBox::question()函数与QMessageBox::critical()类似,不同之处在于这个对话框提供一个问号图标,并且其显示的按钮是“是”和“否”两个。
StandardButton QMessageBox::warning(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton)
QMessageBox::warning()函数与QMessageBox::critical()类似,不同之处在于这个对话框提供一个黄色叹号图标。
通过通过QMessageBox对象使用对话框
QMessageBox msg;
msg.setText("Hello");
msg.exec();
从示例可以看出QMessageBox需要事件循环,exec()同时也是QMessageBox()的槽函数。
更多精彩尽在API 文档...
取代标准C++的做法
QString
Qt定义了QString类作为字符串以取代C++定义的两种风格的字符串。
QString重载了"+"和"+="运算符进行字符串连接,Qt Creator也把字符串字面值当作QString来处理。
QString的sprintf()函数提供了类似C中printf()函数的作用,配合arg()函数使用以提供类型安全,不过作为GUI框架的QT这种用法较少。
对于原生C++的两种字符串+,+=运算符可以将其转换为QString并将其连接。 * QString的toStdString()实例方法和fromStdString()静态方法可将QString和std::String相互转换 *
QString::number()系列重载静态函数可以将数字转换为字符串或者使用str.setNum()完成同样转换。
因为QString::number()函数含有base参数所以可以用作进制转换。
tr.toInt(bool *)
,str.toDouble(bool*)
接收一个bool指针作为参数,若转换成功则返回结果并将参数设为true;否则参数则设为false。
str.mid()
,str.left()
,str,right()
函数提供截取子串功能。
str.indexof(QString sub,int from)
则可以返回子串的位置。
replace()和insert()函数提供代换和插入功能。
trimmed()函数可以去掉字符串首尾的空白字符(空格,[Tab],换行符)。
simplified()函数将连续的空白字符用一个空格代替。
toUpper()和toLower()则进行大小写转换。
QByteArray
QByteArray是一个二进制数组,以字节为单位, 常用作缓冲区。
QByteArray保证结尾一定是' '(其内部也可存储 )这一特性保证它可以转换char *(建议还是用QString)。
QByteArray提供了与QString相似的API。
QVariant
它是一个包含绝大多数Qt类、C++类、C++基本类型的共用体, 可以与任意的Qt类进行转化,常用于泛型。
它被用于构建Meta - Object , 是QCore的一部分。
Qt线性容器
QVector
type必须提供默认构造函数,复制构造函数和赋值运算符。
发布Qt应用
发布Qt 编写的软件需要以"release" 配置编译源代码,Qt Creator左下角的运行工具栏中可以更改配置,Vs在[project/项目]->[属性/properties]中进行配置。
将编译得到的二进制可执行文件与必要的支持库打包。
支持库由.pro文件中设置的模块决定,一般包含core和gui模块的Qt应用需要以下支持库文件:
-
Qt库文件[Qtlib]
-
Qt5Core.dll
-
Qt5Gui.dll
-
Qt5Widgets.dll
-
-
Qt Platform插件[Qtpluginsplatforms]
复制文件夹并删除其中的.pdb文件,只保留.dll文件。
qwindows.dll】同名.dll文件中删除带有d后缀(debug模式所需)的.dll文件,如删除"qwindowsd.dll",保留"qwindows.dll"。
Desktop平台下所需的文件:
- qoffscreen.dll
- qminimal.dll
- ICU库[Qtin]
ICU库用于提供对Unicode字符编码的支持
- icudt53.dll
- icuin53.dll
- icuuc53.dll
-
C++ Runtime Library
-
msvcp120.dll
-
msvcr120.dll
-
-
OpenGl支持库
- libEGL.dll
-
Windows平台相关
-
gpsvc.dll
-
kernel32.dll
-
其它技术
国 际化
Qt 使用Unicode编码表示字符串为国际化创造了基础,常用的有QTextCodec类以及QObject::tr()函数,后者是Qt推荐的做法。
tr函数是translation的简写,tr()函数是QObject类提供的静态函数。
tr()函数接收一个字符串作为参数,并返回翻译后的字符串。
其翻译功能支持由Meta-Object等系统提供(后台硬系列)。
r函数的参数字符串中'&'的字符可以标记其后的一个字符,并将该字符设为快捷键。
在无法使用函数的场合(如数组的初始化列表),QT_TR_NOOP()和QT_TRANSLATE_NOOP()宏可以替代tr()函数,前者接收一个字符串作为参数并将其翻译,后者可以处理多个字符串。
鉴于自动翻译发展的现状,国际化不是一个函数就能完成的,tr()函数是一个标记,国际化仍依赖人工翻译。
(1) 在工程的.pro文件中增加【TRANSLATIONS += *.ts】
*代表ts文件具体文件名,ts文件是XML编码的翻译(源)文件
(2)创建.ts文件
使用lupdate命令,参数为工程的.pro文件
这命令是更新.ts文件,避免重复翻译
(3) 使用Qt Linguist打开.ts文件,进行翻译
Qt Linguist会提出翻译建议,但是翻译工作还要人工做
使用文件->发布命令在工程目录下创建.qm文件
(4) 安装.qm文件
包含头文件【#include
QApplication a(argc, argv);
QTranslator trans;
trans.load("HelloWorld.qm");
a.installTranslator(&trans);
.qm文件为动态加载的,当更换语言后只需要更新.qm文件并重新运行程序即可,无需重新编译。
Qt 多窗口程序设计
-
在项目上选择添加新文件,Qt -> Qt 设计师模板类
-
选择界面模板
-
选择类名,注意不要和已有类重复。
Qt Creator会自动创建响应的头文件(.h)、源文件(.cpp)和界面文件(.ui)
4)声明新的界面类
在main.cpp文件中包含新的界面类头文件
#include "mainwindow2.h"
在namespace Ui中添加新的界面类
namespace Ui {
class MainWindow;
class MainWindow2;
}
根据需要定义界面对象,在需要时调用其show()方法显示界面。
Qt 应用图标设置
运行图标的设置
应用程序在Windows平台上运行时,任务栏中会出现图标,一般窗口的左上角也会出现对应的图标,将这个图标称为运行图标。
运行图标属于整个应用,即QApplication对象,调用QApplication::setWindowIcon(QIcon(QString Path));
实例方法可以设置应用图标。
文件图标的设置
可执行文件也拥有自己的图标,但这个图标由操作系统设置。
windows平台下:
首先将图标的ico文件放入工程目录中,然后定义主文件名与工程同名的.rc文件(注意不是.qrc文件)。
在文件中写入:IDI_ICON1 ICON DISCARDABLE"img.ico"
"img.ico"代表相对路径和文件名)。保存文件并重新编译就可以更新图标。
图标文件会以二进制格式写入.exe文件中,制作发布版时无需包含.rc文件和图标文件。