gpt4 book ai didi

c++ - 一旦消息的当前实例在 MFC 中完成,如何发布消息?

转载 作者:行者123 更新时间:2023-12-02 10:02:09 26 4
gpt4 key购买 nike

我对 Windows 应用程序中的消息没有足够的了解。

我有这个按钮处理程序:

void CChristianLifeMinistryEditorDlg::OnFilePublicTalk()
{
CWeekendMeetingDlg dlgPublicTalk(this);

if (m_pEntry != nullptr)
{
dlgPublicTalk.SetPublicTalkInfo(m_pEntry->GetPublicTalkInfo());
dlgPublicTalk.SetCircuitVisitMode(m_iIncludeMode == kIncludeServiceTalk); // AJT v17.0.7
// AJT v20.0.1
dlgPublicTalk.SetSongInfo(
CChristianLifeMinistryUtils::UseSingOutJoyfullyToJehovah(m_datFirstMonday), m_eForeignLang);
auto iResult = dlgPublicTalk.DoModal();
if (iResult == IDOK || iResult == to_underlying(CWeekendMeetingDlg::EndResult::PreviousDate) ||
iResult == to_underlying(CWeekendMeetingDlg::EndResult::NextDate))
{
m_pEntry->SetPublicTalkInfo(dlgPublicTalk.GetPublicTalkInfo());

SetModified(true);
UpdatePreview(m_iDateIndex);
m_pHtmlPreview->Refresh2(REFRESH_COMPLETELY); // Ensure it has refreshed

// Padlock
// Reminder
// Disable controls

if (iResult == to_underlying(CWeekendMeetingDlg::EndResult::PreviousDate))
{
AfxMessageBox(_T("Move to previous week."));
PostMessage(WM_COMMAND, ID_FILE_PUBLIC_TALK, 0);

// It can't process this message until the current instance one has finished

}
else if (iResult == to_underlying(CWeekendMeetingDlg::EndResult::NextDate))
{
AfxMessageBox(_T("Move to next week."));
PostMessage(WM_COMMAND, ID_FILE_PUBLIC_TALK, 0);

// It can't process this message until the current instance one has finished
}
}
}
}

我删除了代码(替换为两个 AfxMessageBox 调用),但原则上我想重新启动相同的事件处理程序,就像用户在"file"菜单上单击它一样。可以用 PostMessage当消息的当前实例尚未终止时?

我还没有尝试过提供的答案,但是我在介绍两个 PostMessage时遇到了一个问题。调用:
void CChristianLifeMinistryEditorDlg::OnFilePublicTalk()
{
CWeekendMeetingDlg dlgPublicTalk(this);

if (m_pEntry != nullptr)
{
dlgPublicTalk.SetPublicTalkInfo(m_pEntry->GetPublicTalkInfo());
dlgPublicTalk.SetCircuitVisitMode(m_iIncludeMode == kIncludeServiceTalk); // AJT v17.0.7
// AJT v20.0.1
dlgPublicTalk.SetSongInfo(
CChristianLifeMinistryUtils::UseSingOutJoyfullyToJehovah(m_datFirstMonday), m_eForeignLang);

// AJT v20.1.8
dlgPublicTalk.SetPreviousNextDateButtonStates(m_btnMovePrevious.IsWindowEnabled(),
m_btnMoveNext.IsWindowEnabled());
auto iResult = dlgPublicTalk.DoModal();
if (iResult == IDOK || iResult == to_underlying(CWeekendMeetingDlg::EndResult::PreviousDate) ||
iResult == to_underlying(CWeekendMeetingDlg::EndResult::NextDate))
{
m_pEntry->SetPublicTalkInfo(dlgPublicTalk.GetPublicTalkInfo());

SetModified(true);
UpdatePreview(m_iDateIndex);
m_pHtmlPreview->Refresh2(REFRESH_COMPLETELY); // Ensure it has refreshed

if (iResult == to_underlying(CWeekendMeetingDlg::EndResult::PreviousDate))
{
PostMessage(WM_COMMAND, MAKEWPARAM(IDC_MFCBUTTON_PREVIOUS_DATE, BN_CLICKED),
(LPARAM)m_btnMovePrevious.GetSafeHwnd());
PostMessage(WM_COMMAND, ID_FILE_PUBLIC_TALK, 0);
}
else if (iResult == to_underlying(CWeekendMeetingDlg::EndResult::NextDate))
{
PostMessage(WM_COMMAND, MAKEWPARAM(IDC_MFCBUTTON_NEXT_DATE, BN_CLICKED),
(LPARAM)m_btnMoveNext.GetSafeHwnd());
PostMessage(WM_COMMAND, ID_FILE_PUBLIC_TALK, 0);
}
}
}
}

执行操作并重新显示窗口后,然后单击取消我得到:

enter image description here

如果我更改它并直接调用按钮处理程序,如下所示:
void CChristianLifeMinistryEditorDlg::OnFilePublicTalk()
{
CWeekendMeetingDlg dlgPublicTalk(this);

if (m_pEntry != nullptr)
{
dlgPublicTalk.SetPublicTalkInfo(m_pEntry->GetPublicTalkInfo());
dlgPublicTalk.SetCircuitVisitMode(m_iIncludeMode == kIncludeServiceTalk); // AJT v17.0.7
// AJT v20.0.1
dlgPublicTalk.SetSongInfo(
CChristianLifeMinistryUtils::UseSingOutJoyfullyToJehovah(m_datFirstMonday), m_eForeignLang);

// AJT v20.1.8
dlgPublicTalk.SetPreviousNextDateButtonStates(m_btnMovePrevious.IsWindowEnabled(),
m_btnMoveNext.IsWindowEnabled());
auto iResult = dlgPublicTalk.DoModal();
if (iResult == IDOK || iResult == to_underlying(CWeekendMeetingDlg::EndResult::PreviousDate) ||
iResult == to_underlying(CWeekendMeetingDlg::EndResult::NextDate))
{
m_pEntry->SetPublicTalkInfo(dlgPublicTalk.GetPublicTalkInfo());

SetModified(true);
UpdatePreview(m_iDateIndex);
m_pHtmlPreview->Refresh2(REFRESH_COMPLETELY); // Ensure it has refreshed

if (iResult == to_underlying(CWeekendMeetingDlg::EndResult::PreviousDate))
{
//PostMessage(WM_COMMAND, MAKEWPARAM(IDC_MFCBUTTON_PREVIOUS_DATE, BN_CLICKED),
// (LPARAM)m_btnMovePrevious.GetSafeHwnd());
OnBnClickedMfcbuttonPreviousDate();
PostMessage(WM_COMMAND, ID_FILE_PUBLIC_TALK, 0);
}
else if (iResult == to_underlying(CWeekendMeetingDlg::EndResult::NextDate))
{
//PostMessage(WM_COMMAND, MAKEWPARAM(IDC_MFCBUTTON_NEXT_DATE, BN_CLICKED),
// (LPARAM)m_btnMoveNext.GetSafeHwnd());
OnBnClickedMfcbuttonNextDate();
PostMessage(WM_COMMAND, ID_FILE_PUBLIC_TALK, 0);
}
}
}
}

后一种方法有效。我应该指出,这两个按钮处理程序更新一个 HTML 文件并在 Web 浏览器控件(实际上是在父对话框上)中重新绘制它。

像这样直接调用那些按钮处理程序是否可以接受?

使用提供的答案(谢谢)这运行良好:
void CChristianLifeMinistryEditorDlg::OnFilePublicTalk()
{
delay_post_msg dpm{ this };
CWeekendMeetingDlg dlgPublicTalk(this);

if (m_pEntry != nullptr)
{
dlgPublicTalk.SetPublicTalkInfo(m_pEntry->GetPublicTalkInfo());
dlgPublicTalk.SetCircuitVisitMode(m_iIncludeMode == kIncludeServiceTalk); // AJT v17.0.7
// AJT v20.0.1
dlgPublicTalk.SetSongInfo(
CChristianLifeMinistryUtils::UseSingOutJoyfullyToJehovah(m_datFirstMonday), m_eForeignLang);

// AJT v20.1.8
dlgPublicTalk.SetPreviousNextDateButtonStates(m_btnMovePrevious.IsWindowEnabled(),
m_btnMoveNext.IsWindowEnabled());
auto iResult = dlgPublicTalk.DoModal();
if (iResult == IDOK || iResult == to_underlying(CWeekendMeetingDlg::EndResult::PreviousDate) ||
iResult == to_underlying(CWeekendMeetingDlg::EndResult::NextDate))
{
m_pEntry->SetPublicTalkInfo(dlgPublicTalk.GetPublicTalkInfo());

SetModified(true);
UpdatePreview(m_iDateIndex);
m_pHtmlPreview->Refresh2(REFRESH_COMPLETELY); // Ensure it has refreshed

if (iResult == to_underlying(CWeekendMeetingDlg::EndResult::PreviousDate))
{
//PostMessage(WM_COMMAND, MAKEWPARAM(IDC_MFCBUTTON_PREVIOUS_DATE, BN_CLICKED),
// (LPARAM)m_btnMovePrevious.GetSafeHwnd());
OnBnClickedMfcbuttonPreviousDate();
//PostMessage(WM_COMMAND, ID_FILE_PUBLIC_TALK, 0);
dpm.set_active();
}
else if (iResult == to_underlying(CWeekendMeetingDlg::EndResult::NextDate))
{
//PostMessage(WM_COMMAND, MAKEWPARAM(IDC_MFCBUTTON_NEXT_DATE, BN_CLICKED),
// (LPARAM)m_btnMoveNext.GetSafeHwnd());
OnBnClickedMfcbuttonNextDate();
//PostMessage(WM_COMMAND, ID_FILE_PUBLIC_TALK, 0);
dpm.set_active();
}
}
}
}

我不得不使用两个 OnBnClickedMfcbuttonPreviousDate/ OnBnClickedMfcbuttonNextDate不使用 PostMessage 直接处理按钮处理程序模拟按钮点击。我认为这是可以接受的?

最佳答案

正如所写,这是安全的。 PostMessage生成 queued message在当前线程再次调用消息检索函数(如 GetMessage )之前,不会观察到这一点。然而,消息循环被阻塞,等待当前消息处理程序将控制权返回给它。

不幸的是,MFC 提供的(主)消息循环并不是可能调度消息的唯一代码。例如,对话框(如 MessageBox es)会启动它们自己的消息循环。菜单或窗口大小调整实现也是如此。有很多机会可以恢复到您试图防范的重入状态。

更强大的解决方案可以推迟 PostMessage在函数返回之前调用 to。 C++ 提供了实现这一点所需的所有工具:析构函数!

struct delay_post_msg {
delay_post_msg(CWnd* w) : w_{ w }, active_{ false } {}
void set_active() { active_ = true; }
~delay_post_msg()
{
if (active_) w_->PostMessage(WM_COMMAND, ID_FILE_PUBLIC_TALK, 0);
}
private:
CWnd* w_;
bool active_;
};

你会像这样使用它:

void CChristianLifeMinistryEditorDlg::OnFilePublicTalk()
{
// Objects are destroyed in the opposite order they are created.
// If this object's d'tor needs to run last, it has to be created first.
delay_post_msg dpm{ this };

CWeekendMeetingDlg dlgPublicTalk(this);

// ...

if (some_condition)
{
dpm.set_active();
}

// ...

// If active, the d'tor of dpm posts the message just before leaving this function.
}

关于c++ - 一旦消息的当前实例在 MFC 中完成,如何发布消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62101885/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com