1,动态创建按钮
enum{IDD=IDD_DLG1}; 将对话框与类关联起来...
1)增加全局变量 CButton m_btn;
//定义成局部变量不行 1)是一种解决方案;
//方案二是定义指针,在堆上分配内存,与整个应用程序的生命周期是一样的.
pDlg->Create
pDlg->ShowWindow
2)在需要创建的地方
//ID号123可以随意改变 //确实
模态:DoModal
非模态:
多次创建出现非法访问的问题:
方法2:
static BOOL bIsCreate=FALSE; //设置成static,则第一次初始化,以后就不会再改动它了
方法1:
if(m_bIsCreate==FALSE) {} else ... //下面是升级版
方法3:
if(!m_btn.m_hWnd) //如果没有这个条件判断,则会多次创建.
m_btn.Create("维新",BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,CRect(0,0,100,100),this,123);
else
m_btn.DestroyWindow(); //m_bIsCreate=FALSE;
2,复制控件
在dlg上添加控件时,按住ctrl键,拖动就可以复制一模一样的控件
3,控件对齐
在对话框上多个控件对齐,可以用layout菜单或者左下角toolbar
4,动态编辑static静态文本框
CString str;
if(GetDlgItem(IDC_NUMBER1)->GetWindowText(str),str=="Number1:")
GetDlgItem(IDC_NUMBER1)->SetWindowText("数值1:");
else
GetDlgItem(IDC_NUMBER1)->SetWindowText("Number1:");
要让static静态文本框响应消息,需要复选上notify选项
在属性页里面进行修改
5,Edit文本框
获取/设置文本内容
1)方法1
char ch[10];
GetDlgItem(IDC_EDIT1)->GetWindowText(ch1,10);
GetDlgItem(IDC_EDIT3)->SetWindowText(itoa(atoi(ch1),ch1,10));
2)方法2
GetDlgItemText(IDC_EDIT1,ch1,10);
SetDlgItemText(IDC_EDIT3,itoa(atoi(ch1),ch1,10)); //此处10为进制
3)方法3
SetDlgItemInt(IDC_EDIT3,GetDlgItemInt(IDC_EDIT1));//对整型数字的字符串有用
4)关联变量法
对每个Edit控件关联一个变量,设置后记得用UpdateData()
对于显示数字类的文本框,可以定义value和control两种类型变量
DoDataExchange() called by the framework to exchange and validate dialog data
The framework automatically calls UpdateData with bSaveAndValidate set to FALSE when a modal dialog box is created in the default implementation of CDialog::OnInitDialog.
value选择为int类型
void CTestDlg::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);
DDV_MinMaxInt(pDX, m_num1, 0, 100);
DDX_Text(pDX, IDC_EDIT2, m_num2);
DDV_MinMaxInt(pDX, m_num2, 0, 100);
DDX_Text(pDX, IDC_EDIT3, m_num3);
//}}AFX_DATA_MAP
}
以上为变量与控件进行关联...
DDX_Text:将控件与成员变量进行关联 Dialog Data eXchange
DDV_MinMaxInt: Dialog Data Verification
MSDN 搜索DDV_大把
DoDataExchange主要被框架调用,用来交换数据
//问题: 若直接写m_num3=m_num1+m_num2;m_num1,num2 在对话框中显示正确,但调试运行显示num1和num2均为0,得不到其值.查MSDN如下:
Never call this function directly. It is called by the UpdateData member function. Call UpdateData to initialize a dialog box's controls or retrieve data from a dialog box.
BOOL UpdateData( BOOL bSaveAndValidate = TRUE );
- bSaveAndValidate
-
Flag that indicates whether dialog box is being initialized (FALSE) or data is being retrieved (TRUE).
UpdateData() 获取值很直观
控件变量: 代表控件自己本身...
5)利用WM_GETTEXT消息处理获取文本
char ch1[10];
可以用以下四种方法(m_edit1为关联的控制型变量)
在OnBtnAdd函数里面加:
::SendMessage(GetDlgItem(IDC_EDIT1)->m_hWnd,WM_GETTEXT,10,(LPARAM)ch1);
::SendMessage(m_edit1.m_hWnd,WM_GETTEXT,10,(LPARAM)ch1); //已经关联了一个控件变量,所以可以直接调用其m_hWnd得到句柄
GetDlgItem(IDC_EDIT1)->SendMessage(WM_GETTEXT,10,(LPARAM)ch1);
m_edit1.SendMessage(WM_GETTEXT,10,(LPARAM)ch1); //个人以为此为最简单
//以下代码都是一样的:
num1=atoi(ch1);
num2=atoi(ch2);
num3=num1+num2;
itoa(num3,ch3,10);
再: 利用WM_SETTEXT消息处理设置文本
m_edit3.SendMessage(WM_SETTEXT,0,(LPARAM)ch3);
6)直接对对话框控件进行消息发送
SendDlgItemMessage(IDC_EDIT1,WM_GETTEXT,10,(LPARAM)ch1);//获取文本
//组合了:获取对话框句柄+调用SendMessage函数
Using SendDlgItemMessage is identical to retrieving a handle to the specified control and calling the SendMessage function.
SendDlgItemMessage(IDC_EDIT3,WM_SETTEXT,0,(LPARAM)ch3);//设置文本
SendDlgItemMessage(IDC_EDIT3,EM_SETSEL,0,-1);
7)利用EM_GETSEL,EM_SETSEL的消息处理
SendDlgItemMessage(IDC_EDIT3,EM_SETSEL,0,3);
//问题: 并没有显示覆选的部分,因点击Add按钮以后,focus到了Add按钮上
m_edit3.SetFocus();
SendDlgItemMessage(IDC_EDIT3,EM_SETSEL,0,-1);//将所有文本都选择上
//总结:
nGetDlgItem()->Get(Set)WindowText()
nGetDlgItemText()/SetDlgItemText()
nGetDlgItemInt()/SetDlgItemInt()
n将控件和整型变量相关联
n将控件和控件变量相关联
nSendMessage()
nSendDlgItemMessage()
6,对话框收缩
点击"收缩<<"对话框收缩,点击"扩展>>"则扩展, 请看例子代码
第一步: 增加Button, Caption改为"收缩<<"
当点击时,要将窗口切除一部分,再改成"扩张>>"
CTestDlg::OnButton2函数
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,"收缩<<");
}
//分隔符:利用图形控件来表示,将其拉成一条线,改ID为IDC_SEPARATOR, 属性页里面点击sucken,显示出下陷的样子
//要点: 收缩后x坐标不变,只是y方向长度发生变化
static CRect rectLarge;
static CRect rectSmall;
//对话框的尺寸要是保留下来的,故不能重复定义,要声明成static型的.
if(rectLarge.IsRectNull())
{
//注意区别:
Determines whether CRect is empty. CRect is empty if the width and/or height are 0 or negative。
Determines whether the top, bottom, left, and right member variables are all equal to 0.
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);
Windows系统管理三个独立的Z次序——一个用于顶层窗口、一个用于兄弟窗口,还有一个是用于最顶层窗口。最顶层窗口覆盖所有其它非最顶层窗口,而不管它是不是活动窗口或是前台窗口。应用程序通过设置WS_EX_TOPMOST风格创建最顶层窗口。 一般情况下,Windows系统把刚刚创建的窗口放在Z次序的顶部,用户可通过激活另外一个窗口来改变Z次序;Windows系统总是把活动的窗口放在Z次序的顶部,应用程序可用函数BringWindowToTop把一个窗口放置到Z次序的顶部。函数SetWindowPos和DeferWindowPos用来重排Z次序。 任何时候系统中只能有一个顶层窗口是活动的。用户通过单击窗口(或其中的一个子窗口)、使用ALT+TAB或ALT+ESC组合键来激活一个顶层窗口,应用程序则调用函数SetActiveWindow来激活一个顶层窗口。 用户通过单击一个窗口、使用ALT+TAB或ALT+ESC组合键来设置前台窗口,应用程序则用函数SetForegroundWindow设置前台窗口。如果新的前台窗口是一个顶层窗口,那么Windows系统就激活它,换句话说,Windows系统激活相应的顶层窗口。 //详见PPT!! |
}
else
{
SetWindowPos(NULL,0,0,rectLarge.Width(),rectLarge.Height(),
SWP_NOMOVE | SWP_NOZORDER);
}
}
//最后,将IDC_SEPARATOR的Visible设为否
7,多个edit框用Enter键切换的方法,三种方法
OK按钮: 属性-->Styles-->Default botton勾选上,则设为Default
//勾选去掉
//看如下强大的函数
LONG SetWindowLong(
HWND hWnd, int nIndex, LONG dwNewLong );
If the function succeeds, the return value is the previous value of the specified 32-bit integer.
//
1)捕获键盘消息,在消息函数中处理(未提供)
第一步:
2)修改Edit的窗口过程:自己写窗口过程替代原来的窗口过程(比较麻烦的方法)
(1)定义窗口过程类型变量
WNDPROC prevProc; //就在CTestDlg::OnInitDialog()函数之前定义
第三步:如何写窗口过程? 查WNDCLASS!!
(2)定义窗口过程函数
LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam )
{
if(uMsg==WM_CHAR && wParam==0x0d)//如果WM_CHAR消息并且是回车
{
//::SetFocus(::GetNextWindow(hwnd,GW_HWNDNEXT));//获取下一窗口句柄方法一
注意: Edit1: //Styles--MultiLine勾选以后,才能响应回车消息!!
- GW_HWNDNEXT
- Returns a handle to the window below the given window.
- GW_HWNDPREV
- Returns a handle to the window above the given window.
//SetFocus(::GetWindow(hwnd,GW_HWNDNEXT));//方法二
SetFocus(::GetNextDlgTabItem(::GetParent(hwnd),hwnd,FALSE));//方法三
//属性而中General-->Tab Stop (静态文本就没有)
//FALSE搜索下一个控件,TRUE搜索先前控件
return 1;
}
else
return prevProc(hwnd,uMsg,wParam,lParam);
}
//第二步:
(3)添加WM_INITDIALOG对应的函数
(4)在OnInitDialog中添加 //响应WM_INITDIALOG!!
说明在下面:Sent to a dialog box before the dialog box is displayed
prevProc=(WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_hWnd,GWL_WNDPROC,(LONG)WinSunProc);
- GWL_WNDPROC
Sets a new address for the window procedure.
(5)注意 edit控件 MultiLine复选属性选/不选的不同
SetWindowLong changes an attribute of the specified window.
3)在OnOK(default button对应的函数)
//利用OnOk(默认响应)函数实现按Enter键时自动Tab
void CTestDlg::OnOK()
{
// TODO: Add extra validation here
//GetDlgItem(IDC_EDIT1)->GetNextWindow()->SetFocus();//定死为EDIT1,注释之
//GetFocus()->GetNextWindow()->SetFocus();//一直回车,出现非法访问;
//因一直回车,GetFocus()->GetNextWindow()->得到的是一个空指针...
//GetFocus()->GetWindow(GW_HWNDNEXT)->SetFocus();//GW_HWNDNEXT获取下一窗
GetNextDlgTabItem(GetFocus())->SetFocus();//真正正确,第二个参数缺省为FALSE,搜寻下一个控件
// CDialog::OnOK();
}
GetFocus()->GetNextWindow()->SetFocus();//注意最后一个窗口时要判断,不然获取出错
GetFocus()->GetWindow(GW_HWNDNEXT)->SetFocus();//注意同上
GetNextDlgTabItem(GetFocus())->SetFocus();
Layout-->Tab order (shortcut: Ctrl+D)
将收缩按钮设为Default的,则不由IDOK响应函数来响应
注意: 对话框初始的OK的ID号为IDOK,即使删除按钮(OnOk函数存在),依然会响应OnOk函数
注意缺少的虽IDOK 而不是 IDC_OK,切记切记!!
第7课 对话框用户界面程序的编写
动态添加Button
访问对话框上的子窗口:
获取对话框上的项目指针:GetDlgItem()
获取窗口信息:GetWindowText()
更改窗口信息:SetWindowText()
直接取得指定对话框上项目的信息:GetDlgItemText() 想当于GetDlgItem()和GetWindowText()合用。
当然,也有SetDlgItemText() 相当于GetDlgItem()和SetItemText() 合用。
GetDlgItemInt(),SetDlgItemInt()等等,S/GetDlgItemInt()可以处理有符号的整数。
字符到数组的转换:atoi() 转换一个类型到指定类型时,用 类型的第一个字母 to 指定类型的一个字母。
在DoExchange函数里,放置以DDX_为前缀的函数,来关联一个控件和变量,DDV_为前缀的函数,用来校验一个控件内容。
DDX_(对话框数据交换) DDV_(对话框数据校验)
注意,在用数据变量关联控件的方式时,千万注意要使用UpdateData()!
也可以用一个控件变量关联一个控件,用它的成员函数,来对控件进行操作,例如:CEDIT.GetWindowText()
SendMessage()的用法,比较好用,注意,发送消息,是控件向系统发送,由系统处理。
SendDlgItemMessage()。
总结以上:
1, GetDlgItem()->G/SetWindowText()。
2, G/SetDlgItemText()。
3, G/SetDlgItemInt。
4, 将一个控件和一个整型变量相关联。
5, 将一个控件和一个控件变量相关联,用成员函数GetWindowText()和SetWindowText()去访问控件。
6, SendMessage(),可以用平台SDK,也可以用CWND成员函数。
7, SendDlgItemMessage()。
两个好用的消息:EM_GETSEL,EM_SETSEL: 取得与设置选择内容的位置。
改变窗口的大小Wnd::SetWindowPos()对话框从父类继承来的函数。
看一下用控件变量关联控件时,那些成员,例如Button的default。
消息:WM_INITDIALOG,在一个对话框和其上的控件建立完成之后,由对话框发送,当时,对话框还没显示。
Sent to a dialog box before the dialog box is displayed。
伸缩对话框:
判断一个矩形是否为空:IsRectEmpty(), IsRectNull()。前者是判断矩形面积是否为空,后者是判断矩形的四个坐标值是否为0,不关心是否能成为一个矩形。
·····SetWindowPos()改变窗口的大小和Z次序的排列。 ·····
焦点的问题:
SetWindowLong~~~~~~~~ 超强的函数。
::GetNextWindow()
::GetWindow()
::GetNextDlgTabItem()
CWnd::GetWindow()
CWnd::GetNextWindow
CWnd::GetNextDlgTabItem()
缺省OK按钮的ID为IDOK