VC的使用总结
将文字传送到剪贴簿 让我们想像把一个ANSI字串传送到剪贴簿上,并且我们已经有了指向这个字串的指标(pString)。现在希望传送这个字串的iLength字元,这些字元可能以NULL结尾,也可能不以NULL结尾。 首先,通过使用GlobalAlloc来配置一个足以储存字串的记忆体块,其中还包括一个终止字元NULL: 如果未能配置到记忆体块,hGlobal的值将为NULL 。如果配置成功,则锁定这块记忆体,并得到指向它的一个指标: 将字串复制到记忆体块中: 由於GlobalAlloc的GHND旗标已使整个记忆体块在配置期间被清除为零,所以不需要增加结尾的NULL 。以下叙述为记忆体块解锁: 现在就有了表示以NULL结尾的文字所在记忆体块的记忆体代号。为了把它送到剪贴簿中,打开剪贴簿并把它清空: 利用CF_TEXT识别字把记忆体代号交给剪贴簿,关闭剪贴簿: 工作告一段落。 GlobalAlloc 及其它 从用户的角度来看,WIN32的内存管理是非常简单和明了的。每一个应用程序都有自己独立的4G地址空间,这种内存模式叫做“平坦”型地址模式,所有的段寄存器或描述符都指向同样的起始地址,所有的地址偏移都是32位的长度,这样一个应用程序无须变换选择符就可以存取自己的多达4G的地址空间。这种内存管理模式是非常简洁而便于管理的,而且我们再不用和那些令人讨厌的“near”和“far”指针打交道了。在W16下有两种主要类型的API:全局和局部。“全局”的API 分配在其他的段中,这样从内存角度来看他们是一些“far”(远)函数或者叫远过程调用,“局部”API只要和进程的堆打交道,所以把它们叫做“near”(近)函数或者近过程调用。而在WIN32中,这两种内存模式是相同的,无论您调用GlobalAlloc还是LocalAlloc,结果都是一样。 至于分配和使用内存的过程都是一样的: 调用GlobalAlloc函数分配一块内存,该函数会返回分配的内存句柄。 句柄vs指针 句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这 某年,某月,某日。 跟踪之,居然死在了如下语句: 猜测:一定是内存不够啦,遂在某处调用函数得到当前剩余的物理内存数量并使用MessageBox显示。报告曰:自由物理内存还有100多M。鼠标按下OK键,程序居然不死了。恩??? 删除MessageBox()函数—死!加上MessageBox()函数—不死!再删除–死,再加上–不死。晕倒! 捏呆呆郁闷不知道多少时间后,灵光闪烁……把多处的new/delete改写为GlobalAlloc()/GlobalFree(),一切OK。 事后原因分析:使用new和CString,频繁申请,释放内存,一定产生零碎内存块。当使用MessageBox的时候,系统接管程序的运行(因为它在等待着你按OK按纽),它这时候开始回收合并这些零碎的内存块。这样程序就没有问题了。而函数GlobalAlloc()/GlobalFree()本身就有回收合并零碎内存的功能。 友情提示:在频繁使用new,CString的场合,建议把某些(大)数据块的申请用GlobalAlloc替换。 #include<fstream.h>
在主菜单"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学习笔记
用ClassWizard的Member Variables为按钮定义变量,如:m_Button1;
用CWnd类的函数BOOL ShowWindow(int nCmdShow)可以隐藏或显示一个控件。 例1: 例2: 以上方法常用于动态生成控件,虽说用控件的Create函数可以动态生成控件,但这种控件很不好控制,所以用隐藏、显示方法不失为一种替代手段。
用CWnd类的函数MoveWindow()或SetWindowPos()可以改变控件的大小和位置。 void MoveWindow(int x,int y,int nWidth,int nHeight); SetWindowPos()函数使用更灵活,多用于只修改控件位置而大小不变或只修改大小而位置不变的情况: CRect rect; CWnd *pEditWnd=GetDlgItem(IDC_MYEDIT); //获取编辑控件指针,IDC_MYEDIT为控件ID号
一、对单选按钮进行分组: m_Ridio1 = 0; m_Ridio1 = 1; m_Ridio1 = 2; m_Ridio4 = 0; m_Ridio4 = 1; //第五个单选按钮被选中 四、设置默认按钮: m_Edit = m_Spin.GetPos(); CFile file; int k=m_Dlg.DoModal(); //弹出文件对话框
对于可以接收数据的控件,如编辑控件来说,UpdateData()函数至关重要。当控件内容发生变化时,对应的控件变量的值并没有跟着变化,同样,当控件变量值变化时,控件内容也不会跟着变。 UpdateData(true);把控件内容装入控件变量 如:有编辑控件IDC_EDIT1,对应的变量为字符串m_Edit1, VC实现BMP位图文件结构及平滑缩放
// 位图文件的类型,必须为BM DWORD bfSize; // 位图文件的大小,以字节为单位 WORDbfReserved1; // 位图文件保留字,必须为0 WORDbfReserved2; // 位图文件保留字,必须为0 DWORD bfOffBits; // 位图数据的起始位置,以相对于位图 // 文件头的偏移量表示,以字节为单位 } BITMAPFILEHEADER;
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;
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数: 当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;
1. 申请内存空间用于存放位图文件 GlobalAlloc(GHND,FileLength); 2. 位图文件读入所申请内存空间中 LoadFileToMemory( mpBitsSrc,mFileName); 2) 内存占用大; 3) 位图在缩小显示时图形失真大,(可通过安装字体平滑软件来解决);
2) 内存占用少; 3) 缩放显示时图形失真小,4) 在低颜色位数的设备上显示高颜色位数的图形图形时失真小; 5) 通过直接处理位图数据,可以制作简单动画。 1. 在CViewBimap类中添加视频函数等成员 HDRAWDIB m_hDrawDib; // 视频函数 HANDLEmhBitsSrc; // 位图文件句柄(内存) LPSTR mpBitsSrc; // 位图文件地址(内存) BITMAPINFOHEADER *mpBitmapInfo; // 位图信息头
m_hDrawDib= DrawDibOpen();
if( m_hDrawDib != NULL) { DrawDibClose( m_hDrawDib); m_hDrawDib = NULL; }
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; }
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); }
4. 找一个大一点的真彩色的BMP位图,将它拷贝到BITMAP.BMP中。 5. 运行时,点击下拉式菜单“查看(V)- >ViewBitmap”(英文版为View- > ViewBitmap)即可显示BITMAP.BMP位图。 六、CViewBimap类功能说明 1. 在客户区中带有水平和垂直滚动条。在位图大小大于显示客户区时,可以使用滚动条;在位图大小小于显示客户区或全屏显示时,滚动条无效。 2. 在客户区中底部带有状态条。状态条中的第一格为位图信息,第二格为位图显示方法,可以是使用普通函数或使用视频函数。在第二格区域内点击鼠标,可在两者之间接换。第三格为位图显示比例,可以是1;1显示或全屏显示。在第三格区域内点击鼠标,可在两者之间接换。在全屏显示时,如果位图比客户区小,则对位图放大; 如果位图比客户区大,则对位图缩小。 3. 支持文件拖放功能。可以从资源管理器中拖动一个位图文件到客户区,就可以显示该位图。 程序调试通过后,可以找一个较大的真彩色位图或调整客户区比位图小,在全屏显示方式下,比较使用普通函数与使用视频函数的差别。可以看出,位图放大时两者差别不大,但在位图缩小时,两者差别明显; 使用视频函数时位图失真小,显示速度快。 还可以从控制面板中将屏幕显示方式从真彩色显示模式切换到256色显示模式,再比较使用普通函数与使用视频函数显示同一个真彩色位图的差别。现在可以体会到使用视频函数的优越性了吧。 在全屏显示时,位图的xy方向比例不相同,如要保持相同比例,可在显示程序中加以适当调整即可,读者可自行完成. |