原文
https://www.cnblogs.com/mjios/p/14482571.html
控件的基本使用
为了更好地学习Qt控件的使用,建议创建项目时先不要生成ui文件。
不生成ui文件
打开mainwindow.cpp,在MainWindow的构造函数中编写界面的初始化代码。
窗口设置
复制代码
C++
| MainWindow::MainWindow(QWidget *parent) |
| : QMainWindow(parent) |
| { |
| // 设置窗口标题 |
| setWindowTitle("主窗口"); |
| |
| // 设置窗口大小 |
| // 窗口可以通过拖拽边缘进行自由伸缩 |
| // resize(400, 400); |
| |
| // 设置窗口的固定大小 |
| // 窗口不能通过拖拽边缘进行自由伸缩 |
| setFixedSize(400, 400); |
| |
| // 设置窗口的位置 |
| // 以父控件的左上角为坐标原点 |
| // 没有父控件,就以屏幕的左上角作为坐标原点 |
| move(100, 100); |
| } |
Qt坐标系如下图所示。
Qt坐标系
添加子控件
复制代码
C++
| #include <QPushButton> |
| |
| // 创建按钮 |
| QPushButton *btn = new QPushButton; |
| // 设置按钮的文字 |
| btn->setText("登录"); |
| // 设置父控件为当前窗口 |
| btn->setParent(this); |
| // 设置按钮的位置和大小 |
| btn->move(50, 50); |
| btn->resize(100, 50); |
| |
| // 创建第2个按钮 |
| new QPushButton("注册", this); |
new出来的Qt控件是不需要程序员手动delete的,Qt内部会自动管理内存:当父控件销毁时,会顺带销毁子控件。
信号与槽
基本使用
- 信号(Signal):比如点击按钮就会发出一个点击信号
- 槽(Slot):一般也叫槽函数,是用来处理信号的函数
- 官方文档参考:Signals & Slots
信号与槽
上图中的效果是:
- Object1发出信号signal1,交给Object2的槽slot1、slot2去处理
- Object1是信号的发送者,Object2是信号的接收者
- Object1发出信号signal2,交给Object4的槽slot1去处理
- Object1是信号的发送者,Object4是信号的接收者
- Object3发出信号signal1,交给Object4的槽slot3去处理
- Object3是信号的发送者,Object4是信号的接收者
- 1个信号可以由多个槽进行处理,1个槽可以处理多个信号
通过connect函数可以将信号的发送者、信号、信号的接收者、槽连接在一起。
复制代码
C++
| connect(信号的发送者, 信号, 信号的接收者, 槽); |
| |
| // 比如点击按钮,关闭当前窗口 |
| // btn发出clicked信号,就会调用this的close函数 |
| connect(btn, &QAbstractButton::clicked, this, &QWidget::close); |
| |
| // 可以通过disconnect断开连接 |
| disconnect(btn, &QAbstractButton::clicked, this, &QWidget::close); |
自定义信号与槽
信号的发送者和接收者都必须继承自QObject,Qt中的控件最终都是继承自QObject,比如QMainWindow、QPushButton等。
信号的发送者
- sender.h
- Q_OBJECT用以支持自定义信号和槽
- 自定义的信号需要写在signals:下面
- 自定义的信号只需要声明,不需要实现
复制代码
C++
| #ifndef SENDER_H |
| #define SENDER_H |
| |
| #include <QObject> |
| |
| class Sender : public QObject |
| { |
| Q_OBJECT |
| public: |
| explicit Sender(QObject *parent = nullptr); |
| |
| // 自定义信号 |
| signals: |
| void exit(); |
| }; |
| |
| #endif // SENDER_H |
复制代码
C++
| #include "sender.h" |
| |
| Sender::Sender(QObject *parent) : QObject(parent) |
| { |
| |
| } |
信号的接收者
复制代码
C++
| #ifndef RECEIVER_H |
| #define RECEIVER_H |
| |
| #include <QObject> |
| |
| class Receiver : public QObject |
| { |
| Q_OBJECT |
| public: |
| explicit Receiver(QObject *parent = nullptr); |
| |
| // 自定义槽 |
| public slots: |
| void handleExit(); |
| }; |
| |
| #endif // RECEIVER_H |
复制代码
C++
| #include "receiver.h" |
| #include <QDebug> |
| |
| Receiver::Receiver(QObject *parent) : QObject(parent) |
| { |
| |
| } |
| |
| // 实现槽函数,编写处理信号的代码 |
| void Receiver::handleExit() |
| { |
| qDebug() << "Receiver::handleExit()"; |
| } |
连接
复制代码
C++
| #ifndef MAINWINDOW_H |
| #define MAINWINDOW_H |
| |
| #include <QMainWindow> |
| #include "sender.h" |
| #include "receiver.h" |
| |
| class MainWindow : public QMainWindow |
| { |
| Q_OBJECT |
| private: |
| Sender *_sender; |
| Receiver *_receiver; |
| void test1(); |
| |
| public: |
| MainWindow(QWidget *parent = nullptr); |
| ~MainWindow(); |
| }; |
| #endif // MAINWINDOW_H |
复制代码
C++
| #include "mainwindow.h" |
| |
| MainWindow::MainWindow(QWidget *parent) |
| : QMainWindow(parent) |
| { |
| this->_sender = new Sender; |
| this->_receiver = new Receiver; |
| |
| // 连接 |
| connect(this->_sender, |
| &Sender::exit, |
| this->_receiver, |
| &Receiver::handleExit); |
| |
| // 发出信号 |
| // 最终会调用Receiver::handleExit函数 |
| emit this->_sender->exit(); |
| } |
| |
| MainWindow::~MainWindow() |
| { |
| |
| } |
参数和返回值
信号与槽都可以有参数和返回值:
- 发信号时的参数会传递给槽
- 槽的返回值会返回到发信号的位置
复制代码
C++
| // 自定义信号 |
| signals: |
| int exit(int a, int b); |
| |
| // 自定义槽 |
| public slots: |
| int handleExit(int a, int b); |
| |
| int Receiver::handleExit(int a, int b) |
| { |
| // Receiver::handleExit() 10 20 |
| qDebug() << "Receiver::handleExit()" << a << b; |
| return a + b; |
| } |
| |
| // 发出信号 |
| int a = emit this->_sender->exit(10, 20); |
| // 30 |
| qDebug() << a; |
需要注意的是:信号的参数个数必须大于等于槽的参数个数。比如下面的写法是错误的:
复制代码
C++
| // 自定义信号 |
| signals: |
| void exit(int a); |
| |
| // 自定义槽 |
| public slots: |
| void handleExit(int a, int b); |
连接2个信号
比如下图,连接了Object 1的Signal 1A和Object 2的Signal 2A
- 当Object 1发出Signal 1A时,会触发Slot X、Slot Y
- 当Object 2发出Signal 2A时,只会触发Slot Y,而不会触发Slot X
连接2个信号
可以利用connect函数连接2个信号
- 当_sender发出exit信号时,_sender2会发出exit2信号
- 当_sender2发出exit2信号时,_sender并不会发出exit信号
复制代码
C++
| connect(this->_sender, |
| &Sender::exit, |
| this->_sender2, |
| &Sender2::exit2); |
Lambda
也可以直接使用Lambda处理信号。
复制代码
C++
| connect(this->_sender, &Sender::exit, []() { |
| qDebug() << "lambda handle exit"; |
| }); |