目录
一、MFC简介... 4
1.MFC的组织结构... 4
(1)根类... 4
(2)应用程序体系结构类... 4
(3)可视对象类... 6
(4)通用类... 7
(5)OLE类... 8
(6)ODBC数据库类... 8
2.全局变量和函数... 9
3应用程序向导Wizard. 9
二、windows标准控件... 9
1.按钮... 9
(1)创建按钮... 10
(2)和按钮有关的消息... 10
(3)可能用到的成员函数... 11
2.滚动条... 11
(1)创建滚动条... 11
(2)和滚动条有关的消息... 12
(3)可能用到的方法... 12
3.静态控件... 13
(1)创建方法... 13
(2)和该控件有关的消息... 13
(3)可能用到的函数... 13
4.列表框... 13
(1)创建列表框... 13
(2)和列表框有关的消息... 14
(3)可能用到的函数... 15
5.编辑框... 17
(1)Cedit的样式... 17
(2)和编辑框有关的消息... 17
(3)可能用到的函数... 18
6.组合框... 19
(1)组合框的样式... 20
(2)和组合框有关的消息... 20
7.对话框通用控件... 22
(1)Picture. 22
(2)Spin. 22
(3)Progress 23
(5)Date Time Picker 25
(6)List Control 25
(7)Tree Control 28
(8)Extended Combo Box. 33
三、资源... 35
1.菜单... 35
(1)程序主菜单... 35
(2)快捷菜单... 37
(3)工具栏菜单... 39
2.加速键... 42
3.字符串... 42
4.对话框... 43
(1)CDialog可能用到的函数... 43
(2)在资源视图中插入新的Dialog,编辑需要的控件... 43
(3)为这个对话框建立关联的类... 43
(4)在对话框类中为需要的控件添加需要的数据变量... 43
(5)在需要的源文件中使用这个对话框类... 43
5.图标... 44
6.位图... 44
四、单文档SDI和多文档MDI界面... 45
1.可能用到的概念... 45
2.消息映射... 46
3.核心类... 48
(1)CWinApp. 48
(2)CDocument 48
(3)CView.. 50
(4)CDocTemplate. 51
(5)CFrameWnd. 52
(6)5个核心类的相互访问... 53
4.在程序向导上创建SDI和MDI程序... 53
(1)SDI 53
(2)MDI 53
5.MFC多线程... 57
五、数据库... 57
1.有关数据库的基础知识... 57
(1)CRecordView.. 57
(2)CRecordSet 57
(3)CDatabase. 59
(4)RFX.. 60
2.建立ODBC数据源... 60
3.显示数据库中的数据... 61
4.对记录进行排序... 61
5.增添记录... 62
6.删除记录... 63
7.查询记录... 65
8.修改记录... 66
9.移动到指定的位置... 67
六、多媒体... 68
1.音频播放... 68
(1)使用音频函数的方式... 68
(2)使用MCI的方式... 69
2.视频播放... 77
3.图片显示... 78
(1) 创建SDI工程... 78
(2) 在View类中添加数据成员:... 78
(3) 新数据成员的初始化和销毁:... 78
(4) 通过菜单项打开文件:... 79
(5) 对图片进行绘制:... 81
七、网络编程... 83
1.利用WinInet抓取网页... 83
八、附录... 85
1.Visual Studio 2008的快捷键... 85
正文
一、MFC简介
MFC即Microsoft Foundation Class,封装了很多windows api和windows控件,可以明显的缩短程序设计的周期(填充框架、添加功能即可)
1.MFC的组织结构
按照结构和功能上分类
(1)根类
CObject是MFC中大多数类的基类,这个类有序列化、查询对象运行时信息等功能,序列化是指将对象的数据存储下来;更详细的资料需要查看MSDN文档
Serialize() |
|
IsSerializable() |
|
IsKindof() |
是否是某个类或者派生类 |
GetRuntimeClass() |
包括它的类名、基类名等信息 |
(2)应用程序体系结构类
CWinApp和程序的结构框架有关,基于MFC的应用程序几乎从它派生而来
①CCmdTarget
功能上是消息映射,当对象收到消息后决定应该调用哪一个函数,其他和CCmdTarget有关的类:窗口类CWnd、文档模板类CDocTemplate、文档类CDocument、视类CView、框架窗口类CFrameWnd
②CWinThread
创建和控制线程
CreateThread() |
|
SetThreadPriority() |
|
SuspendThread() |
|
③CWinApp
即应用程序对象,继承自CWinThread、CWinThread又继承自CCmdTarget、CCmdTarget继承自CObject,CWinApp的对象在每个应用程序中都是唯一的
部分数据成员
m_pszAppName |
应用程序的名称 |
m_hInstance |
当前应用程序的实例 |
m_lpCmdLine |
指向命令行参数的指针 |
m_nCmdShow |
窗口开始的显示风格 |
m_bHelpMode |
用户按下shift+f1时是否做出帮助响应 |
m_pActiveWnd |
指向应用程序主窗口的指针 |
m_pszExeName |
应用程序可执行文件的名称 |
m_pszHelpFilePath |
帮助文档的路径 |
m_pszProfileName |
.ini初始化文件名 |
m_pszRegistryKey |
初始化文件存放的位置 |
部分函数成员
DoMessageBox() |
弹出一个对话框 |
|
|
|
|
④文档/视类
CDocument负责管理文档的操作,文档模板对象可以创建不同文档类型的文档对象,并且每个文档对象都有一个指向其文档模板对象的指针
CDocTemplate |
文档模板基类 |
CSingleDocTemplate |
单文档界面的文档模板 |
CMultiDocTemplate |
多文档界面的文档模板 |
CDocument |
文档操作 |
CView |
文档数据显示的基类,继承自CWnd |
CView的派生类
CScrollView |
有滚动条的视图 |
CCtrlView |
有树、列表框等控件的视图 |
CDaoRecordView |
显示数据库记录的视图,多用于DAO的查询结果 |
CEditView |
多行文本编辑器的视图 |
CFormView |
表单模板的视图 |
CListView |
列表框控件的视图 |
CRecordView |
显示数据库记录的视图 |
CRichEditView |
富文本编辑控件的视图 |
CTreeView |
树控件的视图 |
CPreviewView |
支持打印预览 |
(3)可视对象类
①CWnd
窗口类,它的派生类有:SDI应用程序框架窗口类CFrameWnd、MDI应用程序框架窗口类CMIDFrameWnd、MDI应用程序文档框架窗口类CMDIChildWnd
②CMenu
对基础api对象HMenu的封装,负责和菜单有关的操作
③CDialog
对话框类,它的派生类有:文件标准对话框CFileDialog、颜色标准对话框CColorDialog、字体标准对话框CFontDialog、文件打印标准对话框CPrintDialog、查询替换标准对话框CFindReplaceDialog、用户自定义的对话框CDialog
④控件类
静态控件 |
CStatic |
|
按钮 |
CButton |
|
编辑框 |
CEdit |
|
富文本编辑框 |
CRichEditCtrl |
|
滚动条 |
CScrollBar |
|
进度条 |
CProgressCtrl |
|
游标 |
CSliderCtrl |
|
列表框 |
CListBox |
|
组合框 |
CComboBox |
|
位图按钮 |
CBitmapButton |
|
数值调整框spin |
CSpinButtonCtrl |
|
动画显示控件 |
CAnimateCtrl |
|
弹出式说明 |
CToolTipCtrl |
|
热键控件窗口 |
CHotKeyCtrl |
用户可以创建“热键”,使某个操作使用更方便 |
⑤控件条类CControlBar
通常充当工具条、状态条等身份,它的基类有:窗口的基类CStatusBar、工具条上的按钮命令CToolbgar、非模态对话框CDialogBar
⑥绘画对象类CGdiObject
和绘画有关,它的子类有:提供操作GDI位图接口的CBitmap、GDI画刷的CBrush、GDI字体的CFont、GDI调色板的CPalette、GDI画笔的CPen、用于剪裁的GDI域CRgn
⑦设备描述表CDC
和绘画有关,它的子类有:
CPaintDC |
简化了BeginPaint和EndPaint的过程,OnPaint、OnDraw对象的成员函数会用到 |
CClientDC |
用户窗口的设备描述表 |
CWindowDC |
整个窗口的设备描述表,包括用户区和框架区 |
CMetaFileDC |
windows元文件的设备描述表,和图形设备接口GDI有关 |
(4)通用类
①文件类
CFile |
提供二进制磁盘文件的总接口,通过CArchive对象被间接访问 |
CMemFile |
提供访问内存文件的总接口 |
CStdioFile |
提供访问缓存磁盘文件的总接口,通常是文本的方式 |
CArchive |
与CFile对象一起实现对象的持久化 |
②异常类CException
不能直接建立CException对象,通常使用它的派生类;产生异常的描述在异常对象的m_cause成员数据中
CNotSupportedException |
不支持服务 |
CMemoryException |
内存异常 |
CFileException |
文件异常 |
CResourceException |
资源异常 |
COleException |
OLE异常 |
CArchiveException |
档案异常 |
CDaoException |
DAO数据库类异常 |
CDBException |
数据库存取异常 |
CUserException |
用户操作异常 |
③模板收集类
CArray、CMap、CList类使用的是全局帮助函数,可能需要编写特定的帮助函数
CArray |
元素存储在数组中 |
CMap |
将键映射到值 |
CList |
元素存储到链表中 |
CTypedPtrList |
将对象指针存储在链表中 |
CTypedPtrArray |
将对象指针存储在数组中 |
CTypedPtrMap |
将键映射到值,键和值都是指针 |
(5)OLE类
OLE指的是对象连接和嵌入,和复合文档的处理有关(通常见到的word、excel),ActiveX在网络编程方面对OLE做了进一步的扩展
普通类 |
COleDocument、COleItem、COleException |
用户类 |
COleClientDoc、COleClientItem |
服务类 |
COleServer、COleTemplate、COleServerDoc、COleServerItem |
可视编辑容器类 |
COleClientItem、COleLinkingDOC |
数据传输类 |
COleDropSource、COleDropTarget、COleDataSource、COleDataObject |
对话类 |
COleInsertDialog |
其他 |
CRectTracker为复合文档中的某项建立边框,使之可移动和可调整大小 |
(6)ODBC数据库类
CDatabase |
面向ODBC驱动程序的一种标准界面 |
CRecordset |
面向ODBC驱动程序的一种标准界面 |
CRecordView |
CFormView的子类,将查询集和显示的字段关联起来,便于直观操作 |
CFieldExchange |
提供上下文信息,支持记录字段交换 |
CLongBinary |
用于存储二进制对象,比如位图 |
CDBException |
数据库存取异常 |
2.全局变量和函数
一般以Afx开头,函数中不包括数据库类的函数和Dialog Data Exchange的内容
AfxMessageBox() |
弹出一个对话框 |
AfxGetApp() |
获取一个指向CWinApp对象的指针 |
AfxGetInstanceHandle() |
获取当前实例的句柄 |
AfxGetResourceHandle() |
获取一个应用程序资源的句柄 |
AfxGetAppName() |
获取一个指向应用程序名称的字符串指针 |
AfxAbort() |
无条件终止一个应用程序 |
AfxBeginThread() |
启动一个新线程 |
AfxEndThread() |
终止当前线程 |
AfxFormatString() |
格式化字符串 |
AfxRegisterWndClass() |
注册windows窗口类 |
3应用程序向导Wizard
使用特定的框架或者添加一些内置的功能
二、windows标准控件
控件几乎都继承了CWnd类具有窗口的属性,因此具有一些通用的方法,比如显示或隐藏控件MoveWindow()、改变控件的位置SetWindowPos()、设置文本内容SetWindowText(),用代码或者在资源视图中拖拽都可以创建控件;在资源视图中右击控件可以添加变量、根据控件的消息添加一些消息处理的代码;格式->Tab键顺序,依次点击可以得到一个想要的tab键切换顺序;项目上右键选择“MFC类”可以扩展出自定义的控件类
1.按钮
AfxGetMainWnd()->PostMessage(WM_QUIT,0,0);或者使用Dialog::OnOk();都可以退出一个对话窗口
(1)创建按钮
BOOL Create(
//按钮上的文本
LPCTSTR lpszCaption,
//按钮的风格
DWORD dwStyle,
//位置和大小
const RECT& rect,
//父窗口的指针
CWnd* pParentWnd,
//按钮的ID
UINT nID);
按钮的风格
BS_AUTOCHECKBOX |
同BS_CHECKBOX,只是单击时按钮会自动反转 |
BS_AUTORADIOBUTTON |
同BS_RADIOBUTTON,只是单击时按钮会自动反转 |
BS_AUTO3STATE |
同BS_3STATE,只是单击按钮时会改变状态 |
BS_DEFPUSHBUTTON |
默认的命令按钮,回车可以直接选中该按钮 |
BS_GROUPBOX |
组框 |
BS_LEFTTEXT |
按钮上的文本左对齐 |
BS_CHECKBOX |
矩形的可选择框 |
BS_RADIOBUTTON |
圆形的可选择按钮 |
BS_3STATE |
同BS_CHECKBOX,只是有三种选择的状态 |
BS_PUSHBUTTON |
指定一个命令按钮 |
BS_OWNERDRAW |
指定一个自绘制按钮 |
(2)和按钮有关的消息
BN_CLICKED |
单击 |
BN_DOUBLECLICKED |
双击 |
(3)可能用到的成员函数
CButton类的成员函数 |
GetCheck() |
获取check类型按钮的选中状态,未选择0、选择1、不确定2 |
SetCheck() |
设置check类型按钮的选中状态 |
|
GetBitmap() |
获取位图 |
|
SetBitmap() |
设置位图 |
|
GetButtonStyle() |
获取按钮的样式 |
|
SetButtonStyle() |
设置按钮的样式 |
|
GetCursor() |
获取光标 |
|
SetCursor() |
设置按钮上的光标 |
|
GetIcon() |
获取按钮上的图标 |
|
SetIcon() |
设置按钮上的图标 |
|
GetState() |
获取按钮的状态,选中、选择、聚焦 |
|
SetState() |
设置按钮的状态 |
|
继承自CButton类的CBitmapButton |
LoadBitmaps() |
载入位图 |
SizeToContent() |
改变位图的大小以适应按钮 |
|
CWnd类的成员函数 |
CheckDlgButton() |
设置按钮的选中状态 |
CheckRadioButton() |
选择组中的一个按钮 |
|
GetCheckedRadioButton() |
选择组中的一个已被选中的按钮 |
|
IsDlgButtonChecked() |
返回按钮的选中状态 |
|
GetWindowText()、GetWindowTextLength()、SetWindowText() |
和按钮上的文字有关 |
2.滚动条
(1)创建滚动条
BOOL Create(
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
UINT nID);
(2)和滚动条有关的消息
SB_TOP |
滚动到最顶部 |
SB_BOTTOM |
滚动到最底部 |
SB_RIGHT |
滚动到右边 |
SB_LEFT |
滚动到左边 |
SB_PAGEUP |
向上滚动一页 |
SB_PAGEDOWN |
向下滚动一页 |
SB_PAGELEFT |
向左滚动一页 |
SB_PAGERIGHT |
向右滚动一页 |
SB_LINEDOWN |
向下滚动一行 |
SB_LINEUP |
向上滚动一行 |
SB_LINELEFT |
向左滚动一行 |
SB_LINERIGHT |
向右滚动一行 |
SB_THUMBPOSITION |
滚动框移动到最新位置 |
SB_THUMBTRACK |
滚动框被拖动 |
SB_ENDSCROLL |
滚动到最终位置 |
(3)可能用到的方法
EnableScrollBar() |
使滚动条的一个或两个箭头有效或无效 |
GetScrollInfo() |
获取滚动条的消息 |
GetScrollLimit() |
获取滚动条的范围 |
GetScrollPos() |
获取滚动条的当前位置 |
GetScrollRange() |
获取滚动条的滚动范围 |
SetScrollInfo() |
设置滚动条的消息 |
SetScrollPos() |
设置滚动滑块的位置 |
SetScrollRange() |
设置滚动条的滚动范围 |
ShowScrollBar() |
显示或隐藏滚动条 |
3.静态控件
一般用在不发送消息也不接收消息的文本或图形上,但是也能想超文本链接那样响应用户的操作,这就要用到SS_NOTIFY样式向父窗口发送WM_COMMAND消息(记事本查看Visual C++ 2008编写的.rc文件可以发现这个问题)
(1)创建方法
Win32的做法或者在资源视图中通过拖拽添加
(2)和该控件有关的消息
STN_CLICKED |
单击静态控件 |
STN_DBLCLK |
双击静态控件 |
STN_ENABLE |
激活静态控件 |
STN_DISABLE |
禁用静态控件 |
(3)可能用到的函数
CString对象可以直接转换成LPCTSTR而且支持格式化.Format(L“”,…);;尽量使用_tcscpy()、_tcscat()、_tcslen()
ModifyStyle(0,SS_BITMAP); |
控件是位图风格 |
SetBitmap(); |
设置位图 |
HBITMAP bBmp=LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(位图的ID)); |
位图资源转换成HBITMAP |
GetObject(m_bmp.GetBitmap(),sizeof(BITMAP),&bmp); |
位图资源转换成BITMAP |
4.列表框
CListBox可以展示像数组一样的数据,允许单选和多选、自带滚动条;
(1)创建列表框
BOOL Create(
DWORD dwStyle,
const Rect& rect,
CWnd* pParentWnd,
UINT nID);
(2)和列表框有关的消息
列表框向应用可能发送的消息 |
LBN_SELCHANGE |
用户的选择发生了改变 |
LBN_DBCLK |
双击 |
|
LBN_SELCANCLE |
取消选择 |
|
LBN_SETFOCUS |
获取输入焦点 |
|
LBN_KILLFOCUS |
失去输入焦点 |
|
应用向列表框可能发送的消息 |
LB_ADDFILE |
在文件列表中插入指定文件 |
LB_ADDSTRING |
加入项 |
|
LB_DELETESTRING |
删除项 |
|
LB_DIR |
在列表框中列出指定文件 |
|
LB_FINDSTRING |
在列表框中查找指定项 |
|
LB_GETCOUNT |
获取多选列表框中项的数目 |
|
LB_GETCURSEL |
获取当前选中项的索引值 |
|
LB_GETSEL |
获取指定项的选中状态 |
|
LB_GETSELCOUNT |
获取多选列表框中选中的项数 |
|
LB_GETTEXT |
获取指定项的文本 |
|
LB_GETTEXTLEN |
获取指定项的文本的长度 |
|
LB_GETTOPINDEX |
获取列表框中第一项的索引值 |
|
LB_INSERTSTRING |
在指定位置加入项 |
|
LB_RESETCONTENT |
清空所有项 |
|
LB_SETSEL |
设置多选列表框中指定项的选中状态 |
|
LB_SETCURSEL |
设置单选列表框中指定项的选中状态 |
|
LB_SETTOPINDEX |
设置列表框中第一项的索引值 |
(3)可能用到的函数
获取当前目录中的所有条目
//tchBuffer是长度为MAX_PAH的TCHAR类型数组
GetCurrentDirectory(MAX_PATH,tchBuffer);
//设置列表框的显示内容
DlgDirList(tchBuffer,列表框的ID,用于显示路径的静态控件ID,0);
通用方法 |
GetHorizontalExtent() |
获取水平滚动的宽度 |
SetHorizontalExtent() |
设置水平滚动的宽度 |
|
GetItemData() |
获取与列表框项有关的32位数值 |
|
SetItemData() |
设置与列表框项有关的32位数值 |
|
GetItemDataPtr() |
获取某一项的指针 |
|
SetItemDataPtr() |
设置某一项的指针 |
|
GetItemHeight() |
获取某一项的高度 |
|
SetItemHeight() |
设置某一项的高度 |
|
GetItemRect() |
获取列表框的矩形 |
|
GetLocale() |
获取列表框的位置局部标识LCID |
|
SetLocale() |
设置列表框的位置标识LCID |
|
GetSel() |
确定某一项的选择状态 |
|
GetText() |
获取某一项的文本内容 |
|
GetTextLen() |
返回列表框字符串的长度 |
|
GetTopIndex() |
获取第一个项的下标,不一定为0 |
|
GetCount() |
获取项的数目 |
|
ItemFromPoint() |
获取和某点最近的某一项的下标 |
|
SetColumnWidth() |
设置多列列表框的列宽度 |
|
SetTabStops() |
设置列表框的制表位位置 |
|
SetTopIndex() |
设置第一个可见项的下标 |
|
单项选择 |
GetCurSel() |
获取当前选择项的下标 |
SetCurSel() |
设置当前选择项的下标 |
|
多项选择 |
GetAnchorIndex() |
获取当前定位项的下标 |
SetAnchorIndex() |
扩充选择设置开始项(定位项) |
|
GetCaretIndex() |
获取具有光标矩形的项的下标 |
|
SetCaretIndex() |
指定下标项设置光标矩形 |
|
GetSelCount() |
获取当前所选项的数目 |
|
GetSelItems() |
获取被选项的下标装入数组 |
|
SelItemRange() |
切换项范围的选择状态 |
|
SetSel() |
切换项的选择状态 |
|
操作字符串 |
AddString() |
向列表框中加入一个字符串 |
DeleteString() |
向列表框中删除一个字符串 |
|
Dir() |
从当前目录加文件名装入列表框 |
|
FindString() |
搜索一字符串 |
|
FindStringExact() |
搜索第一个符合的字符串 |
|
InsertString() |
在指定下标处插入字符串 |
|
ResetContent() |
清空所有项 |
|
SelectString() |
在单选列表框中搜索并选择一字符串 |
|
可以自定义的虚方法 |
CharToItem() |
自绘制列表框处理WM_CHAR |
CompareItem() |
自绘制列表框项的比较方法 |
|
DeleteItem() |
自绘制列表框删除一项 |
|
DrawItem() |
自绘制列表框重绘时的方法 |
|
MeasureItem() |
自绘制列表框创建时,MFC可以获取列表框的维数 |
|
VKeyToItem() |
处理具有LBS_WANTKEYBOARDINPUT样式的WM_KEYDOWN消息 |
5.编辑框
可以是多行文本的矩形窗口,比如windows中的记事本;UpdateData()针对含有编辑框部分的代码更新
(1)Cedit的样式
资源视图中根据属性设置后,可以在.rc文件中找到这些样式
ES_AUTOHSCROLL |
用户在末尾输入字符时,文本向右滚动 |
ES_AUTOVSCROLL |
用户在末尾输入回车时,光标可以向下移动 |
ES_CENTER |
文本居中 |
ES_LEFT |
文本左对齐 |
ES_LOWERCASE |
编辑框中的字符全部小写 |
ES_MULTILINE |
指定是多行编辑框 |
ES_NOHIDESEL |
失去输入焦点后依然选中文本 |
ES_NUMBER |
Windows95上的编辑框中只能输入数字 |
ES_OEMCONVERT |
字符类型转换 |
ES_PASSWORD |
密码框的形式 |
ES_READONLY |
只读 |
ES_RIGHT |
文本右对齐 |
ES_UPPERCASE |
编辑框中的字符全部大写 |
ES_WANTRETURN |
多行编辑框中按下回车表示插入回车符\r,而不是按下对话框的默认按钮 |
(2)和编辑框有关的消息
低字节是控件的标识,高字节是通知码
编辑框向应用程序发送通知码 |
EN_SETFOCUS |
获取输入焦点 |
EN_KILLFOCUS |
失去输入焦点 |
|
EN_CHANGE |
内容发生改变 |
|
EN_UPDATE |
内容被更新 |
|
EN_MAXTEXT |
用户输入已达到最大限度 |
|
EN_HSCROLL |
内容水平滚动 |
|
EN_VSCROLL |
内容垂直滚动 |
|
应用程序向编辑框发送操作码 |
EM_GETRECT |
获取矩形尺寸 |
EM_SETRECT |
设置矩形尺寸 |
|
EM_LINESCROLL |
设置滚动条的步长 |
|
EM_SETHANDLE |
设置输入内容缓冲区句柄 |
|
EM_GETHANDLE |
获取输入内容缓冲区句柄 |
|
EM_LINELENGTH |
获取文本的长度 |
|
EM_GETFONT |
获取编辑框使用的字体 |
|
EM_GETLINECOUNT |
获取多行文本款的文本行数 |
|
EM_REPLACESEL |
替换编辑框中选中的文本 |
|
EM_SETPASSWORDCHAR |
设置密码编辑框中的替代字符 |
|
EM_GETPASSWORDCHAR |
获取密码编辑框中的替代字符 |
|
EM_SETREADONLY |
编辑框只读 |
|
EM_GETSEL |
获取选中的字体 |
|
EM_SETSEL |
设置选中的字体 |
(3)可能用到的函数
通用方法 |
CanUndo() |
编辑操作是否可撤销 |
Clear() |
删除当前的选择 |
|
Copy() |
以CF_TEXT格式复制选择到剪切板中 |
|
Cut() |
以CF_TEXT格式剪切选择到剪切板中 |
|
EmptyUndoBuffer() |
消除一个编辑框控件的“撤销”标志 |
|
GetFirstVisibleLine() |
确定编辑框控件中的最上面的可视行 |
|
GetModify() |
确定一个编辑框控件的内容是否可修改 |
|
GetPasswordChar() |
当用户输入文本时,编辑框控件中显示的密码字符 |
|
GetRect() |
获取编辑框的矩形 |
|
GetSel() |
获取当前选择的开始和结束字符的位置 |
|
LimitText() |
限定用户文本输入的长度 |
|
LineFromChar() |
获取包含指定字符下标的行的行号 |
|
LineLength() |
获取编辑框控件中一行的长度 |
|
LineScroll() |
滚动多行编辑框控件的文本 |
|
Paste() |
将剪切板中的数据粘贴到光标位置 |
|
ReplaceSel() |
用指定文本替换选中的部分 |
|
SetModify() |
设置或清除编辑框控件的修改标志 |
|
SetPasswordChar() |
当用户输入文本时设置或删除一个显示于编辑框控件中的密码字符 |
|
SetReadOnly() |
只读 |
|
SetSel() |
选择字符的范围 |
|
Undo() |
取消最后一个编辑框控件的操作 |
|
UpdateData() |
更新编辑框及其他控件 |
|
多行编辑框支持的方法 |
FmtLines() |
包含软分行符 |
GetHandle() |
获取控件的句柄 |
|
GetLine() |
获取一行文本 |
|
GetLineCount() |
获取文本行的数目 |
|
LineIndex() |
设置一行的字符下标 |
|
SetHandle() |
设置多行文本框将要用到的句柄 |
|
SetRect() |
设置多行文本框的矩形并更新控件 |
|
SetRectNP() |
设置多行文本框的矩形,但是不重绘控件窗口 |
|
SetTabStops() |
设置制表位tab |
6.组合框
CComboBox是一种即可以输入又可以进行选择的控件,看起来像是编辑框和列表框的组合;资源视图上,一组单选按钮的ID值必须连续、第一个按钮选上Group,而且每一组只有第一个按钮能够创建变量
(1)组合框的样式
CBS_DROPDOWN |
由列表框和编辑框组成,列表框平时不可见 |
CBS_DROPDOWNLIST |
由列表框和静态文本组成,列表框平时不可见 |
CBS_AUTOHSCROLL |
编辑框自动水平滚动 |
CBS_SORT |
列表框中各项按字母序排列 |
CBS_SIMPLE |
列表框可见 |
(2)和组合框有关的消息
组合框向应用程序发送消息 |
CBN_SELCHANGE |
列表框中的选中项发生改变 |
CBN_DBLCLK |
双击 |
|
CBN_SETFOCUS |
组合框获得焦点 |
|
CBN_KILLFOCUS |
组合框失去焦点 |
|
CBN_EDITCHANGE |
编辑框中的文本发生改变 |
|
CBN_EDITUPDATE |
编辑框将显示修改过的文本 |
|
CBN_DROPDOWN |
列表框将下拉 |
|
CBN_CLOSEUP |
列表框将隐藏 |
|
应用程序向组合框发送消息 |
CB_SHOWDROPDWON |
显示下拉列表框 |
CB_ADDSTRING |
添加新项 |
|
CB_DELETESTRING |
删除一项 |
|
CB_INSERTSTRING |
插入新项 |
|
CB_FINDSTRING |
查询列表项 |
|
CB_RESETCONTENT |
清空列表框 |
|
CB_DIR |
在列表框中显示指定目录及文件 |
|
CB_SETCURSEL |
设置列表框中选中项的索引值,并在编辑框中显示 |
|
CB_GETCURSEL |
获取列表框中选中项的索引值 |
|
CB_GETCOUNT |
获取列表框中项的数目 |
|
CB_GETLBTEXT |
获取列边框中指定项的文本 |
|
CB_GETLBTEXTLEN |
获取列边框中指定项的文本长度 |
|
CB_LIMITEXT |
限制编辑框中的字符串长度 |
|
CB_GETEDITSEL |
获取编辑框中的选择 |
|
CB_SETEDITSEL |
设置编辑框中的选择 |
(3)可能用到的函数
Clear() |
删除当前选项,清空编辑框中的内容 |
Copy() |
以CF_TEXT格式将选中内容复制到粘贴板 |
Cut() |
以CF_TEXT格式将选中内容剪切到粘贴板 |
GetComboBoxInfo() |
返回CCombox对象的信息 |
GetCount() |
获取列表框项的数目 |
GetCurSel() |
返回所选列表框条目的顺序号 |
GetEditSel() |
返回DWORD数据,低字节是编辑框中选中文字的开始位置,高字节是结束位置 |
GetItemHeight() |
返回组合框中表示列表条目数 |
GetLBText() |
返回组合框的列表中指定条目的字符串 |
GetLBTextLen() |
返回组合框的列表中指定条目的字符串的长度 |
Paste() |
将粘贴板的内容复制到编辑框 |
SetCurSel() |
选中组合框的指定条目 |
SetMinVisibleItems() |
设置下拉列表中可见条目数 |
SetTopIndex() |
指定下拉列表的第一个可见条目 |
AddString() |
在列表条目中添加一字符串 |
DeleteString() |
从列表项中删除一字符串条目 |
FindString() |
查找第一个和指定字符串匹配的字符串序号 |
InsertString() |
将一字符串插入到指定位置 |
ResetString() |
清空组合空中的所有内容 |
SelectString() |
从列表中查找指定字符串,如果找到将其放到编辑框中 |
用CTime类获取本地时间
CTime tNow =CTime::GetCurrentTime();
CString sNow=tNow.Format("%y/%m/%d");
获取对话框中的某个对象
GetDlgItem();
//使对象有效或无效,选择TRUE、FALSE
EnableWindow();
//是对象显示或隐藏,选择SW_SHOW、SW_HIDE
ShowWindow();
_tcscpy()、_tcscat()、_tcslen()
单选按钮组的状态
//初始化按钮组的状态
CheckedRadioButton(开始的ID,结束的ID,选中的ID);
//获取单选按钮组的选择状态,得到的值和各单选按钮的ID进行比较即可
iAgeRadio=GetCheckedRadioButton(IDC_AGE1_RADIO, IDC_AGE3_RADIO);
7.对话框通用控件
(1)Picture
分隔线
Color属性选择Etched
图片
Type选择Icon或者Bitmap,设置Image属性为对应资源的ID时可以显示图片
(2)Spin
需要和其他控件组合使用,比如Edit控件;Spin适合在一个范围内选择精确值
设置Edit控件只读,Spin控件的Allignment选择Right Align、Auto buddy为TRUE
初始化
CSpinButtonCtrl* pSpin=(CSpinButtonCtrl*)GetDlgItem(IDC_SPIN1);
pSpin->SetRange(0,100);
pSpin->SetPos(50);
pSpin->GetBuddy()->SetWindowTextW(L"5.0");
事件响应
//响应对话框的VM_VSCROLL消息
if(pScrollBar->GetDlgCtrlID()==IDC_SPIN1)
{
CString strValue;
//Spin上下移动变化只是1,除以10.0表示这个步长是0.1
strValue.Format(L"%3.1f",nPos/10.0);
((CSpinButtonCtrl*)pScrollBar)->GetBuddy()->SetWindowTextW(strValue);
}
(3)Progress
进度条
初始化
CProgressCtrl* pProg=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
pProg->SetRange(0,100);
pProg->SetPos(50);
启动进度条
//比如某个按钮按下
CProgressCtrl* pProg=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
pProg->SetPos(0);
SetTimer(2008,100,NULL);
事件响应
//响应对话框的VM_TIMER消息
if(nIDEvent==2008)
{
CProgressCtrl* pProg=(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
pProg->SetPos(pProg->GetPos()+1);
if(pProg->GetPos()>=100)
{
KillTimer(nIDEvent);
AfxMessageBox(L"进行完毕");
}
}
(4)Slider
滑块比较方便在一个范围内选择大致的数值
初始化
CString strText1;
CSliderCtrl* pSlider1=(CSliderCtrl*)GetDlgItem(IDC_SLIDER1);
pSlider1->SetRange(0,100);
pSlider1->SetPos(50);
strText1.Format(L"%d",pSlider1->GetPos());
SetDlgItemText(IDC_STATIC_SLIDER,strText1);
事件响应
//响应对话框的WM_HSCROLL消息
if(pScrollBar->GetDlgCtrlID()==IDC_SLIDER1)
{
CSliderCtrl* pSlide=(CSliderCtrl*)pScrollBar;
CString strText;
strText.Format(L"%d",pSlide->GetPos());
SetDlgItemText(IDC_STATIC_SLIDER,strText);
}
(5)Date Time Picker
用户对时间的输入形式是多样的,这就导致了时间不好解析的问题,这时候选择Date Time Picker是很有意义的
初始化
CDateTimeCtrl* pDT=(CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER1);
CString str=_T("'今天是:'yyyy'/'MM'/'dd");
pDT->SetFormat(str);
对日期时间的解析
CDateTimeCtrl* pDT=(CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER1);
CTime t;
pDT->GetTime(t);
CString str=t.Format(L"%Y/%m/%d %A %H:%M:%S");
AfxMessageBox(str);
(6)List Control
类似文件管理器的文件列表;回调项可能会节省程序的存储空间
CListCtrl可能用到的函数
Create() |
创建列表控件 |
SetBkColor() |
设置背景颜色 |
SetImageList() |
设置图像列表 |
SetItem() |
设置列表项数据 |
GetItemRect() |
获取列表项的矩形 |
GetEditControl() |
获取正在编辑的列表项的Edit控件 |
SetTextColor() |
设置文本颜色 |
SetTextBkColor() |
设置文本背景颜色 |
SetItemText() |
设置列表项的标签文字 |
GetHotItem() |
获取鼠标指向的列表项 |
GetSelectionMark() |
获取当前选中的列表项 |
SubItemHitTest() |
获取指定点下的列表项 |
SetBkImage() |
设置背景图片 |
InsertItem() |
插入列表项 |
EditLabel() |
启动显示编辑标签文字 |
CreateDragImage() |
创建用于拖放的图片 |
列表控件的风格
图标:每项显示32*32图标,图标下面显示标签,可以拖动到视图内任意位置;小图标:每项显示16*16图标,图标右边显示标签,可以拖动到视图内任意位置;列表:每项显示16*16图标、按列排列,图标右边显示标签,不能任意拖动图标;报表:每项占一行,第一列显示16*16的图标,图标右边显示标签,再右边的列显示子项由具体程序决定
Windows控件风格 |
|
hover selection |
鼠标在某一项上停留一定时间就自动选择该项 |
虚拟列表视图 |
可以使用DWORD类型的项,是管理数据交给具体程序,控件只负责焦点和选择功能 |
单击和双击激活 |
允许热点跟踪、单击和双击激活高亮选项 |
拖放列排序 |
在报表中允许通过拖放重新排序各项的顺序 |
列表控件支持的四种图片类型
大图标 |
图标风格的时候使用 |
小图标 |
小图标、列表、报表风格使用 |
应用程序状态 |
用于在图标旁边显示应用程序状体的图片 |
标题栏项 |
在报表风格中用于标题栏的显示 |
设置Edit Labels为TRUE,View的属性为Small Icon,在对话框类中添加变量CImageList m_imageList;
初始化
HICON hIcon[8];
int n;
m_imageList.Create(16,16,0,8,8);
hIcon[0]=AfxGetApp()->LoadIcon(IDI_ICON_WHITE);
hIcon[1]=AfxGetApp()->LoadIcon(IDI_ICON_BLACK);
hIcon[2]=AfxGetApp()->LoadIcon(IDI_ICON_RED);
hIcon[3]=AfxGetApp()->LoadIcon(IDI_ICON_BLUE);
hIcon[4]=AfxGetApp()->LoadIcon(IDI_ICON_YELLOW);
hIcon[5]=AfxGetApp()->LoadIcon(IDI_ICON_CYAN);
hIcon[6]=AfxGetApp()->LoadIcon(IDI_ICON_PURPLE);
hIcon[7]=AfxGetApp()->LoadIcon(IDI_ICON_GREEN);
for(n=0;n<8;++n)
m_imageList.Add(hIcon[n]);
//创建标签资源
static TCHAR* color[]={L"white",L"black",L"red",L"blue",L"yellow",L"cyan",L"purple",L"green"};
//创建控件
CListCtrl* pList=(CListCtrl*)GetDlgItem(IDC_LIST1);
pList->SetImageList(&m_imageList,LVSIL_SMALL);
for(n=0;n<8;++n)
pList->InsertItem(n,color[n],n);
pList->SetBkColor(RGB(0,255,255));
pList->SetTextBkColor(RGB(255,0,255));
在列表LVN_ITEMCHANGED消息中添加代码,获取选中的内容
CListCtrl* pList=(CListCtrl*)GetDlgItem(IDC_LIST1);
int nSelected=pNMLV->iItem;
if(nSelected>=0)
{
CString strItem=pList->GetItemText(nSelected,0);
SetDlgItemText(IDC_STATIC_LIST,strItem);
}
在列表NM_RCLICK消息中添加代码,编辑右键选中的内容
//LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<NMITEMACTIVATE>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
NM_LISTVIEW* pNMListView=(NM_LISTVIEW*)pNMHDR;
CListCtrl* pList=(CListCtrl*)GetDlgItem(IDC_LIST1);
int nSelected=pNMListView->iItem;
if(nSelected>=0)
pList->EditLabel(nSelected);
在列表LVN_ENDLABELEDIT消息中添加代码,更新列表的编辑结果
LVITEM item=pDispInfo->item;
CString str=item.pszText;
str.TrimLeft();
str.TrimRight();
if(str.GetLength()>0)
{
CListCtrl* pList=(CListCtrl*)GetDlgItem(IDC_LIST1);
pList->SetItemText(item.iItem,item.iSubItem,item.pszText);
}
(7)Tree Control
CTreeCtrl可能用到的函数
Create() |
创建树控件 |
GetCount() |
获取结点的数目 |
SetIndent() |
设置每层缩进距离 |
SetIamgeList() |
设置图片列表 |
GetNextItem() |
获取指定结点指定方式下的下一个节点 |
InsertItem() |
插入节点 |
GetChildItem() |
获取子节点 |
GetNextSiblingItem() |
获取下一个兄弟节点 |
GetPrevSiblingItem() |
获取上一个兄弟节点 |
GetParentItem() |
获取父节点 |
GetSelectedItem() |
获取选中的节点 |
GetDropHilightItem() |
获取当前释放目标节点 |
GetRootItem() |
获取根节点 |
GetItem() |
获取指定结点的信息 |
GetEditControl() |
获取编辑框控件 |
SetBkColor() |
设置背景颜色 |
ItemHasChildren() |
判断是否有子节点 |
DeleteItem() |
删除节点 |
DeleteAllItems() |
删除所有节点 |
Expand() |
打开或折叠节点 |
CreateDragImage() |
创建用于拖放的图片 |
SortChildren() |
将某节点下的子节点排序 |
设置Has Buttons为TRUE、这样每个展开项之前就有“+”“-”按钮,设置Has Lines为TRUE、这样每个展开项之前就有虚线连接,设置Lines At Root为TRUE、这样第一层节点之间也有虚线连接,设置Edit Labels为TRUE、是标签可编辑
VERIFY()是个类似assert()的东西
初始化
HICON hIcon[8];
int n;
m_imageList.Create(16,16,0,8,8);
//图标icon资源需要提前制作
hIcon[0]=AfxGetApp()->LoadIcon(IDI_ICON_WHITE);
hIcon[1]=AfxGetApp()->LoadIcon(IDI_ICON_BLACK);
hIcon[2]=AfxGetApp()->LoadIcon(IDI_ICON_RED);
hIcon[3]=AfxGetApp()->LoadIcon(IDI_ICON_BLUE);
hIcon[4]=AfxGetApp()->LoadIcon(IDI_ICON_YELLOW);
hIcon[5]=AfxGetApp()->LoadIcon(IDI_ICON_CYAN);
hIcon[6]=AfxGetApp()->LoadIcon(IDI_ICON_PURPLE);
hIcon[7]=AfxGetApp()->LoadIcon(IDI_ICON_GREEN);
for(n=0;n<8;++n)
m_imageList.Add(hIcon[n]);
CTreeCtrl* pTree=(CTreeCtrl*)GetDlgItem(IDC_TREE1);
//包含有图片的形式
pTree->SetImageList(&m_imageList,TVSIL_NORMAL);
//建树的一种结构
TV_INSERTSTRUCT tvinsert;
//没有父节点
tvinsert.hParent=NULL;
//插入到本层最后
tvinsert.hInsertAfter=TVI_LAST;
//掩码:图标、选中图标、文字
tvinsert.item.mask=TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT;
tvinsert.item.hItem=NULL;
tvinsert.item.state=0;
tvinsert.item.stateMask=0;
//文字的最大长度,编译器忽略该参数、但是写程序的人可以获取到
tvinsert.item.cchTextMax=6;
//选中的时候是黑色
tvinsert.item.iSelectedImage=1;
tvinsert.item.cChildren=0;
tvinsert.item.lParam=0;
//创建第一层
tvinsert.item.iImage=1;
tvinsert.item.pszText=L"father";
HTREEITEM hDad=pTree->InsertItem(&tvinsert);
tvinsert.item.iImage=2;
tvinsert.item.pszText=L"mother";
//表示还有子节点
HTREEITEM hMom=pTree->InsertItem(&tvinsert);
//创建第二层
tvinsert.hParent=hDad;
tvinsert.item.iImage=3;
tvinsert.item.pszText=L"son";
//下面没有子节点
pTree->InsertItem(&tvinsert);
tvinsert.item.pszText=L"daughter";
pTree->InsertItem(&tvinsert);
tvinsert.hParent=hMom;
tvinsert.item.iImage=4;
tvinsert.item.pszText=L"son";
pTree->InsertItem(&tvinsert);
tvinsert.item.pszText=L"daughter";
pTree->InsertItem(&tvinsert);
tvinsert.item.pszText=L"cartoon";
HTREEITEM hOther=pTree->InsertItem(&tvinsert);
//创建第三层
tvinsert.hParent=hOther;
tvinsert.item.iImage=7;
tvinsert.item.pszText=L"Tom";
pTree->InsertItem(&tvinsert);
tvinsert.item.pszText=L"Jerry";
pTree->InsertItem(&tvinsert);
在树控件的TVN_SELCHANGED消息中添加代码,实现获取选中的内容
CTreeCtrl* pTree=(CTreeCtrl*)GetDlgItem(IDC_TREE1);
HTREEITEM hSelected=pNMTreeView->itemNew.hItem;
if(hSelected!=NULL)
{
//总长是9个字符,包括最后的'\0'
TCHAR text[9];
TV_ITEM item;
item.mask=TVIF_HANDLE|TVIF_TEXT;
item.hItem=hSelected;
item.pszText=text;
item.cchTextMax=8;
VERIFY(pTree->GetItem(&item));
SetDlgItemText(IDC_STATIC_TREE,item.pszText);
}
在树控件的TVN_ENDLABELEDIT消息中添加代码,三击实现编辑选中的内容
TVITEM item=pTVDispInfo->item;
CString str=item.pszText;
//换成Trim()、中间输入些空格到底行不行?
str.TrimLeft();
str.TrimRight();
if(str.GetLength()>0)
{
CTreeCtrl* pTree=(CTreeCtrl*)GetDlgItem(IDC_TREE1);
pTree->SetItemText(item.hItem,item.pszText);
}
(8)Extended Combo Box
扩展出来的组合框,实现列表项图标和标签的组合显示
CComboBoxEx可能用到的函数
Create() |
创建扩展组合框控件 |
DeleteItem() |
删除一项 |
GetItem() |
获取指定项信息 |
InsertItem() |
插入一项 |
SetImageList() |
设置图片列表 |
GetEditCtrl() |
获取其中的Edit控件 |
GetComboBoxCtrl() |
获取其中的组合框控件 |
初始化
HICON hIcon[8];
int n;
//这是对话框添加的CImageList变量
m_imageList.Create(16,16,0,8,8);
//图标icon资源需要提前制作
hIcon[0]=AfxGetApp()->LoadIcon(IDI_ICON_WHITE);
hIcon[1]=AfxGetApp()->LoadIcon(IDI_ICON_BLACK);
hIcon[2]=AfxGetApp()->LoadIcon(IDI_ICON_RED);
hIcon[3]=AfxGetApp()->LoadIcon(IDI_ICON_BLUE);
hIcon[4]=AfxGetApp()->LoadIcon(IDI_ICON_YELLOW);
hIcon[5]=AfxGetApp()->LoadIcon(IDI_ICON_CYAN);
hIcon[6]=AfxGetApp()->LoadIcon(IDI_ICON_PURPLE);
hIcon[7]=AfxGetApp()->LoadIcon(IDI_ICON_GREEN);
for(n=0;n<8;++n)
m_imageList.Add(hIcon[n]);
static TCHAR* color[]={L"white",L"black",L"red",L"blue",L"yellow",L"cyan",L"purple",L"green"};
CComboBoxEx* pComboEx=(CComboBoxEx*)GetDlgItem(IDC_COMBOBOXEX1);
pComboEx->SetImageList(&m_imageList);
COMBOBOXEXITEM comboItem;
//和下面的操作有关
comboItem.mask=CBEIF_IMAGE|CBEIF_INDENT|CBEIF_SELECTEDIMAGE|CBEIF_TEXT;
for(n=0;n<3;++n)
{
//该项的索引
comboItem.iItem=n;
//项的图标
comboItem.iImage=n;
//选中时候的图标
comboItem.iSelectedImage=n;
//缩进
comboItem.iIndent=n;
comboItem.pszText=color[n];
pComboEx->InsertItem(&comboItem);
}
三、资源
资源和代码是独立的,资源可以是某个.dll、.exe等二进制文件;另存为.res资源文件,在需要的时候可以导入
1.菜单
(1)程序主菜单
出现在界面的最上方,不可以拖动和删除;在View的构造函数和OnDraw函数中填写代码
①菜单编辑器中的属性
Seperator |
分割线 |
Popup |
弹出式窗口 |
Enabled |
已激活 |
Checked |
被选中 |
Grayed |
被禁用 |
Prompt |
提示信息 |
②COMMAND消息
用户点击菜单项的时候会产生该消息
③UPDATE_COMMAND_UI消息
窗口刷新菜单项的时候产生该消息,会用到CCmdUI对象
Enable() |
禁止或启动该菜单项 |
SetCheck() |
菜单项或工具条前面是否有√ |
SetRadio() |
菜单项或工具条前面是否有· |
SetText() |
设置菜单项的显示文字 |
④ON_COMMAND_RANGE消息
也可以用COMMAND消息一个一个的对菜单项添加代码,但是如果菜单项的ID是连续的话,用ON_COMMAND_RANGE会方便很多;引导程序不支持该消息的自动映射、需要动手写代码完成
a.在View的头文件中填写代码
afx_msg void OnOperColorChange(UINT nID);
b.在View的源文件中填写代码
BEGIN_MESSAGE_MAP(CMy0View, CView)
…
ON_COMMAND_RANGE(ID_OPER_RED,ID_OPER_BLUE,OnOperColorChange)
END_MESSAGE_MAP()
void CMy0View::OnOperColorChange(UINT nID)
{
m_nColorIndex=nID-ID_OPER_RED;
//强制刷新,会重新调用OnDraw函数
Invalidate();
}
⑤UPDATE_COMMAND_UI_RANGE消息
对ID连续的菜单项进行更新;引导程序不支持该消息的自动映射、也是需要动手写代码完成
a.在View的头文件中填写代码
afx_msg void OnUpdateOperColorChange(CCmdUI* pCmdUI);
b.在View的源文件中填写代码
BEGIN_MESSAGE_MAP(CMy0View, CView)
…
ON_UPDATE_COMMAND_UI_RANGE(ID_OPER_RED,ID_OPER_BLUE,OnUpdateOperColorChange)
END_MESSAGE_MAP()
void CMy0View::OnUpdateOperColorChange(CCmdUI* pCmdUI)
{
//pCmdUI和之前声明的起始ID、终止ID有关,事件触发的时候将刷新菜单项
pCmdUI->SetRadio(m_nColorIndex==(pCmdUI->m_nID-ID_OPER_RED));
}
(2)快捷菜单
程序主菜单中已经有其中的菜单项,为了方便右键时出现的一组菜单
①CMenu类可能会用到的方法
构造方法 |
Attach() |
把一个菜单句柄附加到CMenu对象上 |
CreateMenu() |
创建一个空菜单并附加到CMenu对象上 |
|
CreatePopupMenu() |
创建一个弹出式菜单并附加到CMenu对象上 |
|
DeleteTempMap() |
删除由FromHandle()创建的任何临时CMenu对象 |
|
DestroyMenu() |
销毁CMenu对象及其下面的菜单 |
|
Deatch() |
从CMenu对象上拆出一个菜单句柄并返回 |
|
FromHandle() |
给定菜单句柄时,返回CMenu对象的指针 |
|
GetSafeHmenu() |
返回由CMenu对象封装的菜单句柄成员 |
|
LoadMenu() |
从可执行文件中加载菜单资源并附加到CMenu对象上 |
|
LoadMenuIndirect() |
从内存中加载菜单资源并附加到CMenu对象上 |
|
操作菜单 |
DeleteMenu() |
删除某个特定菜单中的菜单项 |
TrackPopupMenu() |
在一个POINT对象指定的地方显示快捷菜单 |
|
操作菜单项 |
AppendMenu() |
将新项加到指定的菜单项后面 |
CheckMenuItem() |
弹出式菜单中,菜单项的校验标记或取消下一项的校验标记 |
|
CheckMenuRadioItem() |
把一个单选按钮放到菜单项旁边或取消一个已存在的单选按钮 |
|
EnableMenuItem() |
激活/禁用一个菜单项 |
|
GetMenuItemCount() |
获取菜单项的数目 |
|
GetMenuItemID() |
获取指定位置的菜单项的标识符 |
|
GetMenuState() |
获取指定菜单项的状态 |
|
GetMenuString() |
获取指定菜单项的标记 |
|
GetSubMenu() |
获取指向弹出式才当的指针 |
|
InsertMenu() |
在指定位置插入新的菜单项 |
|
ModifyMenu() |
修改指定位置的菜单项 |
|
RemoveMenu() |
从指定菜单中删除与弹出式菜单结合的菜单项 |
②在资源视图中插入新菜单IDR_MENU_POPUP
③在View的头文件中添加新变量
//快捷菜单
CMenu m_PopMenu;
//快捷菜单的子菜单
CMenu* m_pPop;
④在View的源文件中添加代码
CMy0View::CMy0View()
{
…
//加载菜单资源
m_PopMenu.LoadMenu(IDR_MENU_POPUP);
}
CMy0View::~CMy0View()
{
//销毁菜单资源
m_PopMenu.DestroyMenu();
}
⑤在View的类视图、类的属性面板中选择WM_RBUTTON消息添加处理函数,填写右键后要处理的代码
void CMy0View::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_pPop=m_PopMenu.GetSubMenu(0);
UINT nCheck=m_bShow?MF_CHECKED:MF_UNCHECKED;
m_pPop->CheckMenuItem(ID_OPER_SHOW,MF_BYCOMMAND|nCheck);
m_pPop->CheckMenuRadioItem(ID_OPER_RED,ID_OPER_BLUE,ID_OPER_RED+m_nColorIndex,MF_BYCOMMAND);
ClientToScreen(&point);
m_pPop->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,this);
CView::OnRButtonDown(nFlags, point);
}
(3)工具栏菜单
程序主菜单中也有这些菜单项,通常出现在程序主菜单下方、由一组类似按钮的图标组成,可以拖动和关闭
①CToolBar可能用到的方法
构造方法 |
Create() |
创建工具条并附加到CToolBar对象上 |
CreateEx() |
创建定义了边界的工具条并附加到CToolBar对象上 |
|
SetSizes() |
设置按钮及位图大小 |
|
SetHeight() |
设置工具条的高度 |
|
LoadToolBar() |
加载工具条资源 |
|
LoadBitmap() |
加载包含工具条按钮图像的位图 |
|
SetBitmap() |
设置位图图像 |
|
SetButtons() |
设置按钮并使每个按钮与位图图像相关 |
|
操作工具条按钮 |
CommandToIndex() |
返回给定命令的工具条按钮索引 |
GetItemID() |
返回指定索引的按钮或分隔符的ID |
|
GetItemRect() |
返回指定索引的按钮矩形 |
|
GetButtonStyle() |
获取按钮的风格 |
|
SetButtonStyle() |
设置按钮的风格 |
|
GetButtonInfo() |
获取按钮的ID、风格、图像号 |
|
SetButtonInfo() |
设置按钮的ID、风格、图像号 |
|
GetButtonText() |
获取按钮上的文本内容 |
|
SetButtonText() |
设置按钮上的文本内容 |
②CToolBarCtrl也用于操作工具条,CToolBarCtrl可能用到的方法
CToolBarCtrl() |
构造函数 |
Create() |
创建工具条,这里与具体的工具条资源绑定 |
GetState() |
获取指定按钮的信息,比如被按下、被禁止等 |
HitTest() |
测试一点是否位于某按钮内 |
AddButtons() |
添加按钮 |
InsertButton() |
插入按钮 |
AddStrings() |
添加按钮文字 |
③进入资源视图插入Toolbar
④在CMainFrame的头文件中添加工具条对象
protected:
//如果已经有这个对象,还想建立新工具条的话需要另外创建CToolBar对象
CToolBar m_wndToolBar;
⑤在CMainFrame的源文件中编写代码,完成对工具条的加载
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
…
if(!m_wndToolBar.Create(this,WS_VISIBLE|CBRS_TOP)||!m_wndToolBar.LoadToolBar(IDR_TOOLBAR))
{
TRACE0("Fail to create toolbar.");
return -1;
}
` …
}
⑥可以动态的改变工具条的风格
//使窗口可以移动到用户区的任意位置
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
//改变工具条的风格:Toolbar属性面板中prompt的\n前面的内容显示在状态栏、后面的内容表示鼠标经过时提示的内容
m_wndToolBar.SetBarStyle(CBRS_TOOLTIPS| CBRS_FLYBY| CBRS_SIZE_DYNAMIC);
//使工具条显示或隐藏
ShowControlBar(&m_wndToolBar,TRUE,FALSE);
⑦多列工具栏菜单
if(!m_wndToolBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_FLOAT_MULTI|CBRS_GRIPPER|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC)||!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar");
return -1; // fail to create
}
m_wndToolBar.SetWindowText(_T("标准工具栏"));
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
if(!m_wndExtendBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_FLOAT_MULTI|CBRS_GRIPPER|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC)||!m_wndExtendBar.LoadToolBar(IDR_TOOLBAR))
{
TRACE0("Failed to create extend toolbar");
return -1;
}
m_wndExtendBar.SetWindowText(_T("扩展工具栏"));
m_wndExtendBar.EnableDocking(CBRS_ALIGN_ANY);
CRect rect;
m_wndExtendBar.GetWindowRect(&rect);
rect.OffsetRect(1,0);
this->RecalcLayout(); //关键的一步,重新排列
DockControlBar(&m_wndExtendBar, AFX_IDW_DOCKBAR_TOP, &rect);
⑧多行工具栏菜单
//默认工具栏已经加载
if(!m_wndToolBarNew.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_GRIPPER|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC)||
!m_wndToolBarNew.LoadToolBar(IDR_TOOLBAR))
{
TRACE0("Fail to create toolbar.");
return -1;
}
2.加速键
进入资源视图的文件,双击最后一行、设置与该加速键关联的ID、在属性面板中设置加速键,编译执行
3.字符串
使用字符串资源并在需要的时候动态切换,可以设计出跨语言的程序;进入资源视图、打开String Table,双击最下面的空白一行、填写表示该字符串的ID值、填写字符串的内容,编译执行;CTring类.LoadString(字符串的ID值);加载需要的字符串资源,CSize sizeText=pDC->GetTextExtent(str);可以获取字符串的矩形
4.对话框
DDX:对话框数据交换,MFC将控件和数据建立一种绑定关系
(1)CDialog可能用到的函数
Create() |
创建一个对话框,通常用于非模态对话框的创建 |
Domodal() |
显示模态对话框 |
EndDialog() |
关闭模态对话框 |
GetDlgItem() |
获取对话框上的某个控件指针 |
OnInitDialog() |
初始化对话框 |
OnOk() |
OK按钮被点击,可以重载这个函数 |
OnCancel() |
Cancel按钮被点击,可以重载这个函数 |
(2)在资源视图中插入新的Dialog,编辑需要的控件
(3)为这个对话框建立关联的类
(4)在对话框类中为需要的控件添加需要的数据变量
(5)在需要的源文件中使用这个对话框类
//一个ID为ID_OPER_STRING的菜单项,它的COMMAND消息响应函数OnOperString调用了这个对话框类
//也就是点击这个菜单项的时候会出现这个对话框
#include "InputDlg.h"
void CMy0View::OnOperString()
{
// TODO: 在此添加命令处理程序代码
InputDlg dlgInput;
//这是模态对话框
if(dlgInput.DoModal()==IDOK)
{
m_strShow=dlgInput.m_strInput;
Invalidate();
}
//这是非模态对话框,现在只能用来显示一些消息并不能进行交互
//InputDlg *dlg = new InputDlg;
//dlg->Create(IDD_DIALOG_NEW);
//dlg->ShowWindow(SW_SHOWNORMAL);
}
5.图标
可以在资源视图Icon中可以编辑图标,通常使用的是32*32、16*16的24位图标;也可以添加自己想要的图标,如果把ID值替换成IDR_MAINFRAME,就可以改变应用程序的图标
6.位图
(1)在资源视图中导入.bmp视图并命名ID
(2)在View的OnDraw()中载入位图
//获取窗口的绝对位置,GetClientRect()获取相对位置
CRect rect;
GetWindowRect(&rect);
CDC dcMemory;
dcMemory.CreateCompatibleDC(pDC);
CBitmap bmp1;
bmp1.LoadBitmapW(IDB_BITMAP_24bi);
BITMAP bmpInfo1;
bmp1.GetBitmap(&bmpInfo1);
CBitmap* pOldBitmap=dcMemory.SelectObject(&bmp1);
//pDC->BitBlt(0,0,bmpInfo1.bmWidth,bmpInfo1.bmHeight,&dcMemory,0,0,SRCCOPY);
pDC->StretchBlt(0,0,rect.right-rect.left,rect.bottom-rect.top,&dcMemory,0,0,bmpInfo1.bmWidth,bmpInfo1.bmHeight,SRCCOPY);
dcMemory.SelectObject(pOldBitmap);
四、单文档SDI和多文档MDI界面
SDI只能打开一个类型的一个文档,MDI每次能打开多个类型的多个文档、MDI至少拥有两个主菜单
1.可能用到的概念
和CArchive有关的序列化处理,对象读写字节流的方式还方便了网络、串口传输数据
m_pDocument |
使用该档案的文档 |
Abort() |
在不发送异常的情况下关闭档案 |
Close() |
关闭档案 |
Flush() |
将缓冲中的数据强制写入流 |
operator<< |
将基本类型写入流 |
operator>> |
从流中读出基本类型 |
Read() |
读取字节内容 |
Write() |
写入字节内容 |
ReadString() |
读取字符串 |
WriteClass() |
写入类信息 |
WriteString() |
写入字符串 |
GetFile() |
获取底层的CFile对象 |
GetObjectSchema() |
读取对象版本号 |
SetObjectSchema() |
设置对象版本号 |
IsLoading() |
是否处于读取状态 |
IsStoring() |
是否处于保存状态 |
ReadObject() |
读取序列化对象 |
WriteObject() |
写入序列化对象 |
ReadClass() |
读取类信息 |
和文件打开保存有关的虚函数,可以重载实现对这个过程的具体控制
文档类完整的工作是:显示获取文件名对话框,选择匹配的文件模板,创建关联的框架、文档、视图,打开文件,将文件和档案绑定,调用Serialize
CWinApp::OnFileOpen() |
可以完成整个过程 |
CWinApp::OpenDocumentFile() |
MFC帮你获取文件名 |
CDocTemplate::OpenDocumentFile() |
MFC帮你获取文件名并选择一个模板 |
CDocument::OnOpenDocument() |
MFC获取文件名,选择好模板,创建好关联的框架、文档、视图 |
CDocument::Serialize() |
完成序列化即可 |
CDocument::OnFileSave()/OnFileSaveAs() |
可以完成整个过程 |
CDocument::OnSaveDocument() |
MFC帮你获取文件名 |
2.消息映射
本质是数组,数组中存储了消息传递时的关键信息;某种类型的消息会按照某种顺序从一个对象传递到另一个对象,直到该消息被处理,消息被处理后就不会再传递到后面的对象;这个优先级顺序一般是:文档对象>文档模板>框架窗口>应用程序对象;在BEGIN_MSG_MAP和END_MSG_MAP之间的用宏的方式进行声明
宏/参数 |
描述 |
ON_COMMAND ID Func |
处理WM_COMMAND消息 发出消息的控件的ID void func(); |
ON_COMMAND_RANGE IDFirst IDLast func |
处理ID连续的WM_COMMAND消息 起始控件的ID 终止控件的ID void func(WORD id); |
ON_UPDATE_COMMAND_UI ID func |
处理MFC请求更新界面状态 控件ID void func(CCmdUI* pCmdUI); |
ON_UPDATE_COMMAND_UI_RANGE IDFirst IDLast func |
处理ID连续的界面更新 起始控件的ID 终止控件的ID void func(CCmdUI* pCmdUI); |
ON_NOTIFY Code ID func |
处理来自新风格控件的WM_NOTIFY消息 消息码 控件ID void func(NMHDR* pNotifyStruct,LRESULT* result); |
ON_NOTIFY_RANGE Code IDFirst IDLast func |
处理ID连续的WM_NOTIFY消息 消息码 起始控件的ID 终止控件的ID void func(UINT id,NMHDR* pNotifyStruct,LRESULT* result); |
ON_CONTROL Code ID func |
处理WM_COMMAND中的EN_、BN_消息 消息码 控件ID void func(); |
ON_CONTROL_RANGE Code IDFirst IDLast func |
要求控件ID连续,功能和上一个一样 消息码 起始控件的ID 终止控件的ID void func(UINT id); |
ON_MESSAGE Msg func |
处理任意消息,包括用户自定义消息 消息ID LRESULT func(WPARAM wParam,LPARAM lParam); |
ON_REGISTERD_MESSAGE Msg func |
处理使用RegisterWindowMessage注册的消息 消息ID LRESULT func(WPARAM wParam,LPARAM lParam); |
3.核心类
(1)CWinApp
代表主程序,负责维护进程的启动终止、消息循环、命令行参数、资源管理
常用的成员;调用的方法是使用全局函数AfxGetApp()获取到指针,然后访问
m_pszAppName |
应用程序名称 |
m_lpCmdLine |
命令行参数 |
m_pMainWnd |
应用程序主窗口指针 |
m_pszExeName |
可执行文件的名称 |
m_pszProfileName |
配置INI文件的名称 |
m_pszRegistrKey |
配置注册表主键值 |
LoadCursor |
加载光标 |
LoadIcon |
加载图标 |
GetProfileInt |
从配置读取整数 |
WriteProfileInt |
从配置写入整数 |
GetProfileString |
从配置读取字符串 |
WriteProfileString |
从配置写入字符串 |
AddDocTemplate |
添加文档模板 |
AddToRecentFileList |
向“最近打开的文件”菜单项中添加一个文件 |
InitInstance |
MFC程序的入口 |
Run |
事件循环 |
OnIdle |
空闲事件处理 |
ExitInstance |
MFC程序出口 |
PreTranslateMessage |
筛选消息 |
DoWaitCursor |
出现“沙漏”光标 |
(2)CDocument
提供了文档所需要的最基本功能:打开保存文档、维护文档相关的视图列表、维护文档修改标志、通过电子邮件发送文档,是数据的抽象
可能用到的方法
一般方法 |
GetTitle() |
获取文档标题 |
SetTitle() |
设置文档标题 |
|
GetPathName() |
获取文档的路径 |
|
SetPathName() |
设置文档的路径 |
|
GetDocTemplate() |
获取文档模板的指针 |
|
AddView() |
对与文档相关的视图列表中添加视图 |
|
RemoveView() |
从文档视图列表中移除视图 |
|
UpdateAllViews() |
文档已修改,更新全部相关的视图 |
|
DisconnectViews() |
使文档与视图相分离 |
|
GetFile() |
获取指向CFile类型的指针 |
|
CDocumnet的虚方法 |
OnNewDocument() |
由MFC调用来创建新文档 |
OnOpenDocument() |
由MFC调用来打开文档 |
|
OnSaveDocument() |
由MFC调用来保存文档 |
|
OnCloseDocument() |
由MFC调用来关闭文档 |
|
CanCloseDocument() |
观察文档的框架窗口是否被允许关闭 |
|
DeleteContents() |
在未撤销文档对象时删除文档数据 |
|
ReleaseFile() |
释放文件以允许其他应用程序使用 |
|
SaveModified() |
查询文档的修改状态并保存修改的文档 |
|
IsModified () |
文档是否被修改过 |
|
SetModifiedFlag() |
设置文档是否被修改过的标记 |
|
GetFirstViewPosition() |
获取视图列表头的位置 |
|
GetNextView() |
获取视图列表的下一个视图指针 |
逐个对视图进行操作
POSITION pos=GetFirstViewPosition();
while(pos!=NULL)
{
CView* pView=GetNextView(pos);
…
}
(3)CView
继承自CWnd可以接收任何windows消息;OnDraw()除了负责绘制还处理了打印功能、Invalidate()、UpdateWindow()强制视图重绘,都不能在OnDraw()中调用,否则程序会因为递归循环调用而失去响
可能用到的方法
一般方法 |
GetDocument() |
获取与视图相关联的文档指针 |
DoPreparePrinting() |
设置文档标题 |
|
虚方法 |
IsSelected() |
文档是否被选中 |
OnScroll() |
当用户滚动时触发 |
|
OnInitialUpdate() |
类在第一次构造后由MFC调用 |
|
OnDraw() |
由MFC调用发出文档到设备描述表 |
|
OnUpdate() |
由MFC调用对修改的文档进行响应 |
|
OnPrepareDC() |
调用OnDraw()前由MFC修改设备表述表 |
CView的子类
CEditView |
简单的文本编辑器 |
CListView |
列表视图 |
CTreeView |
树状视图 |
CRichEditView |
富文档编辑器 |
CScrollView |
支持滚动条的视图 |
CFormView |
窗体视图,支持在之上使用对话框控件 |
CRecordView |
连接到ODBC数据库的视图 |
CDaoRecordView |
连接到DAO数据库的视图 |
(4)CDocTemplate
文档模板类将文档、视图和框架窗口对象联系在一起,负责一种文档类型的创建和管理;CSingleDocTemplate、CMultiDocTemplate
可能用到的方法
GetDocString() |
获取与文档相关的字符串 |
LoadTemplate() |
加载指定模板 |
AddDocument() |
给文档模板添加指定模板 |
RemoveDocument() |
从文档模板列表中删除文档 |
GetFirstDocPosition() |
获取与文档模板相关的第一个文档的位置 |
GetNextDoc() |
获取文档即下一个文档 |
CreateNewDocument() |
建立文档 |
CreateNewFrame() |
建立包含文档和视图的框架窗口 |
OpenDocumentFile() |
打开有路径名指定的文档 |
CloseAllDocument() |
关闭所有文档 |
SetDefaultTitle() |
显示文档窗口的标题栏内容 |
SaveAllModified() |
查询文档模板的修改状态并存储相关的所有文档 |
InitialUpdateFrame |
触发关联视图的OnInitialUpdate() |
CloseAllDocuments |
关闭所有关联的文档 |
CDocTemplate文档模板中的字符串,这些是枚举类型中的数据,通过GetDocString()才能访问到字符串
windowTitle |
应用程序的标题栏文字 |
docName |
默认的新文档名 |
fileNewName |
如果有多个模板,先选择模板对话框中显示 |
filterName |
文件对话框中对扩展名的描述 |
filterExt |
文档扩展名 |
regFileTypeId |
该文档类型的注册名 |
regFileTypeName |
该文档类型对应注册表中用户可见的名称 |
(5)CFrameWnd
框架窗口,维护工具条、菜单、状态栏、视图的显示和刷新等;MDI程序中使用的是它的子类CMDIFrameWnd和CMDIChildWnd
类的成员
m_bAutoMenuEnable |
禁用没有消息处理的菜单项 |
rectDefault |
默认尺寸的矩形 |
Create() |
创建窗口,可以重载改变一些窗口属性 |
LoadFrame() |
从资源加载框架 |
SaveBarState() |
保存工具条的状态 |
LoadBarState() |
恢复工具条的状态 |
ShowControlBar() |
显示工具条 |
EnableDocking() |
使一个控制条可以停靠 |
DockControlBar() |
停靠一个控制条 |
FloatControlBar() |
浮动一个控制条 |
GetControlBar() |
获取一个控制条 |
RecalLayout() |
基于当前视图和控制条重新计算显示区域 |
InitialUpdateFrame() |
调用所有关联视图的OnInitialUpdate() |
GetActiveFrame() |
MDI中获取活动框架 |
SetActiveView() |
激活一个视图 |
GetActiveView() |
获取当前激活的视图 |
CreateView() |
创建一个视图 |
GetActiveDocument() |
获取当前激活的文档 |
GetMessageString() |
获取带有命令ID的消息 |
GetMessageText() |
在状态栏显示一条消息 |
GetMessageBar() |
获取指向状态栏的指针 |
(6)5个核心类的相互访问
当前对象 |
要访问的对象 |
访问方法 |
文档 |
视图 |
GetFirstViewPosition()、GetNextView() |
文档 |
模板 |
GetDocTemplate() |
视图 |
文档 |
GetDocment() |
视图 |
框架 |
GetParentFrame() |
框架 |
视图 |
GetActiveView() |
框架 |
文档 |
GetActiveDocument() |
MDI主框架 |
MDI子框架 |
MDIGetActive() |
MDI子框架 |
MDI主框架 |
GetParentFrame() |
任何位置 |
应用程序 |
AfxGetApp() |
任何位置 |
主框架 |
AfxGetMainWnd() |
4.在程序向导上创建SDI和MDI程序
(1)SDI
View类中OnDraw()的填充;
文档序列化
(2)MDI
在类视图中添加类MFC,输入类名和基类
用类似的方法添加视图View类
创建资源
//这个ID要和上一个表示类型的ID数值上连续,如果还有多个类型、可能需要修改#define _APS_NEXT_RESOURCE_VALUE
#define IDR_MYMDITYPE2 135
//在MyMdi.rc文件中IDR_MYMIDTYPE “\n…”后面添加类似的代码
IDR_MYMDITYPE2 “\nMyMdi2\n…”
创建主菜单资源,在MyMdi的资源视图中复制IDR_MYMIDTYPE、修改出ID为IDR_MYMDITYPE2的菜单
创建文档模板类
BOOL CMyMdiApp::InitInstance()
{
…
CMultiDocTemplate* pDocTemplate2;
pDocTemplate2=new CMulitDocTemplate(
IDR_MYMDITYP2,
RUNTIME_CLASS(CMyMdiDoc2);
RUNTIME_CLASS(CChildFrame);
RUNTIME_CLASS(CMyMdiView2);
AddDocTemplate(pDocTemplate2);
…
}
扩展CMyMdiDoc2类、菜单处理函数和文档序列化
View视图的输出
void CMyMdiView2::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CMyMdiDoc2* pDoc=(CMyMdiDoc2*)GetDocument();
m_drawData=new DrawData;
m_drawData->begin=point;
CView::OnLButtonDown(nFlags, point);
}
void CMyMdiView2::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CMyMdiDoc2* pDoc=(CMyMdiDoc2*)GetDocument();
pDoc->SetModifiedFlag(TRUE);
m_drawData->end=point;
CClientDC dc(this);
CBrush* brush=CBrush::FromHandle((HBRUSH)GetStockObject(HOLLOW_BRUSH));
dc.SelectObject(brush);
CRect rect(m_drawData->begin,m_drawData->end);
switch(pDoc->m_drawType)
{
case 0:
dc.MoveTo(m_drawData->begin);
dc.LineTo(m_drawData->end);
break;
case 1:
dc.Ellipse(rect);
break;
case 2:
dc.Rectangle(rect);
break;
}
m_drawData->type=pDoc->m_drawType;
pDoc->m_data.Add(m_drawData);
brush->DeleteObject();
Invalidate();
CView::OnLButtonUp(nFlags, point);
}
void CMyMdiView2::OnDraw(CDC* pDC)
{
CMyMdiDoc2* pDoc=(CMyMdiDoc2*)GetDocument();
// TODO: 在此添加绘制代码
CBrush* brush=CBrush::FromHandle((HBRUSH)GetStockObject(HOLLOW_BRUSH));
pDC->SelectObject(brush);
int i;
for(i=0;i<pDoc->m_data.GetCount();++i)
{
m_drawData=(DrawData*)(pDoc->m_data.GetAt(i));
CRect rect(m_drawData->begin,m_drawData->end);
switch(m_drawData->type)
{
case 0:
pDC->MoveTo(m_drawData->begin);
pDC->LineTo(m_drawData->end);
break;
case 1:
pDC->Ellipse(rect);
break;
case 2:
pDC->Rectangle(rect);
break;
}
}
brush->DeleteObject();
}
5.MFC多线程
DWORD ThreadID;
CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,0,&ThreadID);
void ThreadFunc(){…}
五、数据库
1.有关数据库的基础知识
(1)CRecordView
用于显示和操作数据;可能会出现中文乱码的情况,解决的办法是文件->高级保存选项中选择utf8,资源视图中的所有视图的语言都选成简体中文
①可能用到的函数
CRecordView() |
构造函数 |
OnInitialUpdate() |
将CRecordView子类中的变量和数据库的数据关联起来 |
IsOnFirstRecord() |
当前记录是否是数据库中的第一个记录 |
IsOnLastRecord() |
当前记录是否是数据库中的最后一个记录 |
OnGetRecordset() |
返回一个CRecordset类型的指针 |
OnMove() |
在数据库中移动游标并将记录显示在视图控件中,有类似BOOL的返回值 |
②OnMove参数的取值
ID_RECORD_FIRST |
移动到数据库的第一个记录 |
ID_RECORD_LAST |
移动到数据库的最后一个记录 |
ID_RECORD_NEXT |
向后移动一个记录 |
ID_RECORD_PREV |
向前移动一个记录 |
(2)CRecordSet
表示的是数据集,有两种典型的表:动态保持数据库中的数据dynasets、静态的数据库snapshots
①成员
m_hstmt |
调用Open()后包含有描述ODBC数据源的句柄 |
m_nFields |
数据库的属性变量,它指示了从数据源读取的记录个数 |
m_nParams |
用来指示CRecordset的派生类的参数个数,默认值是0 |
m_pDatabase |
指向CDatabase的指针、指向当前数据库打开的数据源 |
m_strFilter |
构造CRecordset类后、调用Open函数前,使用这个变量填写一个CString对象,就像SQL语句的WHERE条件部分 |
m_strSort |
构造CRecordset类后、调用Open函数前,使用这个变量填写一个CString对象,就像SQL语句的ORDER BY部分 |
②成员函数
Open() |
打开一个数据源,返回类似BOOL的值 |
Close() |
关闭一个数据集 |
CanAppend() |
判断打开的数据源是否允许加入新记录 |
CanBookmark() |
判断数据源是否支持书签的功能 |
CanRestart() |
判断数据源是否支持重新执行查询语句 |
CanScroll() |
判断数据源是否支持翻阅的功能 |
CanTransact() |
判断数据源是否支持事务 |
CanUpdate() |
判断数据源是否能够更新 |
GetRecordCount() |
获取数据库中记录的数目 |
GetStatus() |
获取数据源的状态,这是一个CRecordsetStatus类型的指针 |
GetTableName() |
获取一张表的名称 |
GetSQL() |
获取一个SQL语句,这是CString类型的指针 |
IsOpen() |
判断数据源是否已经打开 |
IsBOF() |
判断数据库是否为空 |
IsEOF() |
判断是否到了最后一条记录 |
IsDeleted() |
判断指向的记录是否是一个被删除的记录 |
AddNew() |
添加一个新纪录,调用Update()后记录才加入到数据源中去 |
CancelUpdate() |
取消对数据源的修改,在AddNew()、Edit()之后,Update()之前才会有效 |
Delete() |
删除当前指向的记录,游标移走后被删除的记录再无法恢复 |
Move() |
在数据库中移动记录指针,类似的函数有MoveNext()、MovePrev()、MoveFirst()、MoveLast()、SetBookmark()、SetAbsolutePosition() |
GetDefaultConnect() |
获取一个默认连接的数据源 |
GetDefaultSQL() |
获取相应的默认的SQL语句 |
Requery() |
刷新snapshots数据库,调用前要使用Open() |
③virtual BOOL Open(UINT nOpenType,LPCTSTR lpszSQL,DWORD dwOptions);的参数
nOpenType |
默认方式AFX_DB_USE_DEFAULT_TYPE 、dynaset、snapshot、dynamic、只能向前翻阅forwardOnly |
lpszSQL |
表示SQL语句的字符串 |
dwOptions |
选择数据的风格,可以填NULL |
④dwOptions数据源的打开方式
openReadOnly |
只读 |
useCursorLib |
加载ODBC Cursor Library DLL |
noOdbcDialog |
不出现ODBC连接对话框 |
forceOdbcDialog |
总要出现ODBC连接对话框 |
⑤virtual void Move(long nRows,WORD wFetchType);的参数
nRows是要移动的行数、wFetchType是要进行的动作
SQL_FETCH_RELATIVE |
默认值,移动到距离第一个记录的指定行上 |
SQL_FETCH_NEXT |
移到下一个记录 |
SQL_FETCH_PRIOR |
移到上一个记录 |
SQL_FETCH_FIRST |
移到第一个记录 |
SQL_FETCH_LAST |
移到最后一个记录 |
SQL_FETCH_ABSOLUTE |
nRows大于0、移到nRows行后,nRows小于0、移到倒数nRows行后,否则返回BOF |
SQL_FETCH_BOOKMARK |
在指定位置设置标签 |
(3)CDatabase
用于连接一个数据源
①可能用到的成员函数
Open() |
打开一个数据源,返回类似BOOL的值 |
Close() |
关闭一个数据源 |
ExecuteSQL() |
执行SQL语句 |
CanTransact() |
判断数据源是否支持事务处理 |
SetLoginTimeout() |
设置连接超时的时间,单位是s |
GetConnect() |
返回当前对象的ODBC数据源的名称 |
Rollback() |
事务回滚 |
GetDatabaseName() |
返回当前连接的数据源的名称,这个名称不一定是ODBC控制台登记的名称 |
IsOpen() |
判断当前对象是否连接着数据源 |
CanUpdate() |
判断数据源是否可修改 |
BeginTrans() |
开始一个事务的操作 |
CommitTrans() |
提交一个数据库事务 |
②virtual BOOL Open(LPCTSTR lpszDSN,BOOL bExclusive,BOOL bReadOnly,LPCTSTR lpszConnect,BOOL bUseCursorLib);的参数
类似的函数是virtual BOOL OpenEX(LPCTSTR lpszConnectString,DWORD dwOptions);
lpszDSN |
ODBC控制台中注册的数据源的名称,如果lpszConnect已经有DSN值的话可以取NULL |
bExclusive |
共享方式打开的数据源取FALSE |
bReadOnly |
只读 |
lpszConnect |
包含用户和密码的描述字符串 |
bUseCursorLib |
加载ODBC的Cursor Library DLL |
lpszConnectString |
包含用户和密码的描述字符串 |
(4)RFX
和DDX类似,RFX用于视图和数据源自动交换数据,有时候需要自定义的代码:带参数的查询、数据库中表之间的连接
(5)CDBException
抛出一个异常void AfxThrowDBException(RETCODE nRetCode,CDatabase* pdb,HSTMT hstmt);
2.建立ODBC数据源
进入Access创建一个空数据库、建立字段、填充数据,这个数据库默认用户名是admin密码为空,如果想要设置用户名和密码可以以独占读取.mdb文件的方式、在工具->安全中设置新的用户名和密码;
控制面板->管理工具-> ODBC 数据源(32 位)->系统DSN->添加.mdb->命名数据源注册的名称、选择数据库文件
3.显示数据库中的数据
如果只是和数据库的记录打交道,在项目向导中选择“不支持文件的数据库视图”;
在资源视图中设计表单的样式、定义各控件的ID;
填充数据到视图的映射代码:
void CMy3View::DoDataExchange(CDataExchange* pDX)
{
CRecordView::DoDataExchange(pDX);
// 可以在此处插入 DDX_Field* 函数以将控件“连接”到数据库字段,例如
// DDX_FieldText(pDX, IDC_MYEDITBOX, m_pSet->m_szColumn1, m_pSet);
// DDX_FieldCheck(pDX, IDC_MYCHECKBOX, m_pSet->m_bColumn2, m_pSet);
// 有关更多信息,请参阅 MSDN 和 ODBC 示例
DDX_FieldText(pDX,IDC_EDIT1,m_pSet->m_Sno,m_pSet);
DDX_FieldText(pDX,IDC_EDIT2,m_pSet->m_Sname,m_pSet);
DDX_FieldText(pDX,IDC_EDIT3,m_pSet->m_Ssex,m_pSet);
DDX_FieldText(pDX,IDC_EDIT4,m_pSet->m_Sage,m_pSet);
DDX_FieldText(pDX,IDC_EDIT5,m_pSet->m_Sdept,m_pSet);
}
4.对记录进行排序
可以在工具栏或菜单项中设计按钮、定义ID,为这个控件的COMMAND消息设计触发事件:
void CMy3View::OnSortPrice()
{
// TODO: 在此添加命令处理程序代码
m_pSet->Close();
m_pSet->m_strSort=L"Sage";
//重新使用成员变量m_strSort
//m_pSet->Open(-1,L"SELECT * FROM Student WHERE Sdept='CS'",NULL);
m_pSet->Open();
//更新表单
UpdateData(FALSE);
}
5.增添记录
清空当前表单,就可以在表单中新添一些数据:
void CMy3View::OnClearRecord()
{
// TODO: ?????í???ü?????í???ò?ú??
m_pSet->SetFieldNull(NULL);
UpdateData(FALSE);
}
在工具栏或菜单项中设计按钮、定义ID,为这个控件的COMMAND消息设计触发事件:
void CMy3View::OnRecordAdd()
{
// TODO: ?????í???ü?????í???ò?ú??
CRecordset* pSet=OnGetRecordset();
if(pSet->CanUpdate() && !pSet->IsDeleted())
{
pSet->Edit();
if(!UpdateData())
return;
pSet->Update();
}
m_pSet->AddNew();
m_pSet->Update();
m_pSet->Requery();
m_pSet->MoveLast();
UpdateData(FALSE);
}
6.删除记录
默认情况下,用户移动一个记录就会对数据库进行修改,所以需要重载View类的OnMove():
BOOL CMy3View::OnMove(UINT nIDMoveCommand)
{
// TODO: ?????í??ר???ú????/?ò?÷???ù?à
switch(nIDMoveCommand)
{
case ID_RECORD_PREV:
m_pSet->MovePrev();
if(!m_pSet->IsBOF())
break;
case ID_RECORD_FIRST:
m_pSet->MoveFirst();
break;
case ID_RECORD_NEXT:
m_pSet->MoveNext();
if(!m_pSet->IsEOF())
break;
if(!m_pSet->CanScroll())
{
m_pSet->SetFieldNull(NULL);
break;
}
case ID_RECORD_LAST:
m_pSet->MoveLast();
break;
default:
ASSERT(FALSE);
}
UpdateData(FALSE);
return TRUE;
//return CRecordView::OnMove(nIDMoveCommand);
}
在工具栏或菜单项中设计按钮、定义ID,为这个控件的COMMAND、UPDATE_COMMAND_UI消息设计触发事件:
void CMy3View::OnDeleteRecord()
{
// TODO: ?????í???ü?????í???ò?ú??
CRecordsetStatus m_cStatus;
try
{
m_pSet->Delete();
}
catch(CDBException* m_pEx)
{
AfxMessageBox(m_pEx->m_strError);
m_pEx->Delete();
m_pSet->MoveFirst();
UpdateData(FALSE);
return;
}
m_pSet->GetStatus(m_cStatus);
if(m_cStatus.m_lCurrentRecord==0)
m_pSet->MoveFirst();
else
m_pSet->MoveNext();
UpdateData(FALSE);
}
void CMy3View::OnUpdateDeleteRecord(CCmdUI *pCmdUI)
{
// TODO: ?????í???ü???ü?????§???????í???ò?ú??
pCmdUI->Enable(!m_pSet->IsEOF());
}
7.查询记录
void CMy3View::OnSearch()
{
// TODO: 在此添加命令处理程序代码
DoFilter(L"Sdept");
}
// 仅供内部重复使用的函数
void CMy3View::DoFilter(CString col)
{
CSearchDlg dlg;
if(dlg.DoModal()==IDOK)
{
CString str=col+L"='"+dlg.m_Edit_Search+L"'";
m_pSet->Close();
m_pSet->m_strFilter=str;
m_pSet->Open();
if(m_pSet->GetRecordCount()==0)
{
MessageBox(L"没有匹配的记录!");
m_pSet->Close();
m_pSet->m_strFilter=L"";
m_pSet->Open();
}
UpdateData(FALSE);
}
}
8.修改记录
默认情况下,用户移动一个记录就会对数据库进行修改,所以需要重载View类的OnMove();
在工具栏或菜单项中设计按钮、定义ID,为这个控件的COMMAND、UPDATE_COMMAND_UI消息设计触发事件:
void CMy3View::OnUpdateRecord()
{
// TODO: ?????í???ü?????í???ò?ú??
m_pSet->Edit();
UpdateData(TRUE);
if(m_pSet->CanUpdate())
{
m_pSet->Update();
}
}
void CMy3View::OnUpdateUpdateRecord(CCmdUI *pCmdUI)
{
// TODO: ?????í???ü???ü?????§???????í???ò?ú??
pCmdUI->Enable(!m_pSet->IsEOF());
}
9.移动到指定的位置
在资源视图中建立对话框和相关的类、编辑框的变量m_RecordID;
在工具栏或菜单项中设计按钮、定义ID,为这个控件的COMMAND消息设计触发事件:
void CMy3View::OnMovetorecord()
{
// TODO: ?????í???ü?????í???ò?ú??
CMoveToRecord dlgMoveTo;
if(dlgMoveTo.DoModal()==IDOK)
{
CRecordset* pSet=OnGetRecordset();
if(pSet->CanUpdate() && !pSet->IsDeleted())
{
pSet->Edit();
if(!UpdateData())
return;
pSet->Update();
}
pSet->SetAbsolutePosition(dlgMoveTo.m_RecordID);
UpdateData(FALSE);
}
}
六、多媒体
1.音频播放
(1)使用音频函数的方式
①BOOL MessageBeep(UINT nType);播放系统提示音
0xFFFFFFFF |
系统默认的声音 |
MB_ICONINFORMATION或MB_ICONASTERISK |
出现信息消息框时的声音 |
MB_ICONEXLAMATION或MB_ICONWARNING |
出现警告消息框时的声音 |
MB_ICONHAND或MB_ICONSTOP或MB_ICONERROR |
出现错误提示框时的声音 |
MB_ICONQUESTION |
出现询问对话框时的声音 |
MB_OK |
系统默认声音 |
②BOOL sndPlaySound(LPCSTR lpszSound,UINT fuSound);播放指定文件名或是注册表中已有的声音
fuSound播放标识
SND_ASYNC |
异步播放声音,进入函数后立即返回,终止的办法是sndPlaySound(…,NULL); |
SND_LOOP |
循环播放声音,但是要和SND_ASYNC一同使用,终止办法和上一个相同 |
SND_MEMORY |
第一个参数是.wav在内存中的映像 |
SND_NODEFAULT |
当无法正常播放声音时不播放系统默认声音 |
SND_NOSTOP |
如果有声音正在播放,则返回FALSE、终止运行 |
SND_SYNC |
同步方式播放声音,只有声音播放结束才返回结果 |
注册表中已有的声音
SystemAsterisk |
出现信息消息框时的声音 |
SystemExclamation |
出现警告消息框时的声音 |
SystemExit |
系统退出时的提示音 |
SystemHand |
出现错误提示框时的声音 |
SystemQuestion |
出现询问对话框时的声音 |
SystemStart |
系统启动提示音 |
③BOOL PlaySound(LPCSTR pszSound,HMODULE hmod,DWORD fdwSound);
fdwSound指定声音的来源,如果没有指定先到注册表中找、再到文件中找;NULL表示停止当前.wav声音,SND_PURGE表示停止其他声音;hmod是资源文件的句柄。
fdwSound的取值
SND_ALIAS |
注册条目 |
SND_RESOURCE |
来自资源 |
SND_FILENAME |
来自文件 |
SND_NOWAIT |
如果设备正使用,立即返回不再播放 |
SND_APPLICATION |
用用应用程序制定的音频 |
SND_PURGE |
停止声音播放 |
SND_ALIAS_ID |
预先确定的声音标识 |
(2)使用MCI的方式
MCI指的是媒体控制接口类Media Control Interface,可以支持更复杂的音频操作:暂停、向前搜索、向后搜索、对音频文件进行编辑等;对MCI设备进行控制的两个方法,MCI命令串mciSendString()、MCI命令消息mciSendCommand(),但是发送命令消息要比发送命令字串要高效。
①可能用到的函数
MCIERROR mciSendCommand(
//接收命令消息的MCI设备ID,可以通过MCI_OPEN()获得
// MCIERROR的低字节存储错误值、高字节存储设备标识,执行正确的返回结果MCIERROR为0
MCIDEVICEID IDDevice,
//要发送的命令消息
UINT uMsg,
//命令消息的标志集
DWORD fdwCommand,
//包含命令消息参数的结构体地址
DWORD_PTR dwParam);
要发送的命令消息uMsg
MCI_BREAK |
为MCI设备设置终止键,默认是ctrl+break |
全部设备 |
MCI_STATUS |
获取一个MCI设备的信息 |
|
MCI_CLOSE |
释放出访问设备的通道 |
|
MCI_SYSINFO |
获取MCI设备的信息 |
|
MCI_GETDEVCAPS |
获取一个设备的静态信息 |
|
MCI_INFO |
获取一个设备的字串信息 |
|
MCI_OPEN |
初始化一个设备 |
|
MCI_CAPTURE |
获取缓冲区中每一帧的内容并存入指定文件 |
数字视频 |
MCI_CONFIGURE |
显示一个对话框用于设置操作 |
|
MCI_UNDO |
撤销最近一次操作 |
|
MCI_LOAD |
加载一个文件 |
|
MCI_PUT |
设置来源、目的和框架矩形 |
|
MCI_UPDATE |
更新显示矩形 |
|
MCI_COPY |
拷贝数据到粘贴板 |
|
MCI_WHERE |
获取视频设备的剪切板模型 |
|
MCI_WINDOW |
指定窗口和窗口特性用于图形设备 |
|
MCI_CUT |
剪切数据到粘贴板 |
|
MCI_MONITOR |
指定陈述的来源 |
|
MCI_PASTE |
将粘贴板上的数据粘贴到文件中 |
|
MCI_QUALITY |
指定多媒体的质量 |
|
MCI_RESERVE |
为下面的记录分配一块磁盘空间 |
|
MCI_RESTORE |
将一幅位图由文件拷贝到缓冲区中 |
|
MCI_SIGNAL |
在工作区中设置一个指定位置 |
|
MCI_PAUSE |
暂停当前播放的位置 |
CD音频、数字视频、MIDI序列、录像机、影碟机、.wav文件 |
MCI_PLAY |
设备开始输出数据 |
|
MCI_SET |
设置设备信息 |
|
MCI_STOP |
停止所有的播放记录并释放缓存 |
|
MCI_CUE |
提示一个设备、使设备以最小的延迟进行播放或重放 |
数字视频、录像机、.wav文件 |
MCI_RESUME |
恢复被暂停的操作 |
|
MCI_FREEZE |
冻结显示中的画面 |
数字视频、录像机 |
MCI_LIST |
获取可用于输入设备关于数量和类型方面的信息 |
|
MCI_SETAUDIO |
设置与音频回放、捕捉相关的变量 |
|
MCI_SETVIDEO |
设置与视频回放相关的变量 |
|
MCI_UNFREEZE |
恢复执行了MCI_FREEZE命令的设备 |
|
MCI_DELETE |
删除文件中的数据 |
数字视频、.wav文件 |
MCI_ESCAPE |
直接发送一个字串到指定设备 |
影碟机 |
MCI_SPIN |
使设备开始转动或停止 |
|
MCI_INDEX |
将屏幕上的显示置为on或off |
录像机 |
MCI_SETTIMECODE |
使用或禁用VCR设备录音的时间代码 |
|
MCI_SETTUNER |
设置调制器的当前频道 |
|
MCI_MARK |
记录或擦除以使MCI_SEEK命令获得更高的寻找速度 |
|
MCI_RECORD |
从当前位置或指定的起始、终止位置开始记录 |
录像机、.wav文件 |
MCI_SAVE |
保存当前文件 |
.wav文件 |
MCI_SEEK |
以最快的速度改变当前内容的输出位置 |
CD音频、数字视频、MIDI序列、录像机、影碟机 |
MCI_STEP |
跳过一帧或多帧 |
数字视频、录像机、CAV格式影碟机 |
检测错误
BOOL mciGetErrorString(
//错误代码
DWORD fdwError,
//用于描述错误内容的字符串
LPTSTR lpszErrorText,
//错误内容的缓冲区容量
UINT cchErrorText);
②环境配置:在stdafx.h中_AFX_NO_AFXCMN_SUPPORT下面添加#include <mmsystem.h>;
右击工程->属性->链接器->输入,在附加依赖项中输入winmm.lib
③对话框类中添加可能用到的数据:
// 判断正在播放的标志
BOOL m_PSign;
// 判断正在暂停的标志
BOOL m_ASign;
// 用来存储错误代码
DWORD dwError;
// 用来存储打开设备的ID值
MCIDEVICEID m_MCIDeviceID;
// 用来存储出错的内容
char szErrorBuf[MAXERRORLENGTH];
④选择要播放的音乐
void CMy0Dlg::OnOpenButton()
{
// TODO: 在此添加控件通知处理程序代码
//文件名
CString fileName;
//文件扩展名
CString fileExt;
MCI_OPEN_PARMS mciOpenParms;
DWORD dwError;
static TCHAR szFilter[]=L"波形音频文件(*.wav)|*.wav|MIDI序列(*.mid)|*.mid||";
CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,szFilter);
if(dlg.DoModal()==IDOK)
{
//这个地方可能有问题?
fileName=dlg.GetFolderPath()+L"\\"+dlg.GetFileName();
fileExt=dlg.GetFileExt();
//AfxMessageBox(L"fileName: "+fileName+L"\nfileExt: "+fileExt);
//如果程序正在播放则关闭
if(m_PSign)
{
dwError=mciSendCommand(m_MCIDeviceID,MCI_CLOSE,0,NULL);
if(dwError)
{
if(mciGetErrorString(dwError,(LPTSTR)szErrorBuf,MAXERRORLENGTH))
MessageBox((LPCTSTR)szErrorBuf,L"MCI出错0",MB_ICONWARNING);
else
MessageBox(L"不明错误标识",L"MCI出错0",MB_ICONWARNING);
return;
}
}
if(!_tcscmp(L"wav",fileExt))
mciOpenParms.lpstrDeviceType=L"waveaudio";
else if(!_tcscmp(L"mid",fileExt))
mciOpenParms.lpstrDeviceType=L"sequencer";
mciOpenParms.lpstrElementName=fileName;
//将打开的文件名存入mciOpenParms结构体中
dwError=mciSendCommand(0,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,(DWORD)(LPVOID)&mciOpenParms);
if(dwError)
{
if(mciGetErrorString(dwError,(LPTSTR)szErrorBuf,MAXERRORLENGTH))
MessageBox((LPCTSTR)szErrorBuf,L"MCI出错1",MB_ICONWARNING);
else
MessageBox(L"不明错误标识",L"MCI出错1",MB_ICONWARNING);
return;
}
m_MCIDeviceID=mciOpenParms.wDeviceID;
m_PSign=FALSE;
m_ASign=FALSE;
}
}
⑤播放音乐
void CMy0Dlg::OnBnClickedPlayButton()
{
// TODO: 在此添加控件通知处理程序代码
//存储与播放有关的信息
MCI_PLAY_PARMS mciPlayParms;
//如果没有正在播放的声音
if(!m_PSign)
{
//为MM_MCINOTIFY消息指定窗口句柄
mciPlayParms.dwCallback=(long)GetSafeHwnd();
//播放位置从头开始
mciPlayParms.dwFrom=0;
dwError=mciSendCommand(m_MCIDeviceID,MCI_PLAY,MCI_FROM|MCI_NOTIFY,(DWORD)(LPVOID)&mciPlayParms);
if(dwError)
{
if(mciGetErrorString(dwError,(LPTSTR)szErrorBuf,MAXERRORLENGTH))
MessageBox((LPCTSTR)szErrorBuf,L"MCI出错",MB_ICONWARNING);
else
MessageBox(L"不明错误标识",L"MCI出错",MB_ICONWARNING);
return;
}
m_PSign=TRUE;
}
}
⑥暂停/继续
void CMy0Dlg::OnBnClickedPauseButton()
{
// TODO: 在此添加控件通知处理程序代码
//有正在播放的声音
if(m_PSign)
{
//不是暂停状态
if(!m_ASign)
{
dwError=mciSendCommand(m_MCIDeviceID,MCI_PAUSE,0,NULL);
if(dwError)
{
if(mciGetErrorString(dwError,(LPTSTR)szErrorBuf,MAXERRORLENGTH))
MessageBox((LPCTSTR)szErrorBuf,L"MCI出错",MB_ICONWARNING);
else
MessageBox(L"不明错误标识",L"MCI出错",MB_ICONWARNING);
return;
}
m_ASign=TRUE;
}
else
{
dwError=mciSendCommand(m_MCIDeviceID,MCI_RESUME,0,NULL);
if(dwError)
{
if(mciGetErrorString(dwError,(LPTSTR)szErrorBuf,MAXERRORLENGTH))
MessageBox((LPCTSTR)szErrorBuf,L"MCI出错",MB_ICONWARNING);
else
MessageBox(L"不明错误标识",L"MCI出错",MB_ICONWARNING);
return;
}
m_ASign=FALSE;
}
}
}
⑦播放结束后需要响应MM_MCINOTIFY,对类中的标记做修改
对话框的头文件中添加
afx_msg LRESULT MciNotify(WPARAM wParam,LPARAM lParam);
对话框的源文件中添加消息映射
ON_MESSAGE(MM_MCINOTIFY,MciNotify)
定义做出响应的函数
LRESULT CMy0Dlg::MciNotify(WPARAM wParam,LPARAM lParam)
{
if(wParam==MCI_NOTIFY_SUCCESSFUL)
{
AfxMessageBox(L"enter.");
m_PSign=FALSE;
m_ASign=FALSE;
return 0;
}
return -1;
}
2.视频播放
资源视图->右键->插入ActiveX控件->选择Windows Media Player;
项目->添加类->ActiveX控件中的MFC类;
来源选择“文件”,“位置”是C:\windows\system32\wmp.dll,“接口”选择IWMPPlayer4;
对话框类的头文件中加入#include “CWMPPlayer4.h”;
再次进入资源视图,为这个ActiveX控件添加变量m_mediaPlay;
为这个ActiveX控件添加触发事件:
void CMy0Dlg::DoubleClickOcx1(short nButton, short nShiftState, long fX, long fY)
{
// TODO: 在此处添加消息处理程序代码
CFileDialog dlg(TRUE,NULL,L"*.*",OFN_FILEMUSTEXIST,
L"ActiveStreamingFormat(*.asf)|*.asf|"
L"AudioVidesInterleaveFormat(*.avi)|*.avi|"
L"RealAudio/RealVideo(*.rm)|*.rm|"
L"WaveAudio(*wav)|*.wav|"
L"MIDIFile(*.mid)|*.mid|"
L"所有文件(*.*)|*.*||");
if(dlg.DoModal()==IDOK)
m_mediaPlay.put_URL(dlg.GetPathName());
}
3.图片显示
OleLoadPicture支持加载.png、.jpg、.gif等格式的图片
(1) 创建SDI工程
(2) 在View类中添加数据成员:
// 用来装载图片的变量
LPPICTURE m_pPicture;
// 是否压缩显示
BOOL m_bScale;
(3) 新数据成员的初始化和销毁:
CMy4View::CMy4View()
: m_bScale(FALSE)
{
// TODO: 在此处添加构造代码
m_pPicture=NULL;
m_bScale=FALSE;
}
CMy4View::~CMy4View()
{
if(m_pPicture)
{
m_pPicture->Release();
}
}
(4) 通过菜单项打开文件:
void CMy4View::OnOperOpen()
{
// TODO: 在此添加命令处理程序代码
//保存文件名的缓冲,有必要测试下这个对象!
TCHAR szFile[MAX_PATH];
//初始化该缓冲
ZeroMemory(szFile,MAX_PATH);
//用于打开文件的结构体
OPENFILENAME ofn;
//初始化该结构
ZeroMemory(&ofn,sizeof(OPENFILENAME));
//设置结构的大小
ofn.lStructSize=sizeof(OPENFILENAME);
ofn.Flags=OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY;
//文件框的父窗口
ofn.hwndOwner=m_hWnd;
ofn.lpstrFilter=
L"Supported Files Types(*.bmp;*.gif;*.jpg;*.ico;*.emf;*.wmf)\0*.bmp;*.gif;*.jpg;*.ico;*.emf;*.wmf\0"
L"Bitmaps(*.bmp)\0*.bmp\0"
L"GIF Files(*.gif)\0*.gif\0"
L"JPEG Files(*.jpg)\0*.jpg\0"
L"Icons(*.ico)\0*.ico\0"
L"Enhanced Metafiles(*.emf)\0*.emf\0"
L"Windows Metafiles(*.wmf)\0*.wmf\0\0";
//文件框的标题
ofn.lpstrTitle=L"选择图片";
//返回文件名的缓冲
ofn.lpstrFile=szFile;
//设置缓冲的长度
ofn.nMaxFile=MAX_PATH;
if(GetOpenFileName(&ofn)==IDOK)
loadPicture(szFile);
}
void CMy4View::loadPicture(CString strFile)
{
//打开文件
HANDLE hFile=CreateFile(strFile,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
_ASSERTE(INVALID_HANDLE_VALUE!=hFile);
//获取文件的大小
DWORD dwFileSize=GetFileSize(hFile,NULL);
_ASSERTE(dwFileSize!=-1);
LPVOID pvData=NULL;
//分配全局内存,获取内存句柄
HGLOBAL hGlobal=GlobalAlloc(GMEM_MOVEABLE,dwFileSize);
_ASSERTE(hGlobal!=NULL);
//锁定内存,获取内存指针
pvData=GlobalLock(hGlobal);
_ASSERTE(pvData!=NULL);
DWORD dwBytesRead=0;
//读取文件
BOOL hRead=ReadFile(hFile,pvData,dwFileSize,&dwBytesRead,NULL);
_ASSERTE(hRead!=FALSE);
GlobalUnlock(hGlobal);
CloseHandle(hFile);
LPSTREAM pstm=NULL;
//从内存数据创建IStream*
HRESULT hr=CreateStreamOnHGlobal(hGlobal,TRUE,&pstm);
_ASSERTE(pstm&&SUCCEEDED(hr));
if(m_pPicture)
m_pPicture->Release();
//赋值、全局作用域(Windows api),从IStream接口加载图片到IPicture中
hr=::OleLoadPicture(pstm,dwFileSize,FALSE,IID_IPicture,(LPVOID*)&m_pPicture);
_ASSERTE(m_pPicture&&SUCCEEDED(hr));
pstm->Release();
Invalidate();
}
(5) 对图片进行绘制:
void CMy4View::OnDraw(CDC* pDC)
{
CMy4Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
if(m_pPicture)
{
long hmWidth;
long hmHeight;
m_pPicture->get_Width(&hmWidth);
m_pPicture->get_Height(&hmHeight);
int nWidth=MulDiv(hmWidth,GetDeviceCaps(pDC->GetSafeHdc(),LOGPIXELSX),HIMETRIC_INCH);
int nHeight=MulDiv(hmHeight,GetDeviceCaps(pDC->GetSafeHdc(),LOGPIXELSY),HIMETRIC_INCH);
CRect rc;
GetClientRect(&rc);
if(m_bScale)
{
//创建内存DC
CDC memdc;
memdc.CreateCompatibleDC(pDC);
//创建位图
CBitmap bmp;
bmp.CreateCompatibleBitmap(pDC,nWidth,nHeight);
//将位图选入内存DC
memdc.SelectObject(bmp);
//将图片以原始尺寸绘制到内存DC中
m_pPicture->Render(memdc.GetSafeHdc(),0,0,nWidth,nHeight,0,hmHeight,hmWidth,-hmHeight,&rc);
//从内存DC缩放拷贝到显示DC
pDC->StretchBlt(0,0,nWidth/2,nHeight/2,&memdc,0,0,nWidth,nHeight,SRCCOPY);
}
else
m_pPicture->Render(pDC->GetSafeHdc(),0,0,nWidth,nHeight,0,hmHeight,hmWidth,-hmHeight,&rc);
}
}
//通过菜单项控制是否缩放
void CMy4View::OnOperSize()
{
// TODO: 在此添加命令处理程序代码
m_bScale=!m_bScale;
Invalidate();
}
void CMy4View::OnUpdateOperSize(CCmdUI *pCmdUI)
{
// TODO: 在此添加命令更新用户界面处理程序代码
pCmdUI->SetCheck(m_bScale);
}
七、网络编程
1.利用WinInet抓取网页
对基于对话框的MFC工程设置设置属性:
工程->属性->链接器->输入WinInet.lib
为CInternetSession m_session;封装一个类;
从网页获取信息:
CString MyWinInetClass::ConnectHttp(const CString sUrl)
{
CString sResult;
CInternetFile* hHttpFile=NULL;
sResult=L"";
sResult=sResult+L"Trying to connect Http sites: "+sUrl+L"\r\n";
hHttpFile=(CInternetFile*)m_session.OpenURL(sUrl);
if(hHttpFile)
{
sResult=sResult+L"Connection established.\r\n";
CString sLine;
while(hHttpFile->ReadString(sLine))
sResult=sResult+sLine+L"\r\n";
hHttpFile->Close();
}
else
sResult=sResult+L"There are some errors in finding this Http sites";
return sResult;
}
更新界面UI:
void CMy5Dlg::OnBnClickedButtonHttp()
{
// TODO: 在此添加控件通知处理程序代码
UpdateData(TRUE);
m_editResult=L"";
m_editResult=m_editResult+m_WinInetClass.ConnectHttp(m_url);
UpdateData(FALSE);
}
八、附录
1.Visual Studio 2008的快捷键
f9 |
设置断点 |
f5 |
编译 |
ctrl+f5 |
运行 |
ctrl+shift+n |
新建项目 |
ctrl+n |
新建文件 |
ctrl+k+c |
注释一行 |
ctrl+k+u |
反注释一行 |
ctrl+h |
快速替换 |
ctrl+j |
对象的成员提示 |
ctrl+] |
括号匹配 |
ctrl+shift+] |
选中括号匹配中的代码 |
ctrl+c,ctrl+x |
可以是行操作,不用选中 |
ctrl+l |
删除一行 |
ctrl+tab |
子窗口切换 |