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