VC6.0的若干实用小技巧 1.检测程序中的括号是否匹配 把光标移动到需要检测的括号(如大括号{}、方括号[]、圆括号()和尖括号<>)前面,键入快捷键 “Ctrl+]”。如果括号匹配正确,光标就跳到匹配的括号处,否则光标不移动,并且机箱喇叭还会发出一 声警告声。 2.查看一个宏(或变量、函数)的宏定义 把光标移动到你想知道的一个宏上,就比如说最常见的DECLARE_MAP_MESSAGE上按一下F12(或右键 菜单中的Go To Defition Of …),如果没有建立Browse files,会出现提示对话框,确定,然后就会跳到定 义那些东西的地方。 相当可喜的是,它也可以看到Microsoft定义的系统宏,非常good. 3.格式化一段乱七八糟的源代码 选中那段源代码,按ATL+F8。 4.在编辑状态下发现成员变量或函数不能显示 删除该项目扩展名为.ncb文件,重新打开该项目。 5.如何整理ClassView视图中大量的类 可以在classview 视图中右键新建文件夹(new folder),再把具有相近性质的类拖到对应的文件夹中, 使整个视图看上去清晰明了. 6.定位预处理指定 在源文件中定位光标到对称的#if, #endif,使用Ctrl+K. 7.如何添加系统中Lib到当前项目 在Project | Settings | Link | Object/library modules:输入Lib名称,不同的Lib之间用空格格开. 8.如何添加系统中的头文件(.h)到当前项目. #include ,告诉编译到VC系统目录去找;使用#include "FileName.h",告诉编译在当前 目录找. 9.如何在Studio使用汇编调试 在WorkBench的Debugger状态下按CTRL+F7. 10.怎样处理ClassZiard找不到的系统消息 如果要在ClassWizard中处理WM_NCHITTEST等系统消息,请在ClassWizard中Class Info页中将 Message filter改为Window就有了. 11.如何干净的删除一个类 先从Workspace中的FileView中删除对应的.h和.cpp文件,再关闭项目,从实际的文件夹中删除对应的.h 和.cpp文件与.clw文件。 12.在Studio中快速切换两个文件 有时,我们需要在最近使用的两个文件中快速切换,换Ctrl+F6。这在两个文件不相今的时候就有用的. 13.取得源程序预处理后的结果: 在Studio里,可以在->PROJECT->SETTINGS->C/C++->Project Options中,在最后加上 /P /EP 这两个编译开关即可做到"只进行预处理".就可以了。编译以后就可以在源程序目录中发现“文件名.I ”的 文本文件。这就是预处理后的结果。 (注意注:区分大小定,请用大定/P) 15.在Debug模式中查看WINAPI调用后的返回值: 很简单,且实用:在watch中加入@hr,err。在CSDN的文档中心有一篇讲得更细,请参考。 14.产生指定源程序文件的汇编代码: 从IDE菜单的Project->Setting打开项目设置,按如下文件做: 1.先在左边选择指定文件,可以多选。 2. 在右边的C++属性页中,在category中选择List Files,接着在下面的List Files Type中选择Assembly and source code(或选择其它),最后在List File Name中输入在个C/C++源文件产生的相应的汇编代 码的文件。 3.编译整个工程。 15.手工编译纯资源成dll: Rc.exe /v data.rc Cvtres.exe /machine:ix86 data.res Link /SUBSYSTEM:WINDOWS /DLL /NOENTRY data.res ;编译成DLL文件 这种方式创建的DLL是最小的,比起你用Win 32 Dynamic Libray等产生的更小。 阅读文档中心里的“充分挖掘你的VC++ IDE的潜能”,作者:zhengyun_ustc,这是一系列的好文章。 附:VC项目文件说明 .dsp 项目参数配置文件,这个文件太重要,重点保护对象。. .dsw 工作区文件,重要性一般,因为它信息不我,容易恢复。 以下文件在项目中是可丢弃的,有些文件删除后,VC会自动生成的。 .clw ClassWizard信息文件,实际上是INI文件的格式,有兴趣可以研究一下.有时候ClassWizard出问题,手 页码,1/2 2006-7-11 file://C:DOCUME~1acerLOCALS~1TempKHU0PWS6.htm 工修改CLW文件可以解决.如果此文件不存在的话,每次用ClassWizard的时候绘提示你是否重建. .ncb 无编译浏览文件(no compile browser)。当自动完成功能出问题时可以删除此文件。build后会自动 生成。 .opt 工程关于开发环境的参数文件。如工具条位置等信息;(可丢弃) .aps (AppStudio File),资源辅助文件,二进制格式,一般不用去管他. .plg 是编译信息文件,编译时的error和warning信息文件(实际上是一个html文件),一般用处不大.在 Tools->Options里面有个选项可以控制这个文件的生成. .hpj (Help Project)是生成帮助文件的工程,用microsfot Help Compiler可以处理. .mdp (Microsoft DevStudio Project)是旧版本的项目文件,如果要打开此文件的话,会提示你是否转换成 新的DSP格式. .bsc 是用于浏览项目信息的,如果用Source Brower的话就必须有这个文件.如果不用这个功能的话,可以在 Project Options里面去掉Generate Browse Info File,可以加快编译速度. .map 是执行文件的映像信息纪录文件,除非对系统底层非常熟悉,这个文件一般用不着. .pch (Pre-Compiled File)是预编译文件,可以加快编译速度,但是文件非常大. .pdb (Program Database)记录了程序有关的一些数据和调试信息,在调试的时候可能有用. .exp 只有在编译DLL的时候才会生成,记录了DLL文件中的一些信息.一般也没什么用. 1:使用vc开发项目时,常会遇到这种情况: 即明明只改动了一个文件,却要把整个项目全部重新编译连接一次。刚刚连接好,一运行,又提示重新编译连接一次,非常讨厌。这是因为出现了未来文件的缘故。 解决方法: 找出对应文件夹下的debug目录,将未来文件全部delete, 再rebuild all一次。(未来 文件即其创建和修改时间都比系统时间靠后) 2:有时,workspace中的classview显示混乱。其表现如下: (1):添加的成员变量或函数不能显示; (2):即使显示出来了变量或函数,双击后不能跳至正确的位置。 解决方法: 删除.ncb文件,再rebuild all. 3:如何干净的删除一个类? 1:先从workspace中的FileView中删除对应的.h和.cpp文件。 2.再关闭项目,从实际的文件夹中删除对应的.h和.cpp文件。 3.灾删除.clw文件。 打开项目,rebuild all。 4:初学者常有这样的疑惑: 直接望工程文件里加入一个CPP原文件再编译连接的话老是提示没有找到预编译头 解决方法: #include "stdafx.h" 5:如何向项目中加入自己定义的类? 方法很多,介绍一个简便的: 选择Insert/New Class菜单 弹出对话框; 选择Class Type为generic; 输入类名。 当然,也可以自己决定该类的基类 6:如何在工作区(Workspace)导入多个项目(Project)? 在打开一个项目(*.dsp文件)后,在利用“Project” 菜单下Insert Project into Workspace 子菜单选择另一个项目文件(*.dsp文件),可插入另一个项目。 在ClassView 视图中,右键可以激活其中某个项目,工作区插入多个项目能方便不同项目间拷贝代码、资源等。 7: 在ClassView 视图中类太多如何整理? 我们可以在ClassView 视图中右键新建文件夹(New Folder),再把具有相近性质的类拖到对应的文件夹中,使整个视图看上去清晰明了。 8:如何快速删除项目下Debug 文件夹中临时文件? 在FileView视图中选中对应项目,右键Clean即可。 9: 打开一个源文件较大的项目编辑操作非常慢,怎么办? 不要打开项目文件(*.dsp文件),直接打开要编辑的单个源文件(*.h或*.cpp)进行编辑,要快得多。 10:如果想把整个项目拷贝到软盘,那些文件可以删掉? 除了项目文件夹中debug文件夹可以删除外,.ncb,.clw,.opt 等文件也可以删除,这些文件Rebuilt all后可以重新生成。 11:怎样快速生成一个与现有项目除了项目名外完全相同的新项目? 利用File菜单下生成新项目中的Custom AppWizard ,选择 An existing Project ,然后选择现有项目的项目文件名(*.dsp)Finish,编译后就生成一个可以生成与现有项目相同但可以重新取名的项目的AppWizard。你可以 象用MFC AppWizard一样用它。如果不想用了,可以在VC 安装目录下CommonMSDev98Template目录中删除该Wizard中.awx和 .pdb文件。 12:如何在源文件中定位光标到对称的{ }和 #if, #endif ? 前者使用Ctrl和 “} ”键 ,后者使用Ctrl和“K”键。 13:如何在VC中设置头文件和库文件? 除了VC缺省头文件和库文件外,如果经常要用到第三方的头文件和库文件可以 在Tools Options 的Directories中设置。如果只是本项目要用到,可以在Project Setting->Link Object/library Modules中设置库文件。 14:如果让控制台应用程序支持MFC类库? 可以在控制台应用程序中include 来引入MFC库,但是控制台应用程序缺省是单线程的,MFC是多线程的,为解决该矛盾,在Project Setting->C/C++ 选项,选择Code Generation,在Use Run-Time Library 下拉框中选择Debug Multithread。 15:如何为一个MFC应用程序添加ODBC功能? (1)在文件Stdafx.h文件末尾添加下面一行: #include // MFC ODBC database classes (2)在文本模式下编辑RC文件(利用File->Open As text 方式) 在下面的程序行(共有两处) #include "l.chsafxprint.rc" // printing/print preview resources 添加下一行: #include "l.chsafxdb.rc" // Database resources 16:数据库表修改后,如何快速更新一个绑定到表的CrecordSet记录集? 利用ClassWizard 中 Member Variables标签下选中记录集类后,利用UpdateColoumns和Bind All。 17:如何汉化只有可执行代码的.exe 文件? 在NT 下利用VC Open File 以Resources方式打开*.exe 文件,直接修改资源文件,然后保存即可。 让我们想像把一个ANSI字串传送到剪贴簿上,并且我们已经有了指向这个字串的指标(pString)。现在希望传送这个字串的iLength字元,这些字元可能以NULL结尾,也可能不以NULL结尾。 首先,通过使用GlobalAlloc来配置一个足以储存字串的记忆体块,其中还包括一个终止字元NULL: hGlobal = GlobalAlloc (GHND | GMEM_SHARE, iLength + 1) ; 如果未能配置到记忆体块,hGlobal的值将为NULL 。如果配置成功,则锁定这块记忆体,并得到指向它的一个指标: pGlobal = GlobalLock (hGlobal) ; 将字串复制到记忆体块中: for (i = 0 ; i < wLength ; i++) *pGlobal++ = *pString++ ; 由於GlobalAlloc的GHND旗标已使整个记忆体块在配置期间被清除为零,所以不需要增加结尾的NULL 。以下叙述为记忆体块解锁: GlobalUnlock (hGlobal) ; 现在就有了表示以NULL结尾的文字所在记忆体块的记忆体代号。为了把它送到剪贴簿中,打开剪贴簿并把它清空: OpenClipboard (hwnd) ;EmptyClipboard () ; 利用CF_TEXT识别字把记忆体代号交给剪贴簿,关闭剪贴簿: SetClipboardData (CF_TEXT, hGlobal) ;CloseClipboard () ; 工作告一段落。 GlobalAlloc 及其它 从用户的角度来看,WIN32的内存管理是非常简单和明了的。每一个应用程序都 有自己独立的4G地址空间,这种内存模式叫做“平坦”型地址模式,所有的段寄存器或描述符都指向同样的起始地址,所有的地址偏移都是32位的长度,这样一 个应用程序无须变换选择符就可以存取自己的多达4G的地址空间。这种内存管理模式是非常简洁而便于管理的,而且我们再不用和那些令人讨厌的“near”和 “far”指针打交道了。在W16下有两种主要类型的API:全局和局部。“全局”的API 分配在其他的段中,这样从内存角度来看他们是一些“far”(远)函数或者叫远过程调用,“局部”API只要和进程的堆打交道,所以把它们叫做 “near”(近)函数或者近过程调用。而在WIN32中,这两种内存模式是相同的,无论您调用GlobalAlloc还是LocalAlloc,结果都 是一样。 至于分配和使用内存的过程都是一样的: 调用GlobalAlloc函数分配一块内存,该函数会返回分配的内存句柄。 调用GlobalLock函数锁定内存块,该函数接受一个内存句柄作为参数,然后返回一个指向被锁定的内存块的指针。 您可以用该指针来读写内存。 调用GlobalUnlock函数来解锁先前被锁定的内存,该函数使得指向内存块的指针无效。 调用GlobalFree函数来释放内存块。您必须传给该函数一个内存句柄。 在WIN32中您也可以用“Local”替代内存分配API函数带有“Global”字样的函数中的“Global”,也即用LocalAlloc、LocalLock等。 在调用函数GlobalAlloc时使用GMEM_FIXED标志位可以更进一步简化操作。使用了该标志后,Global/LocalAlloc返回的是 指向已分配内存的指针而不是句柄,这样也就不用调用Global/LocalLock来锁定内存了,释放内存时只要直接调用Global /LocalFree就可以了。 句柄vs指针 句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这 个 程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址 访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一 个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意 味着它的地址变化 了。如果地址总是如此变化,我们该到哪里去找该对象呢?为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门 登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告 知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的, 当系统卸载时(Unload)又释放给系统。句柄地址(稳定)→记载着对象在内存中的地址→对象在内存中的地址(不稳定)→实际对象。但是,必须注意的是 程序每次从新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成 是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电 影院售给我们的门票总是不同的一个座位是一样的道理。 Debug 某年,某月,某日。 为某一个大型程序,增加一个大型功能。编译,运行,死机。 跟踪之,居然死在了如下语句: CString str; 而且还极不稳定,这次调试死在n行,下次调试死在m行。但都是和内存申请有关。(由于程序很大,其中频繁地申请和释放内存,多处使用new和CString) 猜测:一定是内存不够啦,遂在某处调用函数得到当前剩余的物理内存数量并使用MessageBox显示。报告曰:自由物理内存还有100多M。鼠标按下OK键,程序居然不死了。恩??? 删除MessageBox()函数—死!加上MessageBox()函数—不死!再删除–死,再加上–不死。晕倒! 捏呆呆郁闷不知道多少时间后,灵光闪烁……把多处的new/delete改写为GlobalAlloc()/GlobalFree(),一切OK。 事后原因分析:使用new和CString,频繁申请,释放内存,一定产生零碎 内存块。当使用MessageBox的时候,系统接管程序的运行(因为它在等待着你按OK按纽),它这时候开始回收合并这些零碎的内存块。这样程序就没有 问题了。而函数GlobalAlloc()/GlobalFree()本身就有回收合并零碎内存的功能。 友情提示:在频繁使用new,CString的场合,建议把某些(大)数据块的申请用GlobalAlloc替换。 c++异常处理 #include #include #include void main() { ifstream source("c:abc.txt"); //打开文件 char line[128]; try //定义异常 {if (source.fail()) throw "txt"; //抛掷异常 } catch(char * s) //定义异常处理 { cout<<"error opening the file "<<S<<ENDL; exit(1); } while(!source.eof()) { source.getline(line, sizeof(line)); cout<<LINE<<ENDL;} source.close(); } /////////////////////////////////////////////////////////// C++开发中常见问题 1,简述VC6下如何进行程序的调试。 在主菜单"Build"中,有一个Start Build的子菜单,它下面包含了Go菜单(快捷键为F5),选择后,程序将从当前语句进入调试运行,直到遇到断点或程序结束。 将鼠标移动到要调试的代码行,单击鼠标右键选择“Insert/Remove Breakpoint”,或者按下F9,可以在该行上添加断点,此时断点代码行前面出现一个棕色的圈,再次选择将清除断点。进入调试状态后,Debug菜 单将取代Build菜单出现在菜单栏中,它下面包含常用的调试操作,如Step Over,单步运行并不跟踪到调用的函数内部;其他还包括Step Into,Step Out, Stop Debugging等调试方法。 2, 简述在VC6建立的工程中后缀为.cpp,.h,.rc,.dsp,.dsw的文件的作用是什么? .cpp是源程序代码C++文件 .h是包含函数声明和变量定义的头文件 .rc是定义资源的资源脚本文件 .dsp是工程文件,记录当前工程的有关信息 .dsw是工作区文件,一个工作区可能包含一个或多个工程 3, 已知一个对话框上有一个编辑框控件,ID为IDC_EDIT1,为其关联了CEdit类型的变量m_edit1,使用两种方法,说明如何改变编辑框内部的文本为"Hello",写出程序代码的片断。 第一种方法:m_edit1.SetSel(0,-1); m_edit1.ReplaceSel("Hello"); 第二种方法:SetWindowText("Hello"); 4, 简述使用Windows API编写的一个基本的Windows应用程序框架的结构。 Windows API编写的基本应用程序框架至少应该包含程序入口函数WinMain和窗口函数WndProc。在主函数WinMain里面包含窗口类的定义和注册,窗口的创建和显示以及消息循环。 5, 消息在Windows中的数据类型是什么,它有哪些成员变量,各有什么含义 消息的数据类型是MSG,它是一个结构体,其成员变量主要包括hwnd,表示消息的窗口句柄;message代表消息的类型;wParam和lParam包含消息的附加信息,随不同的消息有所不同。 6, Windows的鼠标消息的长参数lParam与字参数wParam的含义是什么 鼠标消息的长参数lParam的低字节包含了鼠标光标位置的x坐标值,lParam的高字节包含了鼠标光标位置的y坐标值;字参数wParam内包含了指示当前按下的各种虚键状态的值。 7, 说明使用一个非模态对话框的注意问题和用到的Windows API函数 使用一个非模态对话框应该注意一定要在样式中包含WS_VISIBLE才能正常显示;创建对话框使用CreateDialog函数;消息循环部分应该使用IsDialogMessage过滤消息;关闭对话框使用函数DestroyWindow。 8, 简述在MFC应用程序中UpdateData函数的作用及其参数含义与使用场合。 UpdateData只有一个BOOL类型的参数,UpdateData(FALSE)一般用于对话框控件连接的变量值刷新屏幕显示;UpdateData(TRUE)用于获取屏幕数据到对话框控件连接的变量中。 9, 列举列表框控件能够接受的三个消息类型,并说明其作用 LB_ADDSTRING用于在列表框中加入一项字符串;LB_DIR用于在列表框中列出指定文件;LB_GETTEXT用于获取指定项的文本。 10, 在一个对话框上添加了三个单选按钮,要使它们之间自动实现互斥,应该注意什么问题,在VC环境下如何操作? 要实现一组单选按钮的自动互斥,应该让它们的控件ID值连续,并设置第一个单选按钮的Group属性,其他的不设。 11, 简述由一个文档类派生自己的文档类,并实现文档的存取需要哪些步骤。 首先为每一个文档类型从CDocument派生一个相应的文档类;然后为该文档类添加成员变量以保存数据;最后重载Serialize成员函数以实现文档数据的串行化。 12, 列举视图类(CView)的三个子类,并简要说明其作用。 CScrollView类提供视图的滚动显示;CEditView类支持在视图中的文本编辑操作;CHtmlView类支持在视图中显示和操作html文件。 14, 说明位图资源的创建及显示过程的步骤,并给出相应的Windows API函数名。 首先定义位图句柄HBITMAP hBitmap;第二步使用LoadBitMap加载位图;第三步,调用CreateCompatibleDC向系统申请内存设备环境句柄,并调用函数 SelectObject把位图选入内存设备环境;第四步,调用BitBlt函数将位图从内存设备环境输出到指定的窗口设备环境中,从而实现显示位图。 15, 如何获取字体句柄从而实现字体的输出,并给出相应的Windows API函数名。 首先定义字体句柄变量HFONT hF;然后调用函数GetStockObject获取系统的字体句柄,或者调用CreateFont得到自定义的字体句柄;最后调用SelectObject把字体句柄选入设备环境。 16, 列举三种按钮的类型,并说明其作用和创建方法之间的不同之处。 常用的按钮有普通按钮、单选按钮、复选框,和组框。普通按钮作用是帮助用户触发指定动作;单选按钮一般各选项之间存在互斥性;复选框用来显示一组选项供用户选择,各选项之间不存在互斥;组框主要用于把控件分成不同的组并加以说明. 17, 要使一个静态控件显示一个位图并能接受用户输入,应该注意什么问题。 要使静态控件显示位图,必须设定其风格包含SS_BITMAP,并在创建静态控件窗口,即调用CreateWindow时指定并加载位图;要使静态控件能够接收用户输入,必须设定其风格包含SS_NOTIFY。 VC学习笔记 VC学习笔记1:按钮的使能与禁止 用ClassWizard的Member Variables为按钮定义变量,如:m_Button1; 则 m_Button1.EnableWindow(true); 使按钮处于允许状态 m_Button1.EnableWindow(false); 使按钮被禁止,并变灰显示 VC学习笔记2:控件的隐藏与显示 用CWnd类的函数BOOL ShowWindow(int nCmdShow)可以隐藏或显示一个控件。 例1: CWnd *pWnd; pWnd = GetDlgItem( IDC_EDIT1 ); //获取控件指针,IDC_EDIT为控件ID号 pWnd->ShowWindow( SW_HIDE ); //隐藏控件 例2: CWnd *pWnd; pWnd = GetDlgItem( IDC_EDIT1 ); //获取控件指针,IDC_EDIT为控件ID号 pWnd->ShowWindow( SW_SHOW ); //显示控件 以上方法常用于动态生成控件,虽说用控件的Create函数可以动态生成控件,但这种控件很不好控制,所以用隐藏、显示方法不失为一种替代手段。 VC学习笔记3:改变控件的大小和位置 用CWnd类的函数MoveWindow()或SetWindowPos()可以改变控件的大小和位置。 void MoveWindow(int x,int y,int nWidth,int nHeight); void MoveWindow(LPCRECT lpRect); 第一种用法需给出控件新的坐标和宽度、高度; 第二种用法给出存放位置的CRect对象; 例: CWnd *pWnd; pWnd = GetDlgItem( IDC_EDIT1 ); //获取控件指针,IDC_EDIT1为控件ID号 pWnd->MoveWindow( CRect(0,0,100,100) ); //在窗口左上角显示一个宽100、高100的编辑控件 SetWindowPos()函数使用更灵活,多用于只修改控件位置而大小不变或只修改大小而位置不变的情况: BOOL SetWindowPos(const CWnd* pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags); 第一个参数我不会用,一般设为NULL; x、y控件位置;cx、cy控件宽度和高度; nFlags常用取值: SWP_NOZORDER:忽略第一个参数; SWP_NOMOVE:忽略x、y,维持位置不变; SWP_NOSIZE:忽略cx、cy,维持大小不变; 例: CWnd *pWnd; pWnd = GetDlgItem( IDC_BUTTON1 ); //获取控件指针,IDC_BUTTON1为控件ID号 pWnd->SetWindowPos( NULL,50,80,0,0,SWP_NOZORDER | SWP_NOSIZE ); //把按钮移到窗口的(50,80)处 pWnd = GetDlgItem( IDC_EDIT1 ); pWnd->SetWindowPos( NULL,0,0,100,80,SWP_NOZORDER | SWP_NOMOVE ); //把编辑控件的大小设为(100,80),位置不变 pWnd = GetDlgItem( IDC_EDIT1 ); pWnd->SetWindowPos( NULL,0,0,100,80,SWP_NOZORDER ); CFrameWnd *pFrameWnd=GetParentFrame(); //获取框架窗口指针 CRect rect; pFrameWnd->GetClientRect(&rect); //获取客户区尺寸 CWnd *pEditWnd=GetDlgItem(IDC_MYEDIT); //获取编辑控件指针,IDC_MYEDIT为控件ID号 pEditWnd->SetWindowPos(NULL,0,0,rect.right,rect.bottom-50,SWP_NOMOVE | SWP_NOZORDER); //设定控件尺寸,bottom-50是为了让出状态条位置。 } VC学习笔记5:单选按钮控件(Ridio Button)的使用 一、对单选按钮进行分组: 每组的第一个单选按钮设置属性:Group,Tabstop,Auto;其余按钮设置属性Tabstop,Auto。 m_Ridio1 = 0; m_Ridio1 = 1; m_Ridio1 = 2; m_Ridio4 = 0; m_Ridio4 = 1; //第五个单选按钮被选中 } 四、设置默认按钮: 在定义控件变量时,ClassWizard在构造函数中会把变量初值设为-1,只需把它改为其它值即可。 如: //{{AFX_DATA_INIT(CWEditView) m_Ridio1 = 0; //初始时第一个单选按钮被选中 m_Ridio4 = 0; m_Spin.SetBuddy( GetDlgItem( IDC_EDIT1 ) ); //设置编辑控件为Spin控件的伙伴窗口 m_Spin.SetRange( 0, 10 ); //设置数据范围为0-10 return TRUE; } m_Edit = m_Spin.GetPos(); CFile file; if(b_Flag) //b_Flag为文档修改标志,在修改文档时将其置为True { int t; t=::MessageBox(NULL,"文字已经改变,要存盘吗?","警告", MB_YESNOCANCEL | MB_ICONWARNING); //弹出提示对话框 if(t==0 || t==IDCANCEL) return false; if(t==IDYES) { CString sFilter="Text File(*.txt)|*.txt||"; CFileDialog m_Dlg(FALSE,"txt",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,(LPCTSTR)sFilter,NULL); //定制文件对话框 int k=m_Dlg.DoModal(); //弹出文件对话框 if(k==IDCANCEL || k==0) return false; m_PathName=m_Dlg.GetPathName(); //获取选择的文件路径名 file.Write(m_Text,m_TextLen); //数据写入文件 file.Close(); } } } VC学习笔记8:UpdateData() 对于可以接收数据的控件,如编辑控件来说,UpdateData()函数至关重要。当控件内容发生变化时,对应的控件变量的值并没有跟着变化,同样,当控件变量值变化时,控件内容也不会跟着变。 UpdateData()函数就是解决这个问题的。 UpdateData(true);把控件内容装入控件变量 UpdateData(false);用控件变量的值更新控件 如:有编辑控件IDC_EDIT1,对应的变量为字符串m_Edit1, 1、修改变量值并显示在控件中: m_Edit1 = _T("结果为50"); UpdateData(false); 2、读取控件的值到变量中: 用ClassWizard为IDC_EDIT1添加EN_CHANGE消息处理函数, void UpdateData(true); } VC实现BMP位图文件结构及平滑缩放 用普通方法显示BMP位图,占内存大,速度慢,在图形缩小时,失真严重,在低颜色位数的设备上显示高颜色位数的图形图形时失真大。本文采用视频函数显示BMP位图,可以消除以上的缺点。 // 位图文件的类型,必须为BM DWORD bfSize; // 位图文件的大小,以字节为单位 WORDbfReserved1; // 位图文件保留字,必须为0 WORDbfReserved2; // 位图文件保留字,必须为0 DWORD bfOffBits; // 位图数据的起始位置,以相对于位图 // 文件头的偏移量表示,以字节为单位 } BITMAPFILEHEADER; 3. 位图信息头 BMP位图信息头数据用于说明位图的尺寸等信息。typedef struct tagBITMAPINFOHEADER{ DWORD biSize; // 本结构所占用字节数 LONGbiWidth; // 位图的宽度,以像素为单位 LONGbiHeight; // 位图的高度,以像素为单位 WORD biPlanes; // 目标设备的级别,必须为1 WORD biBitCount// 每个像素所需的位数,必须是1(双色), // 4(16色),8(256色)或24(真彩色)之一 DWORD biCompression; // 位图压缩类型,必须是 0(不压缩), // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 DWORD biSizeImage; // 位图的大小,以字节为单位 LONGbiXPelsPerMeter; // 位图水平分辨率,每米像素数 LONGbiYPelsPerMeter; // 位图垂直分辨率,每米像素数 DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数 DWORD biClrImportant;// 位图显示过程中重要的颜色数 } BITMAPINFOHEADER; // 蓝色的亮度(值范围为0-255) BYTErgbGreen; // 绿色的亮度(值范围为0-255) BYTErgbRed; // 红色的亮度(值范围为0-255) BYTErgbReserved;// 保留,必须为0 } RGBQUAD; 颜色表中RGBQUAD结构数据的个数有biBitCount来确定: 当biBitCount=1,4,8时,分别有2,16,256个表项; 当biBitCount=24时,没有颜色表项。 // 位图信息头 RGBQUAD bmiColors[1]; // 颜色表 } BITMAPINFO; 5. 位图数据 位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数: 当biBitCount=1时,8个像素占1个字节; 当biBitCount=4时,2个像素占1个字节; 当biBitCount=8时,1个像素占1个字节; 当biBitCount=24时,1个像素占3个字节; Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,一个扫描行所占的字节数计算方法:DataSizePerLine= (biWidth* biBitCount+31)/8; // 一个扫描行所占的字节数 DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数 位图数据的大小(不压缩情况下): DataSize= DataSizePerLine* biHeight; 二、BMP位图一般显示方法 1. 申请内存空间用于存放位图文件 GlobalAlloc(GHND,FileLength); 2. 位图文件读入所申请内存空间中 LoadFileToMemory( mpBitsSrc,mFileName); 2) 内存占用大; 3) 位图在缩小显示时图形失真大,(可通过安装字体平滑软件来解决); 3. 位图文件读入所申请内存空间中LoadFileToMemory( mpBitsSrc,mFileName); 2) 内存占用少; 3) 缩放显示时图形失真小,4) 在低颜色位数的设备上显示高颜色位数的图形图形时失真小; 5) 通过直接处理位图数据,可以制作简单动画。 四、CViewBimap类编程要点 1. 在CViewBimap类中添加视频函数等成员 HDRAWDIB m_hDrawDib; // 视频函数 HANDLEmhBitsSrc; // 位图文件句柄(内存) LPSTR mpBitsSrc; // 位图文件地址(内存) BITMAPINFOHEADER *mpBitmapInfo; // 位图信息头 2. 在CViewBimap类构造函数中添加打开视频函数 m_hDrawDib= DrawDibOpen(); 3. 在CViewBimap类析构函数中添加关闭视频函数 if( m_hDrawDib != NULL) { DrawDibClose( m_hDrawDib); m_hDrawDib = NULL; } 4. 在CViewBimap类图形显示函数OnPaint中添加GraphicDraw() voidCViewBitmap::OnPaint() { CPaintDC dc(this); // device context for painting GraphicDraw( ); // device context for painting BITMAPFILEHEADER *pBitmapFileHeader; ULONG bfoffBits= 0; CPoint Wid; // 图形文件名有效 (=0 BMP) if( mBitmapFileType < ID_BITMAP_BMP ) return; // 图形文件名有效 (=0 BMP) // 准备显示真彩位图 pBitmapFileHeader= (BITMAPFILEHEADER *) mpBitsSrc; bfoffBits= pBitmapFileHeader->bfOffBits; // 使用普通函数显示位图 if( m_hDrawDib == NULL || mDispMethod == 0) { HBITMAP hBitmap=::CreateDIBitmap(dc.m_hDC, mpBitmapInfo, CBM_INIT, mpBitsSrc+bfoffBits, (LPBITMAPINFO) mpBitmapInfo,DIB_RGB_COLORS); // 建立位图 HDC hMemDC=::CreateCompatibleDC(dc.m_hDC);// 建立内存 HBITMAP hBitmapOld= SelectBitmap(hMemDC, hBitmap); // 选择对象 // 成员CRect mDispR用于指示图形显示区域的大小. // 成员CPoint mPos用于指示图形显示起始位置坐标. if( mPos.x > (mpBitmapInfo- >biWidth - mDispR.Width() )) mPos.x= mpBitmapInfo->biWidth - mDispR.Width() ; if( mPos.y > (mpBitmapInfo- >biHeight- mDispR.Height())) mPos.y= mpBitmapInfo- >biHeight- mDispR.Height(); if( mPos.x < 0 ) mPos.x= 0; if( mPos.y < 0 ) mPos.y= 0; if( mFullViewTog == biWidth, mpBitmapInfo- >biHeight, SRCCOPY); // 删 除 位 图 } else { // 使用视频函数显示位图 if( mPos.x > (mpBitmapInfo- >biWidth - mDispR.Width() )) mPos.x= mpBitmapInfo- >biWidth - mDispR.Width() ; if( mPos.y > (mpBitmapInfo- >biHeight- mDispR.Height())) mPos.y= mpBitmapInfo- >biHeight- mDispR.Height(); if( mPos.x < 0 ) mPos.x= 0; if( mPos.y < 0 ) mPos.y= 0; // 显示真彩位图 DrawDibRealize( m_hDrawDib, dc.GetSafeHdc(), TRUE); if( mFullViewTog == 0) { Wid.x= mDispR.Width(); Wid.y= mDispR.Height(); mpBitmapInfo- >biWidth ) Wid.x = mpBitmapInfo- >biWidth; if( Wid.y > mpBitmapInfo- >biHeight) Wid.y = mpBitmapInfo- >biHeight; DrawDibDraw( m_hDrawDib, dc.GetSafeHdc() , 0, 0, Wid.x, Wid.y, mpBitmapInfo, (LPVOID) (mpBitsSrc+bfoffBits), mPos.x, mPos.y, Wid.x, Wid.y, DDF_BACKGROUNDPAL); } else { DrawDibDraw( m_hDrawDib, dc.GetSafeHdc(), 0, 0, mDispR.Width(), mDispR.Height(), mpBitmapInfo, (LPVOID) (mpBitsSrc+bfoffBits), 0, 0, mpBitmapInfo- >biWidth, mpBitmapInfo- >biHeight, DDF_BACKGROUNDPAL); } } return; } 五、使用CViewBimap类显示BMP位图 1. 在Visual C++5.0中新建一个名称为mymap工程文件,类型为MFC AppWizard[exe]。在编译运行通过后,在WorkSpace(如被关闭,用Alt_0打开)点击ResourceView,点击Menu左侧 的+符号展开Menu条目,双击IDR_MAINFRAME条目,进入菜单资源编辑,在'“查看(V)”下拉式菜单(英文版为View下拉式菜单)的尾部 添加“ViewBitmap”条目,其ID为ID_VIEW_BITMAP。 2. 在Visual C++5.0中点击下拉式菜单Project- >Add To project- >Files...,将Bitmap0.h和Bitmap0.cpp添加到工程文件中。void CMainFrame::OnViewBitmap() { // TODO: Add your command handler code here CViewBitmap *pViewBitmap= NULL; pViewBitmap= new CViewBitmap( "BITMAP.BMP", this); pViewBitmap- >ShowWindow( TRUE); } 并在该程序的头部添加#include "bitmap0.h",然后编译运行。 4. 找一个大一点的真彩色的BMP位图,将它拷贝到BITMAP.BMP中。 5. 运行时,点击下拉式菜单“查看(V)- >ViewBitmap”(英文版为View- > ViewBitmap)即可显示BITMAP.BMP位图。 六、CViewBimap类功能说明 1. 在客户区中带有水平和垂直滚动条。在位图大小大于显示客户区时,可以使用滚动条;在位图大小小于显示客户区或全屏显示时,滚动条无效。 2. 在客户区中底部带有状态条。状态条中的第一格为位图信息,第二格为位图显示方法,可以是使用普通函数或使用视频函数。在第二格区域内点击鼠标,可在两者之 间接换。第三格为位图显示比例,可以是1;1显示或全屏显示。在第三格区域内点击鼠标,可在两者之间接换。在全屏显示时,如果位图比客户区小,则对位图放 大; 如果位图比客户区大,则对位图缩小。 3. 支持文件拖放功能。可以从资源管理器中拖动一个位图文件到客户区,就可以显示该位图。 程序调试通过后,可以找一个较大的真彩色位图或调整客户区比位图小,在全屏显示方式下,比较使用普通函数与使用视频函数的差别。可以看出,位图放大时两者差别不大,但在位图缩小时,两者差别明显; 使用视频函数时位图失真小,显示速度快。 还可以从控制面板中将屏幕显示方式从真彩色显示模式切换到256色显示模式,再比较使用普通函数与使用视频函数显示同一个真彩色位图的差别。现在可以体会到使用视频函数的优越性了吧。 在全屏显示时,位图的xy方向比例不相同,如要保持相同比例,可在显示程序中加以适当调整即可,读者可自行完成.