- 2009-09-11 (金) 18:09
- ソフトウエア
OpenCVでcvNamedWindow()でウィンドウを作って画像を表示しているとき,うっかり右上の閉じるボタン[x]をポチっと押してしまったりしてウィンドウが閉じてしまうとそれなりに悲しい気持ちになります.
そのような残念な事態を少しでも回避できるように,ウィンドウの閉じるボタンを無効化してみました.
タイトルバー右端にある閉じるボタン[x]を無効化するには,ウィンドウのシステムメニューから「閉じる」を取り払えば良い模様なので,手順は以下のようになります.
[手順]
(1)cvNamedWindow()でウィンドウを作る
(2)ウィンドウのシステムメニューから,「閉じる」(SC_CLOSE)を除去する
cvNamedWindow()で作られるウィンドウは,タイトルバーと枠がある親ウィンドウと,画像を表示する子ウィンドウの2層構造でできており,cvGetWindowHandle()で得られるウィンドウハンドルは,子ウィンドウ側のハンドルになるので注意が必要です.
システムメニューをいじくる対象は,cvGetWindowHandle()で得られるウィンドウの親ウィンドウになります.
//●指定名称のウィンドウが存在するか? inline bool cvWndIsExist( const char *name ) { return ( cvGetWindowHandle( name ) != 0 ); } //●閉じるボタン[x]が使えないウィンドウを作る //(ただしウィンドウを閉じるショートカットキーまでは殺せてない) inline int cvNoCloseWindow( const char* name, int flags=CV_WINDOW_AUTOSIZE ) { if( cvWndIsExist( name ) )return 1; int ret = cvNamedWindow( name, flags ); HWND hParent = GetParent( (HWND)cvGetWindowHandle(name) ); if( hParent ) { RemoveMenu( GetSystemMenu( hParent, FALSE ), SC_CLOSE, MF_BYCOMMAND ); } return ret; }指定した名前のウィンドウが既に存在する場合は,なんとなく1を返してみました.
(cvNamedWindowのコードが1を返していたので同じにした)これで閉じるボタン(と,メニューの「閉じる」)は封じましたが,残念ながら「閉じられない」を達成しているわけではありません.Alt+F4とか押されるとやっぱり閉じてしまいます.
でもまぁ,閉じるボタンを灰色表示することで「閉じちゃいやん」という希望を暗に示すことはできたのではないでしょうか? ということで,個人的にはこれくらいで十分ですが…一応,Alt+F4もつぶす方法もやってみました.
Alt+F4が押されると,WM_SYSCOMMANDメッセージが飛んできて,wParamがSC_CLOSEになっています.なので,(3)ウィンドウプロシージャを差し替えて,WM_SYSCOMMAND+SC_CLOSEな時は何もしないようにする
ことで,Alt+F4も撃墜できそうです.コードを以下のように変更します.
LRESULT CALLBACK CV_NoCloseProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if( msg==WM_SYSCOMMAND && wParam==SC_CLOSE ) { return 0; } else { WNDPROC DefWP = (WNDPROC)GetProp( hWnd, "CV_DEF_PROC" ); return CallWindowProc( DefWP, hWnd, msg, wParam, lParam ); } } int cvNoCloseWindow( const char* name, int flags=CV_WINDOW_AUTOSIZE ) { if( cvWndIsExist( name ) )return 1; int ret = cvNamedWindow( name, flags ); HWND hParent = GetParent( (HWND)cvGetWindowHandle(name) ); if( hParent ) { //メニューから「閉じる」を除去(すると,[x]ボタンが灰色になる) RemoveMenu( GetSystemMenu( hParent, FALSE ), SC_CLOSE, MF_BYCOMMAND ); //ウィンドウプロシージャ置き換えでAlt+F4もつぶす SetProp( hParent, "CV_DEF_PROC", (HANDLE)GetWindowLong( hParent, GWL_WNDPROC ) ); SetWindowLong( hParent, GWL_WNDPROC, (LONG)CV_NoCloseProc ); //再描画.こんなんでいいのか? ShowWindow( hParent, SW_HIDE ); ShowWindow( hParent, SW_SHOW ); } return ret; }ウィンドウプロシージャをSetWindowLong()で自前のCV_NoCloseProc()に差し替えています.
つぶしたい処理以外は元のプロシージャに処理してもらいたいので,差し替える前に元のウィンドウプロシージャを取得し,SetProp()で保存しています.
(なんかプロシージャ差し替えコードを追加したところ,閉じるボタンが初期に灰色表示にならないようになったので,ウィンドウ再描画も追加.)とりあえずかなり閉じれない感じになったと思いますが,ここまでやる必要はなさそうというか,cvShowImage()の前に「ウィンドウの存在を確認して,なかったらウィンドウを作る」類のコードを素直に置いた方がよっぽど良いような予感.
- Newer: IplImage*を自動でRelease
- Older: cvFindContoursの結果から座標を得る