wm.c 以 image.c 為範本,wm.c 執行後在畫面上只會看到圖片圖(沒有視窗標題列與邊框),並且可使用滑鼠來拖曳圖片。本範例主要在展示以下的 Nano-X API 程式設計方法:
˙ 如何設定視窗屬性(window manager)。
˙ 如何與使用者做互動(human interactive)。
要寫出「托曳圖片」的功能,首先必須把視窗的標題列與邊框去除,否則只能在標題列上托曳整個「視窗」。做法非常簡單,只要在建立視窗時設定 window manager 即可:
wid = GrNewWindowEx(GR_WM_PROPS_APPWINDOW | GR_WM_PROPS_NODECORATE | GR_WM_PROPS_NOAUTOMOVE, NULL, GR_ROOT_WINDOW_ID, 0, 0, image_jollen.width, /* 圖片寬度 */ image_jollen.height /* 圖片高度 */, 0xFFFFFF);
粗體字的地方是新加入的 window manager 屬性,為了達到我們的要求,我們指定了3個屬性值:
由於我們並未指定 GR_WM_PROPS_CAPTION,因此不會有視窗標題列。 在處理使用者互動上,我們需要自行處理3個滑鼠事件:
因此選擇事件的程式碼應修改成:
GrSelectEvents(wid, GR_EVENT_MASK_MOUSE_POSITION | GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_BUTTON_DOWN);
接下來,要特別注意的地方是「顯示圖片的時機」。我們在這裡設計成在視窗顯示後、進入 event loop 前處理。首先是顯示圖片的程式寫法:
GrMapWindow(wid); GrDrawImageBits(wid, gc, 0, 0, &image_jollen);
接著,修改 event loop,並加上處理以上 3 個事件(粗體字部份)的程式碼:
void event_handler (GR_EVENT *event) { switch (event->type) { case GR_EVENT_TYPE_CLOSE_REQ: GrClose(); case GR_EVENT_TYPE_MOUSE_POSITION: position_event(&event->mouse); break; case GR_EVENT_TYPE_BUTTON_UP: case GR_EVENT_TYPE_BUTTON_DOWN: button_event(&event->button); break; default: break; } }
對於滑鼠按鍵的處理方式為:當滑鼠被按下時,便記錄滑鼠的新座標,然後將視窗移到最上層;若此時使用者移動滑鼠,則將整個「視窗」移到新座標位置。如此一來,使用者就會看到 「整個圖片被托曳」的效果。
處理滑鼠按鍵的程式寫法如下:
void button_event(GR_EVENT_BUTTON *e) { if (e->type == GR_EVENT_TYPE_BUTTON_DOWN) { newx = e->x; newy = e->y; button_down = 1; GrRaiseWindow(e->wid); } else { button_down = 0; } }
先判斷目前所產生的事件是否為 GR_EVENT_TYPE_BUTTON_DOWN;如果是,才記錄新座標,並將 button_down 設為 1。若不是
GR_EVENT_TYPE_BUTTON_DOWN 事件,表示滑鼠按鍵已放開,此時將 button_down 設為 0。
處理滑鼠移動事件的程式寫法如下:
void position_event(GR_EVENT_MOUSE *e) { if (!button_down) return; GrMoveWindow(e->wid, e->rootx-newx, e->rooty-newy); }
先判斷 button_down 是否為 false,若 button_down等於0,表示滑鼠按鍵是放開的,因此不做任何動作。反正,若 button_down 為true,代表滑鼠按鍵仍「持續」按住,此時才能呼叫 GrMoveWindow() 移動視窗。
以下是 wm.c 的完整程式,粗體字是新加入或修改過的程式碼。
/* * Copyright(c) 2003,2004 www.jollen.org * * - Nano-X API example. * - wm.c * */ #include <stdio.h> #define MWINCLUDECOLORS #include <microwin/nano-X.h> #include <microwin/nxcolors.h> GR_WINDOW_ID wid; GR_GC_ID gc; /* 外部影像 */ extern GR_IMAGE_HDR image_jollen; void event_handler (GR_EVENT *event); /* 滑鼠座標 */ int newx, newy; int button_down; int main (void) { if (GrOpen() < 0) { fprintf (stderr, "GrOpen failed"); return -1; } gc = GrNewGC(); GrSetGCForeground (gc, 0xFF0000); wid = GrNewWindowEx(GR_WM_PROPS_APPWINDOW | GR_WM_PROPS_NODECORATE | GR_WM_PROPS_NOAUTOMOVE, NULL, GR_ROOT_WINDOW_ID, 0, 0, image_jollen.width, /* 影像寬度 */ image_jollen.height /* 影像高度 */, 0xFFFFFF); GrSelectEvents(wid, GR_EVENT_MASK_MOUSE_POSITION | GR_EVENT_MASK_BUTTON_UP | GR_EVENT_MASK_BUTTON_DOWN); GrMapWindow(wid); GrDrawImageBits(wid, gc, 0, 0, &image_jollen); GrMainLoop(event_handler); return 0; } void button_event(GR_EVENT_BUTTON *e) { if (e->type == GR_EVENT_TYPE_BUTTON_DOWN) { newx = e->x; newy = e->y; button_down = 1; GrRaiseWindow(e->wid); } else { button_down = 0; } } void position_event(GR_EVENT_MOUSE *e) { if (!button_down) return; GrMoveWindow(e->wid, e->rootx-newx, e->rooty-newy); } void event_handler (GR_EVENT *event) { switch (event->type) { case GR_EVENT_TYPE_CLOSE_REQ: GrClose(); case GR_EVENT_TYPE_MOUSE_POSITION: position_event(&event->mouse); break; case GR_EVENT_TYPE_BUTTON_UP: case GR_EVENT_TYPE_BUTTON_DOWN: button_event(&event->button); break; default: break; } }
注釋
Also See |
|
Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue
您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw