Qt学习之路(一)

Qt的安装

我是在kylin-v10的环境下进行下载的,与ubuntu是类似的

下载地址:https://download.qt.io/official_releases/qt/

可能需要赋予权限:chmod +x qt-opensource-linux-x64-5.14.2.run

打开安装包:./qt-opensource-linux-x64-5.9.2.run

Hello,world

1
2
3
4
5
6
7
8
9
#include <QApplication>
#include <QLabel>
/*头文件对QApplication类和QLabel进行了声明*/
int main(int argc, char *argv[]){
QApplication app(argc, argv); /*创建了QApplication对象,管理整个应用程序*/
QLabel *label = new QLabel("Hello,world!"); /*窗口部件(widget)*/
label->show();
return app.exec();
}

成功啦,显示如下:

image-20210726154217406

有意思的,可以在上述程序的基础上添加html标签:

1
2
3
4
5
6
7
8
9
#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[]){
QApplication app(argc, argv);
QLabel *label = new QLabel("<i>Hello</i>,<b>world!</b>");
label->show();
return app.exec();
}

image-20210726154105106

建立连接

1
2
3
4
5
6
7
8
9
10
#include <QApplication>
#include <QPushButton>

int main(int argc, char *argv[]){
QApplication app(argc, argv);
QPushButton *button = new QPushButton("Quit");
QObject::connect(button, SIGNAL(clicked()), &app, SLOT(quit()));/*通过signal来表明一个用户动作的发生或状态的改变,信号与槽slot相连接,执行里面的函数*/
button->show();
return app.exec();
}

窗口部件的布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <QApplication>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
int main(int argc, char *argv[]){
QApplication app(argc, argv);

QWidget *window = new QWidget;

QLabel *label = new QLabel("Hello,world!");

QPushButton *button = new QPushButton("Quit");
QObject::connect(button, SIGNAL(clicked()), &app, SLOT(quit()));

QHBoxLayout * layout = new QHBoxLayout;
layout->addWidget(label); //将label添加到layout
layout->addWidget(button); //将button添加到layout
window->setLayout(layout); //将layout添加到window
window->show();

return app.exec();
}

image-20210726162046549

将两个widget的值绑定在一起

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 <QApplication>
#include <QLabel>
#include <QPushButton>
#include <QSpinBox>
#include <QSlider>
#include <QHBoxLayout>
int main(int argc, char *argv[]){
QApplication app(argc, argv);

QWidget *window = new QWidget;
QSlider *slider = new QSlider(Qt::Horizontal);
QSpinBox *spinBox = new QSpinBox;
spinBox->setRange(0,130);
slider->setRange(0,130);
QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)));
QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int)));
spinBox->setValue(35);
QHBoxLayout * layout = new QHBoxLayout;
layout->addWidget(spinBox);
layout->addWidget(slider);
window->setLayout(layout);
window->show();

return app.exec();
}

image-20210726163311497

对connect的理解应该会更加深刻了。可以简单理解为两个组件之间的通信。前两个参数包含组件地址和SIGNAL;后两个参数包含另一个组件地址和SLOT

创建对话框

finddialog.h文件

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
#ifndef FINDDIALOG_H
#define FINDDIALOG_H /*防止对这个文件的多重包含*/
/*QDialog 由QWidget派生出来*/
#include <QDialog>
/*声明一些用于对话框实现的Qt类*/
class QCheckBox;
class QLabel;
class QLineEdit;
class QPushButton;
/*定义FindDialog,并让它称为QDialog的子类*/
class FindDialog : public QDialog{
Q_OBJECT /*对所有的定义得SIGNAL和SLOT类,都需要Q_OBJECT宏*/
public:
FindDialog(QWidge*parent = 0); /*默认为空指针,没有父对象*/
signals: /*当用户单击Find时,发射两个SIGNAL,如果向前查询生效,则发射findPrevious信号,否则发射findNext信号*/
/*signals实际上是一个宏*/
void findNext(const QString &str, Qt::CaseSensitivity cs);
void findPrevious(const QString &str, Qt::CaseSensitivity cs);/*Qt::CaseSensitivity是一个枚举类型,具有Qt::CaseSensitive 和 Qt::CaseInsensitive两种取值*/
private slots:
void findClicked();
void enableFindButton(const QString &text);
private:
QLabel *label;
QLineEdit *lineEdit;
QCheckBox *caseCheckBox;
QCheckBox *backwardCheckBox;
QPushButton *findButton;
QPushButton *closeButton;
/*没有使用这些类的相关头文件,而是直接声明该类,可以使得编译过程更快*/
};

#endif // FINDDIALOG_H

再来看看FindDialog的实现:

注意,由于版本的问题,<QtGui>改写为<QtWidgets>

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <QtWidgets>
#include "finddialog.h"
/*构造函数*/
FindDialog::FindDialog(QWidget *parent) : QDialog(parent){
label = new QLabel(tr("Find &what:"));/*tr()函数的作用时把它翻译成其他语言的标记,在字符串周围使用tr()是一个不错的习惯*/
/*&用来表示快捷键。比如使用Alt+F可以用来激活Find*/
lineEdit = new QLineEdit;
label->setBuddy(lineEdit);/*buddy伙伴,在标签按下快捷键时,可以接收到焦点(focus),就会移动到行编辑器上*/

caseCheckBox = new QCheckBox(tr("Match &case"));
backwardCheckBox = new QCheckBox(tr("Search &backward"));

findButton = new QPushButton(tr("&Find"));
findButton->setDefault(true);/*指用户按下Enter时,默认按下的按钮*/
findButton->setEnabled(false);/*禁用,呈现灰色*/

closeButton = new QPushButton(tr("Close"));
connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(enableFindButton(const QString &)));/*当有字符变化时,find按钮启用*/
connect(findButton, SIGNAL(clicked()),this, SLOT(findClicked()));
connect(closeButton, SIGNAL(clicked()),this,SLOT(closed()));
/*QObject FindDialog 的父对象之一,所以可以省略 connect() 函数前面的 QObject: :前缀*/
QHBoxLayout * topleftLayout = new QHBoxLayout;/*打横*/
topleftLayout->addWidget(label);
topleftLayout->addWidget(lineEdit);

QVBoxLayout * leftLayout = new QVBoxLayout;/*打竖*/
leftLayout->addLayout(topleftLayout);
leftLayout->addWidget(caseCheckBox);
leftLayout->addWidget(backwardCheckBox);

QVBoxLayout * rightLayout = new QVBoxLayout;
rightLayout->addWidget(findButton);
rightLayout->addWidget(closeButton);
rightLayout->addStretch();/*分隔符/伸展器,确保按钮占用它们所在布局的上部空间*/

QHBoxLayout * mainLayout = new QHBoxLayout;
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
setLayout(mainLayout);

setWindowTitle(tr("Find"));
setFixedHeight(sizeHint().height());
}

void FindDialog::findClicked(){
QString text = lineEdit->text();
Qt::CaseSensitivity cs = caseCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive;
/*根据backward的选项来确定往前搜索还是往后搜索*/
if(backwardCheckBox->isChecked()){
emit findPrevious(text, cs);
}else{
emit findNext(text, cs);
}
}

void FindDialog::enableFindButton(const QString &text){
findButton->setEnabled(!text.isEmpty());
}

main函数:

1
2
3
4
5
6
7
8
9
10
11
#include <QApplication>

#include "finddialog.h"

int main(int argc, char *argv[]){
QApplication app(argc, argv);
FindDialog *dialog = new FindDialog;
dialog->show();
return app.exec();
}

image-20210727094518994

父子关系:

image-20210727095504820

最终实现:


image-20210726175646948

关于信号与槽

  • 一个信号可以连接多个槽
  • 多个信号可以连接同一个槽
  • 一个信号可以与另外一个信号相连接
  • 连接可以被移除
  • 信号与槽的参数必须具有相同的顺序与类型。(信号的参数若多于槽,则多余参数会被忽略)

参考资料

  • 《C++ GUI Qt 4 编程(第二版)》《C++ GUI programming with Qt4》电子工业出版社

Qt学习之路(一)
https://wuhlan3.github.io/2021/07/26/Qt学习之路(一)/
Author
Wuhlan3
Posted on
July 26, 2021
Licensed under