メインメニューの変更について – プログラミング – Home

メインメニューの変更について
 
通知
すべてクリア

[解決済] メインメニューの変更について

固定ページ 1 / 2

タフマン
 タフマン
(@タフマン)
ゲスト
結合: 16年前
投稿: 26
Topic starter  

VC2005 MFCにてMDIアプリケーションの開発をしています。

メインメニューの大項目やポップアップ項目の動的変更について分からないので質問いた
します。

通常のメニュー項目の変更は
CMainFrame UPDATE_COMMAND_UI
にて変更可能な事は確認したのですが、大項目やポップアップ項目にはIDがなく、変更の
仕方が分かりません。

リソースファイルを見てもMENUITEMではなく、POPUPとなっており、IDがないようです。

どのように変更するかご存知の方がいらっしゃったらよろしくお願いいたします。


引用未解決
トピックタグ
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

以前に
CWnd::GetMenu() + CMenu::ModifyMenu()
と指摘して、タフマンさんから、出来たって報告があった気がしたんだけど、勘違いか
な?


返信引用
タフマン
 タフマン
(@タフマン)
ゲスト
結合: 16年前
投稿: 26
Topic starter  

maruさん

再度ありがとうございます。
以前の質問は多数の質問をしていましたので、こちらに分けさせて頂きました。

以前軽く試したときに、出来ると思ったのですが、再度実装の段階で試してみると
既存のメニュー項目に付加する事しかできませんでした。

CWnd::GetMenu() + CMenu::ModifyMenu()
で行うのは間違いないと思うのですが、ヘルプを見てもフラグの設定などがイマイチ分か
りません。

this->GetMenu()->ModifyMenuA(0, MF_BYPOSITION | MF_POPUP, 0, test);

このような感じでまずは既存のメニューファイルを書き換えたいのですが、ファイルの
項目の中のメニューに1つtestという項目が足されるのみです。

3番目の引数にポインタをセットしていないのがまずいと思うのですが、ポインタの取得
方法が分かりません。

お手数ですが、何かご存知でしたらお願いいたします。


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

テストしてみました。(ただしunicode)
void CMainFrame::OnXXX()
{
CMenu* pMenu = GetMenu();
pMenu->ModifyMenu(0, MF_BYPOSITION | MF_POPUP, 0, _T(test));
}
で、ファイルがtestに書き変わりましたけど。

どこでこの処理を実行していますか?
GetMenu()で正しくメニューを取得出来ていますか?
(といってもどうやって正しいかを確認すればいいんだろう?)


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

サブメニューを残したまま変更するのなら、一旦サブメニューを取得して更新する
必要があるから
{
int position = 0;
CMenu* pMenu = GetMenu();
CMenu* pSub = pMenu->GetSubMenu(position);
pMenu->ModifyMenu(position, MF_BYPOSITION | MF_POPUP
, UINT_PTR(pSub->m_hMenu), _T(test));
DrawMenuBar();
}


返信引用
タフマン
 タフマン
(@タフマン)
ゲスト
結合: 16年前
投稿: 26
Topic starter  

maruさん

ご回答ありがとうございます。

CMainFrame::OnCreate()
の中で行っておりました。

再度試みてみると、正常に書き換わりました。
もしかすると、コードの書き間違いがあったのかも知れません。
申し訳ございません。

またサブメニューの保存方法までご教示頂きありがとうございます。

メインフレームの方は書き換わったのですが、新規作成するとメニューが元に戻ります。
CChildFrameの方でも同様の実装が必要かと思い、オーバーライドできそうな関数を探し
てみたのですが、どこでやってもアプリケーションエラーになってしまいます。
どこで実装するのが適当でしょうか?


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

> メインフレームの方は書き換わったのですが、新規作成するとメニューが元に戻りま
す。
> CChildFrameの方でも同様の実装が必要かと思い、オーバーライドできそうな関数を探

> てみたのですが、どこでやってもアプリケーションエラーになってしまいます。
私には意味がわかりません。
何を「新規作成すると」どのメニューが「が元に戻」るのでしょうか?

CMDIChildWnd クラスのヘルプには
「MDI 子ウィンドウは、表示位置がデスクトップではなく、MDI フレーム ウィンドウ
の中である点を除いて、通常のフレーム ウィンドウのように見えます。MDI 子ウィン
ドウは、自分自身のメニュー バーはありませんが、その代わりに MDI フレーム ウィ
ンドウのメニューを共有します。フレームワークは自動的に MDI フレーム メニュー
を変更して、現在アクティブな MDI 子ウィンドウに対応させます。」
とあるので、CChildFrameを作成すると、MDIフレームのメニューが元に戻るということ
でよろしいでしょうか?
ChildWndの作成方法は
・Create を使って直接構築
・LoadFrame を使って直接構築
・ドキュメント テンプレートを使って間接的に構築
の3種類があるようでです。最初2つは直接構築とあるので、オーバーライドすれば
できそうですが、最後のドキュメント テンプレートを使う場合、間接的に構築とあ
るので、CDocTemplate(CMultiDocTemplate)を調べる必要があるかもしれません。
# かなり大変そう。


返信引用
タフマン
 タフマン
(@タフマン)
ゲスト
結合: 16年前
投稿: 26
Topic starter  

maruさん

言葉足らずですみません。

ファイルメニューの中の新規作成をし、チャイルドウィンドウを表示すると
メニュー全体がチャイルドフレーム用のメニューに切り替わります。

リソースエディタの
Menuの中の
IDR_MAINFRAME → IDR_○○○TYPE
のメニューに切り替わるという事です。

その際にメニューの大項目をCMainFrameの中で変更していた物が全く効いていない状態に
なるということです。
恐らく大項目も別物だという事で、チャイルドフレーム用のメニューでも同コードによる
変更が必要なのではないか?という事で実装先を探しております。

MDIの知識があまりないのですが、
C○○App::InitInstance()
の中で
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_EVPCSOTYPE,
RUNTIME_CLASS(CEvpcsoftDoc),
RUNTIME_CLASS(CChildFrame), // カスタム MDI 子フレーム
RUNTIME_CLASS(CEvpcsoftView));
AddDocTemplate(pDocTemplate);
というコードがあるので、ここで関連付けられているようです。

ということは、maruさんのおっしゃる3番目の一番大変そうな方法になりそうですね。
CChildFrame内で出来る物だと思っていたのですが。

何かいい方法が分かれば報告させて頂きます。


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

CMDIChildWndクラスのprotectedメンバに
 HMENU m_hMenuShared; // menu when we are active
があるから、Create()をオーバーロードしてこのメニューハンドルでメニューを
構築してあげればいいのかな。

参考までに以下のコードでメニューの置き換えができています。
タフマンさんの場合、LoadMenu(IDR_xxxx)の代わりに自分でメニューを作成し、
そのハンドルをm_hMenuSharedにセットすればよいのではないでしょうか。
// 実際に動作しているプログラムからコピペ(&一部変更)したがコンパイルは
// 行っていないのでエラーがおこるかも。
class CMyChildWnd : public CMDIChildWnd
{
/* 途中省略 */
protected:
static CMenu menu; ///< メニュー
public:
virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD
dwStyle = WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, const RECT& rect =
rectDefault, CMDIFrameWnd* pParentWnd = NULL, CCreateContext* pContext = NULL);
}
BOOL CMyChildWnd::Create
( LPCTSTR szTitle
, LONG style /* = 0 */
, const RECT& rect /* = rectDefault */
, CMDIFrameWnd* parent /* = NULL */
)
{ if (menu.m_hMenu == NULL)
{ menu.LoadMenu(IDR_xxxx); // メニューをリソースからロード
}
m_hMenuShared = menu.m_hMenu;

LPCTSTR lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
LoadCursor(NULL, IDC_ARROW),reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_MANDELBROT)));

return CMDIChildWnd::Create(lpszClass, szTitle, style, rect, parent);
}


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

おっと、
static CMenu menu; ///< メニュー
があるから、.cppに
 CMenu CMyChildWnd ::menu; // menu for all HELLO windows
が必要だね。
コメントでMDIサンプル(MDIDOCVW)から持ってきたコードだったことを思い出した。


返信引用
タフマン
 タフマン
(@タフマン)
ゲスト
結合: 16年前
投稿: 26
Topic starter  

maruさん

ありがとうございます。

CMDIChildWndというクラスが見当たらないのですが、どういった環境で作られたもので
しょうか?
試しに、新たにテスト用にMDIのプロジェクトを作ってみましたが、やはりありませんで
した。
m_hMenuSharedで検索してみましたが、プロジェクト内にヒットしませんでした。

的外れな事を言っていたら申し訳ありません。


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

環境は
Microsoft Visual Studio 2005 Professional Edition - 日本語 Service Pack 1
(KB926602)
で、アプリケーション種類は
 MFCアプリケーション、マルチドキュメント
です。

CMDIChildWndは自動的に作成されるCChildFrameの親(派生元クラス)です。
ChildFrm.cpp, hがありませんか?
私の例ではCChildFrameの代わりにCMyChildWndという名前を付けています。

> m_hMenuSharedで検索してみましたが、プロジェクト内にヒットしませんでした。
m_hMenuSharedはMFCのクラスであるCMDIChildWndクラスのメンバですので、プロ
ジェクト内には存在しません。


返信引用
タフマン
 タフマン
(@タフマン)
ゲスト
結合: 16年前
投稿: 26
Topic starter  

maru さん

長い間返信できなくて、本当に申し訳ありません。

CMyChildWndというのはmaruさんが付けた名前だったのですね。
全然気付きませんでした(汗
色々試してみたのですが、やはり駄目でした。

CChildFrame内のCreateにてmaruさんのコードを実装してみたのですが、
IDI_MANDELBROT
がエラーで引っ掛かって先に進めませんでした。

リソースエディタで作成したチャイルドウィンドウ用のメニューは既にあり、チャイルド
ウィンドウが開かれた時にはそちらが表示されているのですが、ここで新たに関連付けさ
せる意味はなんですか?

既にあるチャイルドウィンドウ用のメニューの文字列を変更したいと思っております。


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

> IDI_MANDELBROT
> がエラーで引っ掛かって先に進めませんでした。
は私のアプリのチャイルドフレームに使用されるアイコンのリソースIDですので
そのままではコンパイルできません。IDR_xxxxのように変更しておけばよかった
のですが、気づいていませんでした。どうもすいません。
ただ
LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_MANDELBROT)));
の引数として使用しているので、LoadIconの仕様がわかれば、問題はなかった
はずとも思います。

> リソースエディタで作成したチャイルドウィンドウ用のメニューは既にあり、チャイル

> ウィンドウが開かれた時にはそちらが表示されているのですが、ここで新たに関連付け

> せる意味はなんですか?
そのチャイルドウィンドウ用のメニューを読み込んでいる所がまさにここじゃないか、
と思うんですが。
if (menu.m_hMenu == NULL)
{ menu.LoadMenu(IDR_xxxx); // メニューをリソースからロード
}
となっているでしょ。
タフマンさんの場合、ここでLoadMenuの代わりにCMenuを用意されたテキストファイル
から生成して、そのハンドルをhMenuShared にセットしてあげればいいんじゃないかと。


返信引用
タフマン
 タフマン
(@タフマン)
ゲスト
結合: 16年前
投稿: 26
Topic starter  

maru さん

ありがとうございます。

>の引数として使用しているので、LoadIconの仕様がわかれば、問題はなかった
>はずとも思います。
おっしゃる通りです。
IDI_xxxとなっておりましたので、IDI_という見慣れない文字列で先入観からIDだとは思
いませんでした。
関数仕様を調べればよかったです。申し訳ありませんでした。

やっとおっしゃっている意味が理解できました!
子ウィンドウの方でメニューをロードし、そこで親ウィンドウで行ったのと同じ処理をす
ればできるだろうという事ですね。

所要で出張しておりますので、明日か明後日には試せると思います。
また報告させて頂きます。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました