【问题标题】:How do I detect if a modeless CDialog has been closed?如何检测无模式 CDialog 是否已关闭?
【发布时间】:2012-08-05 19:39:44
【问题描述】:

我已经按照这个问题制作了一个非模态/非模态对话框: How to display a non-modal CDialog?

我在 VS2008 中使用 MFC/C++。我对 C# 和 .net 的使用比对 MFC 和 C++ 更流利。

我的表单中有一个启动对话框的菜单项。只能打开一个对话框实例。对话框显示正常。我可以通过单击角落的 X 来关闭它,当我关闭主窗体时它会关闭。我遇到的问题是单击 X 关闭对话框后无法再次打开对话框。我知道这是因为指针永远不会设置回 NULL。

我在表单的头文件中有这个:

CChildDialog *m_pDialog;

我在表单的构造函数中有这个部分:

m_pDialog = NULL;

单击菜单项时,我在菜单项的方法中有此代码(我从另一个 SO 答案修改了它,因为我只想打开一个对话框实例):

if(m_pDialog == NULL)
{
    // Invoking the Dialog
    m_pDialog = new CChildDialog();
    BOOL ret = m_pDialog->Create(IDD_CHILDDIALOG, this);

    if (!ret)   //Create failed.
    {
        AfxMessageBox(_T("Error creating Dialog"));
    }    

    m_pDialog->ShowWindow(SW_SHOW);
}

现在我知道我需要执行这部分并将指针设置为 NULL,但我不知道该放在哪里:

// Delete the dialog once done
delete m_pDialog;
m_pDialog = NULL;

如果对话框已被释放,我是否需要继续监控?对话框关闭时是否触发了父窗体的事件?

【问题讨论】:

  • 只需为 WM_DESTROY 添加一个重置指针的消息处理程序。

标签: c++ visual-studio-2008 mfc dialog


【解决方案1】:

如果你想在用 X 关闭窗口后回收窗口的内容,你必须在你的对话框中处理 WM_CLOSE 消息:

void CChildDialog::OnClose()
{
    ShowWindow(SW_HIDE);
}

然后在打开窗口的代码中:

if(m_pDialog == NULL)
{
    // Invoking the Dialog
    m_pDialog = new CChildDialog();
    BOOL ret = m_pDialog->Create(IDD_CHILDDIALOG, this);

    if (!ret)   //Create failed.
    {
        AfxMessageBox(_T("Error creating Dialog"));
    }    
}

m_pDialog->ShowWindow(SW_SHOW); //moved outside the if(m_pDialog == NULL)

希望对你有帮助

【讨论】:

    【解决方案2】:

    如果你想删除无模式对话框,那么就这样做吧。

    如果您想在用户关闭无模式对话框时删除对话框的对象,您可以查看WM_PARENTNOTIFY。如果一个子窗口被销毁并且子窗口没有设置扩展窗口样式WS_EX_NOPARENTNOTIFY,那么windows会向父窗口发送一个WM_PARENTNOTIFYwParam=WM_DESTROY。您应该在父窗口中为该消息实现一个处理程序,并检查它是否是被销毁的无模式对话框。

    【讨论】:

      【解决方案3】:

      我起草了问题并准备发布,但后来我有了一个想法并最终解决了我自己的问题。因此,对于在检测到非模式对话框的关闭时遇到问题的其他人,这就是我所做的:

      void Form1::MenuItemMethod()
      {
          if(m_pDialog == NULL)
          {
              // Invoking the Dialog
              m_pDialog = new CChildDialog();
              BOOL ret = m_pDialog->Create(IDD_CHILDDIALOG, this);
      
              if (!ret)   //Create failed.
              {
                  AfxMessageBox(_T("Error creating Dialog"));
              }    
      
              m_pDialog->ShowWindow(SW_SHOW);
          }
          else
          {
              // cannot check if visible at the beginning of method because
              // pointer could be NULL and will throw an exception
      
              if(m_pDialog->IsWindowVisible())
              {
                  return;
              }
      
              m_pDialog->DestroyWindow();
              m_pDialog = NULL;
              MenuItemMethod();
          }
      }
      

      再次单击表单的菜单项后,我刚刚检查了无模式对话框是否可见。如果它是可见的,不要做任何事情。如果不是,则销毁现有的不可见对话框,将指针设置为 NULL,然后再次递归调用该方法。由于指针现在为 NULL,它应该正常重新创建对话框,然后返回正常操作。

      【讨论】:

      • 如果您关闭对话框但不再单击菜单会发生什么?潜在的内存泄漏
      【解决方案4】:

      你必须像这样删除PostNcDestroy中的内存

      void CChildDialog ::PostNcDestroy() 
      {   
          CDialog::PostNcDestroy();
          GetParent()->PostMessage(WM_WIN_CLOSED,0,0);
          delete this;
      }
      

      并向父窗口发送一条用户定义的消息,表明您的窗口已关闭。在父窗口中添加WM_WIN_CLOSED 的消息处理程序,如

      LRESULT CMainDialog::OnMyMethod(WPARAM wParam, LPARAM lParam)
      {
          m_pDialog = NULL; 
          return 0;
      }
      

      【讨论】:

      • 不惜一切代价避免delete this。由于CMainDialog 使用new 创建了子dlg,它也应该处理delete
      猜你喜欢
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 2012-01-29
      • 1970-01-01
      相关资源
      最近更新 更多