繁体   English   中英

MFC:子对话框行为

[英]MFC: child dialog behavior

我试图将我的子对话框创建为主应用程序类的成员,如下所示:

class ParentWindow : public CWinApp
{
public:
    // Other MFC and user-implemented classes before this line
    MiscSettings    activeMiscSettings;

public:
    ParentWindow();
    ~ParentWindow();

// Overrides
    virtual BOOL InitInstance();

// Implementation
    afx_msg void OnAppAbout();
    afx_msg void OnMiscSettingsPrompt();
    DECLARE_MESSAGE_MAP()
};

我想让MiscSettings描述的对话框在程序启动时实例化,在程序退出时销毁,并根据用户选择特定菜单选项还是用户单击“确定”或显示/隐藏来显示/隐藏对话框的“取消”按钮。 但是,当我实现OnMiscSettingsPrompt()处理函数时,如下所示:

void ParentWindow::OnMiscSettingsPrompt()
{
    float temp;
    INT_PTR status = activeMiscSettings.DoModal();
    switch(status)
    {
    case IDOK:
        temp = activeMiscSettings.GetSpeed();
        break;
    case IDCANCEL:
    default:
        break;
    }
}

我无法访问activeMiscSettings.GetSpeed()方法b / c,在调用DoModal()之后,该句柄无效。 在显示子对话框时,我使用了与其他示例类似的方法。 但是,activeMiscSettings的内容不能由ParentWindow类访问。 我知道我可以将处理程序放在MiscSettings类中,以将内容正确地转移到编辑控件和其他用户控件设置的“确定”按钮处理程序中,并传递到应用程序其余部分的适当类内容。 此时,我不确定将子弹出对话框上的设置转移到应用程序其余部分的最干净的方法是什么。

我正在尝试实现的另一个规范是杂项。 设置弹出对话框,用于在用户首次选择菜单选项时首次显示预配置的设置。 更改某些设置并按OK后,如果用户再次打开设置窗口,我希望在用户控件中显示当前设置,而不是显示以前在第一个实例中看到的预先配置的设置。 这是一个容易实现的目标吗?

预先感谢您的评论。

尽管有点奇怪,但是您可以通过无模式对话框实现所需的功能:-在ParentWindow.OnCreate调用对话框Create 将ParentWindow作为父级传递-需要隐式创建对话框,IIRC需要重写CMyDialog::PreCreateWindow打开对话框,请使用dlg.ShowWindow(SW_SHOW)parent.EnableWindow(false) -要关闭,请使用dlg.ShowWindow(SW_HIDE)parent.EnableWindow(true)

但是,我建议不要这样做。

  • 它甚至没有尝试将视图与控制器分开,但这可能是可以原谅的。
  • 它将对话框绑定到一个父对话框,即无法从另一窗口显示它。
  • 不允许正确实施“取消”
  • 最后一点,它感觉很奇怪-可能是代码气味或味道问题。

这就是我认为的“正常”情况:

我所有的设置对话框都与Settings类相关联,并最终遵循以下大致界面:

class CSettings
{
   double speed;
   EDirection direction;
   bool hasSpeedStripes;

   bool IsValid(CString & diagnostics);
};

class CSettingsDialog
{
   CSettings m_currentSettings;
public:
   // that's the method to call!
   bool Edit(CWnd * parent, CSettings & settings)
   {
      m_currentSettings = settings; // create copy for modification
      if (DoModal(parent) != IDOK)
        return false;
      settings = m_currentSettings;
      return true;
   }

   OnInitDialog()
   {
     // copy m_cuirrentSettings to user controls
   }

   OnOK()
   {
     // copy user controls to m_currentSettings
     CString diagnostics;
     if (!m_currentSettings.IsValid(diagnostics))
     {
       MessageBox(diagnostics); // or rather, a non-modal error display
       return;
     }
     EndDialog(IDOK);
   }
};

该副本是验证所必需的。 我再次将设置类用于“ currentSettings”,因为我不太喜欢MFC的DDX / UpdateData()机制,并且经常手动进行传输。

但是,如果您遵循MFC的想法,您将

  • 使用类向导将控件映射到数据成员,您可以在其中进行基本范围验证
  • 在OnInitDialog中,将设置复制到数据成员并调用UpdateData(false)
  • 在OnOK中,调用UpdateData(true),然后“返回”数据成员。

您甚至可以手动编辑DoDataExchange以将控件直接映射到m_currentSettings成员,但这并不总是有效。


由于用户可能会更改值,请检查副本中的值是否不正确,然后再按“取消”键,并希望保留原始值,因此应该在副本上进行相互依赖性验证。 例:

if (speed < 17 && hasSpeedStripes)
{
   diagnsotics = "You are to slow to wear speed stripes!";
   return false;
}

验证应该与对话框类分开(尽管可能会争辩说,生成诊断也不属于设置类,在这种情况下,您确实需要第三个“控制器”实体。尽管我通常不这样做)

至于在DoModal调用之后句柄无效,可能是GetSpeed方法正在尝试访问控制变量。 这不是关闭对话框本身的无效句柄,而是包含速度值的子控件。

如果将“速度”值复制到OnOK中的非控制成员,则在关闭模式对话框后,您的代码即可访问其值。

您应该放弃在启动时创建对话框并隐藏/显示对话框的想法。 这仅适用于无模式对话框。 您可以无模式地创建它,然后模拟模态行为,但这是繁琐的工作。

我假设您要显示/隐藏对话框,因为那样会在整个应用程序中保留设置,并且您想使用该对话框将设置存储在其中。您应该将对话框与设置本身分开。 创建一个仅包含设置而不从CDialog派生的类。 然后,使对话框填充该类的字段。 将设置对象存储在CWinApp派生类中,并在每次要显示它时创建一个Now对话框(使用.DoModal)。

(再次阅读其他答案,这可能是彼得兴所说的话)

从它的声音来看,您需要一个无模式对话框,您可以通过从对话框派生来创建该对话框。

您可以像上面一样在应用中声明它,并在闲暇时创建/销毁。 如果您将其称为模式对话框,则将阻止应用程序的其余部分,尽管在描述您的需求时听起来像不是您想要的模式行为,例如

并根据用户是否选择特定菜单选项显示/隐藏

我最终决定创建一个结构,该结构包含要在父对话框类的子对话框中配置的设置,在调用构造函数时传递指向该结构的指针,并让子对话框的OK按钮处理程序将其内容修改为它是一个指针。 我认为这很干净,因为我现在可以执行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM