简体   繁体   中英

Pass value from a CEdit on one dialog box to another dialogs CEdit Control

I have a Browse file/print file path function and a parent/Child window, I need help in passing path printed on a EditControl from child(dialog2) to parent(dialog1)control edit box. please, HELP: See code below:

dialog1.cpp

   dialog2 Dlg;
   Dlg.DoModal();

    if (Dlg.DoModal() == IDOK)
    {
       //print folderPath from dialog2 CEdit2 to a CEdit1 control on dialog1.
       // DDX_Control(pDX, IDC_EDIT_BOX1, _cEditBox1);
    }

dialog2.cpp

void dialog2::OnBnClickedBrowse()
{
//Lines of Code
//Function related to the question 

    if (pidl != NULL)
    {
        SHGetPathFromIDList(pidl, path);
        SetCurrentDirectory(path);
        _cEditBox2.SetWindowText(path);  //prints selected file path on the edit control
        GetDlgItemText(IDC_EDIT_BOX2, folderPath); //Need to capture the path to print it to 
                                                // dialog1 Editbox1, where I'm struggling 
                                              //DDX_Control(pDX, IDC_EDIT_BOX2, _cEditBox2);
    }
void dialog2::OnBnClickedOk()
{
    CDialogEx::OnOK();

   //not sure what to do here 
   //to pass value to dialog1:EditBox1 in the (DoModal()==IDOK) function 

}

Simply use CEdit 's GetWindowText() and SetWindowText() methods, eg:

dialog2 Dlg;
Dlg.DoModal();

if (Dlg.DoModal() == IDOK)
{
    CString text;
    Dlg._cEditBox2.GetWindowText(text);
    _cEditBox1.SetWindowText(text);
}
  1. Add a button and an edit box (add variables - CEdit m_edit1, CString m_strSendMessage);

  2. Create a new dialog, also add a button and an edit box (add variables - CEdit m_edit2, CString m_strGetMessage);

  3. Add an OnInitDialog() to the sub-dialog: Select Class View->Select MFC Class Wizard->Virtual Function->Add OnInitDialog(), the following is the initialization code to display the assignment when the sub-window is opened.

     BOOL child::OnInitDialog() { CDialogEx::OnInitDialog(); m_edit2.SetWindowTextW(m_strGetMessage); return TRUE; }

    4.Double-click the parent window button to add a message response function.

     void CMFCApplication16Dlg::OnBnClickedButton1() { CString str; m_edit1.GetWindowTextW(str); child *dlg = new child(); dlg->m_strGetMessage = str; dlg->Create(IDD_DIALOG1); dlg->ShowWindow(SW_SHOWNORMAL); }

    5.Double-click the child window button to add a message response function.

    void child::OnBnClickedButton1() {

     CMFCApplication16Dlg *p = (CMFCApplication16Dlg*)GetParent(); CString str; m_edit2.GetWindowTextW(str); p->m_edit1.SetWindowText(str);

    }

Result:

在此处输入图像描述

MFC interoperates with Windows' native windowing system by providing C++ classes that wrap the underlying HWND . This introduces a mismatch between the C++ class instances' lifetimes (from c'tor up to the d'tor call) and the lifetimes of the native windows (manually controlled, from CreateWindowExW until the DestroyWindow call). In the general case, MFC's wrappers outlive 1 the native controls, ie they begin life before the actual window is created, and live beyond the window's destruction.

While that might sound like it is an issue (and it indeed can quickly turn into one ) it is a core feature that enables data interchange. In case of a modal dialog this is commonly implemented using the following sequence:

  • Construct an instance of the CDialog -derived class, typically on the stack, with automatic lifetime
  • Optionally store values in the class instance to initialize controls in the dialog
  • Launch the dialog by calling CDialog::DoModal and wait for its result
    • (We're in the dialog implementation now) Optionally populate the native controls with values stored in class members from the dialog's OnInitDialog override
    • The user interacts with the dialog
    • Store values back from the native controls into class members when the user requests the dialog to be dismissed
  • (Back to the caller of DoModal ) At this point the native dialog window has been destroyed, but the C++ class (including its class members) is still alive; depending on the return value from DoModal ( IDOK , IDCANCEL , ...) client code can read data back from the dialog class instance, and use it for anything, such as populating its native controls

The core principles here that generally apply to any GUI programming (MFC or otherwise) are:

  • Just before a dialog is displayed, populate its controls with values read from an arbitrary data store (in MFC this is commonly the class instance associated with the native dialog)
  • While the dialog is up keep all state purely inside the native controls
  • As the user dismisses the dialog, read back data into the data store

This is all fairly straight forward. The challenge is in providing a full sample. In trying to keep this focused I will omit any includes, and strip down the MFC code to its bare minimum; no fancy icons or other useful stuff will be included.

The following will be roughly based on the dialog-based application, which is generally the simplest one to implement. First up, let's just get the CWinApp out of the way. Its only purpose is to act as the application entry point, spin up the main UI, and then terminate once the main UI has been dismissed.

MFCDataExchange.h

class CMFCDataExchangeApp : public CWinApp
{
private:
    virtual BOOL InitInstance();
};

// Declare the application object in case anyone needs to access it
extern CMFCDataExchangeApp theApp;

MFCDataExchange.cpp

// Define the application instance exactly once
CMFCDataExchangeApp theApp;


// This initializes the application but will also launch (and wait) for
// its main UI
BOOL CMFCDataExchangeApp::InitInstance()
{
    INITCOMMONCONTROLSEX InitCtrls{sizeof(InitCtrls), ICC_WIN95_CLASSES};
    InitCommonControlsEx(&InitCtrls);

    CWinApp::InitInstance();

    CMainDlg dlg;
    m_pMainWnd = &dlg;
    dlg.DoModal();

    // Since we are already done with the program, just pretend that
    // initialization failed so that the application terminates.
    // This is a quirk of the dialog-based app model. No worries, the
    // program will still cleanly terminate, with all d'tors run, etc.
    return FALSE;
}

That's very little code, and once we provide a CMainDlg implementation, that's a full program already. This dialog contains both an EDIT control (to later display the results) and a button to launch a modal dialog (there are also OK and Cancel buttons for easy dismassal of the dialog, that don't require any code to work).

MainDlg.h

class CMainDlg : public CDialog
{
public:
    CMainDlg(CWnd* pParent = nullptr);

private:
    afx_msg void OnBtnClicked();
    DECLARE_MESSAGE_MAP()
};

MainDlg.cpp

CMainDlg::CMainDlg(CWnd* pParent)
    : CDialog(IDD_MAIN, pParent)
{
}

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

BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
    ON_BN_CLICKED(IDC_BTN_1, &CMainDlg::OnBtnClicked)
END_MESSAGE_MAP()


void CMainDlg::OnBtnClicked()
{
    // Create modal dialog class instance
    CModalDlg dlg(this);
    // Optionally supply value to modal dialog for initialization
    dlg.text = L"Sent by owner";
    // Launch the modal dialog
    if (dlg.DoModal() == IDOK) {
        // User confirmed dialog, so let's read data back...
        auto const text = dlg.text;
        // ... and display it in our edit control IDC_EDIT_1
        GetDlgItem(IDC_EDIT_1)->SetWindowTextW(text);
    }
}

Nothing special going on here either. The c'tor delegates to the base class, passing in the proper dialog ID 2 , and there's a message map to wire up a button click to a custom OnBtnClick handler.

The button click handler now performs the steps outlined above: It constructs a modal dialog class instance, supplies values for initialization, waits for it to be dismissed, then then reads back the data and displays it in the edit control.

What's left is the CModalDlg implementation, that's just slightly different since it both populates its controls just before being displayed, as well as reads data back when dismissed.

ModalDlg.h

class CModalDlg : public CDialog
{
public:
    CModalDlg(CWnd* pParent = nullptr);

public:
    // Public data members for data exchange
    CStringW text;

private:
    virtual BOOL OnInitDialog() override;
    virtual void OnOK() override;
};

ModalDlg.cpp

CModalDlg::CModalDlg(CWnd* pParent) : CDialog(IDD_MODAL, pParent) {}

BOOL CModalDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    // Populate the edit control
    GetDlgItem(IDC_EDIT_2)->SetWindowTextW(text);

    return FALSE;
}

void CModalDlg::OnOK()
{
    // Copy values from controls into class members
    GetDlgItem(IDC_EDIT_2)->GetWindowTextW(text);
    // Call into the base class for default processing, which will
    // dismiss the dialog
    CDialog::OnOK();
}

This concludes the program. It provides the functionality to launch a modal dialog (that's initialized with an arbitrary value), allows the user to interact with the modal dialog's controls, and once dismissed using the OK button (or pressing Enter ), it reads back the data and displays it in the main dialog's edit control.


While that works, it's not actually how you'd usually do this in MFC. MFC provides a lot of infrastructure for this, which is commonly referred to as Dialog Data Exchange (DDX) . It is a system that allows you to associate class members with controls, and consolidates populating controls and reading data back into a single function call.

A prime candidate for this would be CModalDlg 's text member. There are only a few changes required to opt-in to DDX:

ModalDlg.h

class CModalDlg : public CDialog
{
    // ...
private:
    // DDX support
    virtual void DoDataExchange(CDataExchange* pDX) override;
    // ...
};

ModalDlg.cpp

BOOL CModalDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    // Populate the edit control using DDX
    UpdateData(FALSE);

    return FALSE;
}

void CModalDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);

    // Associate class members with controls
    DDX_Text(pDX, IDC_EDIT_2, text);
}

void CModalDlg::OnOK()
{
    // Copy values from controls into class members using DDX
    UpdateData(TRUE);

    CDialog::OnOK();
}

The DoDataExchange override is where the associations are set up. The system provides a maddeningly wide range of options, with DDX_Text being probably one of the simplest ones. It wires up a control (usually an edit control) to a class member of type CString . UpdateData(FALSE) copies data from associated class members into controls, and, conversely, UpdateData(TRUE) copies data from controls into associated class members, performing any conversions as needed (for example, converting a string to a number).

While this may not appear to be of much use here, it starts to show its weight once more complex dialogs with multiple controls and multiple class members are involved. Synchronizing state between class members and controls is still just a single call to UpdateData , and it's time invested well to learn about this feature.


1 The exceptions being the CWnd::Attach and CWnd::Detach class members, that allows a C++ class instance to be attached to an existing window, or disassociates the C++ class instance from a window, respectively.

2 All IDs are kept in a header file shared between the source code an the resource script. The source code must use the correct dialog and control IDs. The sample uses the following MFCDataExchange.rc file:

#include "resource.h"

IDD_MAIN DIALOGEX  0, 0, 320, 200
STYLE DS_SHELLFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "MFC Data Exchange"
FONT 8, "MS Shell Dlg"
BEGIN
    EDITTEXT        IDC_EDIT_1,7,7,252,14
    PUSHBUTTON      "Modal", IDC_BTN_1, 263, 7, 50, 14
    DEFPUSHBUTTON   "OK",IDOK,209,179,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,263,179,50,14
END

IDD_MODAL DIALOGEX  0, 0, 320, 200
STYLE DS_SHELLFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "MFC Data Exchange - Modal dialog"
FONT 8, "MS Shell Dlg"
BEGIN
    EDITTEXT        IDC_EDIT_2,7,7,306,14
    DEFPUSHBUTTON   "OK",IDOK,209,179,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,263,179,50,14
END

plus the following resource.h:

#define IDD_MAIN   1002
#define IDC_EDIT_1 1003
#define IDC_BTN_1  1004
#define IDD_MODAL  1005
#define IDC_EDIT_2 1006

If you are following closely, I've made an exception and kept the #include directive in the resource script. It's just too hideous of a trap, since if you forget it the resource compiler will interpret the script differently without you noticing. Until you launch the application and it crashes in obscure places.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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