Visual C++ 2008 MFC、XPです。
ダイアログをモーダルで出している状態で親ウィンドウをクリックすると
ダイアログがフラッシュしますが、これはダイアログ自身の機能なのでしょうか?
それとも、MFCのソースにそのようなコードがあるのでしょうか?
変な作りだと言われてしまうかもしれませんが、
フレームウィンドウから別のフレームウィンドウをモーダルで出していて、
その状態のときにもこの機能を付けられないかと思っています。
内部的には、フレームウィンドウから非表示のダイアログをモーダルで出し、
そこから別のフレームウィンドウを作成して、
ダイアログがタイマで終了を監視するようにしています。
親のフレームウィンドウをクリックすると、警告音はちゃんと鳴っています。
しかし、子のフレームウィンドウがフラッシュしません。
なにか伝達できるような仕組みはあるのでしょうか。
FlashWindow()
FlashWindowEx()
という関数があります。
蛇足。FlushもFlashも正しい英語(笑)。
> FlashWindow()
> FlashWindowEx()
> という関数があります。
ありがとうございます。
ただ、この関数をどのタイミングで呼べば、
フレームウィンドウをモーダルダイアログのようにできるのでしょうか。
標準のモーダルダイアログはなにもしなくても勝手にフラッシュしますが、
「親ウィンドウがクリックされたよ」みないなメッセージでもあって、
モーダルダイアログ自身はそれを見て自分で処理しているのでしょうか?
こういう関係なのですか。
main(WS_OVERLAPPED | WS_DISABLED)
modal-dialog(WS_POPUP, not WS_SHOW)
frame(WS_POPUP | WS_VISIBLE)
以下で実験したところ、フラッシュしました。
main(WS_OVERLAPPED | WS_DISABLED)
modal-dialog1(WS_POPUP | WS_DIABLED, not WS_SHOW) GWL_HWNDPARENT=main
modal-dialog2(WS_POPUP | WS_VISIBLE) GWL_HWNDPARENT=modal-dialog1
中間のウィンドウはWS_DISABLEDになっていますか。
それぞれの所有関係はどうなっていますか(GWL_HWNDPARENT)。
(Spy++/ウィドウ プロパティ/ウィンドウ/親ウィンドウで見ることができます)
ちなみに、
WS_DISABLEのウィンドウをクリックしたときにBeepが鳴るのは、
WM_SETSURSOR(HTERROR)のDefWindowProcのようです(msdn)。
# Spy++で観察すると、
# フラッシュは WM_SYSTIMER(0x118)で
# WM_NCACTIVATEをactive/inactiveに切り替えているようです。
訂正です。
再試験の結果、
> 中間のウィンドウはWS_DISABLEDになっていますか。
これは関係なかったです。
あと、私は非MFCで実験しましたので、フラッシュはAPIの仕様と思います。
> # Spy++で観察すると、
> # フラッシュは WM_SYSTIMER(0x118)で
> # WM_NCACTIVATEをactive/inactiveに切り替えているようです。
これは、たぶんFlashWindowの実装の話です。
いろいろ試していただきありがとうございます。
> こういう関係なのですか。
> main(WS_OVERLAPPED | WS_DISABLED)
> modal-dialog(WS_POPUP, not WS_SHOW)
> frame(WS_POPUP | WS_VISIBLE)
そのような感じです。
なお、frameのほうもWS_OVERLAPPEDとなっていました。
modal-dialogは、念のためサイズ0でWS_VISIBLEとしています。
ちなみに、今になって気づいたのですが、
操作中のフレームウィンドウからさらに設定用のモーダルダイアログを出し、
main(WS_OVERLAPPED | WS_DISABLED)
modal-dialog(WS_POPUP | WS_VISIBLE)
frame(WS_OVERLAPPED | WS_DISABLED)
modal-dialog(WS_POPUP | WS_VISIBLE)
という状態で親のフレームウィンドウをクリックすると、
一番下のダイアログがちゃんとフラッシュしました。
そのダイアログにはWM_NCACTIVATE(active/inactive)が来ていました。
すみません、追記させていただきます。
> そのダイアログにはWM_NCACTIVATE(active/inactive)が来ていました。
モーダルで出しているフレームウィンドウ(frame)にも、
WM_NCACTIVATE(active/inactive)自体は届いていました。
ただし、ダイアログのようにフラッシュはしてくれません。
ダイアログはこのタイミングでなにかやっているということなのでしょうか。
> main(WS_OVERLAPPED | WS_DISABLED)
> modal-dialog(WS_POPUP | WS_VISIBLE)
> frame(WS_OVERLAPPED | WS_DISABLED)
> modal-dialog(WS_POPUP | WS_VISIBLE)
これだと、mainをクリックすると、
上から2番目のdialogがWS_DISABLEDでは無いので、
2番目のdialogをフラッシュすることになりませんか。
(サイズがゼロだからみえないけど)。
ウィンドウの検索は2番目で止まってしまうような気がします。
> これだと、mainをクリックすると、
> 上から2番目のdialogがWS_DISABLEDでは無いので、
> 2番目のdialogをフラッシュすることになりませんか。
ご意見ありがとうございます。
そう思ってダイアログを見えるようにしてテストしてみたのですが、
このダイアログがフラッシュしていることはありませんでした。
また、WM_NCACTIVATE(active/inactive(合計6回?))自体は
フレームウィンドウやそこから出すモーダルダイアログには届いているようなので、
2番目で検索が止まっているというわけではないようです。
フレームウィンドウは、このメッセージが来ても
ダイアログのようにフラッシュしてくれないということなのでしょうか。
私は課題を取り違えているのでしょうか。
VS2003のMFCで実験してみました。
(MFCアプリケーション(MDI Doc/View)。
CAboutにメンバーCWnd m_Wnd を追加し、
CAbout::OnInitDialogに
m_Wnd.CreateEx(WS_EX_CLIENTEDGE,
AfxRegisterWndClass(0, ::LoadCursor(NULL, IDC_ARROW),
(HBRUSH)(COLOR_WINDOW+1)),
_T(Hello World!),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
*this, NULL, 0);
m_Wnd.ShowWindow(SW_SHOW);
を追加する。
このウィンドウをマウスでクリックしてアクティブにすると、
メインウィンドウをクリックしたときにこのウィンドウはフラッシュしました。
試していただきありがとうございます。
> VS2003のMFCで実験してみました。
> (MFCアプリケーション(MDI Doc/View)。
とりあえずメモリリークなどは全く想定してませんが、
ロマさんに試していただいたケースと同じように、VS2005のSDI(Doc/Viewなし)で、
CAboutDlg::OnInitDialog()を以下のようにやってみたところ、
「Hello World!」のウィンドウはちゃんとフラッシュしました。
CWnd* pWnd = new CWnd;
pWnd->CreateEx(
WS_EX_CLIENTEDGE,
AfxRegisterWndClass(
0, ::LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW+1)),
_T(Hello World!), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0, *this, NULL, 0);
pWnd->ShowWindow(SW_SHOW);
ただ、CWndのかわりにフレームウィンドウを出してみたところ、
やはり音が鳴るだけでフラッシュはしませんでした。
CMainFrame* pFrame = new CMainFrame;
pFrame->LoadFrame(
IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, this, NULL);
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
上のコードは、Doc/Viewなしで作成したプロジェクトの
InitInstance()に書かれているものと同じものです
(親ウィンドウはCAboutDlg自身に変更)
内部的に、フレームウィンドウはフラッシュしない仕組みになっているのでしょうか。
また、VS2005でも再現したので、
以下のときのように、Feature Packのクラスの問題というわけでもないようです。
http://rarara.cafe.coocan.jp/cgi-bin/lng/vc/vclng.cgi?print+201011/10110006.txt
ソースを追ってみました。
CFrameWnd::OnActivateでWF_STAYACTIVEを立てて
CFrameWnd::OnNActivateでは、このフラグを見ていました。、
CFrameWndはフラッシュしませんね、残念。
> CFrameWnd::OnActivateでWF_STAYACTIVEを立てて
> CFrameWnd::OnNActivateでは、このフラグを見ていました。、
やはりCFrameWndのときだけフラッシュしないようになっていたのですね。
試しに前述のテストアプリのCMainFrameにOnNcActivate()を追加し、
BOOL CMainFrame::OnNcActivate(BOOL bActive)
{
return CWnd::OnNcActivate(bActive);
}
と、CFrameWnd::OnNActivate()を通さないようにしてみたら、
あっけなくフラッシュしました。
ただ、デスクトップなどクリックしてから再度タイトルバーをクリックした際に
うまくアクティブ表示に戻らないなど、いろいろ問題が発生するようです。
このあたりをもうちょっといろいろ探ってみたいと思いますが、
このWF_STAYACTIVEはどういうことをしたいために立てているものなのか、
ご存じのかたがいらっしゃれば、引き続きご意見いただけると嬉しいです。
ありがとうございます。