【秒懂音視頻開發】05_Qt開發基礎
控件的基本使用
為了更好地學習Qt控件的使用,建議創建項目時先不要生成ui文件。
打開mainwindow.cpp,在MainWindow的構造函數中編寫界面的初始化代碼。
窗口設置
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 設置窗口標題
setWindowTitle("主窗口");
// 設置窗口大小
// 窗口可以通過拖拽邊緣進行自由伸縮
// resize(400, 400);
// 設置窗口的固定大小
// 窗口不能通過拖拽邊緣進行自由伸縮
setFixedSize(400, 400);
// 設置窗口的位置
// 以父控件的左上角為坐標原點
// 沒有父控件,就以屏幕的左上角作為坐標原點
move(100, 100);
}
Qt坐標系如下圖所示。
添加子控件
#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函數可以將信號的發送者、信號、信號的接收者、槽連接在一起。
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:下面
- 自定義的信號只需要聲明,不需要實現
#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
- sender.cpp
#include "sender.h"
Sender::Sender(QObject *parent) : QObject(parent)
{
}
信號的接收者
- receiver.h
- 自定義的槽建議寫在public slots:下面
#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
- receiver.cpp
#include "receiver.h"
#include <QDebug>
Receiver::Receiver(QObject *parent) : QObject(parent)
{
}
// 實現槽函數,編寫處理信號的代碼
void Receiver::handleExit()
{
qDebug() << "Receiver::handleExit()";
}
連接
- mainwindow.h
#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
- mainwindow.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()
{
}
參數和返回值
信號與槽都可以有參數和返回值:
- 發信號時的參數會傳遞給槽
- 槽的返回值會返回到發信號的位置
// 自定義信號
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;
需要注意的是:信號的參數個數必須大於等於槽的參數個數。比如下面的寫法是錯誤的:
// 自定義信號
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
可以利用connect函數連接2個信號
- 當_sender發出exit信號時,_sender2會發出exit2信號
- 當_sender2發出exit2信號時,_sender並不會發出exit信號
connect(this->_sender,
&Sender::exit,
this->_sender2,
&Sender2::exit2);
Lambda
也可以直接使用Lambda處理信號。
connect(this->_sender, &Sender::exit, []() {
qDebug() << "lambda handle exit";
});