質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.49%

  • C++

    3578questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Win32 API

    226questions

    Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

ポップアップメニュー項目のチェック状態が反映されない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,023

hsk

score 692

お世話になっております。

ポップアップメニューの項目にチェック状態を設定しているのですが、うまく記憶させる(次回開くときに反映されている)方法がわかりません。どんな処理が不足しているのかご教示いただけますと幸いです。

void COcxCtrl::OnRButtonDown(UINT nFlags, CPoint point)
{
    HMENU hmenu = ::LoadMenu((HINSTANCE)::GetWindowLong(this->GetSafeHwnd(), GWL_HINSTANCE), MAKEINTRESOURCE(IDR_MENU1));
    HMENU hmenuPopup = ::GetSubMenu(hmenu, 0);

    ::ClientToScreen(this->GetSafeHwnd(), &point);
    ::TrackPopupMenu(hmenuPopup, TPM_LEFTALIGN, point.x, point.y, 0, this->GetSafeHwnd(), NULL);
    ::DestroyMenu(hmenu);

    COleControl::OnRButtonDown(nFlags, point);
}

/// m_checked は、BOOL型のCOcxCtrlメンバー変数

void COcxCtrl::OnPopupCheck()
{
    HMENU hmenu = ::LoadMenu((HINSTANCE)::GetWindowLong(this->GetSafeHwnd(), GWL_HINSTANCE), MAKEINTRESOURCE(IDR_MENU1));
    HMENU hmenuPopup = ::GetSubMenu(hmenu, 0);

    UINT state = ::GetMenuState(hmenu, IDM_POPUP_CHECK, MF_BYCOMMAND);
    ASSERT(state != 0xFFFFFFFF);
    if (state & MF_CHECKED){
        m_checked = false;
        MessageBox(_T("F"));
    }
    else{
        m_checked = true;
        MessageBox(_T("T"));
    }

    ::CheckMenuItem(hmenu, IDM_POPUP_CHECK, MF_BYCOMMAND | (m_checked ? (MF_CHECKED) : (MF_UNCHECKED)));
}

メニューのリソースは次のように作成しています。
メニューリソース
プロパティ

常にチェックが入り(メッセージボックスでは F が毎度表示)、MF_UNCHECKEDを設定しているにもかかわらず、次回開くときにチェックが入っています。プログラミングの間違いで論理が変なのかと思い、上記コードのMF_CHECKEDをMF_UNCHECKEDにしてもチェックはついたまま。プロパティでCheckedをFalseに指定すると、今度は何をしてもチェックは入りません。

だいぶ以前にしたときには出来たのですが、コードはすっかり忘れてしまい、何がおかしいのか思い当たらず困ってしまいました。

何かご指摘いただけますと助かります。


追記
該当メニュー項目プロパティのCheckedをFalseにすると、::CheckMenuItem() の戻り値は 0 です。

>::CheckMenuItem(hmenu, ...

>::CheckMenuItem(hmenuPopup, ...
としてみましたが、同じでした。


再追記
GetMenuItemInfoやSetMenuItemInfoを利用しても、変化ありませんでした(エラーにもなりません)

void COcxCtrl::OnPopupCheck()
{
    HMENU hmenu = ::LoadMenu((HINSTANCE)::GetWindowLong(this->GetSafeHwnd(), GWL_HINSTANCE), MAKEINTRESOURCE(IDR_MENU1));
    HMENU hmenuPopup = ::GetSubMenu(hmenu, 0);

    MENUITEMINFO menuItemInfo;
    ::ZeroMemory(&menuItemInfo, sizeof(menuItemInfo));
    menuItemInfo.cbSize = sizeof(menuItemInfo);
    menuItemInfo.fMask = MIIM_STATE;

    DWORD d = ::GetMenuItemInfo(hmenu, IDM_POPUP_CHECK, false, &menuItemInfo);
    DWORD e = ::GetLastError();

    menuItemInfo.fMask = MIIM_STATE;
    menuItemInfo.fState |= MF_CHECKED;

    DWORD dw = ::SetMenuItemInfo(hmenu, IDM_POPUP_CHECK, false, &menuItemInfo);
    DWORD ee = ::GetLastError();
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

お陰様で、自己解決しました。

毎度 LoadMenu で生成をしてしまっていては、チェック状態は記憶されないようです。
ウインドウ生成時にLoadMenuしたハンドルを保持して、これを操作することで、うまくチェック状態を保持することが出来ました。
親ウインドウのポップアップメニューであれば、SetMenu でウインドウとメニューを結び付け、適宜 GetMenu 経由で操作できますが、子ウインドウ(コントロール)の場合 SetMenu は使えない(エラーコード 1436)ので、ハンドルをメンバー変数として保持することにしました。
WM_CREATE メッセージが飛んできたら LoadMenu でメニューを読み込んでハンドルをメンバー変数に保持、WM_DESTROY メッセージで DestroyMenu を呼び出してメニューハンドルを破棄、ポップアップメニュー表示などのときにはメンバー変数に保持しているハンドルを操作します。

class COcxCtrl : public COleControl
{
  //...
  HMENU m_hMenu = NULL;
  //...
  afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
  afx_msg void OnDestroy();
  //...
}

int COcxCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (COleControl::OnCreate(lpCreateStruct) == -1)
        return -1;

    m_hMenu = ::LoadMenu((HINSTANCE)::GetWindowLong(this->GetSafeHwnd(), GWL_HINSTANCE), MAKEINTRESOURCE(IDR_MENU1));

    return 0;
}

void COcxCtrl::OnDestroy()
{
    if (m_hMenu != NULL)
        ::DestroyMenu(m_hMenu);

    COleControl::OnDestroy();
}


void COcxCtrl::OnPopupCheck()
{
    //...

    MENUITEMINFO menuItemInfo;
    ::ZeroMemory(&menuItemInfo, sizeof(menuItemInfo));
    menuItemInfo.cbSize = sizeof(menuItemInfo);
    menuItemInfo.fMask = MIIM_STATE;

    if (::GetMenuItemInfo(m_hMenu, IDM_POPUP_CHECK, false, &menuItemInfo))
    {
        if (menuItemInfo.fState & MF_CHECKED)
        {
            //...
            menuItemInfo.fState &= ~MF_CHECKED;
        }
        else
        {
            //...
            menuItemInfo.fState |= MF_CHECKED;
        }
        ::SetMenuItemInfo(m_hMenu, IDM_POPUP_CHECK, false, &menuItemInfo);
    }
    //...
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

CheckMenuItemではなくSetMenuItemInfoを使ってみたらどうでしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/20 08:51

    有難う御座います。
    こちらも試してみたのですが、結果は同じでした...

    自分なりに調べてみたところ、毎回LoadMenuでオブジェクトを起こすことが正しいのか、そのあたりが怪しい(SetMenuなどでCWndなどにハンドルを結び付け、永続させる必要があるかもしれない...)ので、試しています。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C++

    3578questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Win32 API

    226questions

    Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。