シングルクリックとダブルクリックの切り分け:タイマを使用(MFC)

ダブルクリックをしたときは、同時にシングルクリックもしています。
2回連続的にシングルクリックしたときに、2回目のクリックがある一定時間以内に発生したときに、Windowsはダブルクリックを認識します。

つまり、Windowsは、アプリケーションに次の順番でメッセージを送ってきます。

WM_LBUTTONDOWN → WM_LBUTTONUP → WM_LBUTTONDBLCLK → WM_LBUTTONUP

ダブルクリックとなる2回目のクリックまでのある一定の時間は、Win32SDKの GetDoubleClickTime() 関数によってミリ秒で取得できます。
これを利用して、タイマを起動し、ダブルクリックが起こらなければ、シングルクリックだとアプリケーションが認識するようにします。

const static int IDT_LCLICK = 1000;

(中略)

// ボタンアップハンドラ
void CMyWnd::OnLButtonDown(UINT nFlags, CPoint point) 
{
    m_ptClickPoint = point;    // 必要があれば位置を記録
    // クリックタイマ起動
    SetTimer(IDT_LCLICK, GetDoubleClickTime(), NULL);
    CScrollView::OnLButtonUp(nFlags, point);
}

// ダブルクリックハンドラ
void CMyWnd::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
    // クリックタイマ停止
    KillTimer(IDT_LCLICK);
    // ダブルクリック時の処理
    OnLButtonDoubleClick();
}

// タイマハンドラ
void CMyWnd::OnTimer(UINT nIDEvent) 
{
    // クリック時の処理
    if(nIDEvent == IDT_LCLICK)
    {
        KillTimer(IDT_LCLICK);
        OnLButtonClick();
    }
    CParentClass::OnTimer(nIDEvent);
}

(後略)


でも、これを実装しても、クリックの動作が遅すぎて、使い物になりません(;_;)
しかも、ダブルクリック待ち中に移動してクリックすると、それは別のクリックですが、タイマを起動するだけなので、クリックの漏れが発生します。

これは、OnLButtonDown() の最初で、以前のクリック位置と異なるかどうかを判定して、クリック位置がずれていて、さらにタイマ処理がまだだったら、タイマ処理を強制実行(OnTimer(IDT_LCLICK) をコール)してから、新しいタイマを起動するようにすると解決できそうです。

ダブルクリックは、2回目のクリックが一定時間以内に発生するかどうかをチェックしなければいけませんので、もし、本当にきちんと対処しようと思うと、どうしても待ち時間が発生してしまいます。

そこで、解決策を考えてみました。

①最初のWM_LBUTTONDOWNでクリック処理を実行してしまいますが、ダブルクリックの場合はキャンセル(アンドゥ)します。(かなり用途は限定されますが)

②あきらめて、小細工しない。WindowsのExplorerなどは、諦めたのか、体感速度を優先したのか、この辺の小細工はしていません。しかも逆にその方が自然な感じで実装できます。

Explorerでは、最初の WM_LBUTTONDOWN でファイル選択し、次の WM_LBUTTONDBLCLK でファイルをオープンします。

Ctrl+クリックで複数選択する場合は、選択済みのファイルの上でダブルクリックすると、最初のクリックで選択が解除されてしまう実装になっています。
気にしないか、ダブルクリックの代替えとなるキーボード操作やボタンなどで対処する方が楽そうです。(Explorerでは Enter キーにあたりますね)


結論

ダブルクリックの前のシングルクリックを受け入れようという事になりました(^^;)
[PR]
by isoq | 2006-08-18 11:43 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇
<< MAMEGAME - まめ蔵の... 小メダカ >>