|
[図9-1] :
しかし,「子ウィンドウ」ではなくて,ただの「オーナー付き」なので,フレームウィンドウが移動したりサイズを変更すると,ウィンドウがずれてしまいます.
しかたがないので,WM_SIZEやWM_MOVEが来るのを見計らって同時に両方をウィンドウを動かしてやるようにしましょう.
あと,ポップアップウィンドウのほうがアクティブにならないような配慮もしなくてはいけません.
と,いろいろな配慮が必要なのでやめたほうがよいでしょう(じゃあ書くなって).
でもこの方法のほうがウィンドウが分離するため非常に安全なので,このような方法もあるということを知っておきましょう.
[図9-2] :
ちなみにこれは失敗です.WM_NCPAINTを完全に自分で処理してしまうと,あとの外枠などを描画する処理をWindowsが行ってくれなくなり,変なことになってしまいます.
こういう場合は,DefWindowProc()を先に呼んでから,自分の処理をするようにします.DefWindowProc()は,メッセージをハンドルしないときに,標準の処理として呼んでおくもので,WM_NCPAINTをハンドルしていないときは,実はいつもDefWindowProc()が非クライアント領域を描画してくれていたのです.
というわけで,先にDefWindowProc()を呼んでおくと,Windowsが非クライアント領域をちゃんと描いてくれるようになり,その後でタイトルバーの部分だけ上書きすれば,あたかもタイトルバーだけ描画されているかのようになります.
ということは,この方法を使うと一度元のタイトルバーが描かれてから自分のタイトルバーを描くので,一瞬ちらつくのでは,と思うかもしれませんが,実はちらついてます(笑).でも気になる速度ではありません.(図9-3).
[図9-3] :
[リスト9-1] :
void MyDrawCaption( HWND hwnd, BOOL fActive ) { COLORREF crCaption, crText; int cxFrame = GetSystemMetrics( SM_CXFRAME ); int cyFrame = GetSystemMetrics( SM_CYFRAME ); int cxButton = GetSystemMetrics( SM_CXSIZE ); int cyButton = GetSystemMetrics( SM_CYSIZE ); if( fActive ) { crCaption = GetSysColor( COLOR_ACTIVECAPTION ); crText = GetSysColor( COLOR_CAPTIONTEXT ); } else { crCaption = GetSysColor( COLOR_INACTIVECAPTION ); crText = GetSysColor( COLOR_INACTIVECAPTIONTEXT ); } RECT rcWnd; char sz[128]; GetWindowRect( hwnd, &rcWnd); GetWindowText( hwnd, sz, sizeof(sz) - 1 ); HDC hdc = GetWindowDC( hwnd ); //テキスト描画の例 RECT rcFill; rcFill.left = cxFrame + cxButton + 1; rcFill.right = (rcWnd.right - rcWnd.left) - (cxFrame + 3*(cxButton+1)); rcFill.top = cyFrame; rcFill.bottom = cyFrame + cyButton; SetTextColor( hdc, crText ); SetBkColor( hdc, crCaption); HBRUSH hbr = CreateSolidBrush( crCaption ); FillRect( hdc, &rcFill, hbr ); DeleteObject( hbr ); DrawText( hdc, sz, lstrlen(sz), &rcFill, DT_RIGHT | DT_VCENTER | DT_SINGLELINE ); //ビットマップ描画の例 HDC hdcMem = CreateCompatibleDC( hdc ); HGDIOBJ hold = SelectObject( hdcMem, hbmp ); #ifdef WIN32 SIZE size; GetTextExtentPoint32( hdc, sz, lstrlen(sz), &size ); int cxText = size.cx; #else int cxText = LOWORD(GetTextExtent( hdc, sz, lstrlen(sz) )); #endif int cxDraw = rcFill.bottom - rcFill.top - 4; int xBmp = rcFill.right - size.cx - cxDraw; StretchBlt( hdc, xBmp, rcFill.top + 2, cxDraw, cxDraw, hdcMem, 0, 0, cxBmp, cyBmp, SRCCOPY ); SelectObject( hdcMem, hold ); DeleteDC( hdc ); ReleaseDC( hwnd, hdc ); }
[リスト9-2] :
case WM_NCPAINT:{ LRESULT ret = DefWindowProc( hwnd, message, wParam, lParam ); if( !IsIconic( hwnd ) ) { #ifdef WIN32 MyDrawCaption( hwnd, GetForegroundWindow() == hwnd ); #else MyDrawCaption( hwnd, GetActiveWindow() == hwnd ); #endif } return ret; } case WM_NCACTIVATE:{ LRESULT ret = DefWindowProc(hwnd , message ,wParam ,lParam); if( !IsIconic( hwnd ) ) { MyDrawCaption( hwnd, wParam ); } return ret; } case WM_SETTEXT:{ LRESULT ret = DefWindowProc( hwnd, message, wParam, lParam ); if( !IsIconic( hwnd ) ) { MyDrawCaption( hwnd, GetForegroundWindow() == hwnd ); } return ret; }
[リスト9-3] :
BOOL CMainFrame::OnNcActivate(BOOL bActive) { BOOL ret; ret = CMDIFrameWnd::OnNcActivate(bActive); if( !IsIconic() ) { MyDrawCaption( m_hWnd, bActive ); } return ret; } void CMainFrame::OnNcPaint() { CMDIFrameWnd::OnNcPaint(); if( !IsIconic() ) { #ifdef WIN32 DrawCaption( m_hWnd, (BOOL)(m_hWnd == GetForegroundWindow()->m_hWnd) ); #else DrawCaption( m_hWnd, (BOOL)(m_hWnd == GetActiveWindow()->m_hWnd) ); #endif } } LONG CMainFrame::OnSetText( UINT wParam, LONG lParam ) { LRESULT ret = DefWindowProc( WM_SETTEXT, wParam, lParam ); MyDrawCaption( m_hWnd, TRUE ); return ret; //メッセージマップで ON_MESSAGE( WM_SETTEXT, OnSetText ) としている }このように,タイミングやメッセージが特定できない場合は,どういうメッセージが来ているかを調べて臨機応変に対応することでたいていの問題は解決することができるはずなので,何だかわからない場合は自分でメッセージを調べてみましょう.