こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

SDKでツールバーの上下移動を可能にしたい

SDK,WinXPで開発しています。(Developer Studio使用です)
現在レバーコントロールにツールバーやちょっとした設定を入れていますが、このツールバーを画面の下部(ステータスバーのすぐ上など)にユーザーが自由に移動可能にしたいのです。
これを実現する為にはレバーコントロールではダメだと思うのですが、どのような手法で行えば良いのでしょうか。
アプリケーションによくある、画面に沢山のウィンドウが張りついていて、各画面を好きな場所に移動したりするものを実現したいのです。
Builderなどならば実現可能なのは分かるのですが、今回はどうしても既存のものを少し改造して実現したいのです。
SDKではムリなのでしょうか。

投稿日時 - 2008-12-05 11:11:09

QNo.4531306

困ってます

質問者が選んだベストアンサー

 こんばんは。
 フローティングツールバーの事でしょうか。此れは説明出来る物ではありません。
 先ずココを参考にしてください。
 http://oshiete1.goo.ne.jp/qa2710782.html

 途中でスタイルをポップアップにチェンジさせるとタスクバーが表示されてしまいます。ダミーウィンドウを指定しても意味が無い為、スタイルチェンジをせずに予め作成しておいた3種類のウィンドウに対して状況に応じてツールバーの乗せる換えをしながら、表示・非表示を切り替えます。
 此れでもまだ一部分に過ぎません。以下参考に。

#include<windows.h>
#include<commctrl.h>
//リソースID
const UINT IDC_TOOLBAR1 = 1000;
//クラス名
const LPCSTR PSZ_APP = "app window";
const LPCSTR PSZ_DUMMY = "dummy window";
const LPCSTR PSZ_LAND = "land window";
const LPCSTR PSZ_FLOAT= "float window";
const LPCSTR PSZ_MOVE = "move window";
//浮揚ツールバーを構成するウィンドウ
struct FLOATINGTB
{
HWND hWndLand;//着地ウィンドウ
HWND hWndFloat;//浮揚ウィンドウ
HWND hWndMove;//移動ウィンドウ
HWND hToolBar;//ツールバー
WNDPROC wndProcTBOld;//ツールバープロシージャ
};
//アプリのデータ
struct DATA
{
HWND hWndApp;//アプリウィンドウ
HWND hWndDummy;//ダミーウィンドウ
FLOATINGTB ftb;//浮揚ツールバーを構成する構造
};
//スタティック変数
static DATA s_data;
//ちょっとした関数
static const RECT GetClientRect(HWND hWnd)
{
RECT rc;
::GetClientRect(hWnd, &rc);
return rc;
}
//ちょっとした関数
static const POINT SetPoint(int x, int y)
{
const POINT pt = {x, y};
return pt;
}
//LPARAMを分解してPOINTにする関数
static const POINT PointFromLParam(LPARAM lParam)
{
const POINT pt = {(int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam)};
return pt;
}
//マウスがウィンドウ内かどうか
static bool IsMouseIn(HWND hWnd)
{
const RECT rc = ::GetClientRect(hWnd);
POINT pt = {rc.left, rc.top};
POINT ptMouse = {0};
::ClientToScreen(hWnd, &pt);
::GetCursorPos(&ptMouse);
return (ptMouse.x > pt.x && ptMouse.x < pt.x + rc.right && ptMouse.y > pt.y && ptMouse.y < pt.y + rc.bottom);
}
//マウスがウィンドウ内の上半分にあるか
static bool IsMouseUpper(HWND hWnd)
{
const RECT rc = ::GetClientRect(hWnd);
POINT pt = {rc.left, rc.top};
POINT ptMouse = {0};
::ClientToScreen(hWnd, &pt);
::GetCursorPos(&ptMouse);
return (ptMouse.y > pt.y && ptMouse.y < pt.y + (rc.bottom / 2));
}
//見ての通り
static ATOM Regist(WNDPROC wndProc, LPCSTR pszClassName)
{
WNDCLASSEX wndclass = {sizeof(wndclass)};
wndclass.style= CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc= wndProc;
wndclass.hInstance= ::GetModuleHandle(NULL);
wndclass.hIcon= ::LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor= ::LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName= NULL;
wndclass.lpszClassName= pszClassName;
wndclass.hIconSm= ::LoadIcon(NULL, IDI_APPLICATION);
return ::RegisterClassEx(&wndclass);
}
//見ての通り
static HWND Open(int x, int y, int w, int h,
LPCSTR lpszClassName, LPCSTR lpszWindowName = "NoName", HWND hParent = NULL,
DWORD dwStyle = WS_OVERLAPPEDWINDOW, DWORD dwExStyle = 0,
HMENU hMenu = NULL)
{
return ::CreateWindowEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, x, y, w, h, hParent, hMenu, ::GetModuleHandle(NULL), NULL);
}
//ウィンドウのスタイルチェンジを真似する
static void TransformWindow(HWND hWndTo, HWND hWndFrom, DWORD dwStyle, DWORD dwExStyle, LPPOINT pptFix = NULL)
{
//ツールバーハンドルを取り出す(hWndFromは必ずツールバーハンドルの所有者でないと駄目)
HWND hToolBar = ::GetDlgItem(hWndFrom, IDC_TOOLBAR1);
RECT rc = ::GetClientRect(hWndFrom);
::AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);
POINT pt = ::SetPoint(rc.left, rc.top);
//ポインタがあれば指定された位置にウィンドウを移動する
if(pptFix)
{
pt = *pptFix;
}
else//ポインタが無いのでhWndFromのクライアント座標をスクリーン座標に変換する
{
::MapWindowPoints(hWndFrom, NULL, &pt, 1);
}
::MoveWindow(hWndTo, pt.x, pt.y, rc.right - rc.left, rc.bottom - rc.top, TRUE);
//ツールバーハンドルの親ウィンドウをhWndToにする
::SetParent(hToolBar, hWndTo);
//hWndToを表示する
::ShowWindow(hWndTo, SW_SHOW);
//hWndFromを非表示にする
::ShowWindow(hWndFrom, SW_HIDE);
}
//上・下を見分けてウィンドウを着地させる位置を返す
static const POINT GetLandWindowPointHelper(DATA* pdata)
{
POINT pt = {0};
//マウスが下半分に居る
if(::IsMouseUpper(pdata->hWndApp))return pt;

//アプリウィンドウの縦幅から着地ウィンドウの縦幅を引いた場所がxの位置に成る
RECT rc = ::GetClientRect(pdata->hWndApp);
pt = ::SetPoint(0, rc.bottom - ::GetClientRect(pdata->ftb.hWndLand).bottom);
return pt;
}
//ツールバーのプロシージャ
LRESULT CALLBACK TBHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
POINT pt = {0};
RECT rc = {0};
int iButton = 0;
TBBUTTON tb = {sizeof(tb)};
switch(uMsg)
{
case WM_LBUTTONDOWN:
//親ウィンドウが着地ウィンドウではないので勧めない
if(::GetParent(hWnd) != s_data.ftb.hWndLand)
break;
//クリックされたマウス位置からツールボタンを探す
pt = ::PointFromLParam(lParam);
iButton = ::SendMessage(hWnd, TB_HITTEST, 0, (LPARAM)&pt);
//ツールボタンが見つかったので勧めない
if(::SendMessage(hWnd, TB_GETBUTTON, iButton, (LPARAM)&tb) == TRUE)
break;
//ココまで来るとツールバーのベルトがクリックされた事に成る
//着地ウィンドウから移動ウィンドウへ変化
::TransformWindow(s_data.ftb.hWndMove, s_data.ftb.hWndLand, WS_BORDER, 0);
//ツールバーの再描写
::UpdateWindow(hWnd);
//移動ウィンドウへメッセージを送る
::SendMessage(s_data.ftb.hWndMove, WM_NCLBUTTONDOWN, HTCAPTION, lParam);
return 0;
}
return ::CallWindowProc(s_data.ftb.wndProcTBOld, hWnd, uMsg, wParam, lParam);
}
//ダミーウィンドウのプロシージャ
LRESULT CALLBACK WndProcDummy(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
//浮揚ツールウィンドウのプロシージャ
LRESULT CALLBACK WndProcFloat(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
POINT pt = {0};
RECT rc = {0};
switch(uMsg)
{
case WM_CLOSE:
//閉じたら強制で着地
pt = GetLandWindowPointHelper(&s_data);
::TransformWindow(s_data.ftb.hWndLand, s_data.ftb.hWndFloat, WS_BORDER, 0, &pt);
return 0;

case WM_EXITSIZEMOVE:
//マウスがアプリウィンドウ内に存在しないので着地しない
if(!::IsMouseIn(s_data.hWndApp))
break;

//着地点を決める
pt = GetLandWindowPointHelper(&s_data);
::TransformWindow(s_data.ftb.hWndLand, s_data.ftb.hWndFloat, WS_BORDER, 0, &pt);
break;
}
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
//移動ウィンドウのプロシージャ
LRESULT CALLBACK WndProcMove(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
POINT pt = {0};
RECT rc = {0};
switch(uMsg)
{
case WM_EXITSIZEMOVE:
//アプリウィンドウの外側に居るので浮揚する
if(!::IsMouseIn(s_data.hWndApp))
{
::TransformWindow(s_data.ftb.hWndFloat, s_data.ftb.hWndMove, WS_OVERLAPPEDWINDOW, WS_EX_TOOLWINDOW);
}
else//アプリウィンドウの内側に居るので着地する
{
//着地点を決める
pt = GetLandWindowPointHelper(&s_data);
::TransformWindow(s_data.ftb.hWndLand, s_data.ftb.hWndMove, WS_BORDER, 0, &pt);
}
break;
}
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
//着地ウィンドウのプロシージャ
LRESULT CALLBACK WndProcLand(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
POINT pt= {0};
RECT rc = {0};
TBBUTTON tb = {sizeof(tb)};//ボタン用の構造体
int i = 0;
switch(uMsg)
{
case WM_CREATE:
//ツールバーを作る
s_data.ftb.hToolBar = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, 1, 1, hWnd, (HMENU)IDC_TOOLBAR1, ::GetModuleHandle(NULL), 0);
::SendMessage(s_data.ftb.hToolBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
//取り合えずボタンを5個作成する
for(i = 0; i < 5; ++i)
{
tb.fsState = TBSTATE_ENABLED;
tb.iBitmap = -1;
tb.idCommand = i;
::SendMessage(s_data.ftb.hToolBar, TB_INSERTBUTTON, 0, (LPARAM)&tb);
}
//サイズあわせ
::SendMessage(s_data.ftb.hToolBar, TB_AUTOSIZE, 0, 0);
//アプリの矩形を取る
rc = ::GetClientRect(s_data.hWndApp);
//ツールバーの高さだけ入れ直す
rc.bottom = ::GetClientRect(s_data.ftb.hToolBar).bottom;
//クライアント矩形からウィンドウサイズを決める
::AdjustWindowRectEx(&rc, WS_BORDER, FALSE, 0);
//最後にきっちりとリサイズ
::MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
//ツールバーをサブクラス化
s_data.ftb.wndProcTBOld = (WNDPROC)::SetWindowLong(s_data.ftb.hToolBar, GWL_WNDPROC, (LONG)&::TBHookProc);
break;

case WM_NCHITTEST:
return HTCAPTION;
}
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
//アプリウィンドウのプロシージャ
LRESULT CALLBACK WndProcApp(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
RECT rc;
switch(uMsg)
{
case WM_CREATE:
//ココで入れておかないと他のウィンドウのWM_CREATEに間に合わない
s_data.hWndApp = hWnd;
//着地ウィンドウを作成(初期で可視)
::GetClientRect(hWnd, &rc);
::Regist(&::WndProcLand, PSZ_LAND);
s_data.ftb.hWndLand = ::Open(0, 0, rc.right, 24, PSZ_LAND, PSZ_LAND, hWnd, WS_BORDER | WS_CHILD | WS_VISIBLE);
//移動ウィンドウを作成(初期で不可視)
::Regist(&::WndProcMove, PSZ_MOVE);
s_data.ftb.hWndMove = ::Open(0, 0, rc.right, 24, PSZ_MOVE, PSZ_MOVE, s_data.hWndDummy, WS_BORDER | WS_POPUP);
//浮揚ツールウィンドウを作成(初期で不可視)
::Regist(&::WndProcFloat, PSZ_FLOAT);
s_data.ftb.hWndFloat = ::Open(0, 0, rc.right, 24, PSZ_FLOAT, PSZ_FLOAT, hWnd, WS_OVERLAPPEDWINDOW, WS_EX_TOOLWINDOW);
break;

case WM_CLOSE:
::DestroyWindow(hWnd);
break;

case WM_DESTROY:
::PostQuitMessage(0);
break;
}
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
//ウィンメイン
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
MSG msg;
//ポップアップウィンドウでタスクバーに表示しない為にダミーウィンドウを作成する
//デスクトップの「縦・横」幅に合わせて作成
HDC hDC = ::GetDC(NULL);
::Regist(&::WndProcDummy, PSZ_DUMMY);
s_data.hWndDummy = ::Open(0, 0, ::GetDeviceCaps(hDC, HORZRES), ::GetDeviceCaps(hDC, VERTRES), PSZ_DUMMY, PSZ_DUMMY, NULL, WS_POPUP);
::ReleaseDC(NULL, hDC);
//アプリウィンドウの作成
::Regist(&::WndProcApp, PSZ_APP);
s_data.hWndApp = ::Open(20, 20, 640, 480, PSZ_APP);
::ShowWindow(s_data.hWndApp, iCmdShow);
//決まり文句
while(::GetMessage(&msg, NULL, 0, 0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return msg.wParam;
}

投稿日時 - 2008-12-06 21:20:56

お礼

machongolaさま、ありがとうございます。
お返事が遅くなり申し訳ありません。
頂いたソースで実際に動作した時は感動でした…
本当に簡単に説明頂けるようなものではないのですね。
もっと簡単に出来るのかと思っていました。
教えて頂いてから、探しても見つからないのは当然かと思いました。
頂いたものを参考にして、実際プログラムに上手く組み込めるかどうか、まだまだ時間がかかりそうです。
今回教えて頂けなかったら、ずっとつまずいたままでした。
感謝しきれないほどです。
ありがとうございました。

投稿日時 - 2008-12-08 10:32:29

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(1)

あなたにオススメの質問