マウスが領域から離れた(WM_MOUSELEAVE)を受け取るには_TrackMouseEvent()が必要


_TrackMouseEvent()を使ってOnMouseLeave()に飛ぶように設定する。


Cソース

BEGIN_MESSAGE_MAP(CImageButton, CButton)
 //{{AFX_MSG_MAP(CImageButton)
 … 
 ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CImageButton::OnMouseMove(UINT nFlags, CPoint point) 
{
 CRect rect;
 GetClientRect(rect);
 if(PtInRect(rect, point)){
  
  // マウス監視開始(LEAVEイベント)
  TRACKMOUSEEVENT tme;
  tme.cbSize = sizeof(tme);
  tme.dwFlags = TME_LEAVE;
  tme.hwndTrack = this->m_hWnd;
  _TrackMouseEvent(&tme);

  InvalidateRect(rect);		// 描画
 }
 CButton::OnMouseMove(nFlags, point);
}
LRESULT CImageButton::OnMouseLeave(WPARAM wparam, LPARAM lparam){
 …
}

ヘッダ

// 生成されたメッセージ マップ関数
protected:
 //{{AFX_MSG(CImgButton)
 …
 afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam);
 //}}AFX_MSG


ネタ元

リストビューにスクロールバーが表示されているのか?表示されていないのか?を判定する方法


GetWindowLong()を使用すれば可能。

//リストビューハンドルを取る
HWND hList = ::GetDlgItem(hDlg, IDC_LIST1);

//リストビューハンドルのスタイルを取る
const DWORD dwStyle = ::GetWindowLong(hList, GWL_STYLE);

//以下の方法で確認できるようです
if(dwStyle & WS_VSCROLL)
{
//縦スクロールバーがある
}

if(dwStyle & WS_HSCROLL)
{
//横スクロールバーがある

ネタ元

ボタンの色などを変えられるCButtonクラス拡張

ネタ元


このコードをみれば普通のボタンの描画手順が分かる。

  • ボタン部分の背景を塗りつぶして
    • FillRect()
    • 色はGetSysColor(COLOR_BTNFACE)
  • テキストを描いて(無効なら無効色で描く)
    • DrawText()
  • ボタンの立体表現を描いて
    • DrawEdge()
    • EDGE_RAISED
  • 押されているなら、押されている表現を描いて
    • DrawEdge()
    • EDGE_SUNKEN 
  • フォーカスが合っているなら、フォーカスラインを描く
    • DrawFocusRect()

手動でWM_ERASEBKGNDをオーバーライドする

VC++6。

MFC ClassWizardを使わない/使えない時に手動でやる方法。WM_ERASEBKGND以外のメッセージも同様。


ヘッダ(.h)の // 生成されたメッセージ マップ関数 というコメントがあるとこの
//{{AFX_MSG(CTabWnd) と //}}AFX_MSG に囲まれた中に

afx_msg BOOL OnEraseBkgnd(CDC* pDC);

を追加。


ソース(.cpp)の中の BEGIN_MESSAGE_MAP(... と END_MESSAGE_MAP() に囲まれた中に

ON_WM_ERASEBKGND()

を追加。


オーバーライド関数本体を追加

BOOL Hoge::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
}

マウスがクライアント領域に入った/外れたを判別する

通常、クライアント領域から離れてしまえば、マウス関連のメッセージが飛んでこなくなるので、SetCapture()で捕まえておいて、外れるときにReleaseCapture()で解放する。


例:

void CHogeButton::OnMouseMove(UINT nFlags, CPoint point)
{
  CRect rect;
  GetClientRect(rect);

  if(PtInRect(rect, point)){
    if(NULL == GetCapture()){
      SetCapture(); <--①
      m_bHover = true;
      RedrawWindow();
    }
  }
  else{
    if(NULL != GetCapture() ){
      ReleaseCapture(); <--②
      m_bHover = false;
      RedrawWindow();
    }
  }

  CButton::OnMouseMove(nFlags, point);
}

ネタ元

CDialogでOnEraseBkgnd()を追加するには、クラス情報でメッセージフィルタを「ウィンドウ」にしてから、WM_ERASEBKGRNDの関数を追加する

背景のクリアを防ぎたいと思って、ClassWizardでWM_ERASEBKGRNDを追加しようとしても、見当たらない。
これはフィルタされているのが原因。

ClassWizard を使わずに手書きしてもいいけど、ClassWizardでも使えるようにできる。

  1. ClassWizard を開き、「クラス情報」ページを選択する
  2. 右上の「クラス名」ドロップダウンリストで対象とするダイアログクラスを選択する
  3. 下の「詳細設定オプション」の中の「メッセージフィルタ」ドロップダウンリストで「ダイアログ」となっているのを「ウィンドウ」に変更する

これで「メッセージマップ」ページにもどれば、「メッセージ」リストで WM_ERASEBKGND も選択できるようになっている。
関数追加したら、他の作業のために忘れないうちにここでメッセージフィルタを「ダイアログ」に戻しておくのが吉。


ネタ元