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

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

新規登録して質問してみよう
ただいま回答率
85.49%
Win32 API

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

C++

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

Q&A

解決済

2回答

5028閲覧

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

hsk

総合スコア728

Win32 API

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

C++

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

0グッド

0クリップ

投稿2016/04/19 06:07

編集2016/04/19 23:49

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

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

C++

1void COcxCtrl::OnRButtonDown(UINT nFlags, CPoint point) 2{ 3 HMENU hmenu = ::LoadMenu((HINSTANCE)::GetWindowLong(this->GetSafeHwnd(), GWL_HINSTANCE), MAKEINTRESOURCE(IDR_MENU1)); 4 HMENU hmenuPopup = ::GetSubMenu(hmenu, 0); 5 6 ::ClientToScreen(this->GetSafeHwnd(), &point); 7 ::TrackPopupMenu(hmenuPopup, TPM_LEFTALIGN, point.x, point.y, 0, this->GetSafeHwnd(), NULL); 8 ::DestroyMenu(hmenu); 9 10 COleControl::OnRButtonDown(nFlags, point); 11} 12 13/// m_checked は、BOOL型のCOcxCtrlメンバー変数 14 15void COcxCtrl::OnPopupCheck() 16{ 17 HMENU hmenu = ::LoadMenu((HINSTANCE)::GetWindowLong(this->GetSafeHwnd(), GWL_HINSTANCE), MAKEINTRESOURCE(IDR_MENU1)); 18 HMENU hmenuPopup = ::GetSubMenu(hmenu, 0); 19 20 UINT state = ::GetMenuState(hmenu, IDM_POPUP_CHECK, MF_BYCOMMAND); 21 ASSERT(state != 0xFFFFFFFF); 22 if (state & MF_CHECKED){ 23 m_checked = false; 24 MessageBox(_T("F")); 25 } 26 else{ 27 m_checked = true; 28 MessageBox(_T("T")); 29 } 30 31 ::CheckMenuItem(hmenu, IDM_POPUP_CHECK, MF_BYCOMMAND | (m_checked ? (MF_CHECKED) : (MF_UNCHECKED))); 32}

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

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

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

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


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

>::CheckMenuItem(hmenu, ...

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


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

C++

1void COcxCtrl::OnPopupCheck() 2{ 3 HMENU hmenu = ::LoadMenu((HINSTANCE)::GetWindowLong(this->GetSafeHwnd(), GWL_HINSTANCE), MAKEINTRESOURCE(IDR_MENU1)); 4 HMENU hmenuPopup = ::GetSubMenu(hmenu, 0); 5 6 MENUITEMINFO menuItemInfo; 7 ::ZeroMemory(&menuItemInfo, sizeof(menuItemInfo)); 8 menuItemInfo.cbSize = sizeof(menuItemInfo); 9 menuItemInfo.fMask = MIIM_STATE; 10 11 DWORD d = ::GetMenuItemInfo(hmenu, IDM_POPUP_CHECK, false, &menuItemInfo); 12 DWORD e = ::GetLastError(); 13 14 menuItemInfo.fMask = MIIM_STATE; 15 menuItemInfo.fState |= MF_CHECKED; 16 17 DWORD dw = ::SetMenuItemInfo(hmenu, IDM_POPUP_CHECK, false, &menuItemInfo); 18 DWORD ee = ::GetLastError(); 19}

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

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

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

C++

1class COcxCtrl : public COleControl 2{ 3 //... 4 HMENU m_hMenu = NULL; 5 //... 6 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 7 afx_msg void OnDestroy(); 8 //... 9} 10 11int COcxCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 12{ 13 if (COleControl::OnCreate(lpCreateStruct) == -1) 14 return -1; 15 16 m_hMenu = ::LoadMenu((HINSTANCE)::GetWindowLong(this->GetSafeHwnd(), GWL_HINSTANCE), MAKEINTRESOURCE(IDR_MENU1)); 17 18 return 0; 19} 20 21void COcxCtrl::OnDestroy() 22{ 23 if (m_hMenu != NULL) 24 ::DestroyMenu(m_hMenu); 25 26 COleControl::OnDestroy(); 27} 28 29 30void COcxCtrl::OnPopupCheck() 31{ 32 //... 33 34 MENUITEMINFO menuItemInfo; 35 ::ZeroMemory(&menuItemInfo, sizeof(menuItemInfo)); 36 menuItemInfo.cbSize = sizeof(menuItemInfo); 37 menuItemInfo.fMask = MIIM_STATE; 38 39 if (::GetMenuItemInfo(m_hMenu, IDM_POPUP_CHECK, false, &menuItemInfo)) 40 { 41 if (menuItemInfo.fState & MF_CHECKED) 42 { 43 //... 44 menuItemInfo.fState &= ~MF_CHECKED; 45 } 46 else 47 { 48 //... 49 menuItemInfo.fState |= MF_CHECKED; 50 } 51 ::SetMenuItemInfo(m_hMenu, IDM_POPUP_CHECK, false, &menuItemInfo); 52 } 53 //... 54} 55 56

投稿2016/04/20 00:26

編集2016/04/20 00:44
hsk

総合スコア728

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

投稿2016/04/19 08:46

PineMatsu

総合スコア3579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hsk

2016/04/19 23:51

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問