MFC   VC++   Visual Studio   Visual Studio   プログラミング

CMFCToolBar上のコンボボックス

 「CMFCToolBar」上に「CMFCToolBarComboBoxButton」のコンボボックスを作成し、値を取得/操作する方法を紹介します。

 「CMFCToolBarComboBoxButton」は、作成時にポインタを取得してメンバ変数などにしておいても、その後、そのポインタは有効ではなくなり、この方法では値を取得できません。
 しかも、スタイルの違いで取得方法が少し違うので、必要なときに値を取得する方法を、スタイル別に紹介していきたいと思います。

 まず、コンボボックスのスタイルを「CBS_DROPDOWNLIST」にした場合のリスト切替え時に取得する方法を紹介します。
 リスト切替え時とは、ユーザーがドロップダウンリストから項目を選択し、表示が切り替わったタイミングのことで、コードはまず、処理したいヘッダファイル内で処理したい関数(ここでは OnChangeComboBox )を宣言し、
    afx_msg void OnChangeComboBox(void);
と宣言し、cppファイル内のメッセージマップに以下を追加、
    ON_CBN_SELENDOK(ID_COMBOBOXBUTTON, &CXXX::OnChangeComboBox)
 ここで「ID_COMBOBOXBUTTON」は「CMFCToolBarComboBoxButton」作成時に関連付けたIDで、「CXXX」は処理するクラス名です。

 次に、関数の中身ですが、
void CXXX::OnChangeComboBox()
{
    CMFCToolBarComboBoxButton* pSrcCombo = NULL;
    CObList listButtons;
    if(CMFCToolBar::GetCommandButtons(ID_COMBOBOXBUTTON, listButtons) > 0)
    {
        for(POSITION posCombo = listButtons.GetHeadPosition(); pSrcCombo == NULL && posCombo != NULL;)
        {
            CMFCToolBarComboBoxButton* pCombo =
                DYNAMIC_DOWNCAST(CMFCToolBarComboBoxButton, listButtons.GetNext(posCombo));

            if(pCombo != NULL && CMFCToolBar::IsLastCommandFromButton(pCombo))
            {
                pSrcCombo = pCombo;
            }
        }
    }

    if(pSrcCombo != NULL)
    {
        ASSERT_VALID(pSrcCombo);

        LPCTSTR lpszSelItem = pSrcCombo->GetItem();    // ここでアイテム名を取得または操作する。
    }
}
 のようになり、「lpszSelItem」に選択されたアイテム名が入ります。

 さらに、このコンボボックスのIDをメニューに入れ、メニューから選択を切り替えたい場合などは、通常のコマンドID処理をするようにすればできます。
 その方法は、ヘッダで処理したい関数を宣言し、cppファイル内のメッセージマップで「ON_COMMAND」を宣言し、cppファイル内の関数で処理します。
ヘッダファイル
    afx_msg void OnCommandComboBox(void);
cppファイル
BEGIN_MESSAGE_MAP(CRenameApp, CWinAppEx)
    ON_COMMAND(ID_COMBOBOXBUTTON, &CXXX::OnCommandComboBox)
END_MESSAGE_MAP()
 関数の中身は、前述の「OnChangeComboBox」とほぼ同じで、「CMFCToolBar::IsLastCommandFromButton(pCombo)」を削除すれば処理できます。
 ここで「CMFCToolBar::IsLastCommandFromButton(pCombo)」は、最後にコマンド送信されたボタンかどうかを調べるものなので、スタイルがドロップダウンリストのとき、リスト変更されたタイミングで処理する場合に有効になります。
 任意のタイミングで値を取得/操作したい場合は、メニューからの処理をする方法で関数を作り、取得したいときにこの関数を呼べば取得/操作できます。

 次回、コンボボックスのスタイルが「CBS_DROPDOWN」での値の取得、操作方法を紹介します。
ランキングへ     posted by 遠雷 | Comment(0) | フレーム

スプリッタウインドウの最小制限 その4

 気付くと4回目になった、スプリッタウインドウの最小制限についてですが、海外のサイトで別の方法が紹介されていました。
 この方法を試してみたところ、やはり同様に、メインフレームなどの親フレームをサイズ変更したとき、一番端のペインの最小サイズは確保されませんでした。

 一応、今わかっているところまでを書いておくと、RecalcLayout関数内でこれらの処理をしていて、その中の_AfxLayoutRowCol内で変更される、ということです。
 よって、この辺をいじればなんとかなりそうなんですが・・・。

 海外のサイトで紹介されていた方法は、RecalcLayout関数をオーバーライドし、そこで最小サイズを確保するようになっていました。
 なので、この辺をうまく改良していけば、今問題になっている部分もうまくいくのではないかと思っています。

 ちなみに、その海外のサイトはcodeguruで、Minimum size splitterという記事で紹介されています。
 このサイトを知っている人は多いと思いますが、沢山の情報があるので、かなり役に立つサイトだと思います。
ランキングへ     posted by 遠雷 | Comment(0) | フレーム

スプリッタウインドウの最小制限 その3

 前回紹介した方法だと、大きくする方向(下/右)へ仕切り線を移動させた場合、一つ下/一つ右の行/列の最小サイズが確保出来ませんでした。
 そこで、今回はその問題を解決する方法を紹介します。
 といっても、前回のものを少し改良するだけなので、変更点だけを掲載します。

 前回の以下の部分を、
    else if (m_pRowInfo[row].nCurSize + m_pRowInfo[row+1].nCurSize
            < pt.y + m_pRowInfo[row+1].nMinSize)
    {
        // not enough room for other pane
        if (GetStyle() & SPLS_DYNAMIC_SPLIT)
            DeleteRow(row + 1);
    }
から、
    else if (m_pRowInfo[row].nCurSize + m_pRowInfo[row+1].nCurSize
            < pt.y + m_pRowInfo[row+1].nMinSize)
    {
        CRect rct;
        GetClientRect(&rct);
        m_pRowInfo[row].nIdealSize =
            rct.Height() - (m_pRowInfo[row+1].nMinSize + m_cySplitter +
            m_cyBorderShare + m_cySplitterGap + m_cyBorder);
        // not enough room for other pane
        if (GetStyle() & SPLS_DYNAMIC_SPLIT)
            DeleteRow(row + 1);
    }
とするだけです。

 上記のコードについて少し説明すると、ペインが2行のときに仕切り線をドラッグして移動させた場合、「row」は常に"0"になるため、"1"のペインについては最小値が適用されずサイズ"0"になってしまいます。
 そこで、「else if」の部分で最小値になるように処理するのですが、仕切り線の位置からペイン"1"のサイズを確保できるように、ペイン"0"のサイズを変更します。
 そのとき、スプリッタウインドウのクライアント領域サイズを取得し、そこから仕切り線の幅などを引いてペイン"1"の最小値が確保できるようにペイン"0"のサイズを変更しています。

 さらに、またしても問題なのですが、メインフレームなどの親フレームをサイズ変更したとき、一番端のペインの最小サイズが確保できないのです。
 この問題については、もう少し調べてみて、解決方法がわかったらまた紹介したいと思います。
ランキングへ     posted by 遠雷 | Comment(0) | フレーム