- 論壇徽章:
- 0
|
當(dāng)鼠標(biāo)在屏幕上移動時,可以使用鼠標(biāo)移動事件跟蹤它的移動。移動事件是當(dāng)鼠標(biāo)指針在窗口內(nèi)移動時發(fā)生的,穿越事件是在鼠標(biāo)指針進(jìn)入或離開GdkWindow窗口時發(fā)生的。移動事件中的典型成員是GDK_MOTION_NOTIFY。有兩種類型的穿越事件:
GDK_ENTER_NOTIFY和GDK_LEAVE_NOTIFY。
有兩種方法跟蹤鼠標(biāo)移動事件。如果在窗口的事件屏蔽中指定了GDK_POINTER_MOTION_MASK,可以接收到X服務(wù)器能產(chǎn)生的盡可能多的事件。如果用戶快速移動指針,程序會被移動事件淹沒,必須快速處理它們,否則應(yīng)用程序在處理大量事件時會反應(yīng)遲鈍。
如果還指定了GDK_POINTER_MOTION_HINT_MASK,那么每次只發(fā)送一個移動事件。也要調(diào)用gdk_window_get_pointer()函數(shù)、鼠標(biāo)指針離開并重新進(jìn)入窗口,或者鼠標(biāo)按鍵或鍵盤事件發(fā)生時,事件才會發(fā)送出去。也就是,每次接收到一個移動事件必須調(diào)用gdk_window_get_pointer()函數(shù)取得鼠標(biāo)指針的當(dāng)前位置,并通知X服務(wù)器已經(jīng)可以接收另一個事件了。
選擇何種模式依賴于應(yīng)用程序。如果需要精確跟蹤指針的軌跡,就得捕獲所有的移動事件。如果僅僅關(guān)心最近的鼠標(biāo)指針位置,為了將網(wǎng)絡(luò)流量最小化,使應(yīng)用程序的響應(yīng)能力最大化,則應(yīng)在應(yīng)用程序的事件屏蔽中包含GDK_POINTER_MOTION_HINT_MASK。
gdk_window_get_pointer()函數(shù)要求在服務(wù)器和客戶之間傳輸數(shù)據(jù)以獲得鼠標(biāo)指針的位置,所以它對應(yīng)用程序的響應(yīng)能力有很大的限制。如果能盡可能快地處理鼠標(biāo)運動事件而不被大量的事件淹沒,應(yīng)用程序看起來會比沒有設(shè)置事件屏蔽GDK_POINTER_MOTION_HINT_MASK要快些。鼠標(biāo)移動事件不可能在一秒鐘內(nèi)發(fā)生200次,所以如果能在5毫秒內(nèi)處理好鼠標(biāo)移動事件,情況就會不錯。
如果想在一個或多個鼠標(biāo)按鍵按下時才接收鼠標(biāo)事件,可以用GDK_BUTTON_MOTION_MASK代替GDK_POINTER_MOTION_MASK。還可以用GDK_POINTER_MOTION_HINT_MASK和GDK_BUTTON_MOTION_MASK一起使用來限制要接收的事件的數(shù)量,就像和GDK_POINTER_MOTION_MASK一起使用一樣。如果僅僅對某個特定的鼠標(biāo)按鍵按下時的鼠標(biāo)移動事件感興趣,可以使用與特定鼠標(biāo)鍵相關(guān)的事件屏蔽GDK_BUTTON1_MOTION_MASK、GDK_BUTTON2_MOTION_MASK以及GDK_BUTTON3_MOTION_MASK。這三個事件屏蔽的任何組合都是允許的。它們也可以與GDK_POINTER_MOTION_HINT_MASK聯(lián)合使用以限制事件發(fā)生的數(shù)量。
總而言之,可以用下面五個事件屏蔽值選擇在什么按鍵狀態(tài)下接收什么鼠標(biāo)移動事件:
GDK_POINTER_MOTION_MASK:不管按鍵狀態(tài),接收所有事件。
GDK_BUTTON_MOTION_MASK:有按鍵按下時接收所有事件。
GDK_BUTTON1_MOTION_MASK:按鍵1按下時接收所有事件。
GDK_BUTTON2_MOTION_MASK:按鍵2按下時接收所有事件。
GDK_BUTTON3_MOTION_MASK:按鍵3按下時接收所有事件。
缺省狀態(tài)下,應(yīng)用程序會被X服務(wù)器能生成的事件所淹沒,最好在事件屏蔽中添加一個GDK_POINTER_MOTION_HINT_MASK,讓事件“一段時間內(nèi)發(fā)生一次”。
移動事件用GdkEventMotion結(jié)構(gòu)描述:
typedefstruct_GdkEventMotionGdkEventMotion;
struct_GdkEventMotion
{
GdkEventTypetype;
GdkWindow*window;
gint8send_event;
guint32time;
gdoublex;
gdoubley;
gdoublepressure;
gdoublextilt;
gdoubleytilt;
guintstate;
gint16is_hint;
GdkInputSourcesource;
guint32deviceid;
gdoublex_root,y_root;
};
大多數(shù)成員與GdkEventButton中的成員是類似的。事實上,唯一與GdkEventMotion不同的成員是is_hint標(biāo)志。如果它是TRUE,GDK_POINTER_MOTION_HINT_MASK標(biāo)志會選中。
如果要寫一個供其他人使用的構(gòu)件,并且想讓他們選擇怎樣接收移動事件,需要設(shè)置這個成員的值。在移動事件處理程序中,可以這么做:
doublex,y;
x=event->motion.x;
y=event->motion.y;
if(event->motion.is_hint)
gdk_window_get_pointer(event->window,&x,&y,NULL);
也就是說,只在必要時調(diào)用gdk_window_get_pointer()函數(shù)。
如果正在使用GDK_POINTER_MOTION_HINT_MASK,給定事件的坐標(biāo)應(yīng)該使用從gdk_window_get_pointer()函數(shù)取得的值,因為它們是更新過的。如果正在接收每個事件,調(diào)用gdk_window_get_pointer()就沒有什么意義,因為這樣做太慢了,并且會引起嚴(yán)重事件積壓—這樣,最終會得到所有的事件,但是應(yīng)用程序的性能會很糟糕。
穿越事件是在鼠標(biāo)指針進(jìn)入或離開一個窗口時發(fā)生的。如果在應(yīng)用程序的GdkWindow之間快速移動,Gdk會為每一個被穿越的窗口產(chǎn)生穿越事件。不過,Gtk+會試圖刪除在多個“穿越”過程中的事件,只將第一個離開窗口事件和最后一個進(jìn)入窗口事件傳給構(gòu)件。這種優(yōu)化能夠提高程序的響應(yīng)速度。如果感覺到應(yīng)該發(fā)生了進(jìn)入/離開事件,可實際上并沒有發(fā)生,可能是上面的優(yōu)化造成的。
GdkEventCrossing結(jié)構(gòu)的定義如下:
typedefstruct_GdkEventCrossingGdkEventCrossing;
struct_GdkEventCrossing
{
GdkEventTypetype;
GdkWindow*window;
gint8send_event;
GdkWindow*subwindow;
guint32time;
gdoublex;
gdoubley;
gdoublex_root;
gdoubley_root;
GdkCrossingModemode;
GdkNotifyTypedetail;
gbooleanfocus;
guintstate;
};
上面所示結(jié)構(gòu)中的很多成員都應(yīng)該是很熟悉的,其中x和y坐標(biāo)是相對于發(fā)生穿越事件的窗口的坐標(biāo);x_root和y_root坐標(biāo)是相對于根窗口的;time成員指明事件的時間;state成員指明發(fā)生事件時按下的鼠標(biāo)按鍵和組合鍵。結(jié)構(gòu)中的前三個成員是GdkEventAny中的三個標(biāo)準(zhǔn)成員。不過,這里還有幾個新成員。
GdkEventCrossing結(jié)構(gòu)中的window成員是一個指向鼠標(biāo)指針要進(jìn)入或離開的窗口指針,x和y坐標(biāo)就是相對于這個窗口的。但是,在“離開”事件發(fā)生之前,鼠標(biāo)指針也許已經(jīng)在接收事件的窗口的子窗口中存在了;當(dāng)“進(jìn)入”事件發(fā)生時,鼠標(biāo)指針也許在一個子窗口中消失了。在這些情況下,subwindow成員應(yīng)該設(shè)置為這個子窗口。否則,可以將subwindow設(shè)置為NULL。注意,如果在子窗口的事件屏蔽值中設(shè)置有GDK_ENTER_NOTIFY_MASK或GDK_LEAVE_NOTIFY_MASK,子窗口也會接收到它自己的“進(jìn)入”或者“離開”事件。
GdkEventCrossing中的mode成員指出事件是正常引發(fā)的還是作為指針獨占的一部分。
當(dāng)指針被獨占或解除獨占時,指針也許會移動。由一個獨占引起的鼠標(biāo)移動事件的mode成員的值為GDK_CROSSING_GRAB,由解除獨占引起的的移動事件的mode成員為GDK_CROSSING_UNGRAB,所有其他情況mode都為GDK_CROSSING_NORMAL。
GdkEventCrossing中的detail成員很少用到。它給出了關(guān)于要離開和進(jìn)入的窗口在X系統(tǒng)窗口樹中的相對位置的一些信息。它有兩個很簡單、很有用的值:
GDK_NOTIFY_INFERIOR標(biāo)志一個當(dāng)指針移進(jìn)或移出一個子窗口時,由父窗口接收到的穿越事件。
GDK_NOTIFY_ANCESTOR標(biāo)志一個當(dāng)指針移進(jìn)或者移出一個父窗口時,由子窗口接收到的穿越事件。其他幾種值也是可能的:GDK_NOTIFY_VIRTUAL,GDK_NOTIFY_INFERIOR,GDK_NOTIFY_NONLINEAR,GDK_NOTIFY_NONLINEAR_VIRTUAL以及GDK_NOTIFY_UNKNOWN。不過,它們絕不會用到,因為它們太復(fù)雜了。
鍵盤焦點
GdkEventCrossing的focus成員指出是事件窗口還是它的子窗口得到鍵盤輸入焦點。鍵盤焦點是一個X概念,用于決定哪一個窗口應(yīng)該接收按鍵事件。窗口管理器決定哪一個頂級窗口應(yīng)該獲得焦點。通常,獲得焦點的窗口是高亮顯示的,并在最前面顯示。大多數(shù)窗口管理器會讓你在“跟隨鼠標(biāo)獲得焦點”和“點擊獲得焦點”間作出選擇。當(dāng)應(yīng)用程序具有焦點時,可以將焦點在它的子窗口間自由移動(例如,在不同的GtkText構(gòu)件間移動)。不過,Gtk+并不對子窗口使用X的焦點機制。
頂級GtkWindow構(gòu)件是唯一接收X焦點的窗口。因而,它們從X服務(wù)器(通過Gdk)接收所有的原始按鍵事件。Gtk+實現(xiàn)了它自己的構(gòu)件焦點概念,它和X的窗口焦點概念是類似的,但實際上是截然不同的。當(dāng)一個頂級窗口接收到按鍵事件,它會將事件傳給具有Gtk+焦點的構(gòu)件。
簡而言之,如果包含事件窗口的頂級GtkWindow窗口目前具有X焦點,focus成員的值就會是TRUE。Focus成員與Gtk+的構(gòu)件焦點概念沒有直接的關(guān)系。
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u3/93660/showart_1996129.html |
|