9月 14, 2008

【筆記】Creating a Event Label

@
  接續前一篇筆記的內容。目前的程式有點普通,所以乾脆順便來寫一個(鍵盤或滑鼠)事件處理器。


  因為需要一個能夠接受事件的標籤元件,所以我定義了一個繼承自 QLabel 的物件:

class QEventLabel : public QLabel
{
    public:
        explicit QEventLabel(QWidget *parent = 0, Qt::WindowFlags f = 0);
        explicit QEventLabel(const QString &text, QWidget *parent = 0,
                                Qt::WindowFlags f = 0);
        ~QEventLabel();

    protected:
        void mouseMoveEvent(QMouseEvent *event);
        void mousePressEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
        void keyPressEvent(QKeyEvent *event);
};


QEventLabel::QEventLabel(QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f)
{
}

QEventLabel::QEventLabel(const QString &text, QWidget *parent,
                            Qt::WindowFlags f) : QLabel(text, parent, f)
{
}

QEventLabel::~QEventLabel()
{
}

  建構子與解構子基本上都不需要做更動。


void QEventLabel::mouseMoveEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>%d, %d</center>", event->x(), event->y());
    this->setText(msg);
}

void QEventLabel::mousePressEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>Press</center>");
    this->setText(msg);
}

void QEventLabel::mouseReleaseEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>Release</center>");
    this->setText(msg);
}

  在這裡的滑鼠是利用 QString 物件搭配 QString::sprintf() 函式來建立字串,以顯示標籤接收到的事件。

  當滑鼠移動,標籤會顯示滑鼠的座標;當滑鼠按鍵被按下,標籤會顯示"Press";當滑鼠按鍵被釋放,標籤會顯示"Release"。

  其中,滑鼠的座標可以由 QMouseEvent::x() 與 QMouseEvent::y() 取得。


void QEventLabel::keyPressEvent(QKeyEvent *event)
{
    QString msg;

    if (event->key() == '<')
    {
        msg = "<center>Type: &lt;</center>";
    }
    else if (event->key() >= Qt::Key_Space && event->key() <= Qt::Key_AsciiTilde)
    {
        msg = "<center>Type: " + event->text() + "</center>";
    }
    else
    {
        msg.sprintf("<center>Type: <font color=red>%d</font></center>", event->key());
    }

    this->setText(msg);
}

  這裡的鍵盤處理器也與滑鼠處理器相同,利用了 QString 物件與 QString::sprintf() 函式來顯示接收到的事件。

  當鍵盤被按下時,若是可以直接印出的字元('D'、' '、'!'、'3'等符號),我利用了 QKeyEvent::text() 取得鍵盤代號所對應的符號,並將之顯示在標籤上;而若是不能印出的功能鍵(Enter、Shift、Home 等),我則利用 QKeyEvent::key() 直接在標籤上顯示鍵盤代號。

  要特別注意的是,若鍵盤代號對應的是上角括號'<',直接利用 QKeyEvent::text() 會被判定為 html 標籤而不顯示。為了避免這種情況,我就將之改成直接輸出"&lt;",也就是'<'的字元實體(character entity)

  然後,別忘了在之前建立 QLabel 實體的地方做一點更動:
    QEventLabel *label = new QEventLabel("<center>No Event</center>", window);

  簡單來說,就是把 QLabel 改成 QEventLabel,並將標籤文字改成"No Event"就可以了。


  這樣應該完成了吧?試著先編譯執行看看。

  當滑鼠在標籤上移動,標籤成功的顯示滑鼠所在的座標。試著按看看滑鼠左右鍵,這個功能也正常運作了,看來一切完美。最後再按一按鍵盤......。等一等,為什麼按下鍵盤卻沒有反應呢?

  這個問題讓我修改又測試了一陣子,我猜想大概是標籤並沒有取得鍵盤的焦點(focus)。有了如此推測之後,又翻了一下官方的函式庫,發現這個 QWidget::setFocus() 函式似乎是我所需要的解答。

    label->setFocus();

  將這段程式碼加進去之後,編譯執行試看看。Bingo!現在標籤也能成功取得鍵盤事件囉。


  完整的程式碼如下:

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QDesktopWidget>
#include <QMouseEvent>
#include <QKeyEvent>

#define WIDTH   290
#define HEIGHT  140

/**************************************
    創建一個能接收事件的 Label 類別
**************************************/
class QEventLabel : public QLabel
{
    public:
        explicit QEventLabel(QWidget *parent = 0, Qt::WindowFlags f = 0);
        explicit QEventLabel(const QString &text, QWidget *parent = 0,
                                Qt::WindowFlags f = 0);
        ~QEventLabel();

    protected:
        void mouseMoveEvent(QMouseEvent *event);
        void mousePressEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
        void keyPressEvent(QKeyEvent *event);
};

/**************************************
    QEventLabel 建構子
**************************************/
QEventLabel::QEventLabel(QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f)
{
}

QEventLabel::QEventLabel(const QString &text, QWidget *parent,
                            Qt::WindowFlags f) : QLabel(text, parent, f)
{
}

QEventLabel::~QEventLabel()
{
}

/**************************************
    QEventLabel 事件處理
**************************************/
void QEventLabel::mouseMoveEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>%d, %d</center>", event->x(), event->y());
    this->setText(msg);
}

void QEventLabel::mousePressEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>Press</center>");
    this->setText(msg);
}

void QEventLabel::mouseReleaseEvent(QMouseEvent *event)
{
    QString msg;
    msg.sprintf("<center>Release</center>");
    this->setText(msg);
}

void QEventLabel::keyPressEvent(QKeyEvent *event)
{
    QString msg;

    if (event->key() == '<')
    {
        // 避免上角括號被當作標籤而不顯示
        msg = "<center>Type: <</center>";
    }
    else if (event->key() >= Qt::Key_Space && event->key() <= Qt::Key_AsciiTilde)
    {
        msg = "<center>Type: " + event->text() + "</center>";
    }
    else
    {
        msg.sprintf("<center>Type: <font color=red>%d</font></center>", event->key());
    }

    this->setText(msg);
}

/**************************************
    Main 主函式
**************************************/
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget *window = new QWidget;
    window->setWindowTitle("Hello, Qt!");
    window->setMinimumSize(WIDTH, HEIGHT);
    window->setMaximumSize(WIDTH, HEIGHT);

    // 調整視窗至螢幕中央
    QSize size = app.desktop()->size();
    window->move((size.width() - WIDTH) / 2, (size.height() - HEIGHT) / 2);
 
    // 建立並設定元件
    QEventLabel *label = new QEventLabel("<center>No Event</center>", window);
    label->setFont(QFont("Courier New", 25, QFont::Bold));
    label->setGeometry(0, 0, 290, 70);

    QPushButton *quit = new QPushButton("&Quit", window);
    quit->setFont(QFont("Monotype Corsiva", 25, QFont::Bold));
    quit->setGeometry(5, 75, 280, 60);

    QObject::connect(quit, SIGNAL(clicked()), &app, SLOT(quit()));

    // 使 Label 變為焦點
    label->setFocus();

    window->show();

    return app.exec();
}

  編譯執行之後的結果:










  編譯出來的程式,我試著轉移到沒有裝 Qt 的電腦執行。沒想到還需要附帶 Qt 目錄下 lib 資料夾的 QtCore4.dll、QtGui4.dll 等動態函式庫。而這些動態函式庫的檔案也都不小,光一個 QtGui4.dll 就要將近 10 MB。

  不過怎麼說,還算是滿好學、好用的,有時間再寫些別的吧!或許來試用一下 Qt Designer。

0 回覆:

張貼留言