Qt6中的輸入事件

Qt是一個跨平臺框架,一般用做圖形工具包,它不只建立CLI應用程序中很是有用。並且它也能夠在三種主要的臺式機操做系統以及移動操做系統(如Symbian,Nokia Belle,Meego Harmattan,MeeGo或BB10)以及嵌入式設備,Android(Necessitas)和iOS的端口上運行。如今咱們爲你提供了免費的試用版。趕快點擊下載Qt6最新試用版>>react

工具推薦:linux

  • QtitanRibbon下載試用: 遵循Microsoft Ribbon UI Paradigm for Qt技術的Ribbon UI組件,致力於爲Windows、Linux和Mac OS X提供功能完整的Ribbon組件。
  • QtitanChart | 下載試用 :是一個C ++庫,表明一組控件,這些控件使您能夠快速地爲應用程序提供漂亮而豐富的圖表。而且支持全部主要的桌面操做系

Qt Quick中鼠標和觸摸事件的傳遞是很複雜的,幾年前咱們就清楚地意識到,咱們須要重構事件繼承層次結構,爲各類事件類型提供一些通用的API,以便共享更多的傳遞代碼。在Qt 5.8中,咱們添加了QQuickPointerEvent和相關的類型,以此做爲原型。它們是QObjects;從那時起,QQuickWindow就開始交付這些包裝器事件,裏面攜帶着原始事件。如今終於在Qt 6中,咱們可以完成QEvent的重構,這樣QQuickWindow就再也不須要包裝器了。與此一塊兒,咱們還可以增長一些功能,並修復一些bug。剩下的許多在 Qt 5 中看起來難以解決的 bug 至少在之後應該能夠修復。git

QPointerEvent和QEventPoint服務器

如今,繼承層次結構以下所示:框架

QPointerEvent是一個新的抽象類型,適用於全部來自指向設備(鼠標、觸摸屏、平板電腦手寫筆)的事件。它擁有通用的API,可以以設備無關的方式處理全部這些事件。因爲QTouchEvent能夠在一個事件中攜帶多個觸摸點,咱們將這個概念標準化:每一個QPointerEvent均可能表明一個QEventPoint實例的集羣(即便大多數事件只攜帶一個點),所以具備適當的API:point()、point(i)和pointCount()。
每一個QInputEvent(包括QPointerEvent)都攜帶一個指向它來自的QInputDevice的指針。這容許事件處理代碼以特定設備的方式進行響應,即便在處理合成鼠標事件時也是如此。ide

每一個QEventPoint都有速度。Qt Quick 在 Qt 5 中使用的 Kalman 過濾器已經被移到了 QtGui 中,所以不管事件在哪裏傳遞,均可以獲得最近幾回移動的平均速度。這使得對速度敏感的行爲(如區分慢速拖動和快速輕彈,或對特定的運動方向作出反應)能夠不受來自哪一個設備的影響。瞬時速度一般對這種目的來講太不穩定了,但若是你須要它,你能夠用(globalPosition()-globalLastPosition())來計算。/ (timestamp() - lastTimestamp())。函數

QSinglePointEvent 是另外一個抽象類型,它將過去在 QMouseEvent、QTabletEvent、QHoverEvent、QWheelEvent 和其餘一些類型中單獨且不一致地實現的位置訪問器標準化。position()取代了 pos()和 posF(), scenePosition()取代了 windowPos(), globalPosition()取代了 screenPos()。舊的訪問器如今仍然存在,但已經廢棄:例如,Qt 5 應用程序不會由於處理 QMouseEvent 而遇到 SC 斷裂。QEventPoint 取代了 QTouchEvent::TouchPoint,但爲了源代碼的兼容性,有一個 "using "聲明。工具

我已經分叉了 clazy,並添加了一個新的 qevent-accessors 檢查,這可能會給你省去一些麻煩:它能夠自動應用 "fixits "來擺脫來自事件訪問器重命名的廢棄警告。ui

在C++中處理與設備無關的事件this

在Qt中的各個地方,咱們如今能夠對鼠標、觸摸和平板電腦事件(如檢測到點擊或拖動)作出響應,或者經過迭代QEventPoints,或者只對第一個點作出響應。下面是一我的爲的例子,說明QQuickItem子類如何作到這一點。

bool MyItem::event(QEvent *ev) override { if (ev->isPointerEvent()) { QPointerEvent *pev = static_cast<QPointerEvent *>(ev); for (QEventPoint &point : pev->points()) { switch (point.state()) { case QEventPoint::State::Pressed: if (reactToPress(point.position())) pev->setExclusiveGrabber(point, this); break; case QEventPoint::State::Updated: ... } } return true; } return QQuickItem::event(ev); }

例如,QQuickFlickable :: childMouseEventFilter()以這種方式工做。這產生了一個有趣的結果:

Flickable如今能夠處理觸摸了

Qt 5的Flickable只能處理實際的鼠標事件和合成的鼠標事件,有不少開放性的bug。Qt只支持一個鼠標,一個鼠標位置,一個光標(到目前爲止,但咱們正在努力解決這個問題......),所以你不能用兩根手指輕觸兩個Flickable。若是你觸摸了Flickable裏面的某個可以處理觸摸事件的組件,可是你在容許的方向上拖動你的手指穿過Flickable,它就會使用childMouseEventFilter()從該組件中竊取抓取;可是這涉及到從實際的觸摸事件切換到合成鼠標事件,並且還要記住將如下更新做爲合成鼠標事件傳遞給Flickable。各類事情都出了問題。好吧......那些日子結束了,由於Flickable::childMouseEventFilter()再也不關心QPointerEvents來自哪一個設備。若是你設置了pressDelay,它就可以暫緩實際的觸摸按壓,而後在定時器過時時重播給裏面的項目。是的,如今你也能夠用多個手指拖動多個Flickables了。

多點觸控雖然仍然不能與其他的只用鼠標的項目(如MouseArea)一塊兒工做,由於這些項目仍然依賴於協同鼠標事件。但能夠避免。通常來講:儘可能使用事件處理程序而不是MouseArea,由於(正如它的名字所示)它並非真的要支持任何比鼠標交互更多的東西。

QTabletEvents(來自你的Wacom手寫筆、三星S-pen、Apple Pencil等)也只是指針事件,它們攜帶了一些更多的屬性,能夠由任何處理鼠標和觸摸事件的設備無關代碼來處理。但咱們會繼續努力改善這些體驗。咱們沒有在QQuickItem中爲它們添加任何新的虛擬函數,但它們很快就會被交付給QQuickItem::event()。

另外一件事咱們還在努力,就是讓Flickable在筆記本觸摸板上表現得更好。很快就會有一個修復方案。

QInputDevice

QInputDevice是一個QObject,它的parent()能夠是另外一個設備,若是有一個天然的層次結構:例如,X11有主設備和從設備,一個平板電腦手寫筆 "屬於 "一個特定的平板設備。在其餘狀況下,父設備只是平臺插件中的一個對象,出於內存管理的目的,它擁有該設備。

在沒有進行設備發現工做的平臺上,QInputEvent::device()歷來不是空的,而多是取自QInputDevice::primaryKeyboard()或QPointingDevice::primaryMouse()的通用實例。不過觸摸屏設備是獨一無二的,咱們在Qt 5中已經這樣作了。

QInputDevice::seatName()對應於Wayland的 "座位 "概念:一個用戶正在使用的一組設備。到目前爲止,對多座位的支持還不多,但隨着時間的推移,它將會獲得改進。若是您配置了一個多指針X服務器,您能夠在不一樣的設備上看到不一樣的座位名稱,但這些名稱是由xcb插件中的xinput ID自動生成的。在Wayland合成器上,如Sway,能夠給座位任意命名;咱們計劃Qt最終會與之合做。

$ xinput list Virtual core pointer id=2 [master pointer (3)] Virtual core XTEST pointer id=4 [slave pointer (2)] ZSA Technology Labs ErgoDox EZ Mouse id=11 [slave pointer (2)] ZSA Technology Labs ErgoDox EZ Consumer Control id=13 [slave pointer (2)] Logitech MX Master 2S id=15 [slave pointer (2)] Virtual core keyboard id=3 [master keyboard (2)] Virtual core XTEST keyboard id=5 [slave keyboard (3)] Power Button id=6 [slave keyboard (3)] Power Button id=7 [slave keyboard (3)] Sleep Button id=8 [slave keyboard (3)] UVC Camera (046d:0992) id=9 [slave keyboard (3)] ZSA Technology Labs ErgoDox EZ id=10 [slave keyboard (3)] ZSA Technology Labs ErgoDox EZ System Control id=12 [slave keyboard (3)] ZSA Technology Labs ErgoDox EZ Keyboard id=14 [slave keyboard (3)] ZSA Technology Labs ErgoDox EZ Consumer Control id=16 [slave keyboard (3)] Logitech MX Master 2S id=17 [slave keyboard (3)] aux pointer id=22 [master pointer (23)] Microsoft Microsoft Optical Mouse by Starck id=19 [slave pointer (22)] aux XTEST pointer id=24 [slave pointer (22)] aux keyboard id=23 [master keyboard (22)] Apple, Inc Apple Keyboard id=20 [slave keyboard (23)] Apple, Inc Apple Keyboard id=21 [slave keyboard (23)] aux XTEST keyboard id=25 [slave keyboard (23)] $ qtdiag Qt 6.0.0 (x86_64-little_endian-lp64 shared (dynamic) debug build; by GCC 10.2.0) on "xcb" OS: Arch Linux [linux version 5.9.11-arch2-1] ... Input devices: 23 QInputDevice::DeviceType::Mouse "Virtual core pointer", seat: "30002" capabilities: Position Scroll Hover QInputDevice::DeviceType::Keyboard "Virtual core keyboard", seat: "30002" capabilities: QInputDevice::DeviceType::Mouse "aux pointer", seat: "170016" capabilities: Position Scroll Hover QInputDevice::DeviceType::Keyboard "aux keyboard", seat: "170016" capabilities: QInputDevice::DeviceType::Mouse "Virtual core XTEST pointer", seat: "30002" capabilities: Position Scroll Hover QInputDevice::DeviceType::Keyboard "Virtual core XTEST keyboard", seat: "30002" capabilities: QInputDevice::DeviceType::Keyboard "Power Button", seat: "30002" capabilities: QInputDevice::DeviceType::Keyboard "Power Button", seat: "30002" capabilities: QInputDevice::DeviceType::Keyboard "Sleep Button", seat: "30002" capabilities: QInputDevice::DeviceType::Keyboard "UVC Camera (046d:0992)", seat: "30002" capabilities: QInputDevice::DeviceType::Keyboard "ZSA Technology Labs ErgoDox EZ", seat: "30002" capabilities: QInputDevice::DeviceType::Mouse "ZSA Technology Labs ErgoDox EZ Mouse", seat: "30002" capabilities: Position Scroll Hover QInputDevice::DeviceType::Keyboard "ZSA Technology Labs ErgoDox EZ System Control", seat: "30002" capabilities: QInputDevice::DeviceType::Mouse "ZSA Technology Labs ErgoDox EZ Consumer Control", seat: "30002" capabilities: Position Scroll Hover QInputDevice::DeviceType::Keyboard "ZSA Technology Labs ErgoDox EZ Keyboard", seat: "30002" capabilities: QInputDevice::DeviceType::Keyboard "ZSA Technology Labs ErgoDox EZ Consumer Control", seat: "30002" capabilities: QInputDevice::DeviceType::Mouse "Logitech MX Master 2S", seat: "30002" capabilities: Position Scroll Hover QInputDevice::DeviceType::Keyboard "Logitech MX Master 2S", seat: "30002" capabilities: QInputDevice::DeviceType::Mouse "Microsoft Microsoft Optical Mouse by Starck", seat: "170016" capabilities: Position Scroll Hover QInputDevice::DeviceType::Keyboard "Apple, Inc Apple Keyboard", seat: "170016" capabilities: QInputDevice::DeviceType::Keyboard "Apple, Inc Apple Keyboard", seat: "170016" capabilities: QInputDevice::DeviceType::Mouse "aux XTEST pointer", seat: "170016" capabilities: Position Scroll Hover QInputDevice::DeviceType::Keyboard "aux XTEST keyboard", seat: "170016" capabilities:

QInputDevice :: availableVirtualGeometry()旨在告訴您該設備能夠訪問虛擬桌面的哪一個區域。例如,您可能正在使用帶有外部顯示器的觸摸屏筆記本電腦:那麼觸摸屏的QPointingDevice :: availableVirtualGeometry()應該與屏幕的QScreen :: geometry()相同。Wacom數位板能夠映射到小於整個屏幕的區域,以提升繪圖精度(使用xinput或特定於操做系統的控制面板)。可是一樣,這項工做還沒有在全部受支持的平臺上完成。

合成鼠標事件

合成鼠標事件仍然存在,儘管咱們如今正試圖減小對它們的依賴。

QEvent::spontaneous()是咱們區分OS產生的事件和合成事件的最古老的方法,但它並不適合區分合成鼠標事件。在Qt 5中,增長了QMouseEvent::source()來幫助你區分由其餘設備、操做系統、Qt或應用程序合成的鼠標事件;但後來咱們發現,假設這樣的事件是由觸摸點合成的,既誘人又錯誤。(例如,它多是由QTabletEvent合成的。)因此咱們建議如今使用event->device()->type()和/或pointerDevice()->pointerType()來區分這些事件。當一個QMouseEvent從其餘類型的事件中合成時,設備實例保持不變,這樣你就能夠知道它到底來自哪裏。

分類日誌

自從幾年前增長了分類日誌後,咱們在Qt中增長了愈來愈多的內部日誌,(在qtbase和qtdeclarative中git grep Q_LOGGING_CATEGORY會發現不少對調試Qt Quick應用頗有用的)。對於排除鼠標和觸摸交互問題來講,最有用的類別是qt.pointer.grab,由於grab轉換是大多數此類問題的症狀或緣由。但還有更多:你能夠在QPA級別、QtGui級別、QQuickWindow中、向項目和/或處理程序傳遞過程當中記錄事件;你還能夠在各類項目和處理程序中記錄交互的各個方面。

我可能會在之後的文章中寫更多關於抓取和接受事件的技術細節。

好了這就是今天的內容了,若是今天的文章未解決你的需求,點擊獲取更多文章教程。不要忘了在評論與咱們分享您的想法和建議。

我可能會在之後的文章中寫有關捕獲和接受事件的更多技術細節。

相關文章
相關標籤/搜索