转自 http://blog.sina.com.cn/s/articlelist_1815328704_0_1.html
1.如果在SDI中要调用对话框
a.先插入一个对话框资源;
b.然后在ClassWizards中为其创建一个类。其目的是比较方便为添加按纽和消息响应函数。
c.然后实例化它。在实例化时,必须将其头文件包含进去。
2.创建非模态对话框,注意它不能是局部变量。当 点击非模态对话框的OnOK按纽时,它并没有关闭,而是隐藏了。需要调用destroyWindow().
3. 一个对象只能一个按纽。为什么?因为在Wincore.cpp的628行有代码 ASSERT(pWnd->m_hWnd == NULL); // only do once而创建后它的m_hWnd就不为0了。此处ASSERT的用法是如果括号里面不为真,则程序崩溃。
4.如何为静态文本框增加消息响应?首先将IDC_STATIC改名。同时还需要将Notify特性复选中。
5.完成加法功能。
a.GetDlgItem();
b.GetDlgItemText();
c.GetDlgItemInt();
d.将IDC_EDIT1关联CEDIT类型变量
e.将IDC_EDIT1关联int型变量。注意调用 UpdateData();
f. //::SendMessage(GetDlgItem(IDC_EDIT1)->m_hWnd,WM_GETTEXT,10,(LPARAM)ch1);
//::SendMessage(m_edit1.m_hWnd,WM_GETTEXT,10,(LPARAM)ch1);
//GetDlgItem(IDC_EDIT1)->SendMessage(WM_GETTEXT,10,(LPARAM)ch1);
m_edit1.SendMessage(WM_GETTEXT,10,(LPARAM)ch1);
g. SendDlgItemMessage(IDC_EDIT1,WM_GETTEXT,10,(LPARAM)ch1);
SendDlgItemMessage(IDC_EDIT2,WM_GETTEXT,10,(LPARAM)ch2);
6.点击按纽改变窗口尺寸
if(GetDlgItemText(IDC_BUTTON2,str),str=="收缩<<")
{
SetDlgItemText(IDC_BUTTON2,"扩展>>");
static CRect rectLarge;
static CRect rectSmall;
if(rectLarge.IsRectNull())
{
CRect rectSeparator;
GetWindowRect(&rectLarge);
GetDlgItem(IDC_SEPARATOR)->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);
}
SetWindowLong()改变窗口的属性。
7.回车时将输入焦点移动到下一个控件
方法1:
改变控件的回调函数,注意IDC_EDIT1的MultiLine要复选上。
WNDPROC prevProc;
LRESULT CALLBACK WinSunProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
if(uMsg==WM_CHAR && wParam==0x0d)
{
//::SetFocus(::GetNextWindow(hwnd,GW_HWNDNEXT));
//SetFocus(::GetWindow(hwnd,GW_HWNDNEXT));
CString str;
str.Format("%d",hwnd);
AfxMessageBox(str);//, UINT nType = MB_OK, UINT nIDHelp = 0 );
// AfxGetApp()->
SetFocus(::GetNextDlgTabItem(::GetParent(hwnd),hwnd,FALSE));
return 1;
}
else
{
return prevProc(hwnd,uMsg,wParam,lParam);
}
}
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TOD Add extra initialization here
prevProc=(WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_hWnd,GWL_WNDPROC,
(LONG)WinSunProc);//设置回调函数
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
方法2:
在OnOK响应函数中加入代码
//GetDlgItem(IDC_EDIT1)->GetNextWindow()->SetFocus();
//GetFocus()->GetNextWindow()->SetFocus();
//GetFocus()->GetWindow(GW_HWNDNEXT)->SetFocus();
GetNextDlgTabItem(GetFocus())->SetFocus();
类的继承图表
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,不要调用基类的成员函数,因为它调用的是EndDialog,which 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接收一个非零的值,如果lpTrans为NULL,GetDlgItemInt不会对错误产生警告 //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 Exchange1 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+TAB或ALT+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 style的control,循环依次调用 菜单项 Layout->TabOrder显示顺序
void CTestDlg::OnOK() 什么时候调用????????
焦点转移的发送处理函数的方法。
WNDPROC prevProc;
LRESULT CALLBACK WinSunProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
if(uMsg==WM_CHAR && wParam==0x0d)
{
//::SetFocus(::GetNextWindow(hwnd,GW_HWNDNEXT));
//SetFocus(::GetWindow(hwnd,GW_HWNDNEXT));
SetFocus(::GetNextDlgTabItem(::GetParent(hwnd),hwnd,FALSE));
return 1;
}
else
{
return prevProc(hwnd,uMsg,wParam,lParam);
}
}
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
prevProc=(WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_hWnd,GWL_WNDPROC,
(LONG)WinSunProc);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
焦点转移的onOK的方法。
void CTestDlg::OnOK()
{
// TODO: Add extra validation here
//GetDlgItem(IDC_EDIT1)->GetNextWindow()->SetFocus();
//GetFocus()->GetNextWindow()->SetFocus();
//GetFocus()->GetWindow(GW_HWNDNEXT)->SetFocus();
GetNextDlgTabItem(GetFocus())->SetFocus();
// CDialog::OnOK();
}
扩展收缩的按扭。
void CTestDlg::OnButton2()
{
// TODO: Add your control notification handler code here
CString str;
if(GetDlgItemText(IDC_BUTTON2,str),str=="收缩<<")
{
SetDlgItemText(IDC_BUTTON2,"扩展>>");
}
else
{
SetDlgItemText(IDC_BUTTON2,"收缩<<");
}
static CRect rectLarge;
static CRect rectSmall;
if(rectLarge.IsRectNull())
{
CRect rectSeparator;
GetWindowRect(&rectLarge);
GetDlgItem(IDC_SEPARATOR)->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);
}
}
变按扭:
void CTestDlg::OnNumber1()
{
// TODO: Add your control notification handler code here
CString str;
if(GetDlgItem(IDC_NUMBER1)->GetWindowText(str),str=="Number1:")
{
GetDlgItem(IDC_NUMBER1)->SetWindowText("数值1:");
}
else
{
GetDlgItem(IDC_NUMBER1)->SetWindowText("Number1:");
}
}
动态创建按扭和加法的运算:
void CTestDlg::OnBtnAdd()
{
// TODO: Add your control notification handler code here
int num1,num2,num3;
char ch1[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);
m_edit3.SetFocus();