1

我有一个预制的模板资源对话框,我想用DialogBoxParam它来显示它,但我在互联网上找不到任何好的例子。该对话框是一个简单的登录对话框,所以有人可以解释如何构建我的lpDialogFunc以及放入dwInitParam什么吗?

4

3 回答 3

9

You've tagged this question as C++, but havn't specified any particular framework (such as ATL or MFC).

So, in the spirit of providing a c++ / OOP answer to the question, without using a framework, the first thing to do is to create a class to wrap the dialog box, as well as provide a way for the dialog proc to reliably retrieve the pointer to the class. The windows API is a C API and cannot call class members directly so it is necessary to create static methods that can then retrieve the classes this pointer from somewhere.

class MyDialog {
  HWND _dlg;
public:
  int RunModal(HINSTANCE resModule, UINT resId,HWND parent){
    return DialogBoxParam(resModule,MAKEINTRESOURCE(resId),parent,&StaticDialogProc,(LPARAM)this);
  }
protected:
  static INT_PTR CALLBACK StaticDialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){
    MyDialog* self;
    if(uMsg == WM_INITDIALOG){
      self = (MyDialog*)lParam;
      self->_dlg = hwndDlg;
      SetWindowLongPtr(hwndDlg,DWLP_USER,lParam);
    }
    else
      self = (MyDialog*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);

    if(self)
      return self->DialogProc(uMsg,wParam,lParam);

    return FALSE;
  }

  virtual UINT_PTR DialogProc(UINT uMsg,WPARAM wParam,LPARAM lParam){
    switch(uMsg){
    case WM_INITDIALOG:
      OnInitDialog();
      break;
    case WM_COMMAND:
      OnCommand(LOWORD(wParam),HIWORD(wParam),(HWND)lParam);
      break;
    default:
      return FALSE;
    }
    return TRUE;
  }

  virtual void OnInitDialog(){
  }
  virtual void OnCommand(int id, USHORT notifyCode,HWND control){
    EndDialog(_hdlg,id);
  }
};

Now, there are hundreds of window messages that Windows can send to a dialog. Add handlers for each message to DialogProc and call a specific virtual function so derived classes can handle the message differently by overriding the virtual.

The critical messages to handle are usually WM_INITDIALOG which is sent as soon as the dialog is created, so is an ideal time to initialize any controls on the dialog - to populate drop down controls, or SetWindowText to initielize text boxes with default values. and WM_COMMAND, which is sent by controls like buttons, when they are clicked, passing in their id, and this is where you would handle the OK and CANCEL buttons.

Once DialogBoxParam returns, the dialog and all its child controls has been destroyed, so you would typically extract all the input fields in the OnCommand handler and store them in class members before calling EndDialog.

于 2012-08-07T12:46:34.480 回答
2

问题第二部分的另一个用例:“要放入什么dwInitParam”?

如果您更喜欢 OO 编程并且不想为您的对话框使用全局范围,您可以传递this给形参dwInitParam

获取指向调用者的指针

template< typename CallerT >
inline CallerT *GetDialogCaller(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    if (WM_INITDIALOG != uMsg) {
        // Retrieves information about the specified window.
        // 1. A handle to the window and, indirectly, the class to which the window belongs.
        // 2. Retrieves the user data associated with the window.
        return reinterpret_cast< CallerT * >(GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
    }

    CallerT * const caller = reinterpret_cast< CallerT * >(lParam);

    // Changes an attribute of the specified window.
    // 1. A handle to the window and, indirectly, the class to which the window belongs.
    // 2. Sets the user data associated with the window.
    // 3. The replacement value.
    SetWindowLongPtr(hwndDlg, GWLP_USERDATA, reinterpret_cast< LONG_PTR >(caller));

    return caller;
}

将消息委托给调用者

class Widget {

public:

    static INT_PTR CALLBACK DialogProcDelegate(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {

        // Retrieve a pointer to the instance of Widget
        // that called DialogBoxParam.
        Widget * const widget = GetDialogCaller< Widget>(hwndDlg, uMsg, wParam, lParam);

        // Delegate the message handling.
        return widget->DialogProc(hwndDlg, uMsg, wParam, lParam);
    }

    INT_PTR Show() const {
        return DialogBoxParam(nullptr, MAKEINTRESOURCE(IDD_WIDGET_SETTINGS), nullptr, DialogProcDelegate, reinterpret_cast< LPARAM >(this));
    }

private:

    INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {

        // Note that this method is not affected by our approach,
        // i.e. this method will still receive a WM_INITDIALOG.
        switch (uMsg) {
            ...
        }

        return FALSE;
    }
};

另一种方法是将调用者置于全局范围内,并限制为所有对话框的单个调用者。

于 2017-08-13T08:41:05.210 回答
0

你可以做这样的事情。dwInitParam 在 WM_INITDIALOG 消息的 lParam 参数中指定要传递给对话框的值。您可以传递任何值或简单地传递 NULL

INT_PTR CALLBACK editDlg(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) {

        switch (msg) {
            case WM_INITDIALOG:                  
                return 1;
            break;
        }
        return 0;
    }

if(DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_EDIT),hwndMain,editDlg,NULL)==IDOK) 
{
}
于 2012-08-07T09:52:33.833 回答