CDialogExがフラッシュしない

[戻る]
NOR 2010/11/05(金) 09:53:51
Visual C++ 2008 MFCです。

以下は試験的なものですが、ダイアログベースのプロジェクトを作成し、
メインダイアログとCAboutDlgの基本クラスをCDialogからCDialogExに変更すると、
CAboutDlgを出した状態でメインダイアログをクリックしても、
CAboutDlgがフラッシュしなくなってしまいます。
CDialogのままだと問題無くフラッシュします。

MSDNには「CDialogExオブジェクトは、CMFCPopupMenuクラスオブジェクトの
親になることができます」という表記があるため、
新しいアプリケーションではCDialogではなく
CDialogExを使っておこうかと思っているのですが、
このへんの細かい問題が発生して困っております。

致命的な問題ではないと思いますが、
回避方法があるのなら理解しておきたいと思っています。
どなたか、ご存じのかたはいらっしゃいませんでしょうか。

えーと 2010/11/05(金) 11:50:04
この件、気がつきませんでした。

とりあえず、MFCソースを見てみるとCMiniFrameWndと関わっているようで、
ドッキングパネルがフロートしているときの同じ扱いにしているのかな?
という感じがします。

とりあえず、今までのダイアログ扱いにしたいのであれば、
WM_ACTIVATE(OnActivate())のメッセージを処理し、

CDialogEx::OnActivate(nState, pWndOther, bMinimized);
を処理せずに
CDialog::OnActivate( nState, pWndOther, bMinimized );
とすれば元に戻ります。

CDialogEx::OnActivate()内部では、OnNcActivate()と連動し
自分自身をWF_STAYACTIVEして、アクティブ状態でありつづけているようです。

モーダルなんだから、同じにしなくてもと言う感じはしますが...

とりあえず、ソースを眺めてみての解決策の1つとして挙げてみましたが、
他にあるかも知れません。

CDialogExはダイアログ背景ぐらいしか変えるもの無いと思っていたので
あえて気にはしていませんでしたが、VisualStudio2010ではダイアログ
の基底が標準でCDialogExになっているので今度から気をつけないといけませんね。


報告まで。

NOR 2010/11/08(月) 08:53:58
[[解決]]
詳しい解説ありがとうございます。
この件も、新しいMFCの内部上の問題なのですね。
問題というか意図的にやっているということになるのかもしれませんが。

> VisualStudio2010ではダイアログ
> の基底が標準でCDialogExになっているので今度から気をつけないといけませんね。

この件に関して、まだ2010を導入していないので確認させていただきたいのですが、
2010ではこのフラッシュしない挙動がダイアログ標準の動作となってしまっている
ということになるのでしょうか?

だとすると、VisualStudioのオプション画面などもフラッシュしないようですし、
これからは気にしなくてもよい仕様なのかなという気もしてきますが。

えーと 2010/11/08(月) 11:08:58
>この件に関して、まだ2010を導入していないので確認させていただきたいのですが、
>2010ではこのフラッシュしない挙動がダイアログ標準の動作となってしまっている
>ということになるのでしょうか?
そうなりますね。
再度確認しましたが、ウィザードで作成したダイアログアプリのCAboutDlgも
その後、リソースエディタでダイアログリソースを追加してクラスを登録
するときも基底はCDialogExですので、自分で意識的に変更しない限りそうなりますね。

>だとすると、VisualStudioのオプション画面などもフラッシュしないようですし、
>これからは気にしなくてもよい仕様なのかなという気もしてきますが
こちらも気がつきませんでした。(笑)
実はVisual Studio2008ではフラッシュしませんが、
Visual Studio2010ではフラッシュするんです。

Microsoft自身が統一できていません。
しかも新しいのに...

フラッシュするかどうかについては、難しいところはありますね。
フラッシュしなくても、音は鳴っているので操作不可ということはわかります。
ただ、難聴の方(もしくはスピーカOFFの場合)が操作できないということが判る
為にはフラッシュしたほうが良いと思います。

また、目がチカチカして紛らわしい場合もあるでしょう。
なので、一概にどちらが良いか私には結論づけできないです。

私の場合は、システム自体の視覚効果のオプションにして欲しいぐらいです。

>MSDNには「CDialogExオブジェクトは、CMFCPopupMenuクラスオブジェクトの
>親になることができます」という表記があるため、
MFCのソース見てみましたが、確かにCMFCPopupMenuによるポップアップメニュー
をサポートはしていますが、なんだか複雑な処理していますね。
CDialogでもCMFCPopupMenuを使ったポップアップメニューの表示は簡単にできます。

WM_COMMAND先をメインフレームにしたい場合は、SetOwnerを指定しておけば
メインフレームに飛びまし、ダイアログ自体に送信したい場合はそのまま
にしておけば良いです。
例.ポップアップメニューを表示し選択結果をメインフレームで処理する

    SetOwner( AfxGetMainWnd() );
    AfxGetApp()->GetContextMenuManager()->ShowPopupMenu( menu, point.x, 
point.y, this, TRUE );
    SetOwner( GetParent() );

CDialogExのメリットとしては
1.背景の変更
2.ダイアログにツールーバーやメニューバーを実装したときのポップアップメニュー
 の処理(メニューバーのメニューが開いているとそちらを閉じたりする)

ぐらいしか私にはソースから思えませんでした。
逆にそれ以外では特に使う必要はないように思えます。

NOR 2010/11/09(火) 10:52:05
> 再度確認しましたが、ウィザードで作成したダイアログアプリのCAboutDlgも
> その後、リソースエディタでダイアログリソースを追加してクラスを登録
> するときも基底はCDialogExですので、自分で意識的に変更しない限りそうなりますね。

動作を教えていただき、ありがとうございます。
これから2010を使っていくようになると、
気づかないうちにフラッシュしないダイアログになってしまうのですね。

> 実はVisual Studio2008ではフラッシュしませんが、
> Visual Studio2010ではフラッシュするんです。

これは予想外の修正でした…。
マイクロソフト的にはやはりフラッシュするのが正当で、
2008のときのオプション画面の動作自体がバグだったのですね。

個人的には、自分もえーとさんの言われるように、
フラッシュの動作がよいのか自体は決められませんが、
2010のオプション画面が修正したのに対して、MFCが逆方向な挙動に変わったのは
MFC自体のうっかりバグなんだろうなと思ってしまいます。

> CDialogでもCMFCPopupMenuを使ったポップアップメニューの表示は簡単にできます。

以前、2008で作成したアプリケーションで、
通常のモーダルダイアログや、フレームウィンドウ内の子ダイアログなどに、
CMFCPopupMenuを使ったコンテキストメニューの機能を入れてみたところ、
メニューを表示したまま他の場所をクリックした際などに
コンテキストメニューがうまく消えなかったりする問題が発生し、
各ダイアログの基本クラスをCDialogExに変更したところ一発で解決したため、

> 2.ダイアログにツールーバーやメニューバーを実装したときのポップアップメニュー
>  の処理(メニューバーのメニューが開いているとそちらを閉じたりする)

この動作と同じような理由のために
CDialogExを使わないといけないのだろうなと解釈していました。

実際、とりあえず2008で標準のままSDIのプロジェクトを作成し、
CAboutDlg::OnContextMenu()を以下のようにすると、上記の現象が発生し、
CAboutDlgの基本クラスをCDialogExにすると直ります。

void CAboutDlg::OnContextMenu(CWnd* pWnd, CPoint point)
{
    CMenu menu;
    menu.LoadMenu(IDR_POPUP_EDIT);
    CMenu* pPopup = menu.GetSubMenu(0);

    CMFCPopupMenu* pPopupMenu = new CMFCPopupMenu;
    pPopupMenu->Create(this, point.x, point.y, pPopup->Detach());
}

えーとさんに提案していただいた
GetContextMenuManager()->ShowPopupMenu()の方法でも、
メニュー外で左クリックしても消えなかったり、
メニューを出したままOKで閉じるとアクセス違反になったりするようです。
これもCDialogExにすると問題無いようでした。

えーと 2010/11/09(火) 12:00:54
>実際、とりあえず2008で標準のままSDIのプロジェクトを作成し、
>CAboutDlg::OnContextMenu()を以下のようにすると、上記の現象が発生し、
>CAboutDlgの基本クラスをCDialogExにすると直ります。
情報ありがとうございます。

確かに発生しました。
# ぐぐって見てもこのような事が起きるという件も見つかりました。

今までCDockablePane上でコントロールを作成した上で表示しかしていなかったので、
まさかダイアログでこのような現象が起きるとは思いませんでした。
この場合、先ほどの例で問題なく動いています。

確かにMFCのソースを追っていくと、CContextMenuManagerがメニューをポップアップ
するときに対象がCDialogExの場合、CDialogEx::SetActiveMenu()を呼び出して
回避処理が走る(マウスフック)のが判りました。
#Createで作成した場合、内部でInitMenu()が走り通知先がCDialogExなら
#CDialogEx::SetActivate()が走るのも確認できました。

今後、フラッシュのON/OFFがなくなるのか、継続するのか、視覚効果になるか
わかりませんが、CDialogExを派生させてON/OFF出来るようにしようと思います。
ポップアップメニューの件もありますし、こちらもCDialogEx(派生)を使用
していきたいと思います。

ありがとうございました。

古いスレッドには追加発言できません。