- 2009-07-26 (日) 9:20
- 技術
●猫を右クリックでポップアップメニューが出るようにする
猫ウィンドウがデフォルトで唯一提供するGUIであるポップアップメニューを実装します.
そして,このポップアップメニューを猫ウィンドウを閉じる手段として利用することにします.
●メニューを作る
ポップアップメニューは::CreatePopupMenu()で作り,::DestroyMenu()で破棄します.
WM_CREATE時にメニューを作成し,WM_DESTROY時に破棄することにします.
CCatWndに,作ったメニューのハンドルを保持するためのm_hPopupMenuを追加し,コンストラクタでNULLに初期化しておきます.
//ポップアップメニュー作成 //※CAT_WND_MENU_ID_EXITは適当な値の定数 bool CCatWnd::CreateDefaultPopupMenu() { if( m_hPopupMenu != NULL )return true; m_hPopupMenu = ::CreatePopupMenu(); if( m_hPopupMenu == NULL )return false; return InsertPopupMenuItem( 0, CAT_WND_MENU_ID_EXIT, std::string("Exit") ); } //ポップアップメニュー破棄 bool CCatWnd::DestroyPopupMenu() { if( m_hPopupMenu ) { if( ::DestroyMenu( m_hPopupMenu ) ) { m_hPopupMenu = NULL; return true; } else { return false; } } return true; } //メニューへの項目追加 bool CCatWnd::InsertPopupMenuItem( UINT PosIndex, UINT ItemID, const std::string &rItemString ) { if( !m_hPopupMenu )return false; if( rItemString.empty() )return false; MENUITEMINFO miinfo = { 0 }; miinfo.cbSize = sizeof( MENUITEMINFO ); miinfo.fMask = MIIM_ID | MIIM_STRING; miinfo.wID = ItemID; miinfo.cch = (UINT)( rItemString.length() ); std::vector< char > Data( rItemString.begin(), rItemString.end() ); //※constでないものを要求されるのでコピーを生成して対応 Data.push_back( '' ); miinfo.dwTypeData = &( Data.at(0) ); bool ret = ( ::InsertMenuItem( m_hPopupMenu, PosIndex, TRUE, &miinfo ) != 0 ); if( ret ) { ::DrawMenuBar( m_hWnd ); } return ret; }ポップアップメニューの項目はデフォルトでは終了のための”Exit”のみですが,項目を追加するInsertPopupMenuItem()をpublicにすることで,利用側からの拡張を可能にしています.
●ポップアップメニューの表示と処理
WndProc()内で,猫を右クリックしたら作っておいたメニューを表示するようにします.
(万が一メニュー作成等に失敗していた場合,ウィンドウを閉じる手段が無くなってしまうので,そのための対策つき)case WM_RBUTTONUP: { //ポップアップメニュー表示 bool bTrackPopup = false; if( m_hPopupMenu ) { //座標取得 int x=0 ,y=0; { POINT pos; pos.x = LOWORD( lParam ); pos.y = HIWORD( lParam ); ::ClientToScreen( m_hWnd, &pos ); x = pos.x; y = pos.y; } //ポップアップメニュー bTrackPopup = ( ::TrackPopupMenu( m_hPopupMenu, TPM_LEFTALIGN|TPM_BOTTOMALIGN, x,y, 0, m_hWnd, NULL ) != 0 ); } //メニュー関連に失敗しているとき用の念のための対策 if( !bTrackPopup ) { DestroyWnd(); } } break;ポップアップメニューを表示する::TrackPopupMenu()関数は,「ポップアップメニュー表示中は処理が返ってこないのに,他のイベント処理はその間も動作している」という謎の動作をしていて不安をあおります…
メニュー項目が選択されるとWM_COMMANDメッセージがくるので,そこに処理を記述します.
メニューのイベント時にはHIWORD(wParam)が0になるとのことなので,それでメニューのイベントであることを判断しています.case WM_COMMAND: { if( HIWORD(wParam)==0 ) //メニューからのメッセージか? { switch( LOWORD(wParam) ) { case CAT_WND_MENU_ID_EXIT: DestroyWnd(); break; default: break; } } } break;これで 右クリック→メニュー出る→”Exit”選択でウィンドウ閉じる が達成できました.
(このままではまだ,追加されたメニュー項目については処理できませんが.)
●アプリ終了へ向かわすには?
ウィンドウは閉じられるようになりましたが,このときにアプリケーションを終了に向かわせるかどうかは,猫ウィンドウの役どころによって変わってきます.
猫ウィンドウがメインウィンドウとして使われているなら,WM_DESTROY時にPostQuitMessage()APIを呼ぶようにします.//メインウィンドウ指定されている場合,アプリ終了へ向かわす
if( this->IsMainWnd() )//※IsMainWnd()はメインウィンドウ指定されているかどうかを返すメンバ関数
{ PostQuitMessage(0); }メインウィンドウとして使うか否かは,ウィンドウ生成時に引数で設定するようにしました.
- Newer: 猫ウィンドウクラスを作る(5)
- Older: 猫ウィンドウクラスを作る(3)