对话框编程(一)

来源:互联网 发布:常熟淘宝拍摄新颜东路 编辑:程序博客网 时间:2024/05/21 09:48

这一节学习了对话框用户界面程序的编写,包括

1.      想对话框控件关联数据成员及其实现机理。

2.      向对话框控件关联控件类。

3.      利用对话框类的成员函数向控件发送消息和截获对话框控件对象。

4.      直接利用对话框控件类操纵对话框控件(发送消息和直接调用成员函数)。

5.      在程序运行时产生和销毁控件。

6.      对话框控件的几种访问方式的优劣比较分析

7.      实现对话框的部分收缩和展开。

8.      利用SetWindowLong改变窗口的窗口过程函数。

9.      利用默认按钮实现随着回车键的按下将输入焦点在对话框中各子控件间一次传递。

 

创建模态和飞模态对话框

//注意加上头文件#include "testdlg.h"

void CMyboleView::OnDialog()

{

       //1.创建模态对话框 

       CTestDlgdlg;

       dlg.DoModal();

      

       //2.创建非模态对话框

       /*CTestDlgdlg;

       dlg.Create(IDD_DIALOG1,this);

       dlg.ShowWindow(SW_SHOW);*/

       //当利用Create函数创建非模态对话框时,还需要调用ShowWindow()函数将这个对话框显示出来

       //而DoModal函数本身就有显示模态对话框的作用,所以不需要ShowWindow()函数

       //这样即使是加上ShowWindow()函数也不能让对话框显示,这里的局部变量会被销毁。故不能显示。

       //CTestDlg*pDlg = new CTestDlg;

       //pDlg->Create(IDD_DIALOG1,this);   //把指定父窗口的指针换成GetParent()看看有什么结果

       //pDlg->ShowWindow(SW_SHOW);

       //这种方法是将局部变量定义成指针,在堆上分配内存。在堆上分配的内存,与程序的整个生命周期是一致的,当然这里是指

       //程序不主动销毁的情况。

       //还有一种方法就是定义为视类的成员变量

       //这样还是有问题的,首先,我们定义的pDlg这个指针变量是一个局部对象,这样当它的生命周期结束时,它

       //所保存的内存地址就丢失了,在程序中也就无法再引用到它所指向的那块内存了

       //这个问题结局方法有两种

       //一.将这个指针变量定义为视类(CMyboleView)的成员变量,然后再CMyboleView类的析构函数中调用delete函数来释放这个

       //指针变量所指向的那块内存。

       //二.在CTestDlg类中重载PostNcDestory虚函数,释放this指针所指向的内存。

       //无论模态还是非模态对话框,单击【OK】或【CANCLE】按钮对话框都会消失。但是对模态对话框而言,此时对话框窗口对象被销毁了

       //而对于非模态对话框而言,对话框对象并未被销毁,只是隐藏了起来。要重写基类的OnOk或OnCancle

       //虚函数,并在重写的函数中调用DestoryWindow函数

}

 

 

voidCTestDlg::DoDataExchange(CDataExchange* pDX) //这个函数由程序框架调用,主要用来完成对话框数据的交换和校验。

{

       CDialog::DoDataExchange(pDX);

       //{{AFX_DATA_MAP(CTestDlg)

       DDX_Control(pDX,IDC_EDIT3, m_edit3);

       DDX_Control(pDX,IDC_EDIT2, m_edit2);

       DDX_Control(pDX,IDC_EDIT1, m_edit1);

       DDX_Text(pDX,IDC_EDIT1, m_num1);  //将ID指定的控件与特定的类成员变量相关联

       DDV_MinMaxInt(pDX,m_num1, 0, 100);

       DDX_Text(pDX,IDC_EDIT2, m_num2);  //因此,就是在DoDataExchange函数内部实现了对话框控件与类成员变量的关联

       DDV_MinMaxInt(pDX,m_num2, 0, 100);

       DDX_Text(pDX,IDC_EDIT3, m_num3);  //MFC提供了多种以DDX_为前缀的函数,这些函数分别用于不同控件的数据交换

       //}}AFX_DATA_MAP

}

 

 

BEGIN_MESSAGE_MAP(CTestDlg, CDialog)

       //{{AFX_MSG_MAP(CTestDlg)

       ON_BN_CLICKED(IDC_BTN_ADD,OnBtnAdd)

       ON_BN_CLICKED(IDC_STATIC_Number1,OnSTATICNumber1)

       ON_BN_CLICKED(IDC_BUTTON1,OnButton1)

       //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// CTestDlg message handlers

 

//在CTestDlg类中重载PostNcDestory虚函数,释放this指针所指向的内存。

void CTestDlg::PostNcDestroy()

{

       //TODO: Add your specialized code here and/or call the base class

       deletethis;

       CDialog::PostNcDestroy();

}

 

 

//动态创建按钮

void CTestDlg::OnBtnAdd()

{

       //1.方法一,定义静态变量判断窗口是否创建

       /*staticBOOL m_bIsCreated = FALSE;

       if(m_bIsCreated== FALSE)

       {

              m_btn.Create("New",BS_DEFPUSHBUTTON| WS_VISIBLE | WS_CHILD,CRect(0,0,100,100),this,123);

              m_bIsCreated= TRUE;

       }

       else

       {

              m_btn.DestroyWindow();

              m_bIsCreated= FALSE;

       }*/

   

       //2.方法二,根据CWnd对象的成员变量m_hWnd是否为空来判断!

       /*if(!m_btn.m_hWnd)

       {

              m_btn.Create("New",BS_DEFPUSHBUTTON| WS_VISIBLE | WS_CHILD,CRect(0,0,100,100),this,123);

       }

       else

       {

              m_btn.DestroyWindow();

       }*/

 

       //编辑框控件

       //1.第一种方式

       /*intnum1,num2,num3;

       charch1[10],ch2[10],ch3[10];

       GetDlgItem(IDC_EDIT1)->GetWindowText(ch1,10);

       GetDlgItem(IDC_EDIT2)->GetWindowText(ch2,10);

 

       num1= atoi(ch1);  //C语言提供的函数,可以将一个由数字组成的字符串转换为相应的数值。

       num2= atoi(ch2);

       num3= num1+num2;

 

       itoa(num3,ch3,10);//将数值转换为字符串。这里面的10表示十进制

       GetDlgItem(IDC_EDIT3)->SetWindowText(ch3);*/

 

       //2.第二种方式

   /*int num1,num2,num3;

       charch1[10],ch2[10],ch3[10];

       GetDlgItemText(IDC_EDIT1,ch1,10);

       GetDlgItemText(IDC_EDIT2,ch2,10);

 

       num1= atoi(ch1);

       num2= atoi(ch2);

       num3= num1+num2;

 

       itoa(num3,ch3,10);

       SetDlgItemText(IDC_EDIT3,ch3);*/

 

       //3.第三种方式

       /*intnum1,num2,num3;

       num1= GetDlgItemInt(IDC_EDIT1);

       num2= GetDlgItemInt(IDC_EDIT2);

 

       num3= num1 + num2;

 

       SetDlgItemInt(IDC_EDIT3,num3);*/

 

       //4.第四种方式(将这3个编辑框分别于对话框类的3个成员变量相关联,然后通过这些成员变量来检索和设置编辑框的文本,这是最简单的访问控

       //件的方式)

       /*UpdateData();

       m_num3= m_num1 + m_num2;

   UpdateData(FALSE);*/

 

       //5.第五种方式(关联控件变量)

   /*int num1,num2,num3;

       charch1[10],ch2[10],ch3[10];

 

       m_edit1.GetWindowText(ch1,10);

       m_edit2.GetWindowText(ch2,10);

 

       num1= atoi(ch1);

       num2= atoi(ch2);

       num3= num1 + num2;

 

       itoa(num3,ch3,10);

       m_edit3.SetWindowText(ch3);*/

 

       //6.第六种方式(给系统发送消息)

       /*intnum1,num2,num3;

       charch1[10],ch2[10],ch3[10];

 

       ::SendMessage(GetDlgItem(IDC_EDIT1)->m_hWnd,WM_GETTEXT,10,(LPARAM)ch1);

       ::SendMessage(m_edit2.m_hWnd,WM_GETTEXT,10,(LPARAM)ch2);

 

       num1= atoi(ch1);

       num2= atoi(ch2);

       num3= num1 + num2;

 

       itoa(num3,ch3,10);

   m_edit3.SendMessage(WM_SETTEXT,0,(LPARAM)ch3);*/

 

       //7.第七种方式(直接给对话框的子控件发送消息)

   int num1,num2,num3;

       charch1[10],ch2[10],ch3[10];

 

       SendDlgItemMessage(IDC_EDIT1,WM_GETTEXT,10,(LPARAM)ch1);

       SendDlgItemMessage(IDC_EDIT2,WM_GETTEXT,10,(LPARAM)ch2);

       num1= atoi(ch1);

       num2= atoi(ch2);

       num3= num1 + num2;

 

       itoa(num3,ch3,10);

       SendDlgItemMessage(IDC_EDIT3,WM_SETTEXT,0,(LPARAM)ch3);

       SendDlgItemMessage(IDC_EDIT3,EM_SETSEL,0,-1);//获取编辑框中的复选内容,用EM_GETSEL消息。

       //EM_开头的消息都是指编辑框控件消息(Edit Control Message)

       m_edit3.SetFocus();  //把焦点设置到控件上,不然点击Add按钮后,它是焦点,复选内容不会出现

}

 

void CTestDlg::OnSTATICNumber1()

{

       CStringstr;

       if(GetDlgItem(IDC_STATIC_Number1)->GetWindowText(str),str== "Number1:") //逗号表达式的结果返回最后一个表达式的值

       {

              GetDlgItem(IDC_STATIC_Number1)->SetWindowText("数值1:");

       }

       else

       {

              GetDlgItem(IDC_STATIC_Number1)->SetWindowText("Number1:");

       }

}

//静态文本控件在默认状态下是不发送通告消息的。

//为了使一个静态文本控件能够响应鼠标单击消息,1.需要改变它的ID,因为默认情况下添加的多个静态文本控件的ID都是相同的

//在ClassWizared中找不到ID,不能添加消息响应函数。 

//2.在它的属性对话框中选中Notify选项

 

 

//对话框伸缩功能实现

void CTestDlg::OnButton1()

{

       //TODO: Add your control notification handler code here

       CStringstr;

       if(GetDlgItemText(IDC_BUTTON1,str),str== "收缩<<")

       {

              SetDlgItemText(IDC_BUTTON1,"扩展>>");

       }

       else

       {

              SetDlgItemText(IDC_BUTTON1,"收缩<<");

       }

       staticCRect rectLarge;//设置为静态变量,一次赋值后以后不再改变

       staticCRect rectSmall;

 

       if(rectLarge.IsRectNull())//如果矩形的的左上角和右下角的4个坐标值都为0,则此函数返回一个非零值;否则,返回0;

       {                         //第一次点击按钮时赋值,后来再点击时,不再改变。判断矩形

              CRectrectSeparator;

              GetWindowRect(&rectLarge);

              GetDlgItem(IDC_SEPERATOR)->GetWindowRect(&rectSeparator);

 

              rectSmall.left= rectLarge.left;

              rectSmall.top  = rectLarge.top;

              rectSmall.right=rectLarge.right;

              rectSmall.bottom= rectSeparator.bottom;

       }

       if(str== "收缩<<")

       {

              SetWindowPos(NULL,0,0,rectSmall.Width(),rectSmall.Height(),SWP_NOMOVE| SWP_NOZORDER);

       }

       else

       {

              SetWindowPos(NULL,0,0,rectLarge.Width(),rectLarge.Height(),SWP_NOMOVE| SWP_NOZORDER);

       }

}

 

//输入焦点的传递

 

 

//添加这两个函数,并且把调用基类的OnOK(),OnCancel()代码注释掉,就会发现点击【确定】,【取消】按钮时,对话框不会再关闭了。

 

//用SetWindowLong函数修改该窗口指定的过程函数。编写一个编辑框控件的窗口过程,然后替换MFC提供的默认的编辑框控件

//窗口过程函数。因为窗口的所有消息都要到该窗口的窗口过程函数中来报到,因此,在这个新过程函数中可以进行一个判断,如果当前到来的是

//一个字符消息,并且该字符是一个回车符,那么就将输入焦点移动到下一编辑框控件。

//注意:1.要修改编辑框的styles中选择Multiline选项,才能接受回车键按下这一消息。

WNDPROC prevProc;

LRESULT CALLBACK NewEditProc(HWND hwnd,UINTuMsg,WPARAM wParam,LPARAM lParam)

{

       if(uMsg== WM_CHAR && wParam == 0x0d)

       {

              //::SetFocus(GetNextWindow(hwnd,GW_HWNDNEXT));

              //SetFocus(::GetWindow(hwnd,GW_HWNDNEXT));

              SetFocus(::GetNextDlgTabItem(GetParent(hwnd),hwnd,FALSE));

              return1;

       }

       else

       {

              returnprevProc(hwnd,uMsg,wParam,lParam);

       }

}

                                                       

//在程序运行时,当对话框及其上的子控件创建完成,将要显示之前会发送WM_INITDLALOG消息

BOOL CTestDlg::OnInitDialog()

{

       CDialog::OnInitDialog();

      

       //TODO: Add extra initialization here

       prevProc=(WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_hWnd,GWL_WNDPROC,(LONG)NewEditProc);

       returnTRUE;  // return TRUE unless you set thefocus to a control

                     // EXCEPTION: OCX Property Pagesshould return FALSE

}

//想让输入焦点在对话框中个控件上依次传递,按照上述方法显然比较麻烦,需要为每一个编辑框设定一个窗口函数

 

//在MFC中,默认情况下,当在对话框窗口中按下回车键时,会调用对话框的默认按钮的响应函数,

//我们可以再此默认按钮的响应函数中把焦点依次向下传递。

void CTestDlg::OnOK()

{

       //GetDlgItem(IDC_EDIT1)->GetNextWindow()->SetFocus();

       //GetFocus()->GetNextWindow()->SetFocus();

       //GetFocus()->GetWindow(GW_HWNDNEXT)->SetFocus();

       //在这里应该把第一个编辑框的styles中选择Multiline选项取消,不然焦点会直接跳到第三个。

       //这种方法在调用时,当对话框中最后一个空间调用此函数时,它返回的这个窗口指针是空指针。此时在对该指针调用SetFocus函数,

       //就会出现非法访问。GetWindow,GetNextWindow这两个函数的调用机理是一样,会出现同样的问题。

       GetNextDlgTabItem(GetFocus())->SetFocus();

       //GetNextDlgTabItem与GetWindow,GetNextWindow搜索窗口的行为是不一样的,前者是查找

       //具有Tab stop属性的控件,并按Tab顺序依次查找各控件。

       //Layout-> Tab order可以查看对话框的Tab顺序

       //CDialog::OnOK();

}

 

void CTestDlg::OnCancel()

{

       //TODO: Add extra cleanup here

      

       //CDialog::OnCancel();

}

 

//当用户按下回车键时,Windows将查看对话框中是否存在指定的默认按钮,如果有,就调用该默认按钮单击消息的响应函数。如果没有,就会

//调用虚拟的OnOk函数,即使对话框没有包含默认的OK按钮,但是一定要注意,这个默认OK按钮的ID是:IDOK.

原创粉丝点击