1. 程式人生 > >【秒懂音視訊開發】05_Qt開發基礎

【秒懂音視訊開發】05_Qt開發基礎

## 控制元件的基本使用 為了更好地學習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";