因為需要一個能夠接受事件的標籤元件,所以我定義了一個繼承自 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: <</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 標籤而不顯示。為了避免這種情況,我就將之改成直接輸出"<",也就是'<'的字元實體(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 回覆:
張貼留言