//控件的介绍
首先控件呢,举个例子吧,就是对话框里面的按钮啦,编辑框,静态文本,图片之类的,这些都是控件,控件有很多,还有进度条,水平滑动条之类,需要注意的是所有的控件都是由Cwnd类派生的,所以他们全部都是能调用Cwnd的函数的(例如GetWindowRect这些)
//对话框
对话框就分2种,模态与非模态,模态对话框就是程序运行到对话框那里就会暂停下来,暂时不执行下面的程序,知道关闭这个模态对话框才继续执行程序的其他任务;
非模态对话框显示时,允许转而执行其他任务,而不用关闭这个对话框。
图中2,3这些就是控件了,至于想在单文档程序中插入一个对话框,首先要在资源文件中创建一个对话框资源,单是资源还不够,程序中需要一个类来与这个资源联系起来,通过操作这个类来操作资源,就像我们之前弄个个位图资源,要用CBitmap类来加载位图,用CMenu类来加载菜单一样,但是对话框貌似不能直接用CDialog类,需要自己新建一个类来联系这个对话框资源,而这个类正是派生于CDialog类的。
直接在那个资源右击,选择添加类,就出现这个对话框,填写相关资料就OK。
创建的这个对话框派生类只有3个函数
1,2分别是类的析构函数,构造函数,3函数貌似很重要,用来做数据交换的,当编辑框控件与特定的变量关联起来的时候,就是用它来实现数据交换的。
模态对话框的创建
模态对话框实现相当简单,例如我们想在程序的(菜单栏->帮助->对话框->弹出模态对话框),首先在菜单资源帮助下面加个对话框,右击,选添加事件处理程序
因为菜单属于主框架类的,所以我习惯单击菜单项作为CMainFrame的函数:
添加的事件的处理函数就这个了,首先创建一个那个对话框资源类的对象,调用DoModal()函数,就可以实现模态对话框出来了,它的显示,更新什么的全部在这个函数帮你搞掂,所以模态对话框相比较起非模态简单很多。
///非模态对话框的创建
这里要用到CDialog::Create函数
Create()函数还不会帮你ShowWindow(),需要自己调用。
程序变成这样,运行时发现对话框出现了一瞬间就消失了,那是因为dlg是局部变量,非模态不像模态,运行到DoModal()那里暂停所以没事,非模态会继续运行下去,离开右花括号时,dlg就会析构了,对话框就更不可能存在了。解决方法:1,把dlg变成CMainFrame的数据成员;2,dlg变成指针,CTestDlg *dlg=new CTestDlg; *dlg指向的是堆中创建的空间,不会在右花括号出现就消失的,这样也可以解决问题,但是指针这种方式有个弊端,右花括号处,虽然那个对象没消失,但是指向那个对象的*dlg会消失,同样是因为*dlg是局部变量,这样就会产生内存泄露了,要么就是把*dlg设为数据成员,在析构函数那里delete内存(⊙﹏⊙b汗,这样用指针还有什么意义呢),要么在CTestDlg类中重载一个叫PostNcDestroy的虚函数,在里面delete this;(this指向CTestDlg本身)。
综上创建非模态最方便的还是设一个数据成员来调用Create函数与ShowWindow()函数。
///对话框控件的访问
图中1是静态文本控件,2是编辑框控件,3是按钮控件。
1:静态文本一般就是显示文本,它的ID号也是一般设置为IDC_STATIC,而且全部静态文本基本都是这个ID了,所以静态文本也不相应什么消息,但是不代表它不能响应消息的,第一步,改变它的ID,第二步,属性中选择Notify选项,这样静态文本同样能响应消息了。
右击静态文本,选添加事件响应函数
检索指向在对话框或其他窗口中指定的控件或子窗口。
CWnd* GetDlgItem( int nID ) const;
顾名思义就是找给定ID的控件,返回指向控件对象的指针,GetWindowText(CString)就是把这个控件的文本存到CString中,SetWindowText就是把参数写到控件中。
2,编辑框控件
实现number1与number2相加放入number3,首先要知道number1与number2中的数字是多少才行,一共又有7种方式,简单介绍几种,着重介绍关联变量的那种,
【原形】
int GetWindowText( LPTSTR lpszStringBuf, int nMaxCount ) const;
void GetWindowText( CString& rString ) const;
【参数】
lpszStringBuf
指向要接收窗口标题的复制字符串的缓冲区。
nMaxCount
指定了要拷贝的缓冲区的最大字符数目。如果字符串比nMaxCount指定的数目还要长,则被截断。
rString
用于接收窗口标题的复制字符串的CString对象。
TCHAR ch1[10];
GetDlgItem(IDC_EDIT1)->GetWindowtext(ch1,10); num1=_ttoi(ch1); _itow_s(num3,ch3,10,10); GetDlgItem(IDC_EDIT3)->SetWindowText(ch3);
还有GetDlgItemText(IDC_EDIT1,ch1,10); SetDlgItemText(IDC_EDIT3,ch3); GetDlgItemInt(IDC_EDIT1,NULL,true); SetDlgItemInt(IDC_EDIT3,num3,true);这样的调用也行。
GetDlgItemInt参数(ID,报错存放地址一般NULL,有没符号)
重点方法:
右击资源编辑控件,选择添加变量
类别选value,这样添加的就是与这个编辑控件关联起来的值,选control就会创建一个代表控件本身的对象(用这个对象直接调用GetWindowtext()这些函数:m_edit1.GetWindowtext(str);就会变成这样),选value,那么编辑框的数就会赋值给m_num1了。
数据交换的实现由一开始介绍的那个函数实现:
不过一般不会直接调用这个函数,而是调用UpdateDate(bool )函数来间接调用它,UpdateData(true)就会获取对话框数据,UpdateDate(false)就会初始化控件内容;
所以在按Add按钮的响应函数中应该是:UpdateData(true); num3=num1+num2; UpdateData(false);就这样就实现了相加的功能了
//对话框的伸缩
如图的伸缩,实现最主要的就是搞清楚伸缩前后,对话框的坐标大小,中间那条线是图片控件,同样也是一个窗口类,在这里主要是学习2个函数:
BOOL SetWindowPos(
const CWnd* pWndInsertAfter,
int x,
int y,
int cx,
int cy,
UINT nFlags
);
pWndInsertAfter
标识将前面的 CWnd 对象(大于)对Z顺序的此 CWnd 对象。 此参数可以是指向 CWnd 或 Pointer 为下列值之一:
wndBottom 将窗口底部的z-顺序。 如果此 CWnd 是一个最顶层窗口,窗口丢失其最顶层的状态;系统将窗口在其他窗口底部。
wndTop 将窗口在z-顺序的顶部。
wndTopMost 将windows首先非最顶层窗口。 即使当停用,窗口保留其最顶层的位置它。
wndNoTopMost 在任何非最顶层窗口的顶部重新定位窗口(即所有最顶层窗口)后。 如果窗口已非最顶层窗口,此标志将不起作用。
有关如何的规则使用此参数,请参见“备注”本主题的一部分。
指定窗口的左侧的新位置。
指定窗口顶部的新位置。
指定窗口的新的宽度。
指定窗口的新高度。
指定大小调整和定位选项。
-
SWP_NOMOVE 保留当前位置(忽略 x 和y 参数)。
-
SWP_NOSIZE 保留当前范围(忽略 cx 和 cy 参数)。
-
SWP_NOZORDER 保留当前排序(忽略 pWndInsertAfter)。 所以SetWindowPos(NULL,0,0,recrLarge.width(),rectLarge.Height(),SWP_NOMOVE | SWP_NOZORDER);这样调用就OK了。
我们在编辑框打完一个数,按TAB可以跳到下一个框,按回车对话框却转为按确定按钮了,修改这个功能,令按回车也能跳到下一个框去,这就是用回车实现了焦点传送,事实上回车按钮被设置为默认按钮了。
所以按回车才会这样,要按回车焦点传送必须先令对话框不消失才行,确定按钮的处理函数OnOk()是虚函数,在CTestDlg类中重载这个函数,注释里面的内容就能断掉它的功能。之后,编辑框本身是个窗口,它有自己对回车的响应函数,要修改它可以修改它的过程函数,把新的过程函数赋给编辑框(要是消息是回车键就焦点传送,不是就用编辑框原来的过程函数来处理),这里有个问题就是编辑框早就定义好了,过程函数也指定好,修改就要用到SetWindowLong函数
LONG WINAPI SetWindowLong( _In_ HWND hWnd, _In_ int nIndex, _In_ LONG dwNewLong);
参数一:想要改变属性的窗口句柄 参数二:DWL_DLGPROC 改变过程函数 GWL_STYLE 设置新的窗口风格 GWL_ID 为窗口设新ID 。。。。
参数三:新的过程函数地址 返回值:修改的属性的旧值
待对话框,控件什么的都创建完了,才能修改过程函数,这里有个BOOL CTestDlg::OnInitDialog()这样的虚函数,右击CTestDlg类,类向导->虚函数就有了,这个虚函数是对话框,控件创建完,将要显示前要运行的函数,在这个函数里面设过程函数
WNDPROC prevproc;//过程函数变量吧,可以这样理解
prevproc=(WNDPROC)SetWindowLong(m_edit1.m_hWnd,GWL_WNDPROC,(LONG)NewEditProc);
而新的过程函数定义为:
LRESULT CALLBACK NewEditProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if(uMsg==WM_CHAR && wParam==0x0d)//如果是回车键 { ::SetFocus(GetNextWindow(hwnd,GW_HWNDNEXT));//设置焦点 return 1; } else { return prevproc(hwnd,uMsg,wParam,lParam);//不是回车就用原来的过程函数处理 } }