我有一个预先制作的模板资源对话框,我想使用DialogBoxParam
来显示它,但我在互联网上找不到任何好的例子。该对话框是一个简单的登录对话框,有人可以解释如何构建我的lpDialogFunc
以及放入dwInitParam
的内容吗?
答案 0 :(得分:5)
您已将此问题标记为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
,它会在创建对话框后立即发送,因此是初始化对话框上任何控件的理想时间 - 填充下拉控件或{{1}使用默认值启动文本框。
和WM_COMMAND,由按钮等控件发送,点击它们,传入它们的id,这就是你可以处理OK和CANCEL按钮的地方。
一旦DialogBoxParam返回,对话框及其所有子控件都已被销毁,因此您通常会在调用SetWindowText
之前提取OnCommand处理程序中的所有输入字段并将它们存储在类成员中。
答案 1 :(得分:1)
问题第二部分的另一个用例:“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;
}
};
替代方案将调用者置于全局范围内,并且仅限于所有对话框的单个调用者。
答案 2 :(得分:0)
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)
{
}