返回列表 发帖

【教学视频】《C语言也能干大事》第十八节:对话框高级操作

【秘籍:免费获得大量鹏币】|【立即购买鹏币(仅需5 元)】
帖子只需购买一次即可以永久使用,不需要每次访问的时候都购买。购买后将会看到如下的视频、资料等下载地址
本主题需向作者支付 50 鹏币 才能浏览 购买主题 已购买人数:356  记录
未购买此贴可以在线观看在线FLV格式的视频:
http://player.youku.com/player.php/sid/XODczOTg1Njg=/v.swf
购买此贴后可以得到清晰版的下载地址和源代码工程下载。

板书:
1、
程序中打开新对话框,其实有代码可参考,WinMain。
DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, Main_Proc);

只要复制一份MainDlg.cpp和MainDlg.h改一下就行了

DialogBox(hInstance, MAKEINTRESOURCE(IDD_MYDLG), NULL, Dlg1_Proc);
怎么传递参数?使用DialogBoxParam函数,对比差别。

传入int;传入字符串;传入结构体。
传出。
怎样判断按下的按钮?通过返回值配合

怎么样在对话框关闭的时候把参数回传回去?SetWindowLong设置的东西是和窗口的实例绑在一起的。什么是窗口实例?一个窗口打开两个、一个窗口打开两次(隐藏/打开、销毁/打开)。
SetWindowLong(hwnd,GWL_USERDATA,(LPARAM)param);

1、在资源中插入新的对话框,并且调整控件
2
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
DialogBox(hInstance, MAKEINTRESOURCE(IDD_LOGINDIALOG), NULL, Main_Proc);

3、每个对话框都有自己的一套MainDlg.cpp类似的代码,Main_Proc、Main_OnInitDialog等等
修改Main_Proc、Main_OnInitDialog等的前缀为LoginDlg_****,函数名不能重复
复制一份LoginDlg.h
#ifndef _MAIN_H等也要修改

DialogBoxParam
parameter:参数

#include "LoginDlg.h"

在OnInitDialog中处理传入参数,lParam就是传入的参数

通过DialogBoxParam来传入参数,在对话框中的***_OnInitDialog的LPARAM lParam来取参数。

long类型,指针就是long了。
传递字符串


TCHAR* buff = "abcd";


DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_LOGINDIALOG), NULL, LoginDlg_Proc,(LPARAM)buff);//LoginDlg_Proc


在对话框之间传字符串(指针)


HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);


LoginData ld;


ld.userName = "yzk";


ld.password = "123456";


//TCHAR* buff = "abcd";


DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_LOGINDIALOG), NULL, LoginDlg_Proc,(LPARAM)&ld);//LoginDlg_Proc



BOOL LoginDlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{

LoginData* ld = (LoginData*)lParam;


SetDlgItemText(hwnd,IDC_EDITUSERNAME,ld->userName);


SetDlgItemText(hwnd,IDC_EDITPASSWORD,ld->password);


return TRUE;

}


DialogBoxParam默认是阻塞运行的

可以设置与窗口句柄关联的数据,SetWindowLong可以看做是把一些数据与窗口管理起来,“让它代为保管”

SetWindowLong、GetWindowLong来在窗口中保存指针就可以了

只有一个文本框的对话框,有两个按钮【确定】、取消,允许对话框的使用者指定一个函数用来进行校验,能够校验值的正确性,如果不正确还会显示错误信息。提示:函数指针。

EndDialog(hwnd, 1);
在调用代码中通过DialogBoxParam的返回值就可以得到EndDialog设定的参数

不要重复同样的错误。不要忘了break。通过调试功能发现的问题。在怀疑的地方加断点调试

LBN_DBLCLK:DoubleClick



if(LBN_DBLCLK==codeNotify)


{


//MessageBox(hwnd,TEXT("
双击"),TEXT(""),MB_OK);

//LB_GETCURSEL
消息

int index = SendDlgItemMessage(hwnd,IDC_LIST1,LB_GETCURSEL,0,0);


TCHAR buff[255];


SendDlgItemMessage(hwnd,IDC_LIST1,LB_GETTEXT,index,(LPARAM)buff);


MessageBox(hwnd,buff,TEXT(""),MB_OK);


}




课后作业:允许用户定制校验策略的InputDialog



2、
Codenotify=LBN_DBLCLK 用户双击列表框中的字符串。


if(LBN_DBLCLK==codeNotify)



{



int index = SendDlgItemMessage(hwnd,IDC_LIST1,LB_GETCURSEL,0,0);



TCHAR buff[255];



SendDlgItemMessage(hwnd,IDC_LIST1,LB_GETTEXT,index,(LPARAM)buff);



MessageBox(hwnd,buff,TEXT(""),MB_OK);



}


3、
LBN_SELCHANGE


http://msdn.microsoft.com/en-us/library/bb773169(VS.85).aspx

购买主题 已购买人数:356  记录

原帖由 erenno1 于 2009-11-2 23:09 发表
lstrcpy(ld->username,username)  这样是不对的,因为老大结构体中定义的是char * username是指针,将字符串复制到一个指针,貌似是不对的!所以,更改结构体的定义  。结构体中定义为char username[256]  然后
l ...


同学,做学问不能模糊哈,将字符串赋值到一个指针,貌似是不对的?所以要改成定长的字符数组?

我想,应该是对指针还不了解吧,不是说将字符串赋值给一个指针就不对,你用str系列的函数的时候,你看到它的参数都是什么类型?
都是 char *,是指针吧?

我想,之所以你说 “貌似是不对的”,还是对lstrcpy这个函数执行的机理没有了解深刻,并不是说不能用指针类型,用指针肯定是对的,之所以“会出错”,是因为你的指针没有开辟空间,也就是说,你的指针变量可以用,但是,它没有指向一片用户程序可用区,所以,它并不能用来对内存的内容进行任何操作,哪怕只是简单的read都不行,更何况你这里还是要对其指向的地址的内容进行修改,更加不可。老大这里的ld->username和ld->password都是在MainDlg中指向了一个静态变量,也就是指向了静态存储区的。

所以,在用strcpy函数之前,你必须要先用malloc或者calloc动态开辟一段空间,如:
ld->username = (TCHAR*)malloc(lstrlen(username)+1);
memset(ld->username, 0x00, lstrlen(username)+1);    //这里最好清空,而且,求长度不能用sizeof(ld->username)这种方式,具体可以想一下为什么?

然后,就可以放心的执行那句话了:
lstrcpy(ld->username, username);         //一般的,我都用memcpy(),这个就很通用,也便于理解strcpy的实质。如果你感兴趣,可以用一用
1

评分人数

English……
           Music……

                           Guitar……
                                         Life……

TOP

原帖由 landsnail 于 2009-11-3 11:19 发表
同意,我也是这样做的,也能达到要求,不过我对于指针不是很了解!



恩,我知道你说的什么了,
的确是正确传入了lParam,具体原因,我已经在上面回复的帖子说明了,ld->username和ld->password因为初始化的时候,是指向的静态变量,也就是他们指向的是静态存储区,此时,并没有为指针真正的开辟一段空间,只是改变了指向而已。
而,指向静态字符串的指针的地址可以改变,但是,指向的空间的内容是不能改变的,因为是静态区的内容。

  1. char* p = "greate";
  2. // *p = 'd';                  //运行到这里,是会出错的。
  3. // cout << p << endl;

  4. char buf[10] = "hello";
  5. strcpy(p, buf);                 //运行到这里,也是会出错的
  6. cout << p << endl;
复制代码


所以,如果,想要用strcpy这种函数来改变指针指向的地址的内容,必须要为指针开辟空间(同时,指针指向的地址就是新开辟的地址了)。我在上面已经说明了……


不知道老大为什么一直没有回复。。。。
1

评分人数

English……
           Music……

                           Guitar……
                                         Life……

TOP

老师忘了~

那个wsprintf(); 老师的 字符数组首地址 与 格式 刚好反了
case:
{
}
break;
千万不能忘!!  ~
1

评分人数

TOP

期待已久的18节课终于出来了


谢谢老师的辛勤付出!
提醒自己   08年6月30日开始自学C

TOP

讲课的时候那个传结构体的问题当时脑子有点乱了,一会儿我回帖说明一下正确的而实现方式。哪位同学也可以先于我来解释呀,那就更牛了,呵呵。

TOP

 刚开始看,听声音貌似都很疲惫了……

 而且一开始还是说的  C语言干大事  十七节, 我还以为我下错了……呵呵……
English……
           Music……

                           Guitar……
                                         Life……

TOP

老大辛苦了!
[fly]三维动画学习中……fly]
kider@rupeng.com

TOP

很不错的一节课  .老大辛苦晒

TOP

十八节又出来罗,很久都没认真弄这个了。老大真的辛苦了!
往日成空已了然,而今欣然迷茫,前事已成忧!晓知理,持之事,费之力,必成大器!

TOP

原帖由 杨中科 于 2009-4-27 11:04 发表
讲课的时候那个传结构体的问题当时脑子有点乱了,一会儿我回帖说明一下正确的而实现方式。哪位同学也可以先于我来解释呀,那就更牛了,呵呵。


其实,那样应该可以取到,不知道为什么老大的机子取不到,我的只是稍微改了一下实现方式,两个对话框的代码如下
BOOL Login_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
LoginDate *lpLogin = (LoginDate *)lParam;
SetWindowLong(hwnd,GWL_USERDATA,(LONG)lParam);
return TRUE;
}

void Login_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch(id)
{
case IDC_BTNSUBMIT:
{
//TCHAR szUerName[MAX_PATH];
//TCHAR szPassWord[MAX_PATH];
LoginDate *lpLogin = (LoginDate * )GetWindowLong(hwnd,GWL_USERDATA);

//就是这里两句和老大的“形式上”稍微不一样我是直接把EDIT控件的内容传给了指针,而老大是定义了字符数组,然后把数组的内容传给了指针,但是实际上还是一回事啊。
GetDlgItemText(hwnd,IDC_EDITUSERNAME,lpLogin->szUerName,sizeof(lpLogin->szUerName)/sizeof(TCHAR));
GetDlgItemText(hwnd,IDC_EDITPASSWORD,lpLogin->szPassWord,sizeof(lpLogin->szPassWord)/sizeof(TCHAR));
EndDialog(hwnd,0);
}
break;
default:break;
}

}

  1. void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  2. {
  3. switch(id)
  4. {
  5. case IDOK:
  6.   {
  7.    LoginDate User1;
  8.    HINSTANCE hInst = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
  9.    DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_LOGINDIALOG),hwnd, Login_Proc,(LPARAM)&User1);
  10.    MessageBox(hwnd,User1.szPassWord,TEXT(""),MB_OK);
  11.   }
  12.   break;
  13. default:break;
  14. }
  15. }
复制代码
我的调用以后,关掉Login的那个Dialog,直接就在MainDialog中,MessageBox出来我在Login中输入的密码了……OK的

照理解说,只要在函数中改变的  指针指向的数据,就可以实现变量的转换的,所以,这样应该是对的啊。
English……
           Music……

                           Guitar……
                                         Life……

TOP

刚用老大的原型来做,发现确实是乱码……

想解决这个问题,于是想到检测DialogBoxParam是不是真的把User1的地址传过去了,所以,我就用了下面的方法,

void Main_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch(id)
{

case IDOK:
  {
   LoginDate User1;
   HINSTANCE hInst = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
   
     TCHAR szBuf[MAX_PATH];
   _ltot((LONG)&User1,szBuf,16);
   MessageBox(hwnd,szBuf,TEXT(""),MB_OK); // 在传值之前,用MessageBox打印出User1的地址

   DialogBoxParam(hInst,MAKEINTRESOURCE(IDD_LOGINDIALOG),hwnd, Login_Proc,(LPARAM)&User1);
   
   MessageBox(hwnd,User1.szPassWord,TEXT(""),MB_OK);
  }
  break;
default:break;
}
}

Login对话框:

BOOL Login_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
  TCHAR szBuf[MAX_PATH];
_ltot(lParam,szBuf,16);
MessageBox(hwnd,szBuf,TEXT(""),MB_OK);// 打印出lParam的值,看是否与第一个MessageBox的相同,相同则证明是传入了正确的User1地址

SetWindowLong(hwnd,GWL_USERDATA,(LONG)lParam);
return TRUE;
}

void Login_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch(id)
{
case IDC_BTNSUBMIT:
  {
   LONG ltemp = (LONG)GetWindowLong(hwnd,GWL_USERDATA);// ltemp获取SetWindowLong存储的数据,即lParam

   TCHAR szBuf[MAX_PATH];
   _ltot(ltemp,szBuf,16);
   MessageBox(hwnd,szBuf,TEXT(""),MB_OK);// 打印出获取的数据,发现,和lParam是相同的,证明SetWindowLong正确存储数据
break;
default:break;
}

}


结果发现:三次MessageBOx,第一次是一个值,第二次和第三次是相等的这个值和第一个不一样),这就证明了SetWindowLong是正确的存储了值,但是貌似就是DialogBoxParam的那个参数没有正确的传入啊!!!!

不知道为什么??老大能不能解释解释……
English……
           Music……

                           Guitar……
                                         Life……

TOP

更正,刚才发的第一个帖子,我刚刚改回来的时候,发现,也变成乱码了,也没用了……饿……昏……
English……
           Music……

                           Guitar……
                                         Life……

TOP

乱码问题解决了……

在MSDN上搜了一下DiaLogBoxParam()这个东西的最后一个参数,发现有说明是说:Specifies the value to pass to the dialog box in the lParam parameter of the WM_INITDIALOG message
意思一看应该清楚了,
然后,我就看了一下Main_Proc里面的消息分流器,正好前几天研究过这个东西,发觉可能是WM_IINITDIALOG这个分流器除了问题,所以,我就干脆直接在Main_Proc里面处理WM_INITDIALOG这个消息,然后直接调用它的 lParam参数,哈哈,这样就解决了,代码如下,其他的不要改:


OOL WINAPI Login_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
  //HANDLE_MSG(hWnd, WM_INITDIALOG, Login_OnInitDialog);
case WM_INITDIALOG://  就是这里,直接处理WM_INITDIALOG消息,不用CRACKER
  {
   TCHAR szBuf[MAX_PATH];
   _ltot(lParam,szBuf,16);
   MessageBox(hWnd,szBuf,TEXT(""),MB_OK);//这个时候MessageBox打印的就和Main里面的那个一样了,返回值也正常了
   LoginDate *lpLogin = (LoginDate *)lParam;
   SetWindowLong(hWnd,GWL_USERDATA,(LONG)lParam);//GWL_USERDATA:保存特定窗口相关联的用户数据
   return TRUE;
  }
  break;
  HANDLE_MSG(hWnd, WM_COMMAND, Login_OnCommand);
  HANDLE_MSG(hWnd,WM_CLOSE, Login_OnClose);
}
return FALSE;
}



我现在想,是不是这个Cracker定义的宏的展开有那个 lParam并不是对应的消息的lParam啊,至少从现在的情况看是这样的……
哪位能解释解释……
English……
           Music……

                           Guitar……
                                         Life……

TOP

关于那个DialogBoxParam()的返回值问题,老大视频中,用了0啊,-1,这两个数.

  MSDN上说,0,和-1都是用来表示DialogBoxParam调用失败了,原句是这样的:If the function fails because the hWndParent parameter is invalid, the return value is zero. The function returns zero in this case for compatibility with previous versions of Microsoft Windows. If the function fails for any other reason, the return value is –1.

意思大家一看应该明白,就不翻译了。。

所以,我觉得最好还是不要用这个的好,我看到一种比较好的方式,就是返回按钮的ID,比如,EndDialog(hwnd,IDOK);因为这个ID正好是和按钮相关联的,既可以起到 "表示按的是哪个按钮的作用",也可以避免使用到 0和-1(这样可读性不强的“数字”)

呵呵,个人拙见,仅供参考……
English……
           Music……

                           Guitar……
                                         Life……

TOP

老大终于又出新教程了,老大您辛苦 了~
Ubuntu linux for human beings 点击下载

TOP

呵呵~顶一个~跟上先~

TOP

老大,辛苦了 我顶顶~

TOP

还没时间看 先顶下

TOP

老大辛苦了,跟着老大永远有饭吃!

TOP

辛苦了,老大

TOP

请问一下

来晚了
C语言也能干大事 这个可以将整个教程放在光盘一起买过来看呢?

TOP

还有后续课程吗

TOP

学习

趁着假期有时间,学习~

TOP

谢谢老大的辛勤付出了。

TOP

这节课听得好晕呀

TOP

老大 你的意思是 复制一份MainDlg.cppMainDlg.h
我 直接 用 main里的MainDlg.cppMainDlg.h 也可以 弹出对话框的 并且在副对话框里 也可以进行操作
这2种方法 那个更好点 为什么 我感觉 用MAIN的的 代码更精简点啊~



  1. switch(id)
  2.     {
  3.         case IDC_OK:
  4.   {
  5.    
  6.    HINSTANCE hInstance = (HINSTANCE) GetWindowLong(hwnd,GWL_HINSTANCE);
  7.    DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOGLOGIN), NULL, Main_Proc);
  8.   }
  9.         break;
  10.   case IDC_BUTTONLOGIN:
  11.    TCHAR USERNAME[255],PASSWORD[255];
  12.    GetDlgItemText(hwnd,IDC_EDITUSERNAME,USERNAME,sizeof(USERNAME)/sizeof(TCHAR));
  13.    MessageBox(NULL,USERNAME,TEXT(""),MB_OK);
  14.         default:
  15.   break;
  16.     }
复制代码


运行通过














附件: 您需要登录才可以下载或查看附件。没有帐号?注册
学习不是因为缺少时间而是缺少努力--MyBlog
  Studies this matter, lacks the time, but is lacks diligently.
                  ----xiao祥 加油 UP UP UP

TOP

我晕 上面的图怎么是个小叉叉啊~~郁闷呢
在来张 实在看不掉 先下 在看啊
附件: 您需要登录才可以下载或查看附件。没有帐号?注册
学习不是因为缺少时间而是缺少努力--MyBlog
  Studies this matter, lacks the time, but is lacks diligently.
                  ----xiao祥 加油 UP UP UP

TOP

原帖由 syx278250658 于 2009-8-20 09:16 发表
老大 你的意思是 复制一份MainDlg.cpp和MainDlg.h
我 直接 用 main里的MainDlg.cpp和MainDlg.h 也可以 弹出对话框的 并且在副对话框里 也可以进行操作
这2种方法 那个更好点 为什么 我感觉 用MAIN的的 代码更精简 ...

每个窗口都有一个处理的单独的代码比较好,你试想一个复杂的软件如果有100个对话框的话,要把100个对话框的代码都写到MainDlg.cpp和MainDlg.h 中的话那是多么恐怖的事情呢?

TOP

原帖由 杨中科 于 2009-8-21 23:46 发表

每个窗口都有一个处理的单独的代码比较好,你试想一个复杂的软件如果有100个对话框的话,要把100个对话框的代码都写到MainDlg.cpp和MainDlg.h 中的话那是多么恐怖的事情呢?


老大的意思 是这样也是可以的咯 就是不怎么方便这一个问题哦~~哈哈 知道啦~3Q老大啊
学习不是因为缺少时间而是缺少努力--MyBlog
  Studies this matter, lacks the time, but is lacks diligently.
                  ----xiao祥 加油 UP UP UP

TOP

返回列表