目录
(2)在资源视图中插入新的Dialog,编辑需要的控件... 43
(4)在对话框类中为需要的控件添加需要的数据变量... 43
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.按钮
(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)可能用到的函数
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 |
多行编辑框可以回车换行 |
(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值);可以加载需要的字符串资源,CString对象可以直接转换成LPCTSTR而且支持格式化.Format(L“”,…);
//获取字符串的矩形
CSize sizeText=pDC->GetTextExtent(str);
//CString转换为string
CString str = _T("CSDN");
std::string s = (CT2A)str;
//字符串输出
pDC->SetBkColor(RGB(255,0,0));
pDC->SetTextColor(RGB(0,255,0));
CFont a;
a.CreateFont(
//高度和宽度
30,0,
//文本的倾斜度
0,
0,FW_NORMAL,
//斜体、下划线、删除线
0,0,0,
GB2312_CHARSET,OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH|FF_DONTCARE,
//字体名称
L"华文行楷");
pDC->SelectObject(a);
HDC hdc=pDC->GetSafeHdc();
CString str=L"无边落木萧萧下";
TextOut(hdc,0,80,str,_tcslen(str));
a.DeleteObject();
4.对话框
DDX:对话框数据交换,MFC将控件和数据建立一种绑定关系;重写OnInitDialog()函数可以初始化对话框中组件的状态;改变对话框的位置csDlg->SetWindowPos(NULL,20,10,0,0,SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER);;AfxGetMainWnd()->PostMessage(WM_QUIT,0,0);或者使用Dialog::OnOk();都可以退出一个对话窗口
(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 |
子窗口切换 |
alt+右箭头 |
自动补全、方法提示 |
ctrl+k |
添加书签 |
shift+f2 |
到下一个书签 |
f2 |
到上一个书签 |
crl+a,ctrl+k+f |
格式化代码 |