如何在 Windows 桌面应用程序(MFC、C++)中的无模式对话框窗口中传递数据?

问题描述 投票:0回答:2

情况很简单,但我不太明白。

我有一个WinMFC应用程序,这也是解决方案项目的名称。我想将应用程序主对话框中的数据(WinMFCDialog.cpp + WinMFCDialog.h)传递到无模式自定义对话框(CustomDialog.cpp + CustomDialog.h)

Modeless 意味着 CustomDialog 作为一个单独的窗口运行,而不将焦点集中在自身上,因此我可以单独与 WinMFCDialog 交互。

以下是代码:

WinMFCDlg.h
#pragma once

class CWinMFCDlg : public CDialogEx
{
public:
    CWinMFCDlg(CWnd* pParent = NULL);   

    enum { IDD = IDD_WINMFC_DIALOG };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    


protected:
    HICON m_hIcon;

    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedButton1();
};
WinMFCDlg.cpp
#include "stdafx.h"
#include "WinMFC.h"
#include "WinMFCDlg.h"
#include "afxdialogex.h"
#include "CustomDialog.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

class CAboutDlg : public CDialogEx
{
public:
    CAboutDlg();

    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    

protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

CWinMFCDlg::CWinMFCDlg(CWnd* pParent /*=NULL*/): 
    CDialogEx(CWinMFCDlg::IDD, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CWinMFCDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CWinMFCDlg, CDialogEx)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON1, &CWinMFCDlg::OnBnClickedButton1)
END_MESSAGE_MAP()

BOOL CWinMFCDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        BOOL bNameValid;
        CString strAboutMenu;
        bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
        ASSERT(bNameValid);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }
    SetIcon(m_hIcon, TRUE);         
    SetIcon(m_hIcon, FALSE);        

    return TRUE;
}

void CWinMFCDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialogEx::OnSysCommand(nID, lParam);
    }
}

void CWinMFCDlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this);

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Нарисуйте значок
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialogEx::OnPaint();
    }
}

HCURSOR CWinMFCDlg::OnQueryDragIcon()
{
    return static_cast<HCURSOR>(m_hIcon);
}


void CWinMFCDlg::OnBnClickedButton1()
{
    // Modeless dialog, in which I want to pass the data
    CustomDialog *pDlg = new CustomDialog();
    pDlg->Create(IDD_CUSTOM_DIALOG, this);
    pDlg->ShowWindow(SW_SHOW);
}
自定义对话框.h
#pragma once

class CustomDialog : public CDialog
{
    DECLARE_DYNAMIC(CustomDialog)

public:
    CustomDialog(CWnd* pParent = NULL);
    virtual ~CustomDialog();

    enum { IDD = IDD_CUSTOM_DIALOG };

protected:
    virtual void DoDataExchange(CDataExchange* pDX);

    DECLARE_MESSAGE_MAP()
};
自定义对话框.cpp
#include "stdafx.h"
#include "WinMFC.h"
#include "CustomDialog.h"
#include "afxdialogex.h"

IMPLEMENT_DYNAMIC(CustomDialog, CDialog)

CustomDialog::CustomDialog(CWnd* pParent /*=NULL*/)
    : CDialog(CustomDialog::IDD, pParent)
{

}

CustomDialog::~CustomDialog()
{
}

void CustomDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CustomDialog, CDialog)
END_MESSAGE_MAP()
WinMFC.h(主应用程序,以防万一)
#pragma once

#ifndef __AFXWIN_H__
    #error "включить stdafx.h до включения этого файла в PCH"
#endif

#include "resource.h"

class CWinMFCApp : public CWinApp
{
public:
    CWinMFCApp();

public:
    virtual BOOL InitInstance();
    DECLARE_MESSAGE_MAP()
};

extern CWinMFCApp theApp;
WinMFC.cpp(主应用程序,以防万一)
#include "stdafx.h"
#include "WinMFC.h"
#include "WinMFCDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CWinMFCApp
BEGIN_MESSAGE_MAP(CWinMFCApp, CWinApp)
    ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()

// Craetion of CWinMFCApp
CWinMFCApp::CWinMFCApp()
{
    m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
}

// Single object CWinMFCApp
CWinMFCApp theApp;

// Initialization of CWinMFCApp
BOOL CWinMFCApp::InitInstance()
{
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);

    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);

    CWinApp::InitInstance();
    AfxEnableControlContainer();
    CShellManager *pShellManager = new CShellManager;
    SetRegistryKey(_T("Test MFC APP"));

    CWinMFCDlg dlg;
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
    }
    else if (nResponse == IDCANCEL)
    {
    }

    if (pShellManager != NULL)
    {
        delete pShellManager;
    }

    return FALSE;
}

我将数据输入到在 WinMFCDlg 中创建的编辑框中:

here how it looks like

数据应显示在 CustomDialog 之后的静态字段元素中:

here how it looks like

因此,我尝试使用 DDX/DDV 函数将 WinMFC 对话框的编辑文本中的数据传递到自定义对话框的静态文本字段中。

这就是我尝试做的:

  1. 我将下面函数的签名添加到 WinMFCh 中(不在类中,因此,它不是方法)
void DDX_TextNotEmpty (CDataExchange* pDX, int nIDC, CString& value);
class CWinMFCApp : public CWinApp
{
// Class definition
}
  1. 我把它的实现写在WinMFC.cpp中
void DDX_TextNotEmpty (CDataExchange* pDX, int nIDC, CString& value)
{
    HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
    if (pDX->m_bSaveAndValidate)
    {
        int nLen = ::GetWindowTextLength(hWndCtrl);
        ::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1);
        value.ReleaseBuffer();
        if (value.IsEmpty ())
        {
            AfxMessageBox (_T("Enter something in the text field."), MB_ICONSTOP);
            pDX->Fail ();   //Fail () sets the focus on to the edit control
        }
    }
    else { ::SetWindowText(hWndCtrl, value); }
}
  1. 在 CustomDialog.h 中我添加了一个公共成员,它应该存储接收到的数据:
class CustomDialog : public CDialog
{
    DECLARE_DYNAMIC(CustomDialog)

public:
    CString m_string;
    CustomDialog(CWnd* pParent = NULL);

// ... Default stuff created by VS2010 ...
}
  1. 我修改了默认构造函数以在 CustomDialog.cpp 中默认设置成员值之后
CustomDialog::CustomDialog(CWnd* pParent /*=NULL*/)
    : CDialog(CustomDialog::IDD, pParent), m_string(_T("default value"))
{

}
  1. 我尝试在 CustomDialog.cpp 中调用该函数后
void CustomDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_TextNotEmpty(pDX, IDC_EDIT_DATA, m_string);
}

最后我收到一个错误:

here it is

好吧,我不知道我到底做错了什么,所以我希望我的问题不是太愚蠢或问起来很烦人,我只是想学习如何使用这个古老但有趣的东西😔。

很高兴获得任何帮助。

c++ visual-studio-2010 mfc
2个回答
1
投票

将数据传递到 MFC 对话框的最简单方法是作为数据成员,在构造函数调用之后设置,当然在

Create()
DoModal()
调用之前设置。您可以选择将数据副本或对父对话框、文档或应用程序维护的数据的引用(例如指针)传递给父对话框、文档或应用程序。关闭时(在
OnOK()
OnCancel()
调用之后),您可以将成员变量中的数据复制回父级(在析构函数调用之前)。大多数 DDX/DDV 示例都是这样做的。例如:

COptionsDialog dlg;                     // Constructor
dlg.m_DataDir = m_Options.sDataDir;     // Pass Data to the dialog class
if (dlg.DoModal()==IDOK)                // Display the dialog
{
    m_Options.sDataDir = dlg.m_DataDir; // Copy modified data back to the parent
}

您面临的问题可能与为不可编辑的控件(静态文本)调用

PrepareEditCtrl()
有关。尝试使用
PrepareCtrl()
代替。或者将
DDX_TextNotEmpty()
调用替换为简单的
DDX_Text()
调用,无需验证 (
DDV_()
);系统如何“验证”来自不允许用户输入的控件的输入?

附注,在完成后,您应该销毁

CustomDialog
类的实例(您使用
new
创建了它)。


0
投票

...好吧,这就是我想出来的...

问题是我在对话框中调用 DDX_TextNotEmpty(pDX, IDC_EDIT_DATA, m_string) ,该对话框尚未创建(在我的例子中是在 CustomDialog 中)。另外,我也用错了😄。这个函数就像Android开发中的绑定。我的意思是,当 UI 中变量 (m_string) 发生更改时,它会更新变量 (m_string)。但是,感谢 Constantine Georgiou, 有一个内置的 DDX_Text,所以不需要在 WinMFCDlg.cpp 中使用该函数。 所以现在看起来像这样:

void CWinMFCDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialogEx::DoDataExchange(pDX);
 DDX_Text(pDX, IDC_EDIT_DATA, m_string);
}

因此,为了将数据传递到模式中,我需要将字符串放入模式对话框中的静态文本元素内,这是通过按下 WinMFCDlg 中的按钮来完成的,同时也从 UI 更新它。为了保留唯一的一个模式对话框而不是多次打开它,我将 CustomDialog 添加为 WinMFCDlg 类中的一个字段:

class CWinMFCDlg : public CDialogEx
{
   public:
    CustomDialog* m_ptrDialog;
    // Don't forget to delete it
    virtual ~CWinMFCDlg(){ delete m_ptrDialog; }
   // Other stuff...
}

在 WinMFCDlg.cpp 中的 BOOL CWinMFCDlg::OnInitDialog() 中初始化指针后,如下所示:

m_ptrDialog = new CustomDialog();
m_ptrDialog->Create(IDD_CUSTOM_DIALOG, this);

最后,为了将我的数据放入模式对话框中,我只需按 WinMFCDlg 中的按钮即可:

void CWinMFCDlg::OnBnClickedButton1() { UpdateData(TRUE); // Modeless dialog m_ptrDialog->SetDlgItemTextW(IDC_STATIC, m_string); m_ptrDialog->ShowWindow(SW_SHOW); }
...并查看结果:

here it is

这就是我想要的!

但不是以我想要的方式...好吧,如果我想出这个“自动更新我想要得到”,我会在这里添加解决方案😊。

感谢您的精神支持和建议。

© www.soinside.com 2019 - 2024. All rights reserved.