讀古今文學網 > 父與子的編程之旅:與小卡特一起學Python > 18.1 事件 >

18.1 事件

如果我在現實生活中問你,「什麼是事件」,你可能會說這是「發生的某件事情」。這是一個很好的定義,這個定義在編程中也同樣適用。很多程序都需要對「發生的事情」做出反應。比如說:

  • 移動或點擊鼠標;

  • 按鍵;

  • 經過了一定時間。

目前為止,我們寫的大多數程序自始至終都沿著一條可以預測的路徑運行,可能中間會有一些循環或條件。不過,除此以外還有另外一類程序,稱為事件驅動程序(event-driven program),它們的做法完全不同。事件驅動程序基本上只是「原地不動」,什麼也不做,等待著有事件發生。一旦事件確實發生,它們就會做出反應,完成所有必要的工作來處理這個事件。

Windows 操作系統(或者其他 GUI)就是這種事件驅動程序的一個很好的例子。打開 Windows 計算機時,啟動後它只是「原地不動」,不會啟動任何程序,你也不會看到鼠標光標在屏幕上移動。不過,如果你開始移動或點擊鼠標,就會有情況發生。鼠標光標會在屏幕上移動,「開始」菜單會彈出,或者會做其他事情。

事件循環

為了讓一個事件驅動程序「看到」有事件發生,它必須「尋找」這些事件。程序必須不斷地掃瞄計算機內存中用來指示事件發生的部分。只要程序在運行,就會反覆這樣做。回顧第 8 章,我們已經瞭解了程序如何反覆做某些事情,這要使用一個循環。不斷尋找事件的這個特殊循環叫做事件循環(event loop)。

前兩章完成的 Pygame 程序中,最後總是有一個 while 循環。我們說過,這個循環會在程序運行期間一直運行。這個 while 循環就是 Pygame 的事件循環。(要瞭解退出代碼是如何工作的,首先要知道這個事件循環。)

事件隊列

只要有人移動或點擊了鼠標或者按下了按鍵,就會發生事件。這些事件去哪裡了呢?在上一節中我說過,事件循環會一直不斷地搜索內存的某個部分。內存中存儲事件的部分叫做事件隊列(event queue)。

術語箱

隊列(queue)讀作「Q」。日常生活中,這就表示排隊。

在編程中,隊列通常指一個列表,其中的元素按某種特定的順序到達,或者將按某種特定的順序使用。

事件隊列就是發生的所有事件的列表,這些事件按它們發生的順序排列。

事件處理器

如果編寫一個 GUI 程序或遊戲,程序必須知道用戶什麼時候按下一個按鍵或者移動了鼠標。這些按鍵、點擊和移動鼠標都是事件,而且程序必須知道如何應對這些事件,它必須處理事件。程序中處理某個事件的部分稱為一個事件處理器(event handler)。

並不是每一個事件都要處理。在桌面上移動鼠標時,會創建成百上千個事件,因為事件循環運行得非常快。每一個瞬間(遠遠不到 1 秒),即使鼠標只是移動了一點點,也會生成一個新的事件。不過你的程序可能並不關心鼠標的每一個小小的移動。它可能只關心用戶什麼時候點擊某個部分。所以你的程序可以忽略 mouseMove 事件,只關注 mouseClick 事件。

事件驅動程序中,對於所關心的各種事件會有相應的事件處理器。如果你有一個遊戲使用鍵盤上的方向鍵來控制一艘船的移動,可能要為 keyDown 事件編寫一個處理器。相反,如果使用鼠標控制這艘船,就可能為 mouseMove 事件寫一個事件處理器。

現在就來看我們的程序中可以使用的一些具體事件。我們還會使用 Pygame,所以這一章後面討論的所有事件都來自 Pygame 的事件隊列。其他 Python 模塊會提供不同的事件。例如,我們將在第 20 章討論另外一個名為 PyQt 的模塊。PyQt 有自己的事件集,其中一些事件與 Pygame 有所不同。不過,對於不同的事件集(甚至在不同的編程語言中),處理事件的方式通常都是一樣的。對於每個事件系統來說可能都不完全一樣,不過相同點還是遠遠多於不同點。