目錄
Qt事件
? 事件介紹
? 事件的處理
? 按鍵事件
? 鼠標事件
? 定時器
? 事件分發器
? 事件過濾器
Qt文件
? Qt文件概述
? 輸入輸出設備類
? 文件讀寫類
? 文件和目錄信息類
Qt事件
? 事件介紹
????????事件是應?程序內部或者外部產?的事情或者動作的統稱。在 Qt 中使??個對象來表??個事件。所有的 Qt 事件均繼承于抽象類 QEvent。事件是由系統或者 Qt 平臺本?在不同的時刻發出的。當??按下?標、敲下鍵盤,或者是窗?需要重新繪制的時候,都會發出?個相應的事件。?些事件是在??操作時發出,如鍵盤事件、?標事件等,另?些事件則是由系統本??動發出,如定時器事件。
常?的 Qt 事件如下:
常?事件描述:?
事件名稱 | 描述 |
?標事件 | ?標左鍵、?標右鍵、?標滾輪,?標的移動,?標按鍵的按下和松開 |
鍵盤事件 | 按鍵類型、按鍵按下、按鍵松開 |
定時器事件 | 定時時間到達 |
進?離開事件 | ?標的進?和離開 |
滾輪事件 | ?標滾輪滾動 |
繪屏事件 | 重繪屏幕的某些部分 |
顯?隱藏事件 | 窗?的顯?和隱藏 |
移動事件 | 窗?位置的變化 |
窗?事件 | 是否為當前窗? |
??改變事件 | 窗???改變 |
焦點事件 | 鍵盤焦點移動 |
拖拽事件 | ??標進?拖拽 |
? 事件的處理
????????事件處理?般常?的?法為:重寫相關的 Event 函數。
????????在 Qt 中,?乎所有的 Event 函數都是虛函數,所以可以重新實現。如:在實現?標的進?和離開事件時,直接重新實現 enterEvent() 和 leaveEvent() 即可。
enterEvent() 和 leaveEvent() 函數原型如下:
? 按鍵事件
????????Qt 中的按鍵事件是通過 QKeyEvent 類來實現的。當鍵盤上的按鍵被按下或者被釋放時,鍵盤事件便會觸發。在幫助?檔中查找 QKeyEvent 類如下:
????????查找按鍵事件中所有的按鍵類型:在幫助?檔中輸?:Qt::Key,如下圖: ?
????????單個按鍵的例子
1、單個按鍵的按下事件:?
void MyWidget::keyPressEvent(QKeyEvent *event)
{if (event->key() == Qt::Key_A) {qDebug() << "按下了 A 鍵";// 執行相應的操作}QWidget::keyPressEvent(event); // 傳遞事件給父類處理
}
2、單個按鍵的釋放事件:?
void MyWidget::keyReleaseEvent(QKeyEvent *event)
{if (event->key() == Qt::Key_A) {qDebug() << "釋放了 A 鍵";// 執行相應的操作}QWidget::keyReleaseEvent(event); // 傳遞事件給父類處理
}
????????組合按鍵的例子
1、同時按下多個鍵的事件:
void MyWidget::keyPressEvent(QKeyEvent *event)
{if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_C) {qDebug() << "同時按下了 Ctrl + C 鍵";// 執行相應的操作}QWidget::keyPressEvent(event); // 傳遞事件給父類處理
}
?2、同時釋放多個鍵的事件:
void MyWidget::keyReleaseEvent(QKeyEvent *event)
{if (event->modifiers() & Qt::ShiftModifier && event->key() == Qt::Key_F) {qDebug() << "同時釋放了 Shift + F 鍵";// 執行相應的操作}QWidget::keyReleaseEvent(event); // 傳遞事件給父類處理
}
在上述示例中:
keyPressEvent()
和keyReleaseEvent()
函數分別處理按鍵按下和釋放事件。- 使用
QKeyEvent
對象的key()
方法獲取按下或釋放的具體按鍵。- 使用
modifiers()
方法可以獲取同時按下的修飾鍵(如 Ctrl、Shift 等)。- 在處理完事件后,通常會調用
QWidget::keyPressEvent(event)
或QWidget::keyReleaseEvent(event)
將事件傳遞給父類處理,以確保其他部分的事件處理邏輯能夠正常運行。
? 鼠標事件
????????在 Qt 中,?標事件是? QMouseEvent 類來實現的。當在窗?中按下?標或者移動?標時,都會產??標事件。
????????利? QMouseEvent 類可以獲取?標的哪個鍵被按下了以及?標的當前位置等信息。在 Qt 幫助?檔中查找QMouseEvent類 如下圖?:
????????鼠標單擊事件的例子
void MyWidget::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {qDebug() << "左鍵被按下";// 執行相應的操作} else if (event->button() == Qt::RightButton) {qDebug() << "右鍵被按下";// 執行相應的操作}QWidget::mousePressEvent(event); // 傳遞事件給父類處理
}
????????鼠標釋放事件的例子
void MyWidget::mouseReleaseEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {qDebug() << "左鍵被釋放";// 執行相應的操作} else if (event->button() == Qt::RightButton) {qDebug() << "右鍵被釋放";// 執行相應的操作}QWidget::mouseReleaseEvent(event); // 傳遞事件給父類處理
}
????????鼠標雙擊事件的例子
void MyWidget::mouseDoubleClickEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {qDebug() << "左鍵雙擊";// 執行相應的操作} else if (event->button() == Qt::RightButton) {qDebug() << "右鍵雙擊";// 執行相應的操作}QWidget::mouseDoubleClickEvent(event); // 傳遞事件給父類處理
}
????????鼠標移動事件的例子
void MyWidget::mouseMoveEvent(QMouseEvent *event)
{qDebug() << "鼠標移動到 (" << event->pos().x() << ", " << event->pos().y() << ")";// 執行相應的操作,例如更新鼠標位置的顯示等QWidget::mouseMoveEvent(event); // 傳遞事件給父類處理
}
????????鼠標滾輪事件的例子?
void MyWidget::wheelEvent(QWheelEvent *event)
{if (event->delta() > 0) {qDebug() << "鼠標向上滾動";// 執行相應的操作} else if (event->delta() < 0) {qDebug() << "鼠標向下滾動";// 執行相應的操作}QWidget::wheelEvent(event); // 傳遞事件給父類處理
}
? 定時器
????????Qt 中在進?窗?程序的處理過程中,經常要周期性的執?某些操作,或者制作?些動畫效果,使?定時器就可以實現。所謂定時器就是在間隔?定時間后,去執?某?個任務。定時器在很多場景下都會使?到,如彈窗?動關閉之類的功能等。
Qt中的定時器分為 QTimerEvent 和 QTimer 這2個類。
????????? QTimerEvent類 ?來描述?個定時器事件。在使?時需要通過 startTimer() 函數來開啟?個定時器,這個函數需要輸??個以毫秒為單位的整數作為參數來表明設定的時間,它返回的整型值代表這個定時器。當定時器溢出時(即定時時間到達)就可以在 timerEvent() 函數中獲取該定時器的編號來進?相關操作。
????????? QTimer類 來實現?個定時器,它提供了更?層次的編程接?,如:可以使?信號和槽,還可以設置只運??次的定時器。
QTimerEvent 類
????????QTimerEvent
類是用來描述定時器事件的類。它通常與 QObject
的 timerEvent()
函數結合使用,用于處理定時器事件的回調操作。
使用方法:
啟動定時器: 通過
startTimer()
函數啟動一個定時器,該函數接受一個毫秒為單位的時間間隔作為參數,并返回一個整型值,代表該定時器的唯一標識符(定時器編號)。定時器事件處理: 當定時器設定的時間間隔到達時,會觸發
timerEvent()
函數。在timerEvent()
函數中,可以通過傳入的參數QTimerEvent *event
來獲取定時器的具體信息,例如定時器的標識符,從而執行相應的操作。代碼示例:
void MyWidget::timerEvent(QTimerEvent *event) {if (event->timerId() == timerId) {qDebug() << "定時器事件觸發,定時器ID:" << event->timerId();// 執行相應的定時操作}QWidget::timerEvent(event); // 傳遞事件給父類處理 }
QTimer 類
????????QTimer
類提供了更高級別的定時器功能,其主要特點是能夠通過信號和槽機制來處理定時器事件,以及提供更多的靈活性和控制選項。
主要功能:
啟動定時器: 通過
QTimer
的start()
函數啟動定時器,該函數接受一個毫秒為單位的時間間隔作為參數,還可以選擇性地設置定時器的單次觸發或重復觸發。定時器信號和槽:
QTimer
可以通過信號timeout()
來定期觸發定時器事件。可以通過連接(connect)這個信號到槽函數來處理定時器事件,這使得定時器的使用更加方便和直觀。單次運行定時器: 可以使用
setSingleShot(true)
方法設置定時器為只運行一次,適用于需要在一段時間后執行一次任務的場景。代碼示例:
// 創建一個 QTimer 對象 QTimer *timer = new QTimer(this);// 設置定時器觸發的時間間隔,單位為毫秒 timer->setInterval(1000); // 1秒// 連接定時器的 timeout() 信號到槽函數 connect(timer, &QTimer::timeout, [=]() {qDebug() << "定時器觸發";// 執行相應的定時操作 });// 啟動定時器 timer->start();
區別和選擇:
QTimerEvent 和 timerEvent(): 適合在自定義的 QObject 派生類中處理定時器事件,需要手動管理定時器的標識符和事件處理邏輯。
QTimer 類: 更高級別的接口,通過信號和槽機制處理定時器事件,適合在需要簡單設置和操作定時器的場景下使用,無需手動管理定時器事件。
? 事件分發器
????????概述
????????在 Qt 中,事件分發器(Event Dispatcher) 是?個核?概念,?于處理 GUI 應?程序中的事件。事件分發器負責將事件從?個對象傳遞到另?個對象,直到事件被處理或被取消。每個繼承? QObject類 或 QObject類 本?都可以在本類中重寫 bool event(QEvent *e) 函數,來實現相關事件的捕獲和攔截。
????????事件分發器?作原理
????????在 Qt 中,我們發送的事件都是傳給了 QObject 對象,更具體點是傳給了 QObject 對象的 event() 函數。所有的事件都會進?到這個函數??,那么我們處理事件就要重寫這個 event() 函數。event() 函數本?不會去處理事件,?是根據 事件類型(type值)調?不同的事件處理函數。事件分發器就是?作在應?程序向下分發事件的過程中,如下圖:
????????如上圖,事件分發器?于分發事件。在此過程中,事件分發器也可以做攔截操作。事件分發器主要是通過 bool event(QEvent *e) 函數來實現。其返回值為布爾類型,若為 ture,代表攔截,不向下分發。
????????Qt 中的事件是封裝在 QEvent類 中,在 Qt 助?中輸? QEvent 可以查看其所包括的事件類型,如下圖示:
????????在Qt中聲明和實現鼠標點擊事件、事件分發器以及攔截事件時,通常會遵循以下步驟。下面是一個基本的示例,分別在頭文件?widget.h
和實現文件?widget.cpp
中展示如何完成這些操作。
在 widget.h
頭文件中聲明
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QMouseEvent>class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr);~Widget();protected:// 聲明鼠標點擊事件處理函數void mousePressEvent(QMouseEvent *event) override;// 聲明事件分發器函數bool event(QEvent *event) override;private:// 聲明攔截事件處理函數bool eventFilter(QObject *watched, QEvent *event) override;
};#endif // WIDGET_H
在 widget.cpp
實現文件中實現
#include "widget.h"
#include <QDebug>Widget::Widget(QWidget *parent) : QWidget(parent)
{// 安裝事件過濾器,用于攔截事件this->installEventFilter(this);
}Widget::~Widget()
{
}// 實現鼠標點擊事件處理函數
void Widget::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton) {qDebug() << "左鍵點擊,位置:" << event->pos();// 執行相應的操作} else if (event->button() == Qt::RightButton) {qDebug() << "右鍵點擊,位置:" << event->pos();// 執行相應的操作}// 將事件傳遞給父類處理QWidget::mousePressEvent(event);
}// 實現事件分發器函數
bool Widget::event(QEvent *event)
{if (event->type() == QEvent::MouseButtonPress) {// 處理鼠標按下事件QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);qDebug() << "事件分發器捕獲到鼠標按下事件,位置:" << mouseEvent->pos();// 執行相應的操作return true; // 表示事件已處理}// 其他事件交給父類處理return QWidget::event(event);
}// 實現事件過濾器函數
bool Widget::eventFilter(QObject *watched, QEvent *event)
{if (watched == this && event->type() == QEvent::MouseMove) {// 攔截并處理鼠標移動事件QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);qDebug() << "事件過濾器捕獲到鼠標移動事件,位置:" << mouseEvent->pos();// 執行相應的操作return true; // 表示事件已處理}// 其他事件交給父類處理return QWidget::eventFilter(watched, event);
}
?代碼說明:
mousePressEvent
函數: 在該函數中處理鼠標點擊事件。根據QMouseEvent
的button()
方法判斷是左鍵還是右鍵,并可以獲取鼠標點擊的位置信息。
event
函數: 這是事件分發器函數,用于捕獲所有類型的事件。在示例中,通過判斷事件的類型 (QEvent::MouseButtonPress
) 來處理鼠標按下事件。
eventFilter
函數: 這是事件過濾器函數,通過調用installEventFilter()
函數安裝到對象上。在示例中,通過判斷事件類型 (QEvent::MouseMove
) 來處理鼠標移動事件。
? 事件過濾器
????????在 Qt 中,?個對象可能經常要查看或攔截另外?個對象的事件,如對話框想要攔截按鍵事件,不讓別的組件接收到,或者修改按鍵的默認值等。通過上?的學習,我們已經知道,Qt 創建了 QEvent事件對象之后,會調?QObject 的 event()函數 處理事件的分發。顯然,我們可以在 event()函數 中實現攔截的操作。由于 event()函數是 protected 的,因此,需要繼承已有類。如果組件很多,就需要重寫很多個event()函數。這當然相當?煩,更不?說重寫 event()函數還得???堆問題。好在 Qt 提供了另外?種機制來達到這??的:事件過濾器。
????????事件過濾器是在應?程序分發到 event事件分發器 之前,再做?次更?級的攔截。如下圖?:
事件過濾器的?般使?步驟:
?? ?1、安裝事件過濾器;
?? ?2、重寫事件過濾器函數:eventfilter() 。?
????????假設我們有一個 MyWidget
類,它繼承自 QWidget
,并希望在該小部件上安裝事件過濾器來攔截按鍵事件。以下是如何在 widget.cpp
中實現這個示例:
#include "widget.h"
#include <QDebug>
#include <QKeyEvent>Widget::Widget(QWidget *parent) : QWidget(parent)
{// 創建一個 QLabel 作為被監視對象QLabel *label = new QLabel("監視對象", this);label->setGeometry(50, 50, 100, 30); // 設置標簽的位置和大小// 安裝事件過濾器到 label 上label->installEventFilter(this);
}bool Widget::eventFilter(QObject *watched, QEvent *event)
{if (watched->objectName() == "監視對象") {if (event->type() == QEvent::KeyPress) {QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);qDebug() << "按鍵事件被攔截:按鍵" << keyEvent->key() << "被按下";// 在此處可以根據需求修改事件或者阻止事件繼續傳遞// 例如,攔截所有按鍵事件,不讓它傳遞給監視對象return true; // 返回 true 表示事件已處理}}// 其他事件交給父類處理return QWidget::eventFilter(watched, event);
}
示例說明:
安裝事件過濾器: 在
Widget
類的構造函數中,我們創建了一個QLabel
對象作為被監視對象,并通過installEventFilter()
函數將當前小部件 (this
) 設置為其事件過濾器。重寫事件過濾器函數: 在
eventFilter()
函數中,我們對事件進行檢查和處理。在示例中,我們檢查了被監視對象的對象名是否為"監視對象"
,如果是,并且事件類型為QEvent::KeyPress
,則我們攔截并處理按鍵事件。在實際應用中,你可以根據需要修改事件內容、記錄日志、阻止事件繼續傳遞等操作。返回值解釋: 如果事件被處理了并且不需要傳遞給被監視對象,則返回
true
;否則,返回QWidget::eventFilter(watched, event)
,以繼續將事件傳遞給父類處理。
Qt文件
? Qt文件概述
?????????件操作是應?程序必不可少的部分。Qt 作為?個通?開發庫,提供了跨平臺的?件操作能?。 Qt提供了很多關于?件的類,通過這些類能夠對?件系統進?操作,如?件讀寫、?件信息獲取、?件復制或重命名等。
? 輸入輸出設備類
????????在 Qt 中,?件讀寫的類為 QFile 。QFile 的?類為 QFileDevice ,QFileDevice 提供了?件交互操作的底層功能。 QFileDevice 的?類是 QIODevice,QIODevice 的?類為 QObject 。
????????QIODevice 是 Qt 中所有輸?輸出設備(input/output device,簡稱 I/O 設備)的基礎類,I/O 設備就是能進?數據輸?和輸出的設備,例如?件是?種 I/O 設備,?絡通信中的 socket 是 I/O 設備, 串?、藍?等通信接?也是 I/O 設備,所以它們也是從 QIODevice 繼承來的。Qt 中主要的?些 I/O 設備類的繼承關系如下圖所?:
上圖中各類的說明如下:
????????? QFile 是?于?件操作和?件數據讀寫的類,使? QFile 可以讀寫任意格式的?件。
????????? QSaveFile 是?于安全保存?件的類。使? QSaveFile 保存?件時,它會先把數據寫??個臨時?件,成功提交后才將數據寫?最終的?件。如果保存過程中出現錯誤,臨時?件?的數據不會被寫?最終?件,這樣就能確保最終?件中不會丟失數據或被寫?部分數據。 在保存?較?的?件或復雜格式的?件時可以使?這個類,例如從?絡上下載?件等。
????????? QTemporaryFile 是?于創建臨時?件的類。使?函數 QTemporaryFile::open() 就能創建?個?件名唯?的臨時?件,在 QTemporaryFile 對象被刪除時,臨時?件被?動刪除。
????????? QTcpSocket 和 QUdpSocket 是分別實現了 TCP 和 UDP 的類。
????????? QSerialPort 是實現了串?通信的類,通過這個類可以實現計算機與串?設備的通信。
????????? QBluetoothSocket 是?于藍?通信的類。?機和平板計算機等移動設備有藍?通信模塊,筆記本電腦?般也有藍?通信模塊。通過QBluetoothSocket類,就可以編寫藍?通信程。如編程實現筆記本電腦與?機的藍?通信。
????????? QProcess 類?于啟動外部程序,并且可以給程序傳遞參數。
????????? QBuffer 以?個 QByteArray 對象作為數據緩沖區,將 QByteArray 對象當作?個 I/O 設備來讀寫。
? 文件讀寫類
????????在 Qt 中,?件的讀寫主要是通過 QFile 類來實現。在 QFile 類中提供了?些?來讀寫?件的?法。對于?件的操作主要有:
????????? 讀數據:QFile 類中提供了多個?法?于讀取?件內容;如 read()、readAll()、readLine()等。
????????? 寫數據:QFile 類中提供了多個?法?于往?件中寫內容;如 write()、writeData()等。
????????? 關閉?件:?件使?結束后必須?函數 close() 關閉?件。
????????訪問?個設備之前,需要使? open()函數 打開該設備,?且必須指定正確的打開模式,QIODevice 中所有的打開模式由 QIODevice::OpenMode 枚舉變量定義,其取值如下:
QIODevice::NotOpen | 沒有打開設備 |
QIODevice::ReadOnly | 以只讀?式打開設備 |
QIODevice::WriteOnly | 以只寫?式打開設備 |
QIODevice::ReadWrite | 以讀寫?式打開設備 |
QIODevice::Append | 以追加?式打開設備,數據將寫到?件末尾 |
QIODevice::Truncate | 每次打開?件后重寫?件內容,原內容將被刪除 |
QIODevice::Text | 在讀?件時,?尾終?符會被轉換為 '\n';當寫??件時,?尾終?符會被轉換為 本地編碼。如 Win32上為'\r\n'; |
QIODevice::Unbuffered | ?緩沖形式打開?件,繞過設備中的任何緩沖區 |
QIODevice::NewOnly | ?件存在則打開失敗,不存在則創建?件 |
? 文件和目錄信息類
????????QFileInfo 是 Qt 提供的?個?于獲取?件和?錄信息的類,如獲取?件名、?件??、?件修改?期等。QFileInfo類中提供了很多的?法,常?的有:
????????? isDir() 檢查該?件是否是?錄;
????????? isExecutable() 檢查該?件是否是可執??件;
????????? fileName() 獲得?件名;
????????? completeBaseName() 獲取完整的?件名;
????????? suffix() 獲取?件后綴名;
????????? completeSuffix() 獲取完整的?件后綴;
????????? size() 獲取?件??;
????????? isFile() 判斷是否為?件;
????????? fileTime() 獲取?件創建時間、修改時間、最近訪問時間等;
代碼示例:
#include <QCoreApplication>
#include <QFileInfo>
#include <QDebug>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 創建一個 QFileInfo 對象,傳入文件路徑或者文件名QFileInfo fileInfo("/path/to/your/file.txt");// 獲取文件名QString fileName = fileInfo.fileName();qDebug() << "文件名:" << fileName;// 獲取文件路徑QString filePath = fileInfo.filePath();qDebug() << "文件路徑:" << filePath;// 獲取文件大小(字節)qint64 fileSize = fileInfo.size(); // 返回 qint64 類型qDebug() << "文件大小:" << fileSize << "bytes";// 獲取文件修改日期和時間QDateTime lastModified = fileInfo.lastModified();qDebug() << "最后修改時間:" << lastModified.toString(Qt::ISODate);// 獲取文件后綴名QString suffix = fileInfo.suffix();qDebug() << "文件后綴名:" << suffix;// 檢查文件是否存在if (fileInfo.exists()) {qDebug() << "文件存在";} else {qDebug() << "文件不存在";}return a.exec();
}
?示例說明:
包含頭文件: 引入了
QFileInfo
類的頭文件<QFileInfo>
,以及用于調試輸出的<QDebug>
。創建
QFileInfo
對象: 使用文件路徑或文件名創建一個QFileInfo
對象,例如"/path/to/your/file.txt"
。獲取文件信息:
- 使用
fileName()
獲取文件名。- 使用
filePath()
獲取文件路徑。- 使用
size()
獲取文件大小,返回qint64
類型表示文件大小的字節數。- 使用
lastModified()
獲取文件最后修改時間,返回QDateTime
對象。- 使用
suffix()
獲取文件后綴名。檢查文件存在性: 使用
exists()
函數檢查文件是否存在,并根據結果輸出相應信息。輸出信息: 使用
qDebug()
輸出獲取到的文件信息。