基本介绍
以下是介绍初始化代码的含义,如果做一个项目,新建一个空项目开始写。
初始程序
新建Application (Qt) 项目,初始main.cpp文件代码如下:
#include <QApplication>
int main(int argc, char *argv[]){
QApplication a(argc, argv);
//只有一个应用程序
MyWidget w;
//MyWidget继承于QWidget,是一个窗口基类,w是一个窗口
w.show();
//窗口默认隐藏,需要人为显示
a.exec();
//一直显示界面
return 0;
//最后两行也可以写成return a.exec();
}
.pro文件说明如下
QT += core gui #模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets #为了兼容QT4
TARGET # 应用程序的名字(标题)
TEMPLATE = app # 指定makefile的类型(可能没有)
SOURCES += main.cpp\
mywidget.cpp
HEADERS += mywidget.h
CONFIG += C++11 #表示支持C++11标准
创建一个myWidget.cpp文件,代码如下:
#include <QWidget>
class MyWidget : public QWidget{
public:
MyWidget(QWidget *parent = 0);
~MyWidget();
}
创建按钮
按钮的相关API如下代码所示,在main.cpp中包含头文件
#include <QPushButton> //在main.cpp中包含头文件
QPushButton b; //创建对象
b.setParent(&w); //指定父对象
b.move(num1, num2); //移动按钮,num1和num2分别为x和y坐标
b.setText(“buttonName”); //设置按钮名称
创建按钮时需要把指定按钮的父对象,不指定的话表现为按钮和主窗口是独立的
指定父对象有两种方式:
-
setParent
b.setParent(&w);
setParent函数参数为指针类型
-
通过构造函数传参
b = new QPushButton(this);
也可以直接在myWidget.h文件中创建按钮
在MyWidget类的私有成员中添加:
QPushButton b1;
QPushButton *b2;
myWidget.cpp文件中,在类的构造函数中定义,其中b1和b2编写方式有所不同:
b1.setParent(this);
b1.setText("ButtonName1");
b2 = new QPushButton(this);
b2->setText("ButtonName2");
信号和槽
信号(signal)就是在特定情况下被发射的事件,比如PushButton常见信号是单击鼠标时发射的clicked()信号
槽(slot)就是对信号响应的函数。与一般C++函数一样,可定义在类的任意部分(public \ private),可以具有任何参数也可以被直接调用。不同的是,槽函数可以与一个信号关联,信号被发射时,关联的槽函数自动执行。
GUI程序设计的主要内容就是对界面上各组件的信号的响应,信号与槽机制是 Qt GUI 编程的基础,使用信号与槽机制可以比较容易地将信号与响应代码关联起来。
在使用信号与槽的类中,必须在类的定义中加入宏 Q_OBJECT。
信号和槽连接函数
信号和槽关联是用QObject::connect()函数实现,基本格式为
connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
connect函数参数解释:
- sender是发射信号的对象名称(指针类型)
- signal()是信号名称。信号可看作特殊函数,需要带括号,有参数需指明参数。
&发射者的类名::信号名 - receiver是接收信号的对象名称
- slot()是槽函数名称(信号处理函数)。
&接收者类名::槽函数名
比如上述代码中,单击b1按钮执行关闭界面功能:
connect(&b1, &QPushButton::clicked, this, &MyWidget::close);
将 btnClose 按钮的 clicked() 信号与窗体(Widget)的槽函数 close() 相关联,当单击 btnClose 按钮(就是界面上的“Close”按钮)时,就会执行 Widget 的 close() 槽函数。
信号和槽连接规则
一个信号可以连接多个槽,多个信号可以连接同一个槽,一个信号可以连接另外一个信号
- 一个信号可以连接多个槽:
sender对象发射信号时,其连接的多个槽按建立连接的顺序依次执行 - 多个信号可以连接同一个槽
任一sender对象发射信号,都会执行槽函数 - 一个信号可以连接另外一个信号
一个信号发射时,也会发射另一信号
自定义槽
槽函数可以是任意的成员函数,普通全局函数,静态函数
槽函数需要和信号一致(参数,返回值)。由于信号没有返回值,所以槽函数一定没有返回值
信号可以带参数,因此可以重载,连接时需要定义函数指针来指明。
信号用signals关键字修饰之后,可以用宏SIGNAL查找,相应地,槽可以用slots修饰,用宏SLOT查找。(QT4)(尽量少使用)
注意,宏查找会将函数名字用字符串替换,不进行错误检查,可能会引发错误
切换窗口
首先在项目中创建一个新类subWindow,在主窗口的私有成员中创建类对象
SubWindow sw;
先在公有成员中定义一个切换窗口和处理子类对象发射信号的函数(切换回主窗口)
void showSub(); //隐藏主窗口,显示子窗口
void showMain(); //隐藏子窗口,显示主窗口
在类中的signals模块中定义信号函数
信号必须有signals关键字来声明,没有返回值,可以有参数
signals: void changeWindow();
设置一个切换窗口的按钮sw1,将sw1的点击事件与函数sendChangeWindowSlot()连接,自定义函数中发射信号:
emit changeWindow();
在主窗口的类myWidget中增加一条连接,连接子窗口发射的信号名changeWindow与showMain()函数。
Lambda
Lambda是C++11新特性,这部分介绍怎么把QT和Lambda结合使用
在自定义槽函数过程中,单击某一按钮发射信号,都需要在主类中定义槽函数,并用connect()函数连接,而使用Lambda可以这样写:
b3 = new QPushButton(this);
b3->setText("print")
connect()b3, &QPushButton::clicked, [](){
qDebug() << "Hello";
}
);
如果想在lambda函数体中使用b3,需要在方括号中传入参数b3,即
connect()b3, &QPushButton::clicked, [b3](){
b3->setText("changed") //如果方括号不加b3参数,该行编译错误(捕获不到)
qDebug() << "Hello";
}
);
方括号里加等号"[=]",表示把外部所有局部变量、类中所有成员以值传递方式传入函数,默认只读,如果需要修改,加mutable修饰
[=]() mutable {
}
菜单栏
如代码所示,一般window应用程序要添加的控件示例
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QToolBar>
#include <QStatusBar>
#include <QLabel>
#include <QPushButton>
#include <QTextEdit>
#include <QDockWidget>
...{
QMenuBar * mBar = menuBar(); //菜单栏
//添加菜单
QMenu *pFile = mBar->addMenu("文件");
QMenu *pEdit = mBar->addMenu("编辑");
QMenu *pTool = mBar->addMenu("工具");
QMenu *pHelp = mBar->addMenu("帮助");
//添加菜单项/动作
QAction *pNew = pFile->addAction("新建");
QAction *pOpen = pFile->addAction("打开");
pFile->addSeparator(); //添加分割线
//添加按钮小控件
QPushButton *b = new QPushButton(this);
b->setText("Save");
toolBar->addWidget(b);
//状态栏
QStatusBar *stBar = statusBar();
QLabel *label = new QLabel(this);
label->setText("Normal Text File");
statusBar->addWidget(label);
//核心控件:文本编辑区
QTextEdit *txEdit = new QTextEdit(this);
setCentralWidget(textEdit);
//浮动窗口
QDockWidget *dock = new QDockWidget(this);
addDockWidget(Qt::RightDockWidgetArea, dock);
}
对话框
对话框(Dialog)分为模态对话框和非模态对话框,常用的是标准对话框和文件对话框
模态和非模态
- 模态对话框要求用户只能处理当前对话框,不能选中其他对话框
- 非模态对话框允许用户处理其他对话框
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QDialog>
...{
QMenuBar *mar = menuBar();
setMenuBar(mBar);
QMenu *menu = mBar->addMenu("对话框");
QAction *p1 = menu->addAction("模态对话框")
connect(p1, &QAction::triggered,
[=](){
QDialog dlg;
dlg.exec();//模态对话框
//dlg.show(); //非模态对话框
}
);
}
运行完connect函数体,非模态对话框会消失,因此需要在主类中创建对话框对象
或者在函数体中动态创建,但是要注意释放,否则内存越用越少。可以设置对话框属性来实现:
p->setAttribute(Qt::WA DeleteOnClose);
标准对话框
标准对话框需要包含头文件#include <QMessageBox>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QDialog>
#include <QMessageBox>
...{
...
QAction *p2 = menu->addAction("标准对话框")
connect(p2, &QAction::triggered,
[=](){
QMessageBox::about(this, "Title", "Context");
}
);
QAction *p3 = menu->addAction("问题对话框")
connect(p3, &QAction::triggered,
[=](){
int ret = QMessageBox::question(this, "Title", "Yes or No?",
QMessageBox::Ok | QMessageBox::Cancle);
swtich(ret){
case QMessageBox::Ok: ... break;
case QMessageBox::Cancle: ... break;
default: break;
}
}
);
}
文件对话框
打开一个文件的对话框
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QDialog>
#include <QMessageBox>
#include <QFileDialog>
...{
...
QAction *p4 = menu->addAction("文件对话框")
connect(p4, &QAction::triggered,
[=](){
QString path = QFileDialog::getOpenFileName(
this,
"Title",
"Path",
"source(*.cpp *.h);;Text(*.txt);;all(*.*)"
//指定格式
);
}
);
}
其他
光标指定某一对象,按F1可跳至帮助文档
QT中输入输出:
#include <QDebug>
可以把qDebug()当作C++中的cout来使用,比如
qDebug() << str.toUtf8().data();
QString类型的str直接打印不能正确输出,必须使用上述的代码转换成utf8格式之后再输出