ツールバーのフローティングイベント

[戻る]
Peng 2006/10/31(火) 14:08:20
フローティング可能なツールバーが
「フローティング状態なった」「再びメインフレームにドッキングした」
「フローティング時に×が押された」などのイベントは、
なにかのメッセージでわかるものなのでしょうか?

あるダイアログベースのプロジェクトに
別途フレームウィンドウを表示できるか挑戦しています。

ドキュメント/ビューを使わないSDI形式のアプリケーションを一時的に作成し、
それらのMainFrame/ChildViewをダイアログベースのプロジェクトに移植し、

pMainFrame = new CMainFrame;
pMainFrame->LoadFrame(...);
pMainFrame->ShowWindow(SW_SHOW);
pMainFrame->UpdateWindow();

としてみたところ、一応はフレームウィンドウを表示できたのですが、
フレームウィンドウベースのアプリケーションのように
ツールバーなどのON_UPDATE_COMMAND_UIがうまくコールされなかったり、
フローティング時にフレームウィンドウが自動調整されなかったりと困っています。

MFCのソースを追いかけてみたところ、
このへんの処理はCWinThread::OnIdleをとおして
CFrameWnd::OnIdleUpdateCmdUIでやっているのかなと思ったのですが、
ダイアログベースではCWinThread::OnIdleが発生しないようなのです。
なにかひとつ処理が終わるたびに手動でフレームウィンドウから

SendMessage(WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
m_wndToolBar.SendMessage(WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);

とやればとりあえずは更新されたのですが、
冒頭のようなイベントが発生した際にも
どうやらこれらの処理を入れなければいけないみたいなのです。

それとも、このような「フレームウィンドウをダイアログベースに追加」
するためのお決まりの方法はありますでしょうか。
よろしくお願いいたします。

Kerry 2006/11/01(水) 18:26:08
ダイアログベースのアプリケーションは、モーダルダイアログと
同じメッセージループの処理(CWnd::RunModalLoop)が実行されます
ので、そのような動作になります。

一番簡単な解決方法としては、メインのダイアログを「モードレス」
にしてみてはいかがでしょうか?

Peng 2006/11/02(木) 13:17:48
> 一番簡単な解決方法としては、メインのダイアログを「モードレス」
> にしてみてはいかがでしょうか?

やはりそのようになってしまうのでしょうか。
たしかに、SDIプロジェクトに移植してみたところ、
フローティングツールバーなどは正常に表示されました。

将来的には、今回のフレームウィンドウは
今後のいろいろな自作アプリケーションに
プラグイン的に組み込めるようにしたいため、
できれば組み込み先のプロジェクトがダイアログベースでも
フレームウィンドウベースでも、
自前でCFrameWnd::OnIdleUpdateCmdUIをコールできればと思っているのですが…。

Kerry 2006/11/02(木) 13:50:30
いや、ダイアログベースのままでも構わないので、「ダイアログを
モードレスにしてみれば?」と言っているのです。

BOOL CXXXApp::InitInstance()
{
    // ..略..

    CHogeDlg* dlg = new CHogeDlg;
    m_pMainWnd = dlg;
    dlg->Create(CXXXDlg::IDD);
    dlg->ShowWindow(SW_SHOW);
    dlg->UpdateWindow();

    return TRUE;
}

void CHogeDlg::PostNcDestroy()
{
    delete this;
}

これだけだと、フレームウィンドウにWM_IDLEUPDATECMDUIメッセージが
流れるかどうかはわかりませんが、少なくともOnIdleは呼ばれるでしょう。

Kerry 2006/11/02(木) 14:10:30
もしくは、ダイアログをモードレスにしたくない、ということであれば、
モーダルダイアログの場合は、アイドル時にWM_KICKIDLEメッセージが
送られるので、それをハンドルするのが良いかもしれません。

#include <afxpriv.h>

BEGIN_MESSAGE_MAP(CHogeDlg, CDialog)
    ON_MESSAGE(WM_KICKIDLE, OnKickIdle)
END_MESSAGE_MAP()

LRESULT CHogeDlg::OnKickIdle(WPARAM wParam, LPARAM lParam)
{
    // TODO:
    return 0L;
}

Peng 2006/11/04(土) 14:11:45
CWinThread::OnIdleをとおしてCFrameWnd::OnIdleUpdateCmdUIが
コールされているようなので、
ひょっとしたらフレームウィンドウ側を別スレッドにしてしまえば、
モーダルダイアログから作成されても独自のメッセージループが回って、
アドレスなどもそのまま共有できるのかなとも思ったのですが、
よくわかりませんでした…。

やはり、このフレームウィンドウを使いたい側がダイアログベースだったら、
自分をモードレス化したりOnKickIdleを使うなりして、
フレームウィンドウ側にアイドル状態を教えてやらなければいけないのですね。

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

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