如何使用DialogBoxParam
How to use DialogBoxParam?
我有一个预先制作的模板资源对话框,我想用DialogBoxParam
来显示它,但我在互联网上找不到任何好的例子。该对话框是一个简单的登录对话框,所以有人可以解释如何构建我的lpDialogFunc
以及在dwInitParam
中放置什么吗?
您已将此问题标记为C++,但尚未指定任何特定的框架(如ATL或MFC)。
因此,本着为这个问题提供c++/OOP答案的精神,在不使用框架的情况下,首先要做的是创建一个类来包装对话框,并为对话框进程提供一种可靠地检索指向该类的指针的方法。windows API是一个C API,不能直接调用类成员,因此有必要创建静态方法,然后可以从某个位置检索类this
指针。
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);
}
};
现在,Windows可以向对话框发送数百条窗口消息。将每条消息的处理程序添加到DialogProc中,并调用特定的虚拟函数,这样派生类就可以通过重写虚拟函数来以不同的方式处理消息。
要处理的关键消息通常是WM_INITDIALOG
,它在对话框创建后立即发送,因此是初始化对话框上任何控件的理想时间-填充下拉控件,或者SetWindowText
初始化具有默认值的文本框。和WM_COMMAND,它是由按钮等控件发送的,当它们被点击时,会传递它们的id,这就是处理OK和CANCEL按钮的地方。
一旦DialogBoxParam返回,对话框及其所有子控件都已被销毁,因此在调用EndDialog
之前,通常会提取OnCommand处理程序中的所有输入字段并将其存储在类成员中。
问题第二部分的另一个用例:"在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;
}
};
备选方案将调用方放在全局范围内,并限制为所有对话框的单个调用方。
您可以这样做。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)
{
}