Akira's Commentary


一応これまでのところでプログラムは動いて 絵を表示できるようにはなりましたが、いまのままでは、

  • 動かせない
  • 隠せない
  • 止められない
  • いつも白目を剥いている!!

という状態ですので、ユーザI/Fを組み込み、 多少は操作できるようにします。とりあえずは基本パターンとして

左マウスボタン選択(TOPに)
右マウスボタンメニュー
ドラッグ 移動

をサポートします。メニューからは

移動Move
隠すHide
説明Aboutダイアログ表示
終了Exit

ぐらいはできるようにします。

まずはリソースにメニューとダイアログを追加します。 ダイアログで使う文字列については ストリングテーブルで別途定義しておきます。

---- romy.rc 追加分 ここから ----
MENU    IDM_POPUP
BEGIN
    MENUITEM    "~Move",    IDM_MOVE
    MENUITEM    "~Hide",    IDM_HIDE
    MENUITEM    "~About",   IDM_ABOUT
    MENUITEM    "E~xit",    IDM_EXIT
END

DLGTEMPLATE IDD_ABOUT
BEGIN
    DIALOG  "", 0, 0, 0, 172, 60, , FCF_DLGBORDER
    BEGIN
        ICON        ID_ROMY, -1, 2, 36, 0, 0
        LTEXT       "Mr.Romy watches You!", -1, 32, 44, 88, 8
        LTEXT       ""  IDD_ROMYTTL, 2, 26, 168, 8
	ENTRYFIELD  "", IDD_ROMYURL, 2, 16, 168, 8, ES_RIGHT | ES_READONLY
        DEFPUSHBUTTON "OK", DID_OK, 40, 2, 40, 12
    END
END

STRINGTABLE
BEGIN
    IDS_ROMYTTL     "Bitmap was taken from Romy's Page at"
    IDS_ROMYURL     "http://village.infoweb.ne.jp/~fwje3068/"
END
---- romy.rc 追加分 ここまで ----

シェイプウィンドウを使う場合には、 メニューバーもシステムアイコンもありませんので、 どうしてもフローティング/コンテキストメニューを使うことになります。 コンテキストメニューを使うには、

hwndMenu = WinLoadMenu(hwndOwner, hmod, idMenu) ;

でメニューウィンドウを生成しておき、

WinPopupMenu(hwndParent, hwndOwner, hwndMenu, x, y, id, fs) ;

でメニューを表示します。

---- メニューの生成/表示 ここから ----
/*
 * context menu
 */

static  HWND    hwndPopup = NULLHANDLE ;    /* context menu */
 
static  void    contextMenu(void)
{
    POINTL  pt   ;
    ULONG   opts ;
    
    if (hwndPopup == NULLHANDLE) {
        hwndPopup = WinLoadMenu(hwndFrame, NULLHANDLE, IDM_POPUP) ;
    }
    if (hwndPopup == NULLHANDLE) {
        printf("failed to load opup menu\n") ;
        return ;
    }
    
    WinQueryPointerPos(HWND_DESKTOP, &pt) ;

    opts = PU_HCONSTRAIN | PU_VCONSTRAIN |
	     PU_KEYBOARD | PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2 ;

    WinPopupMenu(HWND_DESKTOP, hwndFrame, hwndPopup, 
                                pt.x, pt.y, IDM_HIDE, opts) ;
}
---- メニューの生成/表示 ここまで ----

この関数をフレームウィンドウプロシジャで

    case WM_CONTEXTMENU :
	contextMenu() ;
        return (MRESULT) 0 ;

として呼び出せば右マウスボタン(厳密には違いますが)で メニューが表示されます。メニュー項目が選択されたなら、

WM_COMMAND

メッセージがオーナーウィンドウ (この場合にはフレームウィンドウ)に送付されます。 フレームウィンドウはWM_COMMANDの第一パラメタに格納されている メニュー項目のIDをチェックして必要な処理を行ないます。 これらの処理を追加するとフレームウィンドウプロシジャは 以下のようになります。

---- フレームウィンドウプロシジャ ここから ----
/*
 * procFrame - sub-classed frame window procedure
 */

static MRESULT EXPENTRY procFrame(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
    PSWP    pswp ;
    
    TRACE("frame %08x %08x %08x\n", msg, mp1, mp2) ;
    
    switch (msg) {
        
    case WM_ADJUSTWINDOWPOS :
        pswp = (PSWP) PVOIDFROMMP(mp1) ;
	WinSetWindowPos(hwndShape, pswp->hwndInsertBehind,
        	    pswp->x, pswp->y, pswp->cx, pswp->cy, pswp->fl) ;
	pswp->fl &= ~SWP_SHOW ;
	pswp->fl |=  SWP_HIDE ;
	return (*pfnFrame) (hwnd, msg, mp1, mp2) ;

    case WM_SINGLESELECT :
        WinSetWindowPos(hwndShape, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER) ;
        return (MRESULT) 0 ;
 	            
    case WM_BEGINDRAG :
        WinSendMsg(hwndFrame, WM_TRACKFRAME, 
 	        MPFROMSHORT(TF_MOVE | TF_SETPOINTERPOS), NULL) ;
        return (MRESULT) 0 ;
 
    case WM_CONTEXTMENU :
        TRACE("WM_CONEXTMENU\n") ;
 	contextMenu() ;
        return (MRESULT) 0 ;
 	
    case WM_COMMAND :
        switch (SHORT1FROMMP(mp1)) {
 	case IDM_MOVE :
            WinSendMsg(hwndFrame, WM_TRACKFRAME, 
                    MPFROMSHORT(TF_MOVE | TF_SETPOINTERPOS), NULL) ;
            return (MRESULT) 0 ;
 	case IDM_HIDE :
 	    WinShowWindow(hwnd, FALSE) ;
 	    return (MRESULT) 0 ;
 	case IDM_ABOUT :
 	    WinDlgBox(HWND_DESKTOP, hwnd, procAbout, NULLHANDLE, IDD_ABOUT, NULL) ;
 	    return (MRESULT) 0 ;
 	case IDM_EXIT  :
 	    WinPostMsg(hwnd, WM_CLOSE, NULL, NULL) ;
 	    return (MRESULT) 0 ;
        }
        return (MRESULT) 0 ;
    }
    return (*pfnFrame) (hwnd, msg, mp1, mp2) ;
}
---- フレームウィンドウプロシジャ ここまで ----

あとは、説明(About)ダイアログのダイアログプロシジャを書けば 一応動作可能になります。 処理らしいものといえば、 初期化時にストリングテーブルから文字列をロードして 設定するぐらいのものです。

なお、エントリフィールドは、デフォルトでは文字列の長さが 32バイトに制限されているので、拡大しています。

---- ダイアログプロシジャ ここから ----
/*
 * ABOUT dialog box
 */

static  MRESULT EXPENTRY procAbout(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
    HAB     hab ;
    UCHAR   buff[256] ;
    
    switch (msg) {
    
    case WM_INITDLG :
        hab = WinQueryAnchorBlock(hwnd) ;
	WinSendMsg(WinWindowFromID(hwnd, IDD_ROMYTTL), 
                    EM_SETTEXTLIMIT, MPFROMSHORT(128), NULL) ;
	WinSendMsg(WinWindowFromID(hwnd, IDD_ROMYURL), 
                    EM_SETTEXTLIMIT, MPFROMSHORT(128), NULL) ;
        WinLoadString(hab, NULLHANDLE, IDS_ROMYTTL, 256, buff) ;
	WinSetWindowText(WinWindowFromID(hwnd, IDD_ROMYTTL), buff) ;
        WinLoadString(hab, NULLHANDLE, IDS_ROMYURL, 256, buff) ;
	WinSetWindowText(WinWindowFromID(hwnd, IDD_ROMYURL), buff) ;
        return (MRESULT) 0 ;

    case WM_COMMAND :
        switch (SHORT1FROMMP(mp1)) {
	case DID_OK :
	case DID_CANCEL :
	    WinDismissDlg(hwnd, DID_OK) ;
	    return (MRESULT) 0 ;
        }
    }
    return WinDefDlgProc(hwnd, msg, mp1, mp2) ;
}
---- ダイアログプロシジャ ここまで ----

これで、一応はプログラムらしくなったでしょう。 しかし、まだいつも白目を剥いたままです。 最後に目玉を動かすコードを追加してプログラムを完成させます。