CTabView/CMFCTabCtrl のタブをマウスホイールでスクロールさせる

Firefox で Tab Mix Plus とかの設定調整アドオンを使用すると、タブ上にマウスポインタを置き、ホイールをスクロールすると、次々とタブを切り替える事が出来る機能を有効にすることが出来ます。これって結構便利です。

で、MFCのCTabViewを使ってみたところ、タブが収まりきらなくなると画面外にタブが並び、それを画面内に持ってくるにはボタンで、タブを1つずつ移動していかないといけない。これがとても面倒で、タブがたくさんあるとうっとうしい。ボタンが小さくて、右の方にあるから余計に使いにくい。

そこで、マウススクロールでタブを切り替えできないかと、それらしき機能を探したが見つからない。

CTabView で使用しているタブコントロールは、 CMFCTabCtrl です。

一番簡単なのは、CMFCBaseTabCtrl::GetActiveTab() で現在アクティブなタブのインデックスを取得して、CMFCBaseTab::SetActiveTab() を使って、+1 や -1 したインデックスのタブをアクティブにして、EnsureVisible() で画面に表示する方法。

でも、今回は、タブをアクティブにしないでスクロールだけしたかった。
というのも、たくさんタブがあって、その1つ1つがアクティブになった時に画像データを読み込むんだけど、画像データのサイズが半端なくでかい。
最小100MB~最大1GB強の画像データ・・・ってどんなんだ!

A4一枚程度を 1200dpi / 48bit カラーでスキャンした生データなのです。

だから、なるべく使ってない画像は開きたくない。

そこで、次のように、ちょっと危険な手を使って、スクロールを実現してみました。

// CMFCTabCtrl のハッククラス(ポインタをキャストして使用する)
class CMFCTabCtrlEx : public CMFCTabCtrl
{
public:
    int GetTabsHorzOffset(){ return m_nTabsHorzOffset; }    // オフセット取得
    void SetTabsHorzOffset(int nOffset)                     // オフセットをセット
    { 
        m_nTabsHorzOffset = nOffset;
        AdjustTabs();
        AdjustTabsScroll();
        RedrawWindow();
    }
    int GetTabsHorzOffsetMax(){ return m_nTabsHorzOffsetMax; } // オフセットの最大値を取得
private:
    CMFCTabCtrlEx();    // インスタンス化拒否
};
 
BOOL CXxxTabView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
    CMFCTabCtrlEx* pTabCtrlEx = (CMFCTabCtrlEx*)&GetTabControl();
    pTabCtrlEx->ScreenToClient(&pt);
    if(pTabCtrlEx->IsPtInTabArea(pt))
    {
        int nPos = pTabCtrlEx->GetTabsHorzOffset();
        int nMax = pTabCtrlEx->GetTabsHorzOffsetMax();
        int nScroll = 50;    // スクロール量(ピクセル?)
        if(zDelta < 0)
        {
            int nTarget = nPos + nScroll;
            if(nTarget > nMax) nTarget = nMax;
            if(nTarget < 0) nTarget = 0;
            pTabCtrlEx->SetTabsHorzOffset(nTarget);
        }
        else
        {
            int nTarget = nPos - nScroll;
            if(nTarget < 0) nTarget = 0;
            pTabCtrlEx->SetTabsHorzOffset(nTarget);
        }
    }
    else
    {
        return CTabView::OnMouseWheel(nFlags, zDelta, pt);
    }
}



CMFCTabCtrlのソースコードを眺めて、スクロール処理している部分を特定して、擬似的にそれを実行する。
変数が、protected だったから、CMFCTabCtrl のままだとアクセスできないから、ダミーの派生クラスCMFCTabCtrlExを作成して、そのポインタに無理矢理CMFCTabCtrlのアドレスを突っ込んで、独自処理を組み込んだ見せかけの派生クラス上で処理させました。

こんな事が出来るのも、C++だからこそ。
.NETじゃ絶対に出来ないなぁ。
[PR]
by isoq | 2012-01-31 01:06 | C/C++/Win32
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇
<< MFCをまねしたちょこっとした... MFC なぜかメッセージボック... >>