1.1 CDialog简单笔记
用来管理对话框控件的CWnd成员函数
函数名 |
功能 |
CheckDlgButton |
选中或不选中按钮控件。 |
CheckRadioButton |
选择一个指定的单选按钮并使同组内的其它单选按钮不被选择。 |
DlgDirList |
往一个列表框中添加文件、目录或驱动器的列表。 |
DlgDirListComboBox |
往一个组合框中的列表框内添加文件、目录或驱动器的列表。 |
DlgDirSelect |
从一个列表框中获得当前选择的文件、目录或驱动器。 |
DlgDirSelectBomboBox |
从一个组合框中获得当前选择的文件、目录或驱动器。 |
GetCheckedRadioButton |
返回指定的单选按钮组中被选择的单选按钮的ID。 |
GetDlgItem |
返回一个指向一给定的控件的临时对象的指针。 |
GetDlgItemInt |
返回在一个指定的控件中由正文表示的数字值。 |
GetDlgItemText |
获得在一个控件内显示的正文。 |
GetNextDlgGroupItem |
返回一个指向一组控件内的下一个或上一个控件的临时对象的指针。 |
GetNextDlgTabItem |
返回下一个tab顺序的控件的临时对象的指针。 |
IsDlgButtonChecked |
返回一个按钮控件的状态。 |
SendDlgItemMessage |
把一个消息传送给一个控件。 |
SetDlgItemInt |
将一个整数转换为正文,并将此正文赋给控件。 |
SetDlgItemText |
设置一个控件显示的正文。 |
1.2 对话框消息处理技巧
有时,为了处理方便,需要把多个ID连续的控件发出的相同消息映射到同一个处理函数上.这就要用到ON_CONTROL_RANGE宏.ON_CONTROL_RANGE消息映射宏的第一个参数是控件消息码,第二和第三个参数分别指明了一组连续的控件ID中的头一个和最后一个ID,最后一个参数是消息处理函数名。例如,要处理一组单选按钮发出的BN_CLICKED消息,相应的消息映射如下所示:
ON_CONTROL_RANGE(BN_CLICKED, IDC_FIRST, IDC_LAST,OnRadioClicked)
函数OnRadioClicked的声明如下,该函数比上面的OnAdd多了一个参数nID以说明发送通知消息的控件ID.
afx_msg void OnRadioClicked(UINT nID);
ClassWizard不支持ON_CONTROL_RANGE宏,所以需要手工建立消息映射和消息处理函数.
提示:事实上,在使用ClassWizard时只要运用一个小小的技巧,就可以把不同控件的通知消息映射到同一个处理函数上,也可以把一个控件的不同通知消息映射到同一个处理函数上.这个技巧就是在用ClassWizard创建消息处理函数时,指定相同的函数名即可.此方法的优点在于控件的ID不必是连续的,缺点是处理函数没有nID参数,因而不能确定是哪一个控件发送的消息.
1.3 动态创建按钮(CButton-Create)
CButton::Create
xxx.h
private:
CButtonm_Btn;
BOOL m_IsbCreated;//判断是否创建,开始一定要在构造函数中设置为FALSE
///
xxx.cpp
void CCDialogTestDlg::OnBnClickedButton1()
{
//TODO: 在此添加控件通知处理程序代码
if(m_IsbCreated == FALSE)
{
m_Btn.Create(_T("动态创建的按钮"), WS_VISIBLE | WS_CHILD |BS_DEFPUSHBUTTON, CRect(0, 0, 150, 50), this, 12333);
m_IsbCreated= TRUE;
}
else
{
m_Btn.DestroyWindow();
m_IsbCreated= FALSE;
}
//m_Btn.ShowWindow(SW_SHOW);
}
--------------------------------------------------------------------------------------------------
1.4 对话框伸缩功能的实现
添加图片控件并设置ID为IDC_SEPARATOR,属性中Sunken为TRUE。
void CCDialogTestDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
CString str;
GetDlgItemText(IDC_BUTTON2, str);
if (str == "扩展窗口>>")
{
SetDlgItemText(IDC_BUTTON2, _T("收缩窗口<<"));
}
else
{
SetDlgItemText(IDC_BUTTON2, _T("扩展窗口>>"));
}
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);
}
}
--------------------------------------------------------------------------------------------------
附加:
1.5 属性表单和向导的创建
使用类CpropertyPage、
CObject
└CCmdTarget
└CWnd
└CDialog
└CpropertyPage
步骤:
根据属性页页数插入多个资源CDialog,属性页资源有三种类型(大、中、小)
备注:分别为各个页创建对话框模板,去掉缺省的OK和Cancel按钮。每页的模板最好具有相同的尺寸,如果尺寸不统一,则框架将根据最大的页来确定标签对话框的大小。
属性页的设置(与普通对话框属性不同)
指定标题(Caption)的内容。标题的内容将显示在该页对应的标签中。
选择System menu—False、TitleBar---True、Style--Child、Border--ThinBorder和Disable ---True。
根据各个页的模板,用ClassWizard分别为每个页创建CPropertyPage类的派生类。这一过程与创建普通对话框类的过程类似,不同的是在创建新类对话框中应在Base class一栏中选择CPropertyPage而不是CDialog。
用ClassWizard为每页加入与控件对应的成员变量,这个过程与为普通对话框类加入成员变量类似。
注意:为了构建一个属性表单,首先需创建一个Cproperty Sheet对象,在该对象头文件中添加
// CPropSheet
#include "Prop1.h"
#include "Prop2.h"
#include "Prop3.h"
.........................
public:
CProp1 m_prop1;
CProp2 m_prop2;
CProp3 m_prop3;
--------------------------------------------------------------------------------------------------
然后在构造函数中调用AddPage添加属性页
CPropSheet::CPropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
:CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
AddPage(&m_prop1);
AddPage(&m_prop2);
AddPage(&m_prop3);
}
CPropSheet::CPropSheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
:CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
AddPage(&m_prop1);
AddPage(&m_prop2);
AddPage(&m_prop3);
}
--------------------------------------------------------------------------------------------------
注意:有两个构造函数,参数不一样。
典型的标签式对话框创建代码:
void CMyView::DoModalPropertySheet()
{
CPropertySheet propsheet;
CMyFirstPage pageFirst; // derived from CPropertyPage
CMySecondPage pageSecond; // derived fromCPropertyPage
// Move member data from the view (or from thecurrently
// selected object in the view, for example).
pageFirst.m_nMember1 = m_nMember1;
pageFirst.m_nMember2 = m_nMember2;
pageSecond.m_strMember3 = m_strMember3;
pageSecond.m_strMember4 = m_strMember4;
propsheet.AddPage(&pageFirst);
propsheet.AddPage(&pageSecond);
if (propsheet.DoModal() == IDOK)
{
m_nMember1 = pageFirst.m_nMember1;
m_nMember2 = pageFirst.m_nMember2;
m_strMember3 = pageSecond.m_strMember3;
m_strMember4 = pageSecond.m_strMember4;
. . .
}
}
--------------------------------------------------------------------------------------------------
向导的创建
但是步骤5创建的表单有问题,比如第一个属性页就不应该有“上一步”的按钮,所以还要设置如下:
// CProp2 message handlers
BOOL CProp2::OnSetActive()
{
// TODO: Add your specialized code here and/or call thebase class
((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
return CPropertyPage::OnSetActive();
}
--------------------------------------------------------------------------------------------------
1. 处理各个属性页(注意判断用户是否选中各个属性页的选项)
LRESULT CProp2::OnWizardNext()
{
// TODO: Add your specialized code here and/or call thebase class
UpdateData();
if( m_football || m_basketball || m_volleyball|| m_swim)
return CPropertyPage::OnWizardNext();
else
{
MessageBox("请选择你的兴趣爱好!");
return -1;
}
}
--------------------------------------------------------------------------------------------------
2. 完成向导:在最后一个属性页中最后调用函数
BOOL CProp3::OnWizardFinish()
{
// TODO: Add your specialized code here and/or call thebase class
int index;
index=((CComboBox*)GetDlgItem(IDC_COMBO3))->GetCurSel();
((CComboBox*)GetDlgItem(IDC_COMBO3))->GetLBText(index,m_strSalary);
return CPropertyPage::OnWizardFinish();//重点
}
--------------------------------------------------------------------------------------------------
1.6 对话框位置和大小设置
1.6.1 限制对话框大小
主要是afx_msg void OnSize(UINT nType, int cx, int cy);的使用
voidCRestrictRectDlg::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
// TODO: Add your message handler codehere
CRect rect;
GetWindowRect(&rect);//获取窗口矩形区
if(cx > 400)
rect.right = rect.left + 400;//窗体宽度不能大于400
if(cy > 300)
rect.bottom = rect.top + 300;//窗体高度不能大于300
if(cx < 200)
rect.right = rect.left + 200;//窗体宽度不能小于200
if(cy < 150)
rect.bottom = rect.top + 150;//窗体高度不能小于150
MoveWindow(&rect);//修改窗体大小
}
--------------------------------------------------------------------------------------------------
1.6.2 限制最大化时窗体大小
主要是这个函数:afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI);
voidCLimitSizeDlg::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
lpMMI->ptMaxSize.x = 800; //设置对话框最大化时的宽度
lpMMI->ptMaxSize.y = 600; //设置对话框最大化时的高度
lpMMI->ptMaxPosition.x = 50; //设置对话框最大化时左边位置
lpMMI->ptMaxPosition.y = 50; //设置对话框最大化时上访位置
CDialog::OnGetMinMaxInfo(lpMMI);
}
--------------------------------------------------------------------------------------------------
注意,可类似制作最小化时窗体大小。
1.6.3 发送最大化或最小化消息
voidCMaxAndMinDlg::OnButton1()
{
PostMessage(WM_SYSCOMMAND,SC_MAXIMIZE,0);
}
voidCMaxAndMinDlg::OnButton2()
{
PostMessage(WM_SYSCOMMAND,SC_MINIMIZE,0);
}
-------------------------------------------------------------------------------------------------
1.6.4 对话框窗口变化时控件适应大小
使用从CDialog派生的一个类cdxCSizingDialog,用于实现可改变大小的对话框,具体要参见源代码。
1.6.5 始终在最上面的窗体
BOOLCTopWindowDlg::OnInitDialog()
{
.....................
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
//始终在最上面的窗体
::SetWindowPos(AfxGetMainWnd()->m_hWnd,HWND_TOPMOST,10,10,450,300,SWP_NOMOVE);
return TRUE; // return TRUE unless you set the focus to a control
}
-------------------------------------------------------------------------------------------------
1.7 自绘对话框
可以根据具体的要求自己绘制美观的对话框,具体参见源代码。
1.8 换肤窗体
主要是一个组件库的使用,具体参见源代码。
1.9 对话框背景
1.9.1 位图背景
方法一:准备一张位图,主要是在OnPaint()中添加位图。
voidCBmpBKDlg::OnPaint()
{
................
else
{
CPaintDC dc(this); //窗体DC
CBitmap m_bitmap; //位图变量
m_bitmap.LoadBitmap(IDB_BITMAP1);//载入位图资源
CDC memdc; //临时DC
memdc.CreateCompatibleDC(&dc);//创建临时DC
memdc.SelectObject(&m_bitmap);//选中位图对象
int width,height;//定义位图宽度和高度
BITMAP bmp;
m_bitmap.GetBitmap(&bmp);//获取位图信息
width = bmp.bmWidth;//位图宽度
height = bmp.bmHeight;//位图高度
CRect rect;
this->GetClientRect(&rect);//获取窗体大小
//将位图绘制在窗体上作为背景
dc.StretchBlt(rect.left,rect.top,rect.Width(),rect.Height(),&memdc,0,0,width,height,SRCCOPY); }
}
-------------------------------------------------------------------------------------------------
方法二:实现CWnd::OnEraseBkgnd消息函数
BOOLCShowImageDlgDlg::OnEraseBkgnd(CDC *pDC)
{
CRect rect;
GetClientRect(&rect);
CDC memDC;
CBitmap cbmp;
CBitmap* bmp = NULL;
cbmp.LoadBitmap(IDB_MYBITMAP);//装载背景位图
BITMAP bmInfo;
cbmp.GetBitmap(&bmInfo);
memDC.CreateCompatibleDC(pDC);
bmp = memDC.SelectObject(&cbmp);
//pDC->BitBlt(0,0,rect.Width(),rect.Height(),&memDC,0,0,SRCCOPY);
pDC->StretchBlt(rect.left,rect.top,rect.Width(),rect.Height(),&memDC,0,0,bmInfo.bmWidth,bmInfo.bmHeight,SRCCOPY);
if (bmp) memDC.SelectObject(bmp);
return TRUE;
}
-------------------------------------------------------------------------------------------------
注:还可使用第三方的类,具体见源代码。
1.9.2 使用笔刷绘制背景
HBRUSHCBrushBKDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC,pWnd, nCtlColor);
// TODO: Change any attributes of the DChere
CBrush m_brush; //定义画刷
m_brush.CreateSolidBrush(RGB(255,0,0));//指定画刷颜色
CRect m_rect;
GetClientRect(m_rect);//客户区矩形
pDC->SelectObject(&m_brush);//选择画刷
pDC->FillRect(m_rect,&m_brush);//填充矩形区
return m_brush;
}
-------------------------------------------------------------------------------------------------
1.9.3 渐变色背景
修改OnPaint()函数即可。
voidCColorChangeDlg::OnPaint()
{
CPaintDC dc(this);
CBrush brush;
CRect rect;
GetClientRect(&rect);
for(int m=255;m>0;m--)
{
int x,y;
x = rect.Width() * m / 255;
y = rect.Height() * m / 255;
brush.DeleteObject();
brush.CreateSolidBrush(RGB(255,m,0));
dc.FillRect(CRect(0,0,x,y),&brush);
}
}
-------------------------------------------------------------------------------------------------
1.9.3 使用CImage类动态加载图片背景
要使用CImage类,就在对话框类的头文件中定义一个:CImage类
CImagem_DlgBKImage;
再在此对话框的OnInitDialog中进行载入,方法为:
charLoatFilePath[256] = "C://Documents and Settings//Administrator//桌面//20090728//20090728//23.jpg";
HRESULT ImageLoad;
CRect rect;
CWnd::GetClientRect(&rect);
ImageLoad= m_DlgBKImage.Load(LoatFilePath);
if(0== ImageLoad)
{
Messagebox("load file error!");
}
InvalidateRect(&rect,TRUE);
再在对话框的OnPaint方法中:
CPaintDCdc(this); // 用于绘制的设备上下文
CRect rect;
GetClientRect(&rect);
if (!m_DlgBKImage.IsNull())
{
m_DlgBKImage.StretchBlt(dc,rect);
}
//当前目录
CString m_strPath;
char chPath[MAX_PATH];
GetModuleFileName(NULL, chPath, MAX_PATH); //得到执行程序的文件名(包括路径);
m_strPath.Format("%s", chPath); //转换成字符串;
int nPos = m_strPath.ReverseFind('\\'); //从右边找到第一个“\\”字符,返回其数组下标的位置
m_strPath = m_strPath.Left(nPos + 1); //保留字符串的前nPos+1个字符(包括“\\”);
m_strPath+= "test.bmp";
//char LoatFilePath[256] =m_strPath+"test.bmp";
HRESULT ImageLoad;
CRect rect;
CWnd::GetClientRect(&rect);
ImageLoad = m_DlgBKImage.Load(m_strPath);