【秒懂音視訊開發】05_Qt開發基礎
阿新 • • 發佈:2021-03-04
## 控制元件的基本使用
為了更好地學習Qt控制元件的使用,建議建立專案時先不要生成ui檔案。
![不生成ui檔案](https://img2020.cnblogs.com/blog/497279/202103/497279-20210304194032371-721491748.png)
開啟**mainwindow.cpp**,在MainWindow的建構函式中編寫介面的初始化程式碼。
### 視窗設定
```cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 設定視窗標題
setWindowTitle("主視窗");
// 設定視窗大小
// 視窗可以通過拖拽邊緣進行自由伸縮
// resize(400, 400);
// 設定視窗的固定大小
// 視窗不能通過拖拽邊緣進行自由伸縮
setFixedSize(400, 400);
// 設定視窗的位置
// 以父控制元件的左上角為座標原點
// 沒有父控制元件,就以螢幕的左上角作為座標原點
move(100, 100);
}
```
Qt座標系如下圖所示。
![Qt座標系](https://img2020.cnblogs.com/blog/497279/202103/497279-20210304194034450-1153331879.png)
### 新增子控制元件
```cpp
#include
// 建立按鈕
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](https://doc.qt.io/qt-5/signalsandslots.html)
![訊號與槽](https://img2020.cnblogs.com/blog/497279/202103/497279-20210304194036232-2086622242.png)
上圖中的效果是:
- Object1發出訊號signal1,交給Object2的槽slot1、slot2去處理
- Object1是訊號的傳送者,Object2是訊號的接收者
- Object1發出訊號signal2,交給Object4的槽slot1去處理
- Object1是訊號的傳送者,Object4是訊號的接收者
- Object3發出訊號signal1,交給Object4的槽slot3去處理
- Object3是訊號的傳送者,Object4是訊號的接收者
- 1個訊號可以由多個槽進行處理,1個槽可以處理多個訊號
通過connect函式可以將**訊號的傳送者**、**訊號**、**訊號的接收者**、**槽**連線在一起。
```cpp
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:**下面
- 自定義的訊號只需要宣告,不需要實現
```cpp
#ifndef SENDER_H
#define SENDER_H
#include
class Sender : public QObject
{
Q_OBJECT
public:
explicit Sender(QObject *parent = nullptr);
// 自定義訊號
signals:
void exit();
};
#endif // SENDER_H
```
- sender.cpp
```cpp
#include "sender.h"
Sender::Sender(QObject *parent) : QObject(parent)
{
}
```
#### 訊號的接收者
- receiver.h
- 自定義的槽建議寫在**public slots:**下面
```cpp
#ifndef RECEIVER_H
#define RECEIVER_H
#include
class Receiver : public QObject
{
Q_OBJECT
public:
explicit Receiver(QObject *parent = nullptr);
// 自定義槽
public slots:
void handleExit();
};
#endif // RECEIVER_H
```
- receiver.cpp
```cpp
#include "receiver.h"
#include
Receiver::Receiver(QObject *parent) : QObject(parent)
{
}
// 實現槽函式,編寫處理訊號的程式碼
void Receiver::handleExit()
{
qDebug() << "Receiver::handleExit()";
}
```
#### 連線
- mainwindow.h
```cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#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
```
- mainwindow.cpp
```cpp
#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()
{
}
```
#### 引數和返回值
訊號與槽都可以有引數和返回值:
- 發訊號時的引數會傳遞給槽
- 槽的返回值會返回到發訊號的位置
```cpp
// 自定義訊號
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;
```
需要注意的是:訊號的引數個數必須大於等於槽的引數個數。比如下面的寫法是錯誤的:
```cpp
// 自定義訊號
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個訊號](https://img2020.cnblogs.com/blog/497279/202103/497279-20210304194037999-1645593613.jpg)
可以利用**connect**函式連線2個訊號
- 當\_sender發出exit訊號時,_sender2會發出exit2訊號
- 當\_sender2發出exit2訊號時,_sender並不會發出exit訊號
```cpp
connect(this->_sender,
&Sender::exit,
this->_sender2,
&Sender2::exit2);
```
### Lambda
也可以直接使用Lambda處理訊號。
```cpp
connect(this->_sender, &Sender::exit, []() {
qDebug() << "lambda handle exit";