第七章对话框

转自http://www.cn-doc.com/_soft_visual_c_tech_doc/2005_08_18_23/20050818230400236_5.htm                  
类的继承图表

cobject
  ccmdtarget
    cwnd       //
cwnd派生,是一个窗口类
      cdialog     

对话框分为模态对话框和非模态的对话框

cdialog::domodal
 //virtual int domodal()
 
调用domodal()创建一个模态的对话框
 
它的返回值是做为cdialog::enddailog成员函数的参数,这个参数用来关闭对话框  
cdialog::enddailog
 //
用来关闭模态的对话框                
cdialog::create
 //
创建非模态的对话框
 //
初始化一个cdialog对象,创建一个非模态的对话框(modeless dialog box)
 //
把它将一个cdialog对象关联起来
 //bool create( lpctstr lpsztemplatename, cwnd* pparentwnd = null);
 //bool create( uint nidtemplate, cwnd* pparentwnd = null);
 //lpsztemplatename:
对话框模板的名字
 //nidtemplate:     
对话框模板的id
 //pparentwnd:      
对话框父窗口的指针,如果为null,则对话框的父窗口将被设置为主应用程序窗口

模态对话框的显示不用调用showwindow
而非模态的对话框在调用create创建完对话框之后,需要调用showwindow显示对话框//showwindow(sw_show)

caution:
   
对于模态的对话框,在模态的对话框显示时,应用程序是暂停执行的,所以模态的对话框对象可以
 
是局部对象,不会在模态的对话框显示之前析构。
   
而对于非模态的对话框,应用程序不会暂停执行,所以非模态对话框的对象不能是局部对象,非模态的
 
对话框对象有两种定义方法:
 1
:定义对话框成员变量
 2
:在堆上分配内存,在堆上分配的内存和我们整个应用程序的生命周期是一样的,可以如下定义:
    ctestdlg *pdlg=new ctestdlg();    //
注意内存看见的回收,防止memory leak
   
   
caution:
 
对于模态的对话框,当我们点击ok或者cancel按钮时这个对话框窗口是被销毁了的
 
对于非模态的对话框,这个对话框窗口并没有被销毁,只不过是隐藏了,当我们点击ok时,由基类的
 
虚函数onok()响应
 
cdialog::onok
 //virtual void onok();
 //
如果你在一个非模态的对话框中实现了一个ok button,你必须重载onok成员函数,在它内部调用
 //destroywindow,
不要调用基类的成员函数,因为它调用的是enddialogwhich makes the dialog
 //box invisible but does not destroy it.
 
 
cbutton::create
 // BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

 //创建button
 //
按钮也是子窗口,如果dwstyle中不包含ws_visible,则在创建完button后,继续调用showwindow()显示
 //
按钮
 

cwnd和任何由cwnd类派生出来的窗口类对象,内部都有一个成员变量m_hwnd保存和这个对象相关联的窗口的
句柄,没有窗口和它关联时,m_hwnd的值为null

静态的文本框也是一个窗口,要获取静态文本框的文本,可以使用函数 cwnd::getwindowtext
设置文本使用 cwnd::setwindowtext
 cwnd::getwindowtext
  //int getwindowtext( lptstr lpszstringbuf, int nmaxcount )const;
  //void getwindowtext( cstring& rstring ) const;
 cwnd::setwindowtext
  // void setwindowtext( lptstr lpszstring)
  
对于静态的文本框是不能接收通告消息的,如果让它接收通告消息,需要把它的属性的style"notify"项选上

atoi函数
  int atoi( const char *string)  //
将数值字符,转化为整形数值
  char* _itoa( int value, char *string, int radix);  //convert an integer to a string
  //string
指向结果
  //radix 2-36
数值的*进制

访问控件的方式
  
1
、获取对话框上控件的指针
 cwnd::getdlgitem
  cwnd* getdlgitem( int nid ) const;
  void cwnd::getdlgitem( int nid,hwnd* phwnd ) const;
   
2
cwnd::getdlgitemtext
 //int getdlgitemtext( int nid, lptstr lpstr, int nmaxcount ) const;
 //int getdlgitemtext( int nid, cstring& rstring ) const;
cwnd::setdlgitemtext
 //void setdlgitemtext( int nid, lpctstr lpszstring);
 
3
cwnd::getdlgitemint
 //uint getdlgitemint( int nid, bool* lptrans = null, bool bsigned = true ) const;
 //
可以获取控件的文本,并把它转化为无符号整形
 //
如果遇到非数值字符,或者数值超过所能表示的最大值,将会发生错误。此时lptrans指向0,如果没有错误
 //lptrans
接收一个非零的值,如果lptransnullgetdlgitemint不会对错误产生警告
 //bsigned
指示接收的数值字符是否是有符号的
cwnd::setdlgitemint
 //void setdlgitemint( int nid, uint nvalue, bool bsigned = true );

4、控件与成员变量的关联,在dodataexchange函数中
void ctestdlg::dodataexchange(cdataexchange* pdx)
{
 cdialog::dodataexchange(pdx);
 //{{afx_data_map(ctestdlg)
 ddx_text(pdx, idc_edit1, m_num1);          //
将控件idc_edit1与成员变量m_num1相关联
 ddx_text(pdx, idc_edit2, m_num2);
 ddx_text(pdx, idc_edit3, m_num3);
 //}}afx_data_map
}
 ddx_
函数有很多种,关联不同的控件,需要选择不同的ddx_函数,ddx_scroll,ddx_radio
 
dodataexchange
的调用时间:
  //called by the framework to exchange an validate dialog data
  //
由框架调用,来交换和调用对话框的数据
  //never call this function directly.it is called by the updatedata member function.
  //
我们重来不会直接调用这个函数,它由updatedata成员函数调用
  //call updatedata to initialize a dialog box's control or retrive data from a dialog box
  //
调用updatedata来初始化一个对话框控件,或者从对话框获得数据

cwnd::updatedata
 //bool updatdata( bool bsaveandvalidate = true )
 //call the member function to initialize data in a dialog box, or to retrieve and validate
 //dialog data
 //flag that indicates whether dialog box is being initialized (false) or data is being retrieve
 //(true)
 //the framework automatically calls updatedata with bsaveandvalidate set to false when a modal
 //dialog box is created in the default implementation of cdialog::oninitdialog

在控件关联的成员变量设置最大最小值后,dodataexchange函数中会增加如下几条语句

void ctestdlg::dodataexchange(cdataexchange* pdx)
{
 cdialog::dodataexchange(pdx);
 //{{afx_data_map(ctestdlg)
 ddx_text(pdx, idc_edit1, m_num1);           //ddx : dialog data exchange
1 ddv_minmaxint(pdx, m_num1, 0, 100);         //ddv : dialog data validate
 ddx_text(pdx, idc_edit2, m_num2);
2 ddv_minmaxint(pdx, m_num2, 0, 100);         //ddv_
函数也有很多,同ddx_函数一样
 ddx_text(pdx, idc_edit3, m_num3);
 //}}afx_data_map
}

获取文本的消息:wm_gettext
   an application sends a wm_gettext message to copy the text that corresponds to a window into a
   buffer provided by the caller.
   to send this message,call the sendmessage function with the following parameters.
   sendmessage{
          (hwnd) hwnd,              //handle to destination window
          wm_gettext,               //message to send
          (wparam) wparam,          //number of the character to copy
          (lparam) lparam           //text buffer
              }
             
设置文本的时候使用消息 wm_settext  

sendmessage{
          (hwnd) hwnd,              //handle to destination window
           wm_settext,               //message to send
          (wparam) wparam,          //not used;must be zero
          (lparam) lparam           //window-text string (lpctstr)
           }

给对话框的子控件发送消息
cwnd::senddlgmessage
 lresult senddlgitemmessage( int nid, uint message, wparam wparam=0, lparam lparam = 0)
 //
等价于我们现调用getdlgitem再调用sendmessage
 
编辑框消息 em_getsel
 //the em_getsel message retrieves the starting and ending character positions of the current
 //selection in an edit control. you can send this message to either an edit control or a rich 
 //edit control      
 sendmessage{                                                            
           (hwnd) hwnd,              //handle to destination window   
           wm_gettext,               //message to send                      
        (wparam) wparam,           //starting position (lpdword) 
        (lparam) lparam            //ending position (lpdword)                    
          }                                                            
 
em_setsel
设置复选的开始位置和结束位置    
sendmessage{                                                                  
        (hwnd) hwnd,              //handle to destination window       
        wm_settext,               //message to send                    
       (wparam) wparam,           //starting position       
       (lparam) lparam            //ending position         
          }
 //if the start is 0 and the end is -1, all the text in the edit control is selected.
 //if the start is -1,any current selection is deselected
        
设置窗口的焦点 cwnd::setfocus
 cwnd* setfocus();

总结:
   
对话框控件访问七种方式
    1
getdlgitem()->get(set)windowtext()  //常用
    2
getdlgitemtext()/setdlgitemtext()
    3
getdlgitemint()/setdlgitemint()
    4
、将控件和整型变量相关联              //常用
    5
、将控件和控件变量相关联        //常用
    6
sendmessage()                       //不常用
    7
senddlgitemmessage()                //不常用
   
对话框的收缩与扩展
  crect::isrectempty
   //determines whether crect is empty.crect is empty if the width and/or height are 0;
  crect::isrectnull
   //determines whether the top, bottom, left,and right member variables are all equal to 0.
 
  cwnd::getwindowrect
   void getwindowrect( lprect lprect) const;
  //
获取窗口矩形区域的大小
 
  cwnd::setwindowpos
   //bool setwindowpos( const cwnd* pwndinsertafter, int x,int y, int cx, int cy, uint nflags);
   setwindowpos
deferwindowpos用来重排z-order
   //
应用程序通过设置ws_ex_topmost风格创建最顶层窗口。
    //
应用程序可用函数bringwindowtotop把一个窗口放置到z次序的顶部。
兄弟窗口
    
共享同一个父窗口的多个子窗口叫兄弟窗口。
活动窗口
    
活动窗口是应用程序的顶层窗口
    
应用程序则调用函数setactivewindow来激活一个顶层窗口

前台窗口和后台窗口
    
windows系统中,每一个进程可运行多个线程,每个线程都能创建窗口。创建正在使用窗口的线程
 
称之为前台线程,这个窗口就称之为前台窗口。所有其它的线程都是后台线程,由后台线程所创建的
 
窗口叫后台窗口。
    
用户通过单击一个窗口、使用alt+tabalt+esc组合键来设置前台窗口,应用程序则用函数
  setforegroundwindow
设置前台窗口。如果新的前台窗口是一个顶层窗口,那么windows系统就激活它,
 
换句话说,windows系统激活相应的顶层窗口。
 
       setwindowpos???

setwindowlong函数
  //the setwindowlong function changes an attribute of the specified window
  //setwindowlong
函数可以改变指定窗口的属性
  long setwindowlong
  {
   hwnd hwnd,              // handle to window
   int  nindex,            // offset of value to set   
   long dwnewlong          // new value 
 }
 
 
nindex=gwl_wndproc   可以sets a new address for the window procedure
 
此时可以把dwnewlong设置成新的窗口过程的地址。

函数的返回值:
    if the function succeeds, the return value is the previous value of the specified 32-bit integer
    if the function fails , the return value is zero
   
nindex=gwl_wndproc ,它的返回值就是以前的窗口过程的地址
   
当对话框上的子控件全部创建完毕,对话框将要显示时发送消息:wm_initdialog
    //sent to a dialog box before the dialog box is displayed

子控件的创建时间在对话框创建之后,对话框将要显示之前

窗口过程函数的写法:
  lresult callback windowproc{
             hwnd      hwnd,       //handle to window
             uint      umsg,       //message identifier
             wparam    wparam,     //first message parameter
             lparam    lparam      //second message parameter
             }
            
当处理的是wm_char消息时,wparam表示字符的ascii

caution!
  
窗口过程函数是一个全局函数

全局的setfocus函数
    hwnd setfocus(
         hwnd  hwnd    //handle to window
         );     
        
全局的getnextwindow函数:
 hwnd getnextwindow(
      hwnd hwnd,        //handle to current window
      uint ucmd         // direction
      );
   //
ucmd=gw_hwndnext    当前窗口的下一个窗口                                                                      
   //
ucmd=gw_hwndprev    当前窗口的上一个窗口
  
编辑框的style如果如果没有复选multiline属性,则编辑框无法接受回车符发送的消息
取消multiline属性是在 02:29:10 onok函数时

获取窗口句柄的getwindow全局函数
  hwnd  getwindow(
        hwnd hwnd,   // handle to original window
        uint ucmd    // relationship
 
 getnextdlgtabitem
函数
 //the getnextdlgtabitem function retrieves a handle to the first control that has the
 //ws_tabstop style that precedes(
前面)( or follows)the specified control.
 hwnd getnextdlgtabitem(
      hwnd hdlg,       //handle to dialog box
      hwnd hctrl,      //handle to known control
已知控件的句柄
      bool bprevious   //direction flag
方向。if this parameter is true, the function searches
                       //for the previous control in the dialog box.if this parameter is false,
                       //the function searches for the next control in the dialog box
       );
cwnd::getnextwindow
 cwnd* getnextwindow( uint nflag = gw_hwndnext )const;//
具有缺省的方向gw_hwndnext

获取当前具有输入焦点的窗口的指针的函数: cwnd::getfocus  
 
cwnd::getwindow
 cwnd* getwindow( uint ncmd) const;

cwnd::getnextdlgtabitem
 cwnd* getnextdlgtabitem( cwnd* pwndctrl, bool bprevious = false) const;
 //
函数寻找具有ws_tabstop stylecontrol,循环依次调用
 
菜单项 layout->taborder显示顺序

一、           简单的逃跑按钮

//注意下列方法,定义一个类为了捕获鼠标移动点的方便

1,创建一个基于对话框的MFC AppWizard工程

2,在View窗口点右键,添加一个自定义的类(或者用Classwizard工具添加),基类为CButton

class CWeiXinBtn : public CButton

3,给CWeiXinBtn类添加成员变量CWeiXinBtn* m_pBtn;

4,给对话框添加俩按钮,每个按钮都关联一个CWeiXinBtn的变量

5,在OnInitDialog添加

m_btn1.m_pBtn=&m_btn2;

       m_btn2.m_pBtn=&m_btn1;

6CWeiXinBtn::OnMouseMove中添加交换显示的语句

ShowWindow(SW_HIDE);

       m_pBtn->ShowWindow(SW_SHOW);

大功告成!

当然可以SetWindowPos函数实现更客观

二、           属性页的编辑

1CPropertyPage

 sheet的构造函数中添加propertyPage

 prop1sheet::AddPage 把页面添加到sheet

2,属性页变向导类型

 prop1sheep.SetWindowMode();//向导模式语句

 prop1sheet.DoModal();

3,第一页的"上一步",最后一页的"下一步"取消方法

 在第一个/最后一页属性页类添加虚函数PnSetActive,并在其中添加

 ((CPropertySheet *)GetParent())->SetWizardButtons(PSWIZB_NEXT);//第一页

 ((CPropertySheet *)GetParent())->SetWizardButtons(PSWIZB_BACK|PSWIZB_NEXT);//中间的页

 ((CPropertySheet *)GetParent())->SetWizardButtons(PSWIZB_BACK|PSWIZB_FINISH);//最后一页

4,"下一步"之前,检查是否已完成“选择”等

 PropertyPageOnWizardNext函数中检查

5,编辑对话框/属性页上的ComBox控件

 ((CComoBox *)GetDlgItmem(IDC_ComBOX1))->AddString(" ");//增加选项

6,获取ListComBox)控件,并进行编辑

 int sel=((CComoBox *)GetDlgItmem(IDC_ComBOX1))->GetCurSel();

 CString m_str;

 ((CComoBox *)GetDlgItmem(IDC_ComBOX1))->GetLBText(sel,&m_str);//取出用户的选择

7,窗口IDOK==xxx.DoModal()后,其上面的控件生命期仍有效,所以可以用变量接受其值

8,List控件的sort属性选中/不选中,表示是否自动排序,注意有时不需要自己排序

下面讲述一个属性页对话框的使用例程。

1VC++经常问题。

不能为已建好的类打开文件

VC中为资源(对话框、属性页等)添加类时,打开classwizard=>添加类,输入类名,选择baseclass,点OK之后,弹出不能打开文件的错误"Unable to open the file(XXX.h,XXX.cpp) for class xxx"

解决办法:删除类信息文件XXX.clw;再次调用classwizard,重新产生一个xxx.clw即可

2,属性页资源的增加

         Resource ViewDialog处点击右键InsertèDialogèIDD_PROPPAGE_LARGE(English(U.S.))

         注意看属性页资源的属性:类型-ChildBorder-ThinSystem menu不复选,More style中复选了Disabled

         也可以通过修改普通对话框,而成为属性页。

3,创建类

给属性页对话框添加类的时候,基类选为CPropertyPage,而不是CDialog

4,创建属性表单

利用Classwizard插入一个新的类,基类选为CPropertySheet

5,给属性表单添加三个public变量

       CProp1 m_prop1;

       CProp2 m_prop2;

       CProp3 m_prop3;

6,在属性表单的两个构造函数增加表单

       AddPage(&m_prop1);

       AddPage(&m_prop2);

       AddPage(&m_prop3);

7,在View类添加一个菜单项,添加响应函数,添加下列语句

       CPropSheet propSheet("维新属性表单程序");

       //propSheet.SetWizardMode();//向导类时增加这一句

       if(ID_WIZFINISH==propSheet.DoModal())

       {

              //获取各个表单项的选项,仅作为例子

              m_iOccupation=propSheet.m_prop1.m_occupation;

              m_strWorkAddr=propSheet.m_prop1.m_workAddr;

              m_bLike[0]=propSheet.m_prop2.m_football;

              m_strSalary=propSheet.m_prop3.m_strSalary;

              Invalidate();

       }

属性表单创建完毕。属性页具体内容的编辑和内容的显示过程省略

向导类的创建

1,在Domodal之前添加

       propSheet.SetWizardMode();

2,设置最初/末页的“上一步”和“下一步”

CProp1类处右键,加载需函数OnSetActive,并在CProp1::OnSetActive中添加

((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);

CProp4::OnSetActive中添加

((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);

为每一页添加限制条件:只有在当页进行必要操作后,才能“下一步”

1  为每个属性页添加虚函数DoDataExchange,其中不添加代码

2  为最后一页添加虚函数OnWizardFinish,其他页添加OnWizardNext函数,并在其中添加“下一步”的判断条件

数据交换

UpdateData(TRUE);//从控件中取回值

UpdateData(FALSE);//给变量值赋赋控件

    欢迎以任何形式转载本文,只要对您有用

 

你可能感兴趣的:(windows,function,String,null,dialog,Exchange)