MFC教程

更新时间:2024-04-16 08:00:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

VS2010/MFC编程入门之二十四(常用控件:列表框控件ListBox)

前面两节讲了比较常用的按钮控件,并通过按钮控件实例说明了具体用法。本文要讲的是列表框控件(ListBox)及其使用实例。 列表框控件简介

列表框给出了一个选项清单,允许用户从中进行单项或多项选择,被选中的项会高亮显示。列表框可分为单选列表框和多选列表框,顾名思义,单选列表框中一次只能选择一个列表项,而多选列表框可以同时选择多个列表项。

列表框也会向父窗口发送通知消息。这些通知消息及含义如下:

LBN_DBLCLK :用户用鼠标双击了一列表项,只有具有LBS_NOTIFY 的列表框才能发送该消息

LBN_ERRSPACE :列表框不能申请足够的动态内存来满足需要 LBN_KILLFOCUS :列表框失去输入焦点

LBN_SELCANCEL: 当前的选择被取消,只有具有LBS_NOTIFY 的列表框才能发送该消息

LBN_SELCHANGE:单击鼠标选择了一列表项,只有具有LBS_NOTIFY 的列表框才能发送该消息

LBN_SETFOCUS:列表框获得输入焦点

WM_CHARTOITEM:当列表框收到WM_CHAR 消息后, 向父窗口发送该消息, 只有具有LBS_WANTKEYBOARDINPUT 风格的列表框才会发送该消息

WM_VKEYTOITEM:当列表框收到WM_KEYDOWN 消息后,向父窗口发送该消息,只有具有LBS_WANTKEYBOARDINPUT 风格的列表框才会发送该消息 列表框控件的创建

MFC将列表框控件的所有操作都封装到了CListBox类中。

创建列表框控件时,可以在对话框模板中直接拖入列表框控件Listbox,然后添加控件变量使用。但如果需要动态创建列表框,就要用到CListBox类的Create成员函数了。Create成员函数的原型如下:

virtual BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

参数rect指定了列表框的位置和尺寸,pParentWnd为父窗口的指针,nID用于指定列表框控件的ID。最后重点讲讲参数dwStyle,它指定了列表框控件的风格,以下是各种风格说明:

LBS_EXTENDEDSEL:支持多重选择,在点击列表项时按住Shift 键或Ctrl 键即可选择多个项

LBS_HASSTRINGS:指定一个含有字符串的自绘式列表框

LBS_MULTICOLUMN:指定一个水平滚动的多列列表框, 通过调用CListBox::SetColumnWidth 来设置每列的宽度

LBS_MULTIPLESEL:支持多重选择。列表项的选择状态随着用户对该项单击或双击鼠标而翻转

LBS_NOINTEGRALHEIGHT:列表框的尺寸由应用程序而不是Windows 指定。通常,Windows指定尺寸会使列表项的某些部分隐藏起来

LBS_NOREDRAW:当选择发生变化时防止列表框被更新,可发送消息改变该风格 LBS_NOTIFY:当用户单击或双击鼠标时通知父窗口

LBS_OWNERDRAWFIXED:指定自绘式列表框,即由父窗口负责绘制列表框的内容,并且列表项有相同的高度

LBS_OWNERDRAWVARIABLE:指定自绘式列表框,并且列表项有不同的高度 LBS_SORT:使插入列表框中的项按升序排列

LBS_STANDARD:相当于指定了WS_BORDER|WS_VSCROLL|LBS_SORT LBS_USETABSTOPS:使列表框在显示列表项时识别并扩展制表符(?\\t?),默认的制表宽度是32 个对话框单位

LBS_WANTKEYBOARDINPUT:允许列表框的父窗口接收WM_VKEYTOITEM 和WM_CHARTOITEM 消息,以响应键盘输入

LBS_DISABLENOSCROLL:使列表框在不需要滚动时显示一个禁止的垂直滚动条 dwStyle可以是以上所列风格的组合。与其他控件一样,除了这些风格一般还要为列表框控件设置WS_CHILD、WS_VISIBLE、WS_TABSTOP、WS_BORDER、WS_VSCROLL等风格。一般创建单选列表框时,风格要设置为:WS_CHILD|WS_VISIBLE|WS_TABSTOP|LBS_STANDARD,如果不希望列表框项排序显示则应去掉LBS_STANDARD。创建多选列表框时,只需要在单选列表框风格后添加LBS_MULTIPLESEL或LBS_EXTENDEDSEL风格。

对于对话框模板中直接添加的列表框控件,其属性页中的属性包含了以上风格,例如属性Multicolumn对应的就是LBS_MULTICOLUMN风格。 CListBox

类的主要成员函数

int GetCount( ) const;

返回值:返回列表框中列表项的数目,如果发生错误则返回LB_ERR。

int GetSel(int nIndex) const; 参数:nIndex指定某个列表项的索引。

返回值:返回nIndex指定列表项的状态。如果此列表项被选择了则返回一个正值,否则返回0,若发生错误则返回LB_ERR。

int SetSel(int nIndex,BOOL bSelect = TRUE);

此函数只用于多选列表框,使用它可以选择或取消选择指定的列表项。

参数:nIndex指定某个列表项的索引,若为-1则相当于指定了所有列表项。bSelect为TRUE时选择指定列表项,否则取消选择指定列表项。 返回值:如果发生错误则返回LB_ERR。 int AddString(LPCTSTR lpszItem);

此函数用来向列表框中添加字符串。如果列表框指定了LBS_SORT风格,字符串就被以排序顺序插入到列表框中,如果没有指定LBS_SORT风格,字符串就被添加到列表框的结尾。

参数:lpszItem指定了要添加的字符串。

返回值:返回字符串在列表框中添加的位置。如果发生错误则返回LB_ERR,内存不够则返回LB_ERRSPACE。

int InsertString(int nIndex, LPCTSTR lpszItem);

该函数用来在列表框中的指定位置插入字符串。与AddString函数不同的是,InsertString函数不会导致LBS_SORT风格的列表框重新排序。不要在具有LBS_SORT风格的列表框中使用InsertString函数,以免破坏列表项的次序。

参数:。参数nIndex 给出了插入位置(索引),如果值为-1,则字符串将被添加到列表的末尾。参数lpszItem 指定了要插入的字符串。

返回值:返回实际的插入位置,若发生错误,会返回LB_ERR 或LB_ERRSPACE。 int DeleteString(UINT nIndex); 该函数用于删除指定的列表项。 参数:nIndex 指定了要删除项的索引。

返回值:函数的返回值为剩下的列表项数目,如果nIndex 超过了实际的表项总数,则返回LB_ERR。

void ResetContent(); 该函数用于清除所有列表项。

int GetText(int nIndex,LPTSTR lpszBuffer) const; void GetText(int nIndex,CString& rString) const;

这两个成员函数用于获取指定列表项的字符串。参数nIndex 指定了列表项的索引。参数lpszBuffer 指向一个接收字符串的缓冲区。引用参数rString 则指定了接收字符串的CString对象。第一个版本的函数会返回获得的字符串的长度,若出错,则返回LB_ERR;第二个版本的函数则不会。

int GetTextLen(int nIndex) const; 该函数返回指定列表项的字符串的字节长度。 参数:nIndex 指定了列表项的索引。 返回值:若出错则返回LB_ERR。

int GetCurSel() const;

该函数仅适用于单选列表框,用来返回当前被选择项的索引,如果没有列表项被选择或有错误发生,则函数返回LB_ERR。 int SetCurSel(int nSelect);

该函数仅适用于单选列表框,用来选择指定的列表项。该函数会滚动列表框以使选择项可见。参数nIndex 指定了列表项的索引,若为-1,那么将清除列表框中的选择。若出错函数返回LB_ERR。

int GetSelCount() const;

该函数仅用于多重选择列表框,它返回选择项的数目,若出错函数返回LB_ERR。 int FindString(int nStartAfter,LPCTSTR lpszItem) const;

该函数用于对列表项进行与大小写无关的搜索。参数nStartAfter 指定了开始搜索的位置,合理指定nStartAfter 可以加快搜索速度,若nStartAfter 为-1,则从头开始搜索整个列表。参数lpszItem 指定了要搜索的字符串。函数返回与lpszItem 指定的字符串相匹配的列表项的索引,若没有找到匹配项或发生了错误,则会返回LB_ERR。FindString 函数先从nStartAfter指定的位置开始搜索,若没有找到匹配项,则会从头开始搜索列表。只有找到匹配项,或对整个列表搜索完一遍后,搜索过程才会停止,所以不必担心会漏掉要搜索的列表项。

int SelectString(int nStartAfter,LPCTSTR lpszItem);

该函数仅适用于单选列表框,用来选择与指定字符串相匹配的列表项。该函数会滚动列表框以使选择项可见。参数的意义及搜索的方法与函数FindString 类似。如果找到了匹配的项,函数返回该项的索引,如果没有匹配的项,函数返回LB_ERR 并且当前的选择不被改变。 CListBox

类应用实例

最后鸡啄米给大家写一个简单的实例,说明CListBox的几个成员函数及通知消息等的

使用方法。此实例实现的功能:在单选列表框中显示一个网站列表,然后在用鼠标左键选择某列表项时,将选中列表项的文本显示到编辑框中。下面是具体实现步骤: 1. 创建一个基于对话框的MFC工程,名称设置为“Example24”。

2. 在自动生成的对话框模板IDD_EXAMPLE24_DIALOG中,删除“TODO: Place dialog controls here.”静态文本控件、“OK”按钮和“Cancel”按钮。添加一个Listbox控件,ID设置为IDC_WEB_LIST,Sort属性设为False,以取消排序显示。再添加一个静态文本控件和一个编辑框,静态文本控件的Caption属性设为“您选择的站点:”,编辑框的ID设为IDC_SEL_WEB_EDIT,Read Only属性设为True。此时的对话框模板如下图:

3. 为列表框IDC_WEB_LIST添加CListBox类型的控件变量m_listBox。

4. 在对话框初始化时,我们将站点名加入到列表框中,那么需要修改CExample24Dlg::OnInitDialog()函数为:

C++代码 1. BOOL CExample24Dlg::OnInitDialog() 2. { 3. CDialogEx::OnInitDialog(); 4. 5. // Add \ 6. 7. // IDM_ABOUTBOX must be in the system command range. 8. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 9. ASSERT(IDM_ABOUTBOX < 0xF000); 10. 11. CMenu* pSysMenu = GetSystemMenu(FALSE); 12. if (pSysMenu != NULL) 13. { 14. BOOL bNameValid; 15. CString strAboutMenu; 16. bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 17. ASSERT(bNameValid); 18. if (!strAboutMenu.IsEmpty()) 19. { 20. pSysMenu->AppendMenu(MF_SEPARATOR); 21. pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 22. } 23. } 24.

25. // Set the icon for this dialog. The framework does this automatically 26. // when the application's main window is not a dialog 27. SetIcon(m_hIcon, TRUE); // Set big icon 28. SetIcon(m_hIcon, FALSE); // Set small icon 29. 30. // TODO: Add extra initialization here 31. m_listBox.AddString(_T(\新浪\)); // 在列表框结尾添加字符串“新浪” 32. m_listBox.AddString(_T(\鸡啄米\)); // 在列表框结尾添加字符串“鸡啄米” 33. m_listBox.AddString(_T(\猫扑\)); // 在列表框结尾添加字符串“猫扑” 34. m_listBox.InsertString(2, _T(\百度\)); // 在列表框中索引为2的位置插入字符串“百度” 35. 36. return TRUE; // return TRUE unless you set the focus to a control 37. } 5. 我们希望在选中列表项改变时,将最新的选择项实时显示到编辑框中,那么这就要用到LBN_SELCHANGE通知消息。为列表框IDC_WEB_LIST的通知消息LBN_SELCHANGE添加消息处理函数CExample24Dlg::OnLbnSelchangeWebList(),并修改如下: C++代码 1. void CExample24Dlg::OnLbnSelchangeWebList() 2. { 3. // TODO: Add your control notification handler code here 4. CString strText; 5. int nCurSel; 6. 7. nCurSel = m_listBox.GetCurSel(); // 获取当前选中列表项 8. m_listBox.GetText(nCurSel, strText); // 获取选中列表项的字符串 9. SetDlgItemText(IDC_SEL_WEB_EDIT, strText); // 将选中列表项的字符串显示到编辑框中 10. } 6. 运行程序,弹出结果对话框,在对话框的列表框中用鼠标改变选中项时,编辑框中的显示会相应改变。效果图如下:

关于列表框ListBox的讲解就到此为止了。大家如果想试验更多的列表框成员函数,可以在上面的小例子中加入更多的功能来体会。最后依然感谢大家对鸡啄米的关注。

VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)

上一节鸡啄米讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box。组合框同样相当常见,例如,在Windows系统的控制面板上设置语言或位置时,有很多选项,用来进行选择的控件就是组合框控件。它为我们的日常操作提供了很多方便。 组合框控件简介

组合框其实就是把一个编辑框和一个列表框组合到了一起,分为三种:简易(Simple)组合框、下拉式(Dropdown)组合框和下拉列表式(Drop List)组合框。下面讲讲它们的区别。

简易组合框中的列表框是一直显示的,效果如下图:

下拉式组合框默认不显示列表框,只有在点击了编辑框右侧的下拉箭头才会弹出列表框,列表框弹出后如下图:

下拉列表式组合框的编辑框是不能编辑的,只能由用户在下拉列表框中选择了某项后,在编辑框中显示其文本。下拉列表式组合框如下图:

经过上面的介绍,大家应该知道,最常用的当属下拉式组合框和下拉列表式组合框了,它们在很多时候能使程序看起来更专业,更简洁,让用户在进行选择操作时更方便。 组合框被操作时会向父窗口发送通知消息,这些通知消息及其含义如下: CBN_CLOSEUP:组合框的列表框组件被关闭,简易组合框不会发送该通知消息 CBN_DBLCLK:用户在某列表项上双击鼠标,只有简易组合框才会发送该通知消息 CBN_DROPDOWN:组合框的列表框组件下拉,简易式组合框不会发送该通知消息 CBN_EDITUPDATE:在编辑框准备显示改变了的正文时发送该消息,下拉列表式组合框不会发送该消息

CBN_EDITCHANGE:编辑框的内容被用户改变了,与CBN_EDITUPDATE不同,该消息是在编辑框显示的正文被刷新后才发出的,下拉列表式组合框不会发送该消息 CBN_ERRSPACE:组合框无法申请足够的内存来容纳列表项

CBN_SELENDCANCEL:表明用户的选择应该取消,当用户在列表框中选择了一项,然后又在组合框控件外单击鼠标时就会导致该消息的发送

CBN_SELENDOK:用户选择了一项,然后按了回车键或单击了下滚箭头,该消息表明用户确认了自己所作的选择

CBN_KILLFOCUS:组合框失去了输入焦点

CBN_SELCHANGE:用户通过单击或移动箭头键改变了列表的选择 CBN_SETFOCUS:组合框获得了输入焦点 组合框控件的创建

MFC将组合框控件的所有操作都封装到了CComboBox类中。

我们在对话框中加入组合框时,可以往对话框模板中拖入Combo Box控件,而后添加CComboBox类型的控件变量使用,但如果我们想在程序中动态创建的话,就要使用CComboBox类的成员函数Create了。Create函数的原型如下:

virtual BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

大家可以看出,CComboBox类的Create成员函数同前面几个控件类的Create成员函数非常类似,dwStyle指定组合框控件的风格,rect为列表框弹出后组合框的位置和尺寸,pParentWnd是指向父窗口的指针,不能为NULL,nID指定组合框控件的ID。最后还是重点讲讲dwStyle参数。组合框控件的风格包括以下几种,并给出了相应说明: CBS_AUTOHSCROLL:使编辑框组件具有水平滚动的风格

CBS_DISABLENOSCROLL:使列表框在不需要滚动时显示一个禁止的垂直滚动条 CBS_DROPDOWN:指定一个下拉式组合框

CBS_DROPDOWNLIST:指定一个下拉列表式组合框 CBS_HASSTRINGS:指定一个含有字符串的自绘式组合框

CBS_LOWERCASE:将编辑框和列表框中的所有文本都自动转换为小写字符 CBS_NOINTEGRALHEIGHT:组合框的尺寸由应用程序而不是Windows 指定,通常,由Windows指定尺寸会使列表项的某些部分隐藏起来

CBS_OEMCONVERT:使编辑框组件中的正文可以在ANSI 字符集和OEM字符集之间相互转换。这在编辑框中包含文件名时是很有用的

CBS_OWNERDRAWFIXED:指定自绘式组合框,即由父窗口负责绘制列表框的内容,并且列表项有相同的高度

CBS_OWNERDRAWVARIABLE:指定自绘式组合框,并且列表项有不同的高度 CBS_SIIMPLE:指定一个简易组合框

CBS_SORT:自动对列表框组件中的项进行排序

CBS_UPPERCASE:将编辑框和列表框中的所有文本都自动转换为大写字符 dwStyle参数可以是以上风格的组合。跟其他控件一样,创建时一般也还要指定WS_CHILD、WS_VISIBLE、WS_TABSTOP和WS_VSCROLL等风格。

在对话框模板中直接添加组合框控件时,其属性页中的属性包含了以上风格,例如属性Uppercase设为True就相当于指定了CBS_UPPERCASE风格。 CComboBox

类的主要成员函数

因为组合框是由编辑框和列表框组合而成的,所以组合框的操作和编辑框与列表框的

操作有很多相似之处,同样的,CComboBox类的成员函数也和CEdit类与CListBox类的成员函数有很多相似之处,不但功能相似,甚至函数名和参数也很相似。鸡啄米下面大概讲解下CComboBox类的主要成员函数,更详细的内容可以参见MSDN。

int GetCount( ) const;

获取组合框控件的列表框中列表项的数量。 int GetCurSel( ) const;

获取组合框控件的列表框中选中项的索引,如果没有选中任何项,该函数返回CB_ERR。

int SetCurSel(int nSelect);

在组合框控件的列表框中选择某项。nSelect参数指定了要选择的列表项的索引,如果为-1则列表框中当前选择项被取消选中,编辑框也被清空。 DWORD GetEditSel( ) const;

获取组合框控件的编辑框中当前选择范围的起始和终止字符的位置。该函数返回一个32位数,低16位存放起始位置,高16位存放选择范围后第一个非选择字符的位置。如果该函数用于下拉列表式组合框时,会返回CB_ERR。 BOOL SetEditSel(int nStartChar,int nEndChar);

用于在组合框控件的编辑框中选择字符。nStartChar参数指定起始位置,nEndChar参数指定终止位置。

DWORD_PTR GetItemData(int nIndex) const;

获取组合框中指定项所关联的32位数据。nIndex参数指定组合框控件的列表框某项的索引(从0开始)。

int SetItemData(int nIndex,DWORD_PTR dwItemData);

为某个指定的组合框列表项设置一个关联的32位数。nIndex参数指定要进行设置的列表项索引。dwItemData参数指定要关联的新值。

void GetLBText(int nIndex,CString& rString) const;

从组合框控件的列表框中获取某项的字符串。nIndex参数指定要获取字符串的列表项的索引,CString参数用于接收取到的字符串。 int GetLBTextLen(int nIndex) const;

获取组合框控件的列表框中某项的字符串长度。nIndex参数指定要获取字符串长度的列表项的索引。

int GetTopIndex( ) const;

获取组合框控件的列表框中第一个可见项的索引。 int SetTopIndex(int nIndex);

将组合框控件的列表框中某个指定项设置为可见的。nIndex参数指定了该列表项的索引。该函数成功则返回0,有错误发生则返回CB_ERR。 BOOL LimitText(int nMaxChars);

用于限制用户在组合框控件的编辑框中能够输入的最大字节长度。nMaxChars参数指定了用户能够输入文字的最大字节长度,如果为0则长度被限制为65535个字节。 int AddString(LPCTSTR lpszString);

为组合框控件中的列表框添加新的列表项。lpszString参数是指向要添加的字符串的指针。该函数的返回值如果大于等于0,那么它就是新列表项的索引,而如果有错误发生则会返回CB_ERR,如果没有足够的内存存放新字符串则返回CB_ERRSPACE。

int DeleteString(UINT nIndex);

删除组合框中某指定位置的列表项。nIndex参数指定了要删除的列表项的索引。该函数的返回值如果大于等于0,那么它就是组合框中剩余列表项的数量。如果nIndex指定的索引超出了列表项的数量则返回CB_ERR。

int FindString(int nStartAfter,LPCTSTR lpszString) const;

在组合框控件的列表框中查找但不选中第一个包含指定前缀的列表项。nStartAfter参数指定了第一个要查找的列表项之前的那个列表项的索引。lpszString指向包含要查找的前缀的字符串。该函数的返回值如果大于等于0,那么它是匹配列表项的索引,如果查找失败则返回CB_ERR。

int InsertString(int nIndex,LPCTSTR lpszString);

向组合框控件的列表框中插入一个列表项。nIndex参数指定了要插入列表项的位置,lpszString参数则指定了要插入的字符串。该函数返回字符串被插入的位置,如果有错误发生则会返回CB_ERR,如果没有足够的内存存放新字符串则返回CB_ERRSPACE。 int SelectString(int nStartAfter,LPCTSTR lpszString);

在组合框控件的列表框中查找一个字符串,如果查找到则选中它,并将其显示到编辑框中。参数同FindString。如果字符串被查找到则返回此列表项的索引,如果查找失败则返回CB_ERR,并且当前选择项不改变。

此外,CComboBox类还继承了CWnd类的成员函数GetWindowText、SetWindowText等。

CComboBox

类应用实例

最后鸡啄米给大家写一个简单的实例,说明CComboBox的几个成员函数及通知消息等的使用方法。此实例实现的功能:在组合框中包含一个网站列表,切换组合框控件的列表框中选择的列表项时,将新选中的列表项的文本显示到编辑框中。下面是具体实现步骤: 1. 创建一个基于对话框的MFC工程,名称设置为“Example25”。

2. 在自动生成的对话框模板IDD_EXAMPLE25_DIALOG中,删除“TODO: Place dialog controls here.”静态文本控件、“OK”按钮和“Cancel”按钮。添加一个Combo Box控件,ID设置为IDC_WEB_COMBO,Type属性设为Drop List,为下拉列表式组合框,编辑框不允许用户输入,Sort属性设为False,以取消排序显示。再添加一个静态文本控件和一个编辑框,静态文本控件的Caption属性设为“您选择的网站:”,编辑框的ID设为IDC_SEL_WEB_EDIT,Read Only属性设为True。此时的对话框模板如下图:

3. 为组合框IDC_WEB_COMBO添加CComboBox类型的控件变量m_comboWeb。 4. 在对话框初始化时,我们将站点名加入到组合框中,并默认选择第一项,那么需要修改CExample25Dlg::OnInitDialog()函数为:

C++代码 1. BOOL CExample25Dlg::OnInitDialog() 2. { 3. CDialogEx::OnInitDialog(); 4. 5. // Add \ 6. 7. // IDM_ABOUTBOX must be in the system command range. 8. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 9. ASSERT(IDM_ABOUTBOX < 0xF000); 10. 11. CMenu* pSysMenu = GetSystemMenu(FALSE); 12. if (pSysMenu != NULL) 13. { 14. BOOL bNameValid; 15. CString strAboutMenu; 16. bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); 17. ASSERT(bNameValid); 18. if (!strAboutMenu.IsEmpty()) 19. { 20. pSysMenu->AppendMenu(MF_SEPARATOR); 21. pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 22. } 23. } 24. 25. // Set the icon for this dialog. The framework does this automatically 26. // when the application's main window is not a dialog 27. SetIcon(m_hIcon, TRUE); // Set big icon 28. SetIcon(m_hIcon, FALSE); // Set small icon 29. 30. // TODO: Add extra initialization here 31. // 为组合框控件的列表框添加列表项“鸡啄米” 32. m_comboWeb.AddString(_T(\鸡啄米\)); 33. // 为组合框控件的列表框添加列表项“百度” 34. m_comboWeb.AddString(_T(\百度\)); 35. // 在组合框控件的列表框中索引为1的位置插入列表项“新浪” 36. m_comboWeb.InsertString(1, _T(\新浪\)); 37. 38. // 默认选择第一项 39. m_comboWeb.SetCurSel(0); 40. // 编辑框中默认显示第一项的文字“鸡啄米” 41. SetDlgItemText(IDC_SEL_WEB_EDIT, _T(\鸡啄米\)); 42. 43. return TRUE; // return TRUE unless you set the focus to a control 44. } 5. 我们希望在组合框中选中的列表项改变时,将最新的选择项实时显示到编辑框中,那么这就要用到CBN_SELCHANGE通知消息。为列表框IDC_WEB_COMBO的通知消息CBN_SELCHANGE添加消息处理函数CExample25Dlg::OnCbnSelchangeWebCombo(),并修改如下: C++代码 1. void CExample25Dlg::OnCbnSelchangeWebCombo() 2. { 3. // TODO: Add your control notification handler code here 4. CString strWeb; 5. int nSel; 6. 7. // 获取组合框控件的列表框中选中项的索引 8. nSel = m_comboWeb.GetCurSel(); 9. // 根据选中项索引获取该项字符串 10. m_comboWeb.GetLBText(nSel, strWeb); 11. // 将组合框中选中的字符串显示到IDC_SEL_WEB_EDIT编辑框中 12. SetDlgItemText(IDC_SEL_WEB_EDIT, strWeb); 13. } 6. 运行程序,弹出结果对话框,在对话框的组合框中改变选择项时,编辑框中的显示会相应改变。效果图如下:

组合框的内容就是这些了。相对于CComboBox类数量不少的成员函数来说,本节的实例只是用到了很少的几个,大家可以根据上面所讲试试其他的成员函数。有问题欢迎继续到鸡啄米来交流讨论。

VS2010/MFC编程入门之二十六(常用控件:滚动条控件Scroll Bar)

VS2010/MFC编程入门之三十(常用控件:树形控件Tree Control 上)

VS2010/MFC编程入门之三十一(常用控件:树形控件Tree Control 下)

前面一节讲了树形控件Tree Control的简介、通知消息以及相关数据结构,本节继续讲下半部分,包括树形控件的创建、CTreeCtrl类的主要成员函数和应用实例。 树形控件的创建

MFC为树形控件提供了CTreeCtrl类,它封装了树形控件的所有操作。

树形控件的创建也是有两种方式,一种是在对话框模板中直接拖入Tree Control控件创建,另一种就是通过CTreeCtrl类的Create成员函数创建。下面主要讲后者。 CTreeCtrl类的Create成员函数的原型如下: virtual BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

此函数的原型与前面讲到的所有控件类的Create函数都类似。dwStyle指定树形控件风格的组合,rect指定树形控件窗口的位置和大小,pParentWnd为指向树形控件父窗口的指针,nID指定树形控件的ID。下面还是主要讲讲树形控件的主要风格以及含义。 TVS_DISABLEDRAGDROP:禁止树形控件发送TVN_BEGINDRAG通知消息,即不支持拖动操作

TVS_EDITLABELS:用户可以编辑节点的标签文本

TVS_HASBUTTONS:显示带有"+"或"-"的小方框来表示某项能否被展开或已展开

TVS_HASLINES:在父节点与子节点间连线以更清晰地显示树的结构 TVS_LINESATROOT:在根节点处连线

TVS_SHOWSELALWAYS:即使控件失去输入焦点,仍显示出项的选择状态 同样,动态创建树形控件时,除了能够指定上述风格的组合外,一般还要指定WS_CHILD和WS_VISIBLE风格。

在对话框模板中直接拖入Tree Control创建树形控件时,可以在树形控件的属性页中设置其风格,与上面的风格是对应的,例如,属性Has Lines对应的就是TVS_HASLINES风格。

CTreeCtrl

类的主要成员函数

CImageList* SetImageList(CImageList * pImageList,int nImageListType); 如果树节点需要显示图标时,则必须先创建一个CImageList类的对象,并为其添加多个图像组成一个图像序列,然后调用SetImageList函数为树形控件设置图像序列,在用InsertItem插入节点时传入所需图像在图像序列中的索引即可。后面的例子中会演示。参数pImageList为指向图像序列类CImageList的对象的指针,若为NULL则删除树形控件的所有图像。参数nImageListType指定图像序列的类型,可以是TVSIL_NORMAL(普通图像序列)或TVSIL_STATE(状态图像序列,用图像表示节点的状态)。 UINT GetCount( ) const; 获取树形控件中节点的数量。

DWORD_PTR GetItemData(HTREEITEM hItem) const;

获取树形控件中某个指定节点的附加32位数据。参数hItem为指定的树节点的句柄。 BOOL SetItemData(HTREEITEM hItem,DWORD_PTR dwData);

为树形控件中某个指定节点设置附加的32位数据。参数hItem同上,dwData为要设置的32位数据。

CString GetItemText(HTREEITEM hItem) const;

获取树形控件中某个指定节点的标签文本。参数hItem同上。返回值是包含标签文本的字符串。

BOOL SetItemText(HTREEITEM hItem,LPCTSTR lpszItem);

为树形控件中某个指定节点设置标签文本。参数hItem同上,lpszItem为包含标签文本的字符串的指针。

HTREEITEM GetNextSiblingItem(HTREEITEM hItem) const;

获取树形控件中某个指定节点的下一个兄弟节点。参数hItem同上。返回值是下一个兄弟节点的句柄。

HTREEITEM GetPrevSiblingItem(HTREEITEM hItem) const;

获取树形控件中某个指定节点的上一个兄弟节点。参数hItem同上。返回值是上一个兄弟节点的句柄。

HTREEITEM GetParentItem(HTREEITEM hItem) const;

获取树形控件中某个指定节点的父节点。参数hItem同上。返回值是父节点的句柄。 HTREEITEM GetRootItem( ) const; 获取树形控件根节点的句柄。

HTREEITEM GetSelectedItem( ) const; 获取树形控件当前选中节点的句柄。 BOOL DeleteAllItems( );

删除树形控件中的所有节点。删除成功则返回TRUE,否则返回FALSE。 BOOL DeleteItem(HTREEITEM hItem);

删除树形控件中的某个节点。参数hItem为要删除的节点的句柄。删除成功则返回TRUE,否则返回FALSE。

HTREEITEM InsertItem(LPCTSTR lpszItem,int nImage,int nSelectedImage,HTREEITEM hParent = TVI_ROOT,HTREEITEM hInsertAfter = TVI_LAST);

在树形控件中插入一个新节点。参数lpszItem为新节点的标签文本字符串的指针,参数nImage为新节点的图标在树形控件图像序列中的索引,参数nSelectedImage为新节点被选中时的图标在图像序列中的索引,参数hParent为插入节点的父节点的句柄,参数hInsertAfter为新节点的前一个节点的句柄,即新节点将被插入到hInsertAfter节点之后。 BOOL SelectItem(HTREEITEM hItem);

选中指定的树节点。参数hItem为要选择的节点的句柄。若成功则返回TRUE,否则返回FALSE。

树形控件的应用实例

最后鸡啄米还是给大家写一个简单的实例,说明CListCtrl类的几个成员函数及树形控件通知消息等的使用方法。

此实例实现的功能:在一个树形控件中显示鸡啄米网站的简单结构分层,共有三层,分别为鸡啄米网站、各个分类和文章。用鼠标左键单击改变选中节点后,将选中节点的文本显示到编辑框中。另外,还要实现一个常见的效果,就是鼠标划过除根节点外的某个树节点时,显示相应的Tip提示信息。下面是具体实现步骤:

1. 创建一个基于对话框的MFC工程,名称设置为“Example31”。

2. 在自动生成的对话框模板IDD_EXAMPLE31_DIALOG中,删除“TODO: Place dialog controls here.”静态文本框、“OK”按钮和“Cancel”按钮。添加一个Tree Control控件,ID设置为IDC_WEB_TREE,属性Has Buttons、Has Lines和Lines At Root都设为True,为了在鼠标划过某个节点时显示提示信息还需要将Info Tip属性设为True。再添加一个静态文本框和一个编辑框,静态文本框的Caption属性设为“您选择的节点:”,编辑框的ID设为IDC_ITEM_SEL_EDIT,Read Only属性设为True。此时的对话框模板如下图:

3. 导入需要为树形控件的节点添加的图标。鸡啄米在这里找了三个32x32的Icon图标,保存到工程的res目录下。然后在Resource View资源视图中,右键点击Icon节点,在右键菜单中选择“Add Resource...”,弹出“Add Resource”对话框,再从左边“Resource type”列表中选择“Icon”,点击右边的“Import...”按钮,就可以选择三个图标文件进行导入了。导入成功后,分别修改它们ID为IDI_WEB_ICON、IDI_CATALOG_ICON和IDI_ARTICLE_ICON。

4. 为树形控件IDC_WEB_TREE添加CTreeCtrl类型的控件变量m_webTree。并在Example31Dlg.h文件中为CExample31Dlg类添加成员对象:CImageList m_imageList;。 5. 在对话框初始化时,我们在树形控件中添加鸡啄米网站的树形结构,那么需要修改CExample31Dlg::OnInitDialog()函数为:

C++代码 1. BOOL CExample31Dlg::OnInitDialog() 2. { 3. CDialogEx::OnInitDialog(); 4. ......略 5. 6. // TODO: Add extra initialization here 7. HICON hIcon[3]; // 图标句柄数组 8. HTREEITEM hRoot; // 树的根节点的句柄 9. HTREEITEM hCataItem; // 可表示任一分类节点的句柄 10. HTREEITEM hArtItem; // 可表示任一文章节点的句柄 11. 12. // 加载三个图标,并将它们的句柄保存到数组 13. hIcon[0] = theApp.LoadIcon(IDI_WEB_ICON); 14. hIcon[1] = theApp.LoadIcon(IDI_CATALOG_ICON); 15. hIcon[2] = theApp.LoadIcon(IDI_ARTICLE_ICON); 16. 17. // 创建图像序列CImageList对象 18. m_imageList.Create(32, 32, ILC_COLOR32, 3, 3); 19. // 将三个图标添加到图像序列 20. for (int i=0; i<3; i++) 21. { 22. m_imageList.Add(hIcon[i]); 23. } 24. 25. // 为树形控件设置图像序列 26. m_webTree.SetImageList(&m_imageList, TVSIL_NORMAL); 27. 28. // 插入根节点 29. hRoot = m_webTree.InsertItem(_T(\鸡啄米\), 0, 0); 30. // 在根节点下插入子节点 31. hCataItem = m_webTree.InsertItem(_T(\互联网\), 1, 1, hRoot, TVI_LAST); 32. // 为“IT互联网”节点添加附加的编号数据,在鼠标划过该节点时显示 33. m_webTree.SetItemData(hCataItem, 1); 34. // 在“IT互联网”节点下插入子节点 35. hArtItem = m_webTree.InsertItem(_T(\百度文章1\), 2, 2, hCataItem, TVI_LAST); 36. // 为“百度文章1”节点添加附加的编号数据,在鼠标划过该节点时显示 37. m_webTree.SetItemData(hArtItem, 2); 38. // 在“IT互联网”节点下插入另一子节点 39. hArtItem = m_webTree.InsertItem(_T(\谷歌文章2\), 2, 2, hCataItem, TVI_LAST); 40. // 为“谷歌文章2”节点添加附加的编号数据,在鼠标划过该节点时显示 41. m_webTree.SetItemData(hArtItem, 3); 42. // 在根节点下插入第二个子节点 43. hCataItem = m_webTree.InsertItem(_T(\数码生活\), 1, 1, hRoot, TVI_LAST); 44. // 为“数码生活”节点添加附加的编号数据,在鼠标划过该节点时显示 45. m_webTree.SetItemData(hCataItem, 4); 46. // 在“数码生活”节点下插入子节点 47. hArtItem = m_webTree.InsertItem(_T(\智能手机文章1\), 2, 2, hCataItem, TVI_LAST); 48. // 为“智能手机文章1”节点添加附加的编号数据,在鼠标划过该节点时显示 49. m_webTree.SetItemData(hArtItem, 5);

50. // 在“数码生活”节点下插入另一子节点 51. hArtItem = m_webTree.InsertItem(_T(\平板电脑文章2\), 2, 2, hCataItem, TVI_LAST); 52. // 为“平板电脑文章2”节点添加附加的编号数据,在鼠标划过该节点时显示 53. m_webTree.SetItemData(hArtItem, 6); 54. // 在根节点下插入第三个子节点 55. hCataItem = m_webTree.InsertItem(_T(\软件开发\), 1, 1, hRoot, TVI_LAST); 56. // 为“软件开发”节点添加附加的编号数据,在鼠标划过该节点时显示 57. m_webTree.SetItemData(hCataItem, 7); 58. // 在“软件开发”节点下插入子节点 59. hArtItem = m_webTree.InsertItem(_T(\编程入门系列1\), 2, 2, hCataItem, TVI_LAST); 60. // 为“C++编程入门系列1”节点添加附加的编号数据,在鼠标划过该节点时显示 61. m_webTree.SetItemData(hArtItem, 8); 62. // 在“软件开发”节点下插入另一子节点 63. hArtItem = m_webTree.InsertItem(_T(\编程入门2\), 2, 2, hCataItem, TVI_LAST); 64. // 为“VS2010/MFC编程入门2”节点添加附加的编号数据,在鼠标划过该节点时显示 65. m_webTree.SetItemData(hArtItem, 9); 66. // 在根节点下插入第四个子节点 67. hCataItem = m_webTree.InsertItem(_T(\娱乐休闲\), 1, 1, hRoot, TVI_LAST); 68. // 为“娱乐休闲”节点添加附加的编号数据,在鼠标划过该节点时显示 69. m_webTree.SetItemData(hCataItem, 10); 70. // 在“娱乐休闲”节点下插入子节点 71. hArtItem = m_webTree.InsertItem(_T(\玛雅文明文章1\), 2, 2, hCataItem, TVI_LAST); 72. // 为“玛雅文明文章1”节点添加附加的编号数据,在鼠标划过该节点时显示 73. m_webTree.SetItemData(hArtItem, 11); 74. // 在“娱乐休闲”节点下插入另一子节点 75. hArtItem = m_webTree.InsertItem(_T(\笑话2\), 2, 2, hCataItem, TVI_LAST); 76. // 为“IT笑话2”节点添加附加的编号数据,在鼠标划过该节点时显示 77. m_webTree.SetItemData(hArtItem, 12); 78. 79. return TRUE; // return TRUE unless you set the focus to a control 80. } 6. 我们希望在选中节点改变时,将最新的选择项实时显示到编辑框中,那么可以响应TVN_SELCHANGED通知消息。为树形控件IDC_WEB_TREE的通知消息TVN_SELCHA

NGED添加消息处理函数CExample31Dlg::OnTvnSelchangedWebTree,并修改函数体如下: C++代码 1. void CExample31Dlg::OnTvnSelchangedWebTree(NMHDR *pNMHDR, LRESULT *pResult) 2. { 3. LPNMTREEVIEW pNMTreeView = reinterpret_cast(pNMHDR); 4. // TODO: Add your control notification handler code here 5. *pResult = 0; 6. 7. CString strText; // 树节点的标签文本字符串 8. 9. // 获取当前选中节点的句柄 10. HTREEITEM hItem = m_webTree.GetSelectedItem(); 11. // 获取选中节点的标签文本字符串 12. strText = m_webTree.GetItemText(hItem); 13. // 将字符串显示到编辑框中 14. SetDlgItemText(IDC_ITEM_SEL_EDIT, strText); 15. } 7. 还有一个功能需要实现,那就是鼠标划过除根节点外的某个树节点时,显示相应的Tip提示信息,本实例中提示信息为节点的编号。这需要响应TVN_GETINFOTIP通知消息。为树形控件IDC_WEB_TREE的通知消息TVN_GETINFOTIP添加消息处理函数CExample31Dlg::OnTvnGetInfoTipWebTree,并修改函数体如下:

C++代码 1. void CExample31Dlg::OnTvnGetInfoTipWebTree(NMHDR *pNMHDR, LRESULT *pResult) 2. { 3. LPNMTVGETINFOTIP pGetInfoTip = reinterpret_cast(pNMHDR); 4. // TODO: Add your control notification handler code here 5. *pResult = 0; 6. NMTVGETINFOTIP* pTVTipInfo = (NMTVGETINFOTIP*)pNMHDR; // 将传入的pNMHDR转换为NMTVGETINFOTIP指针类型 7. HTREEITEM hRoot = m_webTree.GetRootItem(); // 获取树的根节点 8. CString strText; // 每个树节点的提示信息 9. 10. if (pTVTipInfo->hItem == hRoot) 11. { 12. // 如果鼠标划过的节点是根节点,则提示信息为空 13. strText = _T(\); 14. } 15. else 16. { 17. // 如果鼠标划过的节点不是根节点,则将该节点的附加32位数据格式化为字符串 18. strText.Format(_T(\), pTVTipInfo->lParam); 19. } 20. 21. // 将strText字符串拷贝到pTVTipInfo结构体变量的pszText成员中,这样就能显示内容为strText的提示信息 22. wcscpy(pTVTipInfo->pszText, strText); 23. } 8. 运行程序,弹出结果对话框。效果如下图:

树形控件的知识就讲到这里了,相比之前的控件可能稍有复杂。不过用的多了,就会觉得得心应手了。鸡啄米欢迎大家继续关注后面的VS2010/MFC编程入门教程。

VS2010/MFC编程入门之三十六(工具栏:工具栏资源及CToolBar类)

上一节中鸡啄米讲了菜单及CMenu类的使用,这一节讲与菜单有密切联系的工具栏。 工具栏简介

工具栏一般位于主框架窗口的上部,菜单栏的下方,由一些带图片的按钮组成。当用户用鼠标单击工具栏上某个按钮时,程序会执行相应的操作,如果鼠标没有点击,只是停留在某个按钮上一会后,会弹出一个小窗口显示提示信息。

一般工具栏中的按钮在菜单栏中都有对应的菜单项中,即点击工具栏按钮与点击菜单项的效果相同。但工具栏中的按钮都显式的排列出来,操作很方便,而且按钮上的图片描述功能更直观,所以工具栏作为用户操作接口来说比菜单更加便捷。 VS2010

工具栏资源详解

鸡啄米仍然以VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)中创建的单文档工程Example34为基础,讲解工具栏资源。

在Example34工程中,打开Resource View资源视图,展开Example->Example34.rc->Toolbar,我们可以看到有一个ID为IDR_MAINFRAME的工具栏资源,双击打开,工具栏资源显示如下:

以IDR_MAINFRAME工具栏的第一个按钮为例说明工具栏按钮的各项属性。用鼠标单击工具栏资源上的第一个按钮,属性页中就会显示其属性。下面分别讲解各项属性。 ID属性:ID_FILE_NEW。不知大家是否还记得,菜单IDR_MAINFRAME的菜单项File->New的ID也是ID_FILE_NEW,两者ID相同,正是如此才使得工具栏第一个按钮与菜单项File->New能实现相同的功能。所以大家一定要记住,如果想让工具栏某个按钮与菜单栏某个菜单项点击后执行的操作相同,就要为两者设置相同的ID。

Prompt属性:Create a new document\\nNew。此属性为工具栏按钮的提示文本。在鼠标指向此按钮时,状态栏中会显示“Create a new document”,当弹出提示信息窗口时会显示包含“New”的提示信息。“\\n”是两者的分隔转义符。 Height属性:15。此属性为工具栏按钮的像素高度。 Width属性:16。此属性为工具栏按钮的像素宽度。

工具栏资源的最右边总是会有一个待编辑的按钮,我们对其进行编辑后,工具栏资源会自动增加一个新的空白按钮,这也实现了按钮的添加操作。如果我们想要删除某个按钮,就可以用鼠标左键点住它,拖出工具栏资源的范围即可。

另外,我们看到,第三个按钮(保存按钮)和第四个按钮(剪切按钮)之间有一些间隙,在运行程序后会出现一个竖的分隔线,所以想要在两个按钮之间添加分隔线的话,可以用鼠标左键拖住右边的按钮往右稍移动一些就可以了。 CToolBar

类的主要成员函数

MFC为工具栏的操作提供了CToolBar类。下面介绍CToolBar类的主要成员函数。 virtual BOOL CreateEx( CWnd* pParentWnd,

DWORD dwCtrlStyle = TBSTYLE_FLAT,

DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP, CRect rcBorders = CRect(0, 0, 0, 0), UINT nID = AFX_IDW_TOOLBAR );

创建工具栏对象。参数pParentWnd为工具栏父窗口的指针。参数dwCtrlStyle为工具栏按钮的风格,默认为TBSTYLE_FLAT,即“平面的”。参数dwStyle为工具栏的风格,默认取值WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP,由于是主框架窗口的子窗口,所以要有WS_CHILD和WS_VISIBLE风格,CBRS_ALIGN_TOP风格表示工具栏位于父窗口的顶部, 各种风格可以参见MSDN的Toolbar Control and Button Styles中的定义。参数rcBorders为工具栏边框各个方向的宽度,默认为CRect(0, 0, 0, 0),即没有边框。参数nID为工具栏子窗口的ID,默认为AFX_IDW_TOOLBAR。 BOOL LoadBitmap(UINT nIDResource);

为工具栏加载位图。参数nIDResource为位图资源的ID。成功则返回TRUE,否则返回FALSE。注意,这里的位图资源应当为每个工具栏按钮都提供位图,如果图片不是标准大小(16像素宽,15像素高),则需要调用SetSizes成员函数调整按钮大小和图片大小。 BOOL LoadToolBar(UINT nIDResource);

加载由nIDResource指定的工具栏。参数nIDResource为要加载的工具栏的资源ID。成功则返回TRUE,否则返回FALSE。

void SetSizes(SIZE sizeButton,SIZE sizeImage);

设置工具栏按钮的大小和图片的大小。参数sizeButton为工具栏按钮的像素大小。参数sizeImage为图片的像素大小。

void SetButtonStyle(int nIndex,UINT nStyle);

设置工具栏按钮或分隔线的风格,或者为按钮分组。参数nIndex为将要进行设置的按钮或分隔线的索引。参数nStyle为按钮风格,可以是以下取值:

TBBS_BUTTON 标准按钮(默认) TBBS_SEPARATOR 分隔条 TBBS_CHECKBOX 复选框 TBBS_GROUP 标记一组按钮的开始

TBBS_CHECKGROUP 标记一组复选框的开始 TBBS_DROPDOWN 创建下拉列表按钮

TBBS_AUTOSIZE 按钮的宽度根据按钮文本计算,而不基于图片大小 TBBS_NOPREFIX 按钮的文本没有快捷键前缀 UINT GetButtonStyle(int nIndex) const;

获取工具栏按钮或分隔条的风格。风格可参考SetButtonStyle。参数nIndex为按钮或分隔条的索引。

BOOL SetButtonText(int nIndex,LPCTSTR lpszText);

设置工具栏按钮的文本。参数nIndex为工具栏按钮的索引。参数lpszText为指向要设置的文本字符串的指针。设置成功则返回TRUE,否则返回FALSE。 CString GetButtonText(int nIndex) const;

获取工具栏按钮上显示的文本。参数nIndex为工具栏按钮的索引。

本节内容就讲到这里了,下节继续讲解VS2010工具栏的有关知识。谢谢大家对鸡啄米和本教程的持续关注!

VS2010/MFC编程入门之三十七(工具栏:工具栏的创建、停靠与使用)

鸡啄米在上一节教程中讲了工具栏资源及CToolBar类,本节继续讲解工具栏的相关知识,主要内容包括工具栏的创建、停靠与使用。 工具栏的使用

上一节中鸡啄米提到过,一般情况下工具栏中的按钮在菜单栏中都有对应的菜单项,两者实现的功能相同,要想实现这种效果,只需要将工具栏按钮的ID与对应的菜单栏中菜单项的ID设置为相同值即可。

在实际使用工具栏时,除了前面讲的资源编辑外,其他使用与菜单类似。例如,对COMMAND消息和UPDATE_COMMAND_UI消息,可以像VS2010/MFC编程入门之三十五(菜单:菜单及CMenu类的使用)中的菜单应用实例那样为工具栏按钮添加消息处理函数。 如果工具栏按钮对应的菜单项已经添加了消息处理函数,那么就不必再为它添加了,因为它的ID与菜单项相同,所以会调用同样的消息处理函数。这样点击工具栏按钮与点击

相应菜单项执行相同的功能,在菜单项为选中、激活或禁用等状态时,工具栏按钮会有一样的状态。

工具栏的创建

大家在第三十四讲创建的Example34工程的CMainFrame类中看到,它创建工具栏所使用的类并不是常用的CToolBar类,而是CMFCToolBar类。CMFCToolBar类是自VS2008以来MFC提供的类,它与CToolBar类有些类似,但功能更丰富。这里要注意,CMFCToolBar类与CToolBar类并没有任何派生关系。

鸡啄米这里就以CMFCToolBar类来讲讲工具栏的创建步骤: 1. 创建工具栏资源。

2. 构造CMFCToolBar类的对象。

3. 调用CMFCToolBar类的Create或CreateEx成员函数创建工具栏。 4. 调用LoadToolBar成员函数加载工具栏资源。

大家可以对应着看看Example34的CMainFrame类自动生成的代码中创建工具栏的过程。

工具栏IDR_MAINFRAME的资源已经自动创建好。在MainFrm.h文件对CMainFrame类的声明中,定义了CMFCToolBar类的对象作为成员对象:CMFCToolBar m_wndToolBar;。然后在CMainFrame::OnCreate函数的实现中可以看到工具栏的创建以及加载工具栏资源的代码,如下:

C++代码 1. int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 2. { 3. if (CFrameWndEx::OnCreate(lpCreateStruct) == -1) 4. return -1; 5. ......略 6. 7. // 调用CreateEx函数创建工具栏,并调用LoadToolBar函数加载工具栏资源 8. if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || 9. !m_wndToolBar.LoadToolBar(theApp.m_bHiColorIcons ? IDR_MAINFRAME_256 : IDR_MAINFRAME)) 10. { 11. TRACE0(\); 12. return -1; // fail to create 13. } 14. 15. ......略 16. 17. return 0; 18. } 因为创建框架窗口时需要调OnCreate函数,所以工具栏的创建也是在OnCreate中完成的。

工具栏的停靠

在创建好工具栏后,如果想要停靠工具栏,也需要添加相应的停靠代码。工具栏停靠的步骤及需要调用的函数如下(前两个步骤可以颠倒顺序): 1. 在框架窗口中启用停靠。

若要将工具栏停靠到某个框架窗口,则必须启用该框架窗口(或目标)以允许停靠。可以在CFrameWndEx类中调用下面的成员函数来实现: BOOL EnableDocking(DWORD dwDockStyle);

该函数采用一个DWORD参数,用来指定框架窗口的哪个边可以接受停靠,可以有四种取值:CBRS_ALIGN_TOP(顶部)、CBRS_ALIGN_BOTTOM(底部)、CBRS_ALIGN_LEFT(左侧)、CBRS_ALIGN_RIGHT(右侧)。如果希望能够将控制条停靠在任意位置,将CBRS_ALIGN_ANY作为参数传递给EnableDocking。 2. 工具栏启用停靠。

框架窗口启用停靠准备好后,必须以相似的方式准备工具栏。为想要停靠的每一个工具栏CMFCToolBar对象调用下面的函数:

virtual void EnableDocking(DWORD dwAlignment);

允许工具栏停靠到框架窗口,并指定工具栏应停靠的目标边。此函数指定的目标边必须与框架窗口中启用停靠的边匹配,否则工具栏无法停靠,为浮动状态。 3. 停靠工具栏。

当用户试图将工具栏放置在允许停靠的框架窗口某一边时,需要框架CFrameWndEx类调用以下函数:

void DockPane(CBasePane* pBar,UINT nDockBarID=0,LPCRECT lpRect=NULL);

参数pBar为要停靠的控制条的指针,参数nDockBarID为要停靠的框架窗口某条边的ID,可以是以下四种取值:AFX_IDW_DOCKBAR_TOP、AFX_IDW_DOCKBAR_BOTTOM、AFX_IDW_DOCKBAR_LEFT、AFX_IDW_DOCKBAR_RIGHT。

下面我们接着看Example34的CMainFrame类的OnCreate函数实现中,工具栏的停靠过程:

C++代码 1. int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 2. { 3. if (CFrameWndEx::OnCreate(lpCreateStruct) == -1) 4. return -1; 5. 6. ......略 7. 8. // 调用CreateEx函数创建工具栏,并调用LoadToolBar函数加载工具栏资源 9. if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || 10. !m_wndToolBar.LoadToolBar(theApp.m_bHiColorIcons ? IDR_MAINFRAME_256 : IDR_MAINFRAME)) 11. { 12. TRACE0(\); 13. return -1; // fail to create 14. } 15. 16. ......略 17. 18. // TODO: Delete these five lines if you don't want the toolbar and menubar to be dockable 19. m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY); 20. // 为m_wndToolBar启用停靠 21. m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); 22. // 为框架窗口启用停靠 23. EnableDocking(CBRS_ALIGN_ANY); 24. DockPane(&m_wndMenuBar); 25. // 停靠工具栏 26. DockPane(&m_wndToolBar); 27. 28. ......略 29. 30. return 0; 31. } 关于工具栏的知识就讲到这里了。鸡啄米感谢大家长期以来的支持。

前面两节为大家讲了列表视图控件List Control,这一节开始介绍一种特殊的列表--树形控件Tree Control。 树形控件简介

树形控件在Windows系统中是很常见的,例如资源管理器左侧的窗口中就有用来显示目录的树形视图。树形视图中以分层结构显示数据,每层的缩进不同,层次越低缩进越多。树形控件的节点一般都由标签和图标两部分组成,图标用来抽象的描述数据,能够使树形控件的层次关系更加清晰。

树形控件在插入新的树节点时会稍麻烦些,回顾之前的列表框,插入新列表项时调用AddString成员函数就可以了,而对于树形控件则需要指定新节点与已有节点的关系。另外,树形控件与列表视图控件一样,可以在每一个节点的左边加入图标。这些都使得树形控件给人一种复杂的感觉,但我们在使用它一两次后会发现其实树形控件用起来还是很方便的。 树形控件的通知消息

下面列出树形控件特有的通知消息中比较常用的几个:

TVN_SELCHANGING和TVN_SELCHANGED:在用户改变了对树节点的选择时,控件会发送这两个消息。消息会附带一个指向NMTREEVIEW结构的指针,程序可从该结构中获得必要的信息。两个消息都会在该结构的itemOld成员中包含原来的选择项信息,在itemNew成员中包含新选择项的信息,在action成员中表明是用户的什么行为触发了该通知消息(若是TVC_BYKEYBOARD则表明是键盘,若是TVC_BYMOUSE则表明是鼠标,若是TVC_UNKNOWN则表示未知)。两个消息的不同之处在于,如果TVN_SELCHANGING的消息处理函数返回TRUE,那么就阻止选择的改变,如果返回FALSE,则允许改变。 TVN_KEYDOWN:该消息表明了一个键盘事件。消息会附带一个指向NMTVKEYDOWN结构的指针,通过该结构程序可以获得按键的信息。

TVN_BEGINLABELEDIT和TVN_ENDLABELEDIT:分别在用户开始编辑和结束编辑节点的标签时发送。消息会附带一个指向NMTVDISPINFO结构的指针,程序可从该结构中获得必要的信息。在前者的消息处理函数中,可以调用GetEditControl()成员函数返回一个指向用于编辑标题的编辑框的指针。如果处理函数返回FALSE,则允许编辑,如果返回TRUE,则禁止编辑。在后者的消息处理函数中,NMTVDISPINFO结构中的item.pszText指向编辑后的新标题,如果pszText为NULL,那么说明用户放弃了编辑,否则,程序应负责更新节点的标签,这可以由SetItem()或SetItemText()函数来完成。

树形控件的相关数据结构 1. HTREEITEM句柄

树形控件中的每个节点都可以由一个HTREEITEM类型的句柄表示。我们通过CTreeCtrl类的成员函数对树进行访问和操作时,很多时候都要用到HTREEITEM句柄。 2. TVITEM结构体

TVITEM结构体描述了树形控件节点的属性,定义如下:

C++代码 1. typedef struct tagTVITEM { 2. UINT mask; // 包含一些掩码位(下面的括号中列出)的组合,用来表明结构的哪些成员是有效的 3. HTREEITEM hItem; // 树节点的句柄(TVIF_HANDLE) 4. UINT state; // 树节点的状态(TVIF_STATE) 5. UINT stateMask; // 状态的掩码组合(TVIF_STATE) 6. LPTSTR pszText; // 树节点的标签文本(TVIF_TEXT) 7. int cchTextMax; // 标签文本缓冲区的大小(TVIF_TEXT) 8. int iImage; // 树节点的图像索引(TVIF_IMAGE) 9. int iSelectedImage; // 选中项的图像索引(TVIF_SELECTEDIMAGE) 10. int cChildren; // 表明节点是否有子节点,为1则有,为0则没有(TVIF_CHILDREN) 11. LPARAM lParam; // 一个32 位的附加数据(TVIF_PARAM) 12. } TVITEM, *LPTVITEM; 此结构体中多个元素涉及到了图像和状态等,有必要具体解释下。

树形控件节点需要显示图标时,就要为树形控件关联一个图像序列,上面的iImage成员就代表了该结构体对应的树节点的图标在图像序列中的索引,iSelectedImage则代表该树节点被选中时显示的图标在图像序列中的索引。对于如何为树形控件关联图像序列,鸡啄米将在后面的实例中讲到。

stateMask用来说明要获取或设置树节点的哪些状态。下面是state和stateMask的一些常用值及含义:

state 对应的stateMask 含义

TVIS_CUT TVIS_CUT 节点被选择用来进行剪切和粘贴操作

TVIS_DROPHILITED TVIS_DROPHILITED 节点成为拖动操作的目标 TVIS_EXPANDED TVIS_EXPANDED 节点的子节点被展开 TVIS_EXPANDEDONCE TVIS_EXPANDEDONCE 节点的子节点曾经被展开过

TVIS_SELECTED TVIS_SELECTED 节点被选中 lParam在实际开发中常用来存放与树节点有关的附加数据。 3. NMTREEVIEW结构体

NMTREEVIEW结构体中包含了树形控件通知消息的相关信息。树形控件的大多数通知消息都会带有指向该结构体的指针。NMTREEVIEW结构体的定义如下:

C++代码 1. typedef struct tagNMTREEVIEW { 2. NMHDR hdr; // 标准的NMHDR结构 3. UINT action; // 表明是用户的什么行为触发了该通知消息 4. TVITEM itemOld; // 原节点的属性 5. TVITEM itemNew; // 新节点的属性 6. POINT ptDrag; // 事件发生时鼠标的客户区坐标 7. } NMTREEVIEW, *LPNMTREEVIEW; 4. TVINSERTSTRUCT结构体

向树形控件中插入新节点时需要用到TVINSERTSTRUCT结构体,它常与TVM_INSERTITEM消息一起使用。定义如下:

C++代码 1. typedef struct tagTVINSERTSTRUCT { 2. HTREEITEM hParent; // 父节点的句柄 3. HTREEITEM hInsertAfter; // 指明插入到同层中哪一项的后面 4. #if (_WIN32_IE >= 0x0400) 5. union 6. { 7. TVITEMEX itemex; 8. TVITEM item; 9. } DUMMYUNIONNAME; 10. #else 11. TVITEM item; // 要添加的新节点的属性 12. #endif 13. } TVINSERTSTRUCT, *LPTVINSERTSTRUCT; 若hParent成员为TVI_ROOT或NULL,那么新节点将被作为树的根节点插入。hInsertAfter除了可以是某个节点的句柄,还可以有四种取值:TVI_FIRST(插入到树形控件的最前面)、TVI_LAST(插入到树形控件的最后面)、TVI_ROOT(作为根节点插入)和TVI_SORT(按字母顺序插入)。 5. NMTVDISPINFO结构体

NMTVDISPINFO结构体中包含了与树节点的显示有关的信息。定义如下:

C++代码 1. typedef struct tagNMTVDISPINFO { 2. NMHDR hdr; 3. TVITEM item; 4. } NMTVDISPINFO, *LPNMTVDISPINFO; 关于树形控件的使用本节先讲这么多,在下节将继续讲解CTreeCtrl类的相关知识和实例。鸡啄米谢谢大家能一直跟随着我学习VS2010/MFC,继续加油!

VS2010/MFC编程入门之三十八(状态栏的使用详解)

上一节中鸡啄米讲了工具栏的创建、停靠与使用,本节来讲解状态栏的知识。 状态栏简介

状态栏相信大家在很多窗口中都能见到,它总是用来显示各种状态。状态栏实际上也是一个窗口,一般分为几个窗格,每个窗格分别用来显示不同的信息和状态等,如菜单项和工具栏按钮的提示信息。

用MFC向导生成的单文档或多文档程序都会自动创建状态栏,大家可以运行下VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)中创建的Example34程序,在结果界面中可以看到窗口底部有个状态栏,该状态栏被分为了几个窗格,分别用来显示菜单项和工具栏按钮的提示信息及Caps Lock、Num Lock、Scroll Lock键的状态。 当然,我们可以自定义状态栏,加入新的提示信息或指示器。 CStatusBar

MFC为状态栏提供了CStatusBar类,封装了状态栏的属性和操作。 下面是CStatusBar类几个主要的成员函数:

virtual BOOL Create(CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, UINT nID = AFX_IDW_STATUS_BAR);

创建一个状态栏。参数pParentWnd为状态栏父窗口的指针,参数dwStyle为状态栏的风格,除了标准的Windows风格外,它还支持: CBRS_TOP:位于框架窗口的顶部。 CBRS_BOTTOM:位于框架窗口的底部。

CBRS_NOALIGN:父窗口大小改变时状态栏不会被重新定位。 参数nID指定状态栏的ID。

BOOL SetIndicators(const UINT* lpIDArray, int nIDCount);

为每个指示器设置显示文本,具体来说,就是用lpIDArray数组中的对应元素为每个指示器设置一个ID,然后加载每个ID代表的字符串,设置为这些指示器的显示文本。参数lpIDArray为指向一个ID数组的指针,参数nIDCount为lpIDArray数组的元素个数。 UINT GetItemID(int nIndex) const;

获取由nIndex指定的指示器的ID。参数nIndex为要获取ID的指示器索引。 CString GetPaneText(int nIndex) const;

获取状态栏窗格中显示的文本。参数nIndex为要获取文本的窗格的索引。返回值为包含窗格文本的CString对象。

BOOL SetPaneText(int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE);

设置状态栏窗格的显示文本。参数nIndex为要设置文本的窗格的索引,参数lpszNewText为指向新的窗格文本的指针,参数bUpdate表示是否设置后立即更新显示。如果设置成功则返回TRUE,否则返回FALSE。 状态栏的创建

在Example34程序中,我们在CMainFrame类中看到,创建状态栏时使用的是CMFCStatusBar类对象。CMFCStatusBar类是自VS2008以来提供的状态栏类,用法与CStatusBar类相似,甚至很多成员函数也类似,但它的功能更加丰富。关于CMFCStatusBar类的成员函数可以查阅MSDN了解。

鸡啄米下面就以Example34程序的CMFCStatusBar类对象为例,来讲讲状态栏的创建步骤:

1. 构造一个CMFCStatusBar类的对象。

在MainFrm.h文件中,为CMainFrame类定义了一个成员对象:CMFCStatusBar m_wndStatusBar;。

2. 调用CMFCStatusBar::Create函数来创建状态栏窗口。

在CMainFrame::OnCreate函数的实现中,我们可以找到CMFCStatusBar::Create函数的调用:

C++代码 1. if (!m_wndStatusBar.Create(this)) 2. { 3. TRACE0(\); 4. return -1; // fail to create 5. } 3. 调用CMFCStatusBar::SetIndicators函数为状态栏划分窗格,并为每个指示器设置显示文本。

CMFCStatusBar::SetIndicators函数需要一个ID数组的参数,在MainFrm.cpp中,如下定义了一个窗格ID的数组:

C++代码 1. static UINT indicators[] = 2. { 3. ID_SEPARATOR, // status line indicator 4. ID_INDICATOR_CAPS, 5. ID_INDICATOR_NUM, 6. ID_INDICATOR_SCRL, 7. }; indicators数组定义了状态栏窗格的划分信息。第一个元素一般为ID_SEPARATOR,对应的窗格用来显示命令提示信息,上面数组中的后三项为指示器文本的字符串ID,可以根据这些ID在String Table字符串资源中找到相应的字符串,查找方法是,在Resource View资源视图中,打开String Table字符串资源,可以看到有ID、Value和Caption三列,在ID列中找到需要的ID,对应的Caption列文本就是要查找的字符串。ID_INDICATOR_CAPS、ID_INDICATOR_NUM和ID_INDICATOR_SCRL对应的字符串分别是CAP、NUM、SCRL,对应的三个窗格分别为Caps Lock指示器、Num Lock指示器和Scroll Lock指示器。

定义了指示器数组就可以使用CMFCStatusBar::SetIndicators函数为状态栏划分窗格了,依然是在CMainFrame::OnCreate函数中调用:

C++代码 1. m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)); 这样状态栏就创建完成了,之后我们可以通过CMFCStatusBar::SetPaneText设置窗格的文本。

状态栏应用实例

鸡啄米看到网上有很多人在问,怎样在状态栏添加一个时间窗格,用来显示系统时间,本节就给出这样一个实例。此实例依然是在Example34的基础上进行修改的。步骤如下: 1. 在Resource View资源视图中打开String Table字符串资源,然后在最后一行的下一个空白行中,或者任意处点右键选择“New String”,添加一个新的字符串资源,ID为ID_INDICATOR_TIME,Value设为一个不与任何其他字符串资源重复的整数值,Caption设为\,这是为了给时间的显示预留空间,因为状态栏会根据字符串的长度为相应的窗格确定缺省宽度。

2. 在indicators数组的第一个元素ID_INDICATOR_SCRL后插入ID_INDICATOR_TIME。

C++代码 1. static UINT indicators[] = 2. { 3. ID_SEPARATOR, // status line indicator 4. ID_INDICATOR_CAPS, 5. ID_INDICATOR_NUM, 6. ID_INDICATOR_SCRL, 7. ID_INDICATOR_TIME 8. }; 3. 要实时显示系统时间,就需要使用一个定时器,每秒钟更新一次时间显示。在CMainFrame::OnCreate函数中开启定时器,代码如下:

C++代码 1. int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 2. { 3. if (CFrameWndEx::OnCreate(lpCreateStruct) == -1) 4. return -1; 5. 6. ......略 7. 8. // 启动定时器,定时器ID为1,定时时间为1000ms,即1s 9. SetTimer(1, 1000, NULL); 10. 11. return 0; 12. } 4. 在Class View类视图中找到CMainFrame类,右键选择“Properties”,然后在显示出来的属性页中,点工具栏上的Messages按钮,即显示出消息列表,找到WM_TIMER消息,添加其消息处理函数void CMainFrame::OnTimer(UINT_PTR nIDEvent),并修改此函数实现如下:

C++代码 1. void CMainFrame::OnTimer(UINT_PTR nIDEvent) 2. { 3. // TODO: Add your message handler code here and/or call default 4. CString strTime; 5. // 获取系统当前时间,并保存到curTime 6. CTime curTime = CTime::GetCurrentTime(); 7. 8. // 格式化curTime,将字符串保存到strTime 9. strTime = curTime.Format(_T(\)); 10. // 在状态栏的时间窗格中显示系统时间字符串 11. m_wndStatusBar.SetPaneText(4, strTime); 12. 13. CFrameWndEx::OnTimer(nIDEvent); 14. } 5. 运行程序,我们看到状态栏的最后一个窗格中能够实时显示系统时间,如下图:

状态栏的内容就讲这些,其实还是比较简单的。鸡啄米欢迎大家常来此学习。

VS2010/MFC编程入门之二十七(常用控件:图片控件Picture Control)

VS2010/MFC编程入门之四十(文档、视图和框架:各对象之间的关系)

前面一节中鸡啄米进行了文档、视图和框架的概述,本节主要讲解文档、视图、框架结构中各对象之间的关系。 各个对象之间的关系

文档、视图、框架结构中涉及到的对象主要有:应用程序对象、文档模板对象、文档对象、视图对象和框架窗口对象等。根据上一节的概述,大家对它们的概念已经有所了解了,下面就对它们之间的关系进行总结和概括,并对各个关系中用到的类的成员函数进行介绍。 1. 应用程序对象保存了一个文档模板的列表。在任何对象中调用全局函数AfxGetApp都可以获得应用程序对象的指针。通过调用CWinAppEx::GetFirstDocTemplatePosition、CWinAppEx::GetNextDocTemplate函数可以遍历所有的文档模板。

2. 文档模板对象用于维护文档、视图和框架窗口的映射关系,它包含有一个已打开文档的列表。我们可以通过调用CDocTemplate::GetFirstDocPosition、CDocTemplate::GetNextDoc来遍历该文档模板对应的所有文档。

3. 框架窗口对象中包含有指向当前活动视图对象的指针。AfxGetApp()->m_pMainWnd即为主框架窗口对象的指针。我们可以通过调用CFrameWndEx::GetActiveView来获取当前活动视图对象的指针,并且使用CFrameWndEx::GetActiveDocument函数可以获得当前活动视图对应的文档。

4. 文档对象中维护着该文档的视图列表,以及创建该文档的文档模板对象的指针。我们可以通过调用CDocument::GetFirstViewPosition,CDocument::GetNextView来遍历该文档关联的所有视图,调用CDocument::GetDocTemplate获取创建该文档的文档模板对象的指针。

5. 视图是框架窗口的子窗口,它保存有指向对应的文档对象的指针。我们可以通过调用CView::GetParentFrame获取其所属的框架窗口对象的指针,调用CView::GetDocument获取该视图对应的文档对象的指针。

另外,在MDI多文档程序中,调用CMDIFrameWnd::MDIGetActive可以获取当前活动的MDI子窗口。

文档和视图的关系

应用程序可以是单文档程序也可以是多文档程序。单文档程序中主框架窗口和文档框架窗口重合,而多文档程序的主框架窗口中有客户窗口,客户窗口中又包含了多个文档框架窗口。

文档和视图是一对多的关系。一个文档可以对应多个视图,例如在Word中一个文档有普通视图、大纲视图、Web版式视图、阅读版式视图等多种视图。而一个视图只能属于一个文档。最简单的应用程序是单文档单视图程序,除此之外还有单文档多视图程序、多文档程序等。

每个文档对象都保存着一个视图列表,可以通过CDocument::AddView函数添加视图,通过CDocument::RemoveView函数删除视图,在数据发生变化时调用CDocument::UpdateAllViews函数更新所有视图。

在MFC中文档可以有三种视图模式:

1. 文档有多个视图对象,它们是同一个视图类的对象,每个视图对象位于一个独立的文档框架窗口中。

2. 文档的基于同一个视图类的多个视图对象,位于同一个文档框架窗口中。Word的子窗口就是这种视图模式。

3.文档的视图对象属于不同的视图类,但所有的视图对象位于同一文档框架窗口中。 鸡啄米在网上找到了一张分别对应三种视图模式的图如下:

有关文档、视图和框架等对象之间的关系就讲到这里了,鸡啄米谢谢大家一贯的支持。

VS2010/MFC编程入门之四十一(文档、视图和框架:分割窗口)

上一节中鸡啄米讲了文档、视图和框架结构中各对象之间的关系,本节主要讲讲在MFC中如何分割窗口。 分割窗口概述

分割窗口,顾名思义,就是将一个窗口分割成多个窗格,在每个窗格中都包含有视图,

或者是同一类型的视图,或者是不同类型的视图。 MFC分割窗口的方式有两种,动态分割和静态分割。

动态分割窗口通常用于创建同一个文档对应的多个视图,而且这些视图一般都是同一类型的视图,能够在用户编辑文档的不同部分时提供方便。

大家看下Word里的动态分割窗口就很明白了,以Word 2007文档为例,在菜单中点击“视图”->“拆分”,就可以看到一条随鼠标移动的分隔条,当我们在文档中某个位置按下鼠标左键时,分割条就固定了下来,生成了上下两个分割窗格,通过滚动每个窗格中的垂直滚动条可以看到,两个窗格中的内容相同,这就是所说的对应同一个文档的同一类视图。 动态分割窗口最多可以有两行两列。

静态分割窗口比较常见。我们经常能看到某个软件打开后,界面窗口默认被分割成了几个窗格,这就是静态分割窗口。

静态分割窗口指在窗口创建时,分割的窗格就已经生成了,而且用户不能改变窗格的数量和顺序。静态分割窗口最多支持16行16列。通常静态分割窗口的每个窗格中包含不同类的视图,当然也可以是同一类的视图。 CSplitterWnd

MFC中的分割窗口类-CSplitterWnd类提供了分割窗口的功能。CSplitterWnd类中包含一个分割器窗口,该分割器窗口就是一个包含多个窗格的窗口。我们分割窗口时就是直接在此分割器窗口中分割的。

鸡啄米下面介绍三个最常用的成员函数:

C++代码 1. virtual BOOL Create( 2. CWnd* pParentWnd, 3. int nMaxRows, 4. int nMaxCols, 5. SIZE sizeMin, 6. CCreateContext* pContext, 7. DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | SPLS_DYNAMIC_SPLIT, 8. UINT nID = AFX_IDW_PANE_FIRST 9. ); 创建动态分割窗口。参数pParentWnd为分割器窗口的父框架窗口;参数nMaxRows为分割器窗口的最大行数,不能超过2;参数nMaxCols为分割器窗口的最大列数,也不能超过2;参数sizeMin为窗格能显示的最小尺寸,如果窗格尺寸小于sizeMin则不显示;参数pContext为指向CCreateContext结构的指针,大多数情况下可以赋值为父框架窗口的pContext;参数dwStyle指定窗口风格;参数nID为分割窗口的ID,除非分割器窗口嵌入到另一个分割器窗口中,否则可以取值AFX_IDW_PANE_FIRST。

C++代码

1. virtual BOOL CreateStatic(

2. CWnd* pParentWnd, 3. int nRows, 4. int nCols, 5. DWORD dwStyle = WS_CHILD | WS_VISIBLE, 6. UINT nID = AFX_IDW_PANE_FIRST 7. ); 创建静态分割窗口。参数pParentWnd、dwStyle和nID同上;参数nRows为行数,不能超过16;参数nCols为列数,同样不能超过16。

C++代码 1. virtual BOOL CreateView( 2. int row, 3. int col, 4. CRuntimeClass* pViewClass, 5. SIZE sizeInit, 6. CCreateContext* pContext 7. ); 为静态分割窗口创建窗格视图。参数row指定分割器窗口中放置新视图的行;参数col指定放置新视图的列;参数pViewClass指定新视图的CRuntimeClass对象;参数sizeInit指定新视图的初始大小;参数pContext为指向CCreateContext结构的指针,通常可以赋值为传递给父框架窗口的重载函数CFrameWnd::OnCreateClient的pContext参数值。 动态分割窗口

创建动态分割窗口的步骤为:

1. 在父框架类中定义一个CSplitterWnd类型的成员对象。 2. 重载父框架类的CFrameWnd::OnCreateClient成员函数。

3. 在重载的CFrameWnd::OnCreateClient函数中调用CSplitterWnd成员对象的Create函数。

下面鸡啄米给大家一个实例。同样以VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)中创建Example34工程为例,我们要实现在主框架窗口的客户区中创建两行两列的动态分割窗口。以下是创建动态分割窗口的具体步骤:

1. 在MainFrm.h文件中为CMainFrame类添加成员对象:CSplitterWnd m_wndSplitter;。

2. 在Class View类视图中找到CMainFrame类,右键点击,在右键菜单中选择Properties,就会显示属性页,然后在属性页的工具栏上点击Tip为Overrides的按钮,下面的列表中就列出了能够重载的函数,找到OnCreateClient生成重载函数。

3. 在MainFrm.cpp文件中找到刚重载的OnCreateClient函数修改如下:

C++代码 1. BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 2. { 3. // TODO: Add your specialized code here and/or call the base class 4. // 创建动态分割窗口,两行两列 5. return m_wndSplitter.Create(this,2, 2, CSize(10, 10), pContext); 6. 7. //return CFrameWndEx::OnCreateClient(lpcs, pContext); 8. } 4. 在Resource View资源视图中,打开Menu下的IDR_MAINFRAME菜单,在View下添加一个菜单项,Caption设为Splitter Window,ID设为(一定要设为)ID_WINDOW_SPLIT。这样在运行结果界面中点击此菜单项时MFC会执行一些操作显示动态分割窗口。 5. 运行程序,点击菜单中的View->Splitter Window菜单项,创建动态分割窗口后效果如下:

静态分割窗口

创建静态分割窗口的步骤为:

1. 在父框架类中定义一个CSplitterWnd类型的成员对象。 2. 重载父框架类的CFrameWnd::OnCreateClient成员函数。

3. 在重载的CFrameWnd::OnCreateClient函数中调用CSplitterWnd成员对象的CreateStatic成员函数,然后可以调用CSplitterWnd成员对象的CreateView成员函数为每个窗格创建视图。

鸡啄米仍通过Example34工程给大家一个实例,目的是在主框架窗口中的客户区创建一个两行一列的静态分割窗口。如果已经试验过动态分割窗口的创建,那么麻烦撤销那些修改吧。创建静态分割窗口的具体步骤如下:

1. 在MainFrm.h文件中为CMainFrame类添加成员对象:CSplitterWnd m_wndSplitter;。

2. 在Class View类视图中找到CMainFrame类,右键点击,在右键菜单中选择Properties,就会显示属性页,然后在属性页的工具栏上点击Tip为Overrides的按钮,下面的列表中就列出了能够重载的函数,找到OnCreateClient生成重载函数。

3. 在MainFrm.cpp文件中找到刚重载的OnCreateClient函数进行修改。因为鸡啄米没有新建其他视图类,所以上下两个窗格的视图都是CExample34View。为了能识别CExample34View类,还需在MainFrm.cpp文件中添加#include \,在Example34View.h文件中添加#include \。最终OnCreateClient函数修改如下:

C++代码 1. BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 2. { 3. // TODO: Add your specialized code here and/or call the base class 4. CRect rc; 5. 6. // 获取框架窗口客户区的CRect对象 7. GetClientRect(&rc); 8. 9. // 创建静态分割窗口,两行一列 10. if (!m_wndSplitter.CreateStatic(this, 2, 1)) 11. return FALSE; 12. 13. // 创建上面窗格中的视图 14. if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CExample34View), CSize(rc.Width(), rc.Height()/2), pContext)) 15. return FALSE; 16. 17. // 创建下面窗格中的视图 18. if (!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CExample34View), CSize(rc.Width(), rc.Height()/2), pContext)) 19. return FALSE; 20. 21. return TRUE; 22. 23. //return CFrameWndEx::OnCreateClient(lpcs, pContext); 24. } 4. 运行程序,在结果界面中关掉其他面板后效果如下:

如果大家想创建在其中某个窗格中再嵌套分割窗口,那么就需要再定义一个CSplitterWnd对象,以父窗格所在的CSplitterWnd对象为父框架窗口创建分割窗口即可。 分割窗口的内容就讲到这里了。鸡啄米依然谢谢大家的支持。

VS2010/MFC编程入门之四十二(MFC常用类:CString类)

上一节鸡啄米讲了分割窗口的有关知识,本节开始讲解MFC的一些常用类,先来说说CString类。 CString

类简介

CString类作为MFC的常用类,当之无愧。可以这样说,只要是从事MFC开发,基本都会遇到使用CString类的场合。因为字符串的使用比较普遍,而CString类又提供了对字符串的便捷操作,所以它给MFC开发人员带来了高的开发效率,受到了开发者的欢迎。 大家使用VS2010的话,可能会见到CStringT,实际上它是一个操作可变长度字符串的模板类。CStringT模板类有三个实例:CString、CStringA和CStringW,它们分别提供对TCHAR、char和wchar_t字符类型的字符串的操作。char类型定义的是Ansi字符,wchar_t类型定义的是Unicode字符,而TCHAR取决于MFC工程的属性对话框中的Configuration Properties->General->Character Set属性,如果此属性为Use Multi-Byte Character Set,则TCHAR类型定义的是Ansi字符,而如果为Use Unicode Character Set,则TCHAR类型定义的是Unicode字符。

三个字符串类的操作是一样的,只是处理的字符类型不同。鸡啄米以CString类为讲解对象。 CString

类的字符串操作

1. CString类的构造函数

CString类有很多构造函数,这里只介绍几个比较常用的: CString(const CString& stringSrc);

将一个已经存在的CString对象stringSrc的内容拷贝到该CString对象。例如:

C++代码 1. CString str1(_T(\)); // 将常量字符串拷贝到str1 2. CString str2(str1); // 将str1的内容拷贝到str2 CString(LPCTSTR lpch, int nLength);

将字符串lpch中的前nLength个字符拷贝到该CString对象。例如:

C++代码 1. CString str(_T(\),3); // 构造的字符串对象内容为\w\ CString(TCHAR ch, int nLength = 1);

使用此函数构造的CString对象中将含有nLength个重复的ch字符。例如:

本文来源:https://www.bwwdw.com/article/k64p.html

Top