MFC界面程序
目录
(2)在资源视图中插入新的Dialog,编辑需要的控件... 44
(4)在对话框类中为需要的控件添加需要的数据变量... 44
正文
一、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.vs的快捷键
f9 | 设置断点 |
f5 | 编译 |
ctrl+f5 | 运行 |
ctrl+k+c | 注释一行 |
ctrl+k+u | 反注释一行 |
ctrl+h | 快速替换 |
ctrl+] | 括号匹配 |
ctrl+shift+] | 选中括号匹配中的代码 |
ctrl+c,ctrl+x | 可以是行操作,不用选中 |
ctrl+l | 删除一行 |
ctrl+tab | 子窗口切换 |
alt+右箭头 | 自动补全、方法提示 |
ctrl+k | 添加书签 |
shift+f2 | 到下一个书签 |
f2 | 到上一个书签 |
选中代码中的内容,f1 | 在MSDN中查找对应的文档 |
crl+a,ctrl+k+f | 格式化代码 |
选中代码中的内容,f12 | 转到定义 |
alt+鼠标向下拖动 | 编辑列 |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步