对话框用户界面程序的编写,如何向对话框控件联接数据成员及其实现机理,如何向对话框控关联控件类,如何利用对话框类的成员函数向控件发送消息和获取对话框控件的类指针,如何直接利用对话框控件类操纵对话框控件(发送消息和直接调用成员函数)。如何在程序运行时产生和销毁控件。对话框控件的几种操作方式的优劣比较分析。如何实现对话框的部分收缩和展开。如何让对话框上的文本框在程序启动后立即获得焦点,如何利用SetWindowLong改变窗口的回调函数,通过改变文本框的默认回车处理方式进行演示。实现多个输入文本框间通过回车逐一向下传递焦点的另一种巧妙方法(用缺省按钮来处理)。
1.模态对话框和非模态对话框
模态对话框就是指那种“显示出来就不可以点选位于其下面的对话框”的对话框;反之的就是非模态对话框。
两者的区别:
一. 非模态对话框的模板必须具有Visible风格(Visible=True),否则对话框将不可见,而模态对话框则无需设置该项风格。在实际编程中更加保险的办法是调用CWnd::ShowWindow(SW_SHOW)来显示对话框,而不管对话框是否具有Visible风格。
二. 非模态对话框对象是用new操作符来动态创建的,而不是以成员变量的形式嵌入到别的对象中或以局部变量的形式构建的。通常应在对话框的拥有者窗口类内声明一个指向对话框类的指针成员变量,通过该指针可访问对话框对象。
三. 通过调用CDialog::Create函数来启动对话框,而不是CDialog::DoModal,这是两者之间区别的关键所在。由于Create函数不会启动新的消息循环,对话框与应用程序共用同一个消息循环,这样对话框就不会垄断用户输入。Create在显示了对话框后就立即返回,而DoModal是在对话框被关闭后才返回的。由于在Create返回后,不能确定对话框是否已关闭,这样也就无法确定对话框对象的生存期,因此只好在堆栈中构建对话框对象,而不能以局部变量的形式来构建之。
四. 必须调用CWnd::DestroyWindow而不是CDialog::EndDialog来关闭非模态对话框。调用CWnd::DestroyWindow是直接删除窗口的一般方法。由于缺省的CDialog::OnOK和CDialog::OnCancel函数均调用EndDialog,故程序员必须编写自己的OnOK和OnCancel函数并且在函数中调用DestroyWindow来关闭对话框。
五. 因为是用new操作符构建非模态对话框对象,因此必须在对话框关闭后,用delete操作符删除对话框对象。在屏幕上一个窗口被删除后,框架会调用CWnd::PostNcDestroy,这是一个虚拟函数,程序可以在该函数中完成删除窗口对象的工作,具体代码如下
void CModelessDialog::PostNcDestroy
{delete this; //删除对象}
这样,在删除屏幕上的对话框后,对话框对象将被自动删除。拥有者就不必显式地调用delete来删除对话框对象了。
六. 必须有一个标志表明非模态对话框是否打开的。这样做的原因是用户有可能在打开一个模态对话框的情况下,又一次选择打开命令。程序根据标志来决定是打开一个新的对话框,还是仅仅把原来打开的对话框激活。通常可以用拥有者窗口中的指向对话框对象的指针作为这种标志,当对话框关闭时,给该指针赋NULL值,以表明对话框对象已不存在了。例如:
创建模态对话框
CTestDlg dlg;
dlg.DoModal();
创建非模态对话框
CTestDlg * dlg = new CTestDlg;
dlg->Create(IDD_TEST_DLG);
dlg->ShowWindow(SW_SHOW);
2.在对话框上添加按钮控件和创建按钮:
通过在一个对话框上添加一个按钮控件,然后通过按钮控件来创建一个动态的按钮,不过每一次创建之前都要对其进行判断是否已经创建,如果创建就对其进行销毁,反之就创建一个按钮!
static BOOL bIsCreate = FALSE;//通过一个静态变量来判断! //if (m_bIsCreate == FALSE)//判断按钮是否已创建! if (bIsCreate == FALSE) { m_btn.Create(TEXT("AAA"), BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD, CRect(0, 0, 100, 100), this, 123);//创建一个按钮!按钮其实也是一个窗口! //m_bIsCreate = TRUE; bIsCreate = TRUE; } else { m_btn.DestroyWindow(); //m_bIsCreate = FALSE; bIsCreate = FALSE; } if (!m_btn.m_hWnd)//通过按钮的句柄来进行判断! { m_btn.Create(TEXT("AAA"), BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD, CRect(0, 0, 100, 100), this, 123); } else { m_btn.DestroyWindow(); }
3.在对话框上对静态文本框和编辑文本框的操作:
一.静态文本框不能进行接收通告消息的,如果想要其接收通告消息,就需要进行以下三个方面的修改:a.要对文本框的ID号进行修改。b.在属性中要讲notify勾选上!c.要添加一个消息响应函数.具体的代码如下:
CString str; if (GetDlgItem(IDC_NUMBER1)->GetWindowText(str), str == TEXT("Number1:"))//先获取子控件的指针,再对静态文本框上的内容作修改! { GetDlgItem(IDC_NUMBER1)->SetWindowTextW(TEXT("数值1:")); } else { GetDlgItem(IDC_NUMBER1)->SetWindowTextW(TEXT("Number1:")); }
以上代码的实现功能是:当点击静态文本框上的内容的时候,如果是英文就转换为中文,如果是中文的就转换为英文!
二.对话框控件访问七种方式:GetDlgItem()->Get(Set)WindowText()GetDlgItemText()/SetDlgItemText()GetDlgItemInt()/SetDlgItemInt()将控件和整型变量相关联将控件和控件变量相关联SendMessage()SendDlgItemMessage()下面就是这其中方法的具体实现代码://对编辑框内容的七种操作方法! //第一种方法 int num1, num2, num3; TCHAR ch1[10], ch2[10], ch3[10]; GetDlgItem(IDC_EDIT1)->GetWindowTextW(ch1, 10); GetDlgItem(IDC_EDIT2)->GetWindowTextW(ch2, 10); num1 = _ttoi(ch1);//由字符转换为数值! num2 = _ttoi(ch2); num3 = num1 + num2; _itot_s(num3, ch3, 10);//由数值转换为字符!10代表的是十进制!而不是其数组的容量! GetDlgItem(IDC_EDIT3)->SetWindowTextW(ch3); //第二种方法 int num1, num2, num3; TCHAR ch1[10], ch2[10], ch3[10]; GetDlgItemText(IDC_EDIT1, ch1, 10);//获取文本框的内容 GetDlgItemText(IDC_EDIT2, ch2, 10); num1 = _ttoi(ch1); num2 = _ttoi(ch2); num3 = num1 + num2; _itot_s(num3, ch3, 10); SetDlgItemText(IDC_EDIT3, ch3);//设置文本框的内容! //第三种方法 int num1, num2, num3; num1 = GetDlgItemInt(IDC_EDIT1);//获取文本框的内容,并将其转换为整形数! num2 = GetDlgItemInt(IDC_EDIT2); num3 = num1 + num2; SetDlgItemInt(IDC_EDIT3, num3); //第四种方法 UpdateData();//刷新控件的值到对应的变量 m_num3 = m_num1 + m_num2;//与文本框关联的int成员变量 UpdateData(FALSE);//拷贝变量值到控件显示 //第五种方法 int num1, num2, num3; TCHAR ch1[10], ch2[10], ch3[10]; m_edit1.GetWindowTextW(ch1, 10);//与文本框关联的control的成员变量! m_edit2.GetWindowTextW(ch2, 10); num1 = _ttoi(ch1); num2 = _ttoi(ch2); num3 = num1 + num2; _itot_s(num3, ch3, 10); m_edit3.SetWindowTextW(ch3); //第六种方法 /*int num1, num2, num3; TCHAR ch1[10], ch2[10], ch3[10];*/ ::SendMessage(GetDlgItem(IDC_EDIT1)->m_hWnd, WM_GETTEXT, 10, (LPARAM)ch1);//利用API的函数 ::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);//利用wnd下的函数 m_edit2.SendMessage(WM_GETTEXT, 10, (LPARAM)ch2); num1 = _ttoi(ch1); num2 = _ttoi(ch2); num3 = num1 + num2; _itot_s(num3, ch3, 10); m_edit3.SendMessage(WM_SETTEXT, 10, (LPARAM)ch3); //第七种方法 int num1, num2, num3; TCHAR ch1[10], ch2[10], ch3[10]; SendDlgItemMessage(IDC_EDIT1, WM_GETTEXT, 10, (LPARAM)ch1);//其功能相当于GetDlgItem()和SendMessage()两个函数的功能! SendDlgItemMessage(IDC_EDIT2, WM_GETTEXT, 10, (LPARAM)ch2); num1 = _ttoi(ch1); num2 = _ttoi(ch2); num3 = num1 + num2; _itot_s(num3, ch3, 10); SendDlgItemMessage(IDC_EDIT3, WM_SETTEXT, 10, (LPARAM)ch3); SendDlgItemMessage(IDC_EDIT3, EM_SETSEL, 1, 3);//设置文本复选的内容! m_edit3.SetFocus();//设置焦点!
通过在对话框上的一个按钮来对对话框的收缩与扩展,其主要的步骤就是对分割前窗口的大小获取与分割后窗口的尺寸获取,实现的函数是setwindowpos(),其实现的代码如下:CString str; if (GetDlgItemText(IDC_BUTTON2, str), str == TEXT("收缩<<")) { SetDlgItemText(IDC_BUTTON2, TEXT("扩展>>")); } else { SetDlgItemText(IDC_BUTTON2, TEXT("收缩<<")); } static CRect rectLarge;//保存整个对话框的尺寸 static CRect rectSmall;//保存切割后的对话框的尺寸 if (rectLarge.IsRectNull()) { CRect rectSeparator;//分割线的矩形尺寸! GetWindowRect(&rectLarge); GetDlgItem(IDC_SEPARATOR)->GetWindowRect(&rectSeparator); rectSmall.left = rectLarge.left; rectSmall.right = rectLarge.right; rectSmall.top = rectLarge.top; rectSmall.bottom = rectSeparator.bottom; } if (str == TEXT("收缩<<")) { 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); }
这里有两种方法,第一种就是通过其回调函数来实现,但是在vs2008中,会出现错误,解决不了,其方法也挺麻烦的,所以只是给出如下代码:WNDPROC prevProc; LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if (uMsg == WM_CHAR && 0x0d == wParam) { //::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: 在此添加额外的初始化 prevProc = (WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_hWnd, GWL_WNDPROC, (LONG)WindowProc); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE }
第二种方法:主要在onok()函数中来完成,利用其缺省的性质可以完成我们所需要的功能,以下的一行代码就可以实现://GetDlgItem(IDC_EDIT1)->GetNextWindow()->SetFocus(); //GetFocus()->GetNextWindow()->SetFocus();//获取当前焦点的窗口指针,再获取下一个窗口的指针,设置焦点! /GetFocus()->GetWindow(GW_HWNDNEXT)->SetFocus();//同上的函数! GetNextDlgTabItem(GetFocus())->SetFocus();