iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 4
0
Software Development

Qt 跨平台應用程式開發系列 第 5

D05: Qt 信號槽 signal/slot

本系列文大綱

D05: Qt 信號槽 signal/slot

昨天的 D04: Qt 排版系統裡,我們已經可以在視窗上添加按鈕了,今天我們就要來說明怎麼讓按鈕發生作用。

大多數的 GUI 圖形介面程式都是「事件驅動」的。什麼叫「事件驅動」呢?

比方說使用者「按下列印按鈕」後開始列印文件,使用者「按了 Ctrl+C」把內容保存到剪貼簿,使用者「點了滑鼠右鍵」彈出右鍵選單。「按鈕被按下」「敲擊鍵盤」「滑鼠點擊」這些就是事件。程式收到事件後,做出行動回應事件。如果沒有事件發生,那程式就靜靜的等待。

所以撰寫 GUI 程式時,很重要的一部分就是連結「事件」和「回應的行動」

今天要介紹的 signal/slot 信號槽,就是 Qt 處理這部份的機制。

程式範例

今天的範例一樣是由一個 Qt 專案檔 (.pro) + 一個 CPP 組成。不知道怎麼設定跟編譯 Qt 程式的人,請參考 D03: 第一支 Qt 程式

這是 Qt 專案檔,檔名 myqt-d05.pro:

QT += widgets           # 引入 Qt widgets 模組
TEMPLATE = app          # 這是一支應用程式 (app)
TARGET = QtLayout       # 指定執行檔名字
SOURCES = myqt-d05.cpp  # 這支專案有一個 CPP

這是 CPP 檔,檔名 myqt-d05.cpp

// 這是 myqt-d05.cpp
#include <QApplication>
#include <QWidget>
#include <QHBoxLayout>
#include <QPushButton>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget w;

    QHBoxLayout* layout = new QHBoxLayout;
    w.setLayout(layout);

    QPushButton* button = new QPushButton("關於 Qt");
    layout->addWidget(button);
    QObject::connect(button, &QPushButton::clicked, &app, &QApplication::aboutQt); //建立連結

    w.show();
    return app.exec();
}

如果你很快的掃過程式碼,你會知道這隻CPP跟昨天的CPP大同小異,唯一差別是今天視窗上只有一個按鈕。而且呼叫了一個沒看過的 QObject::connect() 函數。

Qt 信號槽機制的奧秘就在 QObject::connect() 函數裡。

QObject::connect(監聽的物件, 監聽的事件, 事件接收者, 事件的處理函數);

前面我們提過撰寫 GUI 程式時連結事件和回應行動是關鍵QObject::connect() 的任務就是建立這個連結。QObject::connect() 的前兩個參數指定你要監聽的對象和事件,後兩個參數則是指定事件的接收者和怎麼處理。

以我們的程式碼為例子:

QObject::connect(button, &QPushButton::clicked, &app, &QApplication::aboutQt);

這行程式碼的意思就是,我們想要監聽 button 按鈕物件的 clicked (點擊)事件。一旦點擊事件發生了,就呼叫 app 物件的 QApplication::aboutQt() 函數。

QApplication::aboutQt() 是 QApplication 的成員函數,功用是彈出當前 Qt 的版本和版權等等資訊。

接著請你編譯並執行程式碼,點擊按鈕看看,是不是能看到彈出視窗。

在 Qt 裡面,我們通常把這些事件稱作「signal(信號)」。QPushButton 物件最常用的信號當然就是 clicked (點擊),你可到官方文件查找還有哪些其他信號。

而事件的回應行動,就叫做「slot(槽)」,在目前的 Qt 版本中 slot 通常是一個物件的成員函數。一旦建立連接,該物件就成了專門負責處理這事件的負責人。

請注意,連結 signal/slot 的時候,傳入的是成員函數的指標,函數名前面要加上一個 & 符號。(例如 &QPushButton::clicked&QApplication::aboutQt)

亂數產生器

QObject::connect() 除了連接成員函數,其實也可以連接 C++11 的 lambda 函數。以下我們就示範用 lambda 寫一個亂數產生器。

// 亂數產生器
#include <QApplication>
#include <QWidget>
#include <QHBoxLayout>
#include <QPushButton>
#include <cstdlib>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget w;

    QHBoxLayout* layout = new QHBoxLayout;
    w.setLayout(layout);

    QPushButton* button = new QPushButton("產生亂數");
    layout->addWidget(button);
    QObject::connect(button, &QPushButton::clicked, [=]
    {
        button->setText(QString::number(rand() % 100));
    });

    w.show();
    return app.exec();
}

在這個例子裡,按鈕點擊事件的回應函數變成了 lambda 函數。而在這個 lambda 函數裡面,我們產生一個範圍在 0-99 之間的隨機亂數,並且透過 QPushButton::setText() 把數字顯示在按鈕上。

QString::number(i) 這個函數的作用是變數轉型,把 int 轉型成 Qt 的字串型態 (QString)。

明天開始,我們會逐漸開始介紹各種常用的 Qt 視窗元件,並試著寫一些簡單的小應用出來,敬請期待。


上一篇
D04: Qt 排版系統
系列文
Qt 跨平台應用程式開發5
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言