- 締切済み
WIN32APIアプリでツールバー/スステータスバーの表示切り替え
VC++6.0のwin32sdkで、MFCのSDI標準テンプレートのようにメニューでツールバー,ステータスバーを切り替えるアプリケーションにしたいと思います。 以下のようなコードにしていますが、このままでは表示非表示を切り替えた場合、中央ウインドウのサイズが変更されません。 ドラッグして全体のサイズを変更すると中央メインウインドウも正常な表示になりますが、なにか中央のウインドウを再描画する処理が必要と思われます。その再描画処理についてご教示くださいますようお願いします。 1)ステータスバーの高さ,ツールバーの高さをグローバル変数にする 2)メニューからのメッセージでこのグローバル変数を表示(夫々のバーの高さ)、非表示(夫々のバーの高さ=0)を切り替える。 3)WndProcのWM_SIZEで中央メインウインドウをMoveMindowする [グローバル変数] ---------------------------------------------- static int bShow = 16;//ステータスバーの高さ(非表示は0) static int tbShow = 25;//ツールバーの高さ(非表示は0) ---------------------------------------------- [LRESULT CALLBACK WndProcの一部] ----------------------------------------------- case WM_SIZE: ...... MoveWindow(中央のハンドル, 0, tbShow, LOWORD(lp), HIWORD(lp)-tbShow-bShow, TRUE); break; -----------------------------------------------
- みんなの回答 (4)
- 専門家の回答
みんなの回答
- machongola
- ベストアンサー率60% (434/720)
こんにちは。補足頂きました。 本格的に試してみた所、すんません、計算ミスです。 ×MoveWindow(hTree, 0, tbShow, rc.right, rc.bottom - (tbShow - bShow), TRUE); ○MoveWindow(hTree, 0, tbShow, rc.right, rc.bottom - (tbShow + bShow), TRUE); で表示されています。 ::に関しては以下URLの「グローバルスコープ」が参考になるでしょう。 http://wisdom.sakura.ne.jp/programming/cpp/cpp7.html 簡単に言えば、C++のキーワードの一つで ::Function() と書けば、グローバル関数を意味します。此れは書かなくても構わない物です。 別の意味で言うと、当方の使用しているモノがVC++であるため、::と入力した瞬間、APIや自作したグローバル関数等が、一瞬にしてリスト表示される機能がある為に、書いているという事実も有ります。
- machongola
- ベストアンサー率60% (434/720)
こんばんは。補足頂きました。 メインのウィンドウ(場合によってはhTreeの親ウィンドウ)からウィンドウサイズを取り出し、其れを利用して計算した位置に、hTreeを動かさないといけないのではないでしょうか。 ・MoveWindow(hTree, 0, tbShow,LOWORD(lp),HIWORD(lp)-tbShow-bShow,TRUE); ・LOWORD(lp),HIWORD(lp) 上記のLPARAM分析で得られた値は、少なくともこのメッセージ内(case ID_VIEW_STATUS_BAR, case ID_VIEW_TOOLBAR)においては、ウィンドウのサイズを示している物では無いので、使用出来ないのです。 RECT rc = {0}; ::GetClientRect(hWnd/*外側のウィンドウ又はhTreeの親ウィンドウ*/, &rc); ::MoveWindow(hTree, 0, tbShow, rc.right, rc.bottom - (tbShow - bShow), TRUE); と言った具合だと思います。 後、InValidRect()というのは再描画を強制するAPIであり、ウィンドウの移動やサイズ変更とは基本的に関係のない代物です。 取り敢えず以上で試されて下さい。もし無理であれば、其の時改めて補足して頂ければ、時間の折り合いが付き次第、此方からある程度のサンプルは提示出来るかもしれません。
補足
ありがとうございます。何分sdkを勉強中でこの辺の仕組みがよく理解できてないのです。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){ RECT rc = {0}; GetClientRect(hWnd, &rc); と、先頭に追加し、 case ID_VIEW_STATUS_BAR: .... SetMenuItemInfo(hMenu , ID_VIEW_STATUS_BAR , FALSE , &mi); MoveWindow(hTree, 0, tbShow, rc.right, rc.bottom - (tbShow - bShow), TRUE); break; .... case ID_VIEW_TOOLBAR: .... SetMenuItemInfo(hMenu , ID_VIEW_TOOLBAR , FALSE , &mi); MoveWindow(hTree, 0, tbShow, rc.right, rc.bottom - (tbShow - bShow), TRUE); break; と、二つのバーの処理に同じMoveWindowを入れたところ、ツールバーの表示切替でhTreeは正常に動きましたが、今度は表示切替によってステータスバーが表示されなくなりました。 全ウインドウの最小化復元で3つの子ウインドウが正常に再表示されるのは前と同じです。よろしくお願いします。 それともう一つ..... MoveWindow(hTree, 0, tbShow, rc.right, rc.bottom - (tbShow - bShow), TRUE); の先頭に::が有るのと無いのとで何か違いがあるのでしょうか? 語頭の::の意味についても参考までに教えてください。
- machongola
- ベストアンサー率60% (434/720)
こんばんは。チラッと見た限りでは、 case ID_VIEW_STATUS_BAR: memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STATE; if (bShow) { ShowWindow(hStatus, SW_HIDE); mi.fState = MFS_UNCHECKED; bShow = 0; } else { ShowWindow(hStatus, SW_SHOW); mi.fState = MFS_CHECKED; bShow = 16; } SetMenuItemInfo(hMenu , ID_VIEW_STATUS_BAR , FALSE , &mi); //此処で論点のウィンドウをMoveWindow()やSetWindowPos()でサイズ調整する break; // ツールバーの表示非表示切り替え(メニューから) case ID_VIEW_TOOLBAR: memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STATE; if (tbShow) { ShowWindow(hToolBar, SW_HIDE); mi.fState = MFS_UNCHECKED; tbShow = 0; } else { ShowWindow(hToolBar, SW_SHOW); mi.fState = MFS_CHECKED; tbShow = 26; } SetMenuItemInfo(hMenu , ID_VIEW_TOOLBAR , FALSE , &mi); //此処で論点のウィンドウをMoveWindow()やSetWindowPos()でサイズ調整する break; } では無いでしょうか。
補足
ありがとうございます。 ご指摘の位置に MoveWindow(hTree, 0, tbShow,LOWORD(lp),HIWORD(lp)-tbShow-bShow,TRUE); を入れた場合、メニューの表示非表示切替をクリックすると中央のツリービューウインドウが消えてしまいます。 ところがこの消えた状態で、ウインドウを最小化復元するかメインウインドウの境界をドラッグしてサイズを変更すると(多分WM_SIZEが発生して)中央ウインドウが正常な位置に再描画されます。InValidRectを入れても変わりませんでした。 MFCのSDIテンプレートではこのような不具合は発生せず、クリックと同時に中央ウインドウのサイズが変更されますがどこがおかしいのでしょうか??
- anmochi
- ベストアンサー率65% (1332/2045)
ちょっとプログラムが部分的すぎてよく分からんが、強制的に再描画させるならInvaliDateRect(HWND, RECT*, BOOL) Win32APIを使ってみてはどうだろう。 第二引数にNULLを食わせればHWND全体を再描画してくれるはずですぜ。第三引数がFALSEだと再描画されない(風に見える)場合があるのでその時はTRUEをセットしましょう。
補足
当方のウィンドウプロシージャは以下の通りです。 InvalidateRect(hWnd, NULL, TRUE); をどのイベントで発生させたらよいか、よくわかりません。 よろしくお願いします。 //ウィンドウプロシージャ --------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { static HMENU hMenu; MENUITEMINFO mi; static HWND hStatus; static HWND hTree; static TCHAR strMsg[80]; static int bShow = 16; static int tbShow = 25; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; // ステータスバーの表示非表示切り替え(メニューから) case ID_VIEW_STATUS_BAR: memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STATE; if (bShow) { ShowWindow(hStatus, SW_HIDE); mi.fState = MFS_UNCHECKED; bShow = 0; } else { ShowWindow(hStatus, SW_SHOW); mi.fState = MFS_CHECKED; bShow = 16; } SetMenuItemInfo(hMenu , ID_VIEW_STATUS_BAR , FALSE , &mi); break; // ツールバーの表示非表示切り替え(メニューから) case ID_VIEW_TOOLBAR: memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STATE; if (tbShow) { ShowWindow(hToolBar, SW_HIDE); mi.fState = MFS_UNCHECKED; tbShow = 0; } else { ShowWindow(hToolBar, SW_SHOW); mi.fState = MFS_CHECKED; tbShow = 26; } SetMenuItemInfo(hMenu , ID_VIEW_TOOLBAR , FALSE , &mi); break; } break; case WM_CREATE: InitCommonControls(); // ステータスバー作成 hStatus = MyCreateStatusbar(hWnd); wsprintf(strMsg , TEXT("Ready")); SendMessage(hStatus, SB_SETTEXT, (WPARAM)0 | 0, (LPARAM)strMsg); // ツールバーウインドウ作成 hToolBar = CreateToolbarEx( hWnd, WS_CHILD | WS_VISIBLE,ID_TOOLBAR, 4, hInst,IDB_TOOLBAR,tbb, 8, 0, 0, 16, 15, sizeof(TBBUTTON)); SendMessage(hToolBar, TB_INSERTBUTTON,7, (LPARAM)&tb); // ツリービューウインドウの作成 hTree = CreateWindowEx(0, WC_TREEVIEW, "", WS_CHILD | WS_BORDER | WS_VISIBLE | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT, 0, 0, 0, 0,hWnd, (HMENU)ID_MYTREE, hInst, NULL); break; case WM_PAINT: break; case WM_SIZE: SendMessage(hToolBar, WM_SIZE, wp, lp); SendMessage(hStatus, msg, wp, lp); // ツリービューウインドウの再配置(中央に配置) MoveWindow(hTree, 0, tbShow,LOWORD(lp),HIWORD(lp)-tbShow-bShow,TRUE); break; case WM_CLOSE: DestroyWindow(hWnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; } -------------------------------------------------------------------------------
お礼
ありがとうございました。出来ました!全て解決しました。 SDKの勉強中はちょっと自分の知識や技量を逸脱すると迷路に入って解決できなくなります。サポート感謝しています。 MFCのSDI標準テンプレートで自動的にやってくれることですが、MFCはブラックボックスが多すぎて好きになれません。その点SDKは最初とっつきにくいものの中身が見えるので好きです。RECTの使い方が勉強になりました。 ::の使い方もよくわかりました。クラスで同じ名のメンバー関数が有る場合意味がありますね。 どうもありがとうございました。
補足
ありがとうございました。二週間が過ぎましたので締め切ります。 あとで調べてみると以下のように強制的にWM_SIZEを発生させて再描画する方法もありそうです。 GetClientRect(hWnd, &rc); SendMessage(hWnd, WM_SIZE, (WPARAM)SIZE_RESTORED, MAKELPARAM(rc.right, rc.bottom)); UpdateWindow(hWnd);