使用SkinMagic Toolkit美化界面
1、将SkinMagicTrial.dll放置在调试目录
2、设置库文件目录,在项目[连接器]的[附加依赖项]中加入库SkinMagicTrial.lib
3、在项目的stdafx.h文件中加入头文件 #include "SkinMagicLib.h"
[创建过程]
1、初始化SkinMagic库:
要使用SkinMagic,这一步必不可少。在应用程序类的InitInstance()函数中行加入如下代码(粗体部分):
CWinApp::InitInstance();
VERIFY( 1 == InitSkinMagicLib(AfxGetInstanceHandle(), NULL ,
NULL, NULL ));
说明:
int InitSkinMagicLib( //初始化SkinMagic工具库
HINSTANCE hInstance, //应用程序句柄
char* szApplication , //皮肤文件中定义的应用程序名,置为NULL即可
char* szRegCode, //SkinMagic的使用注册码。若无置为NULL
char* szReserved2 //保留位,为NULL
);
2、调入皮肤文件:
皮肤的调用有两种方法,一是直接从皮肤文件中调用,另一种方法是从资源文件中调用,分别说明如下:
1)从皮肤文件中调用皮肤:紧接上句,加入如下代码
VERIFY( 1 == LoadSkinFile("corona.smf"));
2)从资源文件中调用皮肤:
VERIFY(1 == LoadSkinFromResource(NULL,"FUTURA","skin"));
说明: int LoadSkinFromResource(
HMODULE hModule, //包含皮肤文件的模块句柄,若NULL表面在本模块中
char* lpSkinName , //皮肤资源的名称
char* lpType); //资源的类型
3、为窗口添加皮肤:
1)为标准窗口(拥有标题栏、系统菜单、可变大小等特征,比如文档/视图结构和有菜单的对话框)添加皮肤,通常用于主窗口。在应用程序类的InitInstance()函数的底部加入如下代码:
VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
说明:
int SetWindowSkin(
HWND hWnd, //要使用皮肤的窗口句柄
char* lpSkinName //为skinFrameWnd对象指定的名称
);
2)为对话框添加皮肤
在对话框显示之前调用,通常在应用程序初始化函数中调用
VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));
VERIFY( 1 == SetDialogSkin( "Dialog" ) );
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
说明:
int SetDialogSkin(
char* lpSkinName //为skinFrameWnd对象指定的名称
);
使用该函数后,以后程序创建的对话框都将使用该皮肤,但对话框大小不可变。
3)为单个对话框窗口添加皮肤,例如在对话框视图中:重载对话框视图的创建函数OnCreate,加入如下代码:
VERIFY( 1 == SetSingleDialogSkin( m_hWnd, "Dialog" ) );
EnableWindowScrollbarSkin( m_hWnd , SB_BOTH );
说明:
int SetSingleDialogSkin(
HWND hWnd, //要使用皮肤的窗口句柄
char* lpSkinName //为skinFrameWnd对象指定的名称
);
int EnableWindowScrollbarSkin( //为滚动条添加皮肤
HWND hWnd, //要使用皮肤的窗口句柄
int* fnBar //要使用皮肤的滚动条,SB_BOTH表明是横竖都是用皮肤
);
4、释放SkinMagic资源
重载应用程序的ExitInstance()函数,添加如下代码:
ExitSkinMagicLib();
如何有效地使用对话框
BOOL CYourDlg::OnInitDialog() { CDialog::OnInitDialog(); // Create the toolbar. To understand the meaning of the styles used, you // can take a look at the MSDN for the Create function of the CToolBar class. ToolBar.Create(this, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_TOOLTIPS |CBRS_FLYBY | CBRS_BORDER_BOTTOM); // I have assumed that you have named your toolbar''s resource as IDR_TOOLBAR1. // If you have given it a different name, change the line below to accomodate // that by changing the parameter for the LoadToolBar function. ToolBar.LoadToolBar(IDR_TOOLBAR1); CRect rcClientStart; CRect rcClientNow; GetClientRect(rcClientStart); // To reposition and resize the control bar RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST,0, reposQuery, rcClientNow); CPoint ptOffset(rcClientNow.left - rcClientStart.left,rcClientNow.top-rcClientStart.top); CRect rcChild; CWnd* pwndChild = GetWindow(GW_CHILD); while (pwndChild) { pwndChild->GetWindowRect(rcChild); ScreenToClient(rcChild); rcChild.OffsetRect(ptOffset); pwndChild->MoveWindow(rcChild, FALSE); pwndChild = pwndChild->GetNextWindow(); } CRect rcWindow; GetWindowRect(rcWindow); rcWindow.right += rcClientStart.Width() - rcClientNow.Width(); rcWindow.bottom += rcClientStart.Height() - rcClientNow.Height(); MoveWindow(rcWindow, FALSE); // And position the control bars RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); return TRUE; // return TRUE unless you set the focus to a control }

可用下面一些函数:
CreatePolygonRgn
CreateRectRgn
CreateRoundRectRgn 等.
CRgn m_rgn; // Put this in your dialog''s header file. i.e. a member variable // This Gets the size of the Dialog: This piece of code is to be placed in the // OnInitDialog Function of your dialog. CRect rcDialog GetClientRect(rcDialog); // The following code Creates the area and assigns it to your Dialog m_rgn.CreateEllipticRgn(0, 0, rcDialog.Width(), rcDialogHeight()); SetWindowRgn(GetSafeHwnd(), (HRGN) m_rgn, TRUE);

可用下面二种方法
// Handler for WM_LBUTTONDOWN message void CYourDialog::OnLButtonDown(UINT nFlags, CPoint point) { CDialog::OnLButtonDown(nFlags, point); PostMessage( WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM( point.x, point.y)); } // Handler for WM_NCHITTEST message LONG CYourDialog::OnNcHitTest( UINT uParam, LONG lParam ) { int xPos = LOWORD(lParam); int yPos = HIWORD(lParam); UINT nHitTest = CDialog::OnNcHitTest(CSize(xPos, yPos)); return (nHitTest == HTCLIENT) ? HTCAPTION : nHitTest; }

在 OnInitDialog 中加入下面代码:
SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, NULL);

在 WM_SIZING中加入下面代码:
void CYourDialog::OnSizing(UINT fwSide, LPRECT pRect) { if(pRect->right - pRect->left <=200) pRect->right = pRect->left + 200; if(pRect->bottom - pRect->top <=200) pRect->bottom = pRect->top + 200; CDialog::OnSizing(fwSide, pRect); }

定义 CStatusBar 变量:
CStatusBar m_StatusBar;定义状态条指定状态:
static UINT BASED_CODE indicators[] = { ID_INDICATOR_CAPS, ID_INDICATOR_NUM };在 OnInitDialog 中加入下面代码:
m_StatusBar.CreateEx(this,SBT_TOOLTIPS,WS_CHILD|WS_VISIBLE|CBRS_BOTTOM,AFX_IDW_STATUS_BAR); // Set the indicators namely caps and nums lock status m_StatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT)); CRect rect; GetClientRect(&rect); m_StatusBar.SetPaneInfo(0,ID_INDICATOR_CAPS,SBPS_NORMAL,rect.Width()/2); m_StatusBar.SetPaneInfo(1,ID_INDICATOR_NUM,SBPS_STRETCH ,rect.Width()/2); RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,ID_INDICATOR_NUM); m_StatusBar.GetStatusBarCtrl().SetBkColor(RGB(180,180,180));
如何手工编写.mak文件?
myprogram.exe : myprogram.obj
$(LINKER) $(GUIFLAGS) -OUT: myprogram.exe myprogram.obj $(GUILIBS)
myprogram.obj : myprogram.c myprogram.h
$(CC) $(CFLAGS) myprogram.c
.mak 文件包含一个或多个段,每段以一个左顶格行开始,首先列出的是一个目标
文件,后跟一个冒号,再跟一个或多个目标文件的依赖文件。这一行后面跟一行或多
行缩进命令,这些命令根据依赖文件来创建目标文件。
任何一个依赖文件的最后一次修改日期和时间比目标文件的最后一次修改日期和
时间晚,则会执行缩进的命令行,以创建最新的目标文件。
.mak文件的分析是从底向上的,因为大多数底部行的目标文件是上部行目标文件
的依赖文件。
你应该在你的Autoexec.bat 文件中设置如下语句:
CALL /Micros~1/BIN/VCVARS32.BAT
其中Micros~1是你的VC所在的目录,VCVARS32.BAT是VC命令行编译的必需的Dos
环境变量。
其中(LINKER) .....都是设置的环境变量宏,这样做的原因只是为了节省.mak
文件的复杂程度,因为我们编译的时候多半都是需要差不多的命令行。
因此还需要以下的批处理文件:(假设命令为C.bat)
rem C.bat
rem -----------------------------------------------------
SET CC=cl
SET CFLAGS=-c -DSTRICT -G3 -Ow -W3 -Zp -Tp
SET CFLAGSMT=-c -DSTRICT -G3 -MT -Ow -W3 -Zp -Tp
SET LINKER=link
SET GUIFLAGS=-SUBSYSTEM:windows
SET DLLFLAGS=-SUBSYSTEM:windows -DLL
SET GUILIBS=-DEFAULTLIB:user32.lib gdi32.lib winmm.lib comdlg32.lib comctl32.lib
SET RC=rc
SET RCVARS=-r -DWIN32
rem -------------------------------------------------------
以上批处理摘自《window95程序设计》,差不多包含了所必须的编译命令。
你同样应该在你的Autoexec.bat 文件中执行这个批处理文件。同时避免环境变量
空间的溢出,你必须扩大你的环境变量空间,用如下命令行:
shell=C:/windows/command.com /e:4096(见本版1188封信)
这样你自己应该可以写自己的比较简单的.mak文件了。
如何与资源管理器互动剪切/拷贝/粘贴文件
1,用户在资源管理器(Windows Explorer)中剪切/拷贝(Cut/Copy)文件,然后在自己的应用程序中进行粘贴(Paste)操作;
2.用户在自己的应用程序中剪切/拷贝文件,在资源管理其中粘贴操作。
二.本文中的代码编写工具及测试环境:
1,VC6.0, Platform SDK(无须MFC);
2.Windows 2000。
三.概述
我们知道,在Windows中可以通过剪贴板(Clipboard)来共享和传递数据,比如在资源管理器(Windows Explorer)中可以剪切/拷贝/粘贴文件。同样我们也可以在自己的应用程序中通过剪贴板来完成这些工作,从而提高我们自己的应用程序与Windows操作系统之间的互操作性。但我们如何才能与资源管理器之类的应用程序共享和传递数据呢?本文提供的方法是:使用Windows本身提供的一些数据结构和API,通过剪贴板来实现数据共享和传递。
四.实现方法
首先,Windows在剪切/拷贝文件时并不是把文件名称写入剪贴板,而是在剪贴板中放入了一个DragAndDrop文件对象,并写入了一个状态值来标识操作类型(移动/拷贝,剪切其实就是移动,如果你剪切之后并没有粘贴,那么该文件依然存在而不会被删除)。依据这个知识,我们首先来看看在应用程序中如何识别出Windows 资源管理器的剪切/拷贝动作。
在使用剪贴板前,我们首先要打开它:
BOOL OpenClipboard(HWND hWnd); 参数 hWnd 是打开剪贴板的窗口句柄,成功返回TRUE,失败返回FALSE。之后,可以用GetClipboardData来得到剪贴板中的数据:
HANDLE GetClipboardData(UINT uFormat);uFormat是所需要数据的格式,例如本文拖放对象的格式为CF_HDROP。而表明该拖放对象类型(Move/Copy)的数据格式并不是Windows标准的剪贴板数据结构,而是一个简单的DWORD指针。我们可以通过下面的语句来注册一下数据类型 :
UINT uDropEffect=RegisterClipboardFormat("Preferred DropEffect");这里返回的uDropEffect就是我们将要代入GetClipboardData函数的该数据结构的代码,
GetClipboardData函数返回是一个句柄,这只是Windows为了统一性而做的工作,我们可以根据需要来转换成相应的数据形式,比如我们的uDropEffect就 是一个DWORD指针。
前面我已经说过在剪贴板中放的是一个拖放对象,因此我们可以通过如下语句得到该对象:
HDROP hDrop = HDROP( GetClipboardData( CF_HDROP));如果确实存在一个hDrop对象,我们应该取得uDropEffect的数据,以便我们处理后面的文件:
DWORD dwEffect=*((DWORD*)(GetClipboardData( uDropEffcet)));关于这个值的含义,我们只要包含一下"OLEIDL.H"头文件即可,在该头文件中5种状态的定义而本文只关注:
#define DROPEFFECT_COPY ( 1 ) #define DROPEFFECT_MOVE ( 2 )因此,我们可以通过
if(dwEffect & DROPEFFECT_COPY) CopyFile(....); else (dwEffect & DROPEFFECT_MOVE) MoveFile(...);来完成剪切/拷贝操作。
在我们取得uDropEffect状态之后,我们需要得到文件列表,得到拖放对象中的文件列表可以通过DragQueryFile来实现:
UINT DragQueryFile(HDROP hDrop, UINT iFile,LPTSTR lpszFile,UINT cch);第二个参数是文件序列号,可以通过将iFile置为-1的方法来得到文件数量。
最后我们给出完整的例子:
#include <Shellapi.h> #include <oleidl.h> .... UINT uDropEffect=RegisterClipboardFormat("Preferred DropEffect"); if( OpenClipboard( hWnd)) { HDROP hDrop = HDROP( GetClipboardData( CF_HDROP)); if( hDrop) { DWORD dwEffect,*dw; dw=(DWORD*)(GetClipboardData( uDropEffect)); if(dw==NULL) dwEffect=DROPEFFECT_COPY; else dwEffect=*dw; char Buf[4096]; Buf[0] = 0; UINT cFiles = DragQueryFile( hDrop, (UINT) -1, NULL, 0); POINT Point; char szFile[ MAX_PATH]; for( UINT count = 0; count < cFiles; count++ ) { DragQueryFile( hDrop, count, szFile, sizeof( szFile)); lstrcat(Buf,szFile); lstrcat(Buf,"/n"); } if(dwEffect & DROPEFFECT_MOVE) { MessageBox(NULL,Buf,"Move Files",MB_OK); } else if(dwEffect & DROPEFFECT_COPY) { MessageBox(NULL,Buf,"Copy Files",MB_OK); } CloseClipboard(); } }在这个例子中,我并没有进行文件操作,只是简单的显示一个消息框,实际应用时,需要使用MoveFile和CopyFile函数来完成,本文不做讨论。
知道如何识别其他程序的剪切/拷贝 文件的动作后,我们对该操作的数据结构已经很了解了,要想让其他程序能识别我们的剪切/拷贝 文件动作其实就是将以上数据结构放入剪贴板的过程。
在我们这个例子中,往剪贴板中放的数据必须是内存对象:HGLOBAL。这个对象可以通过GlobalAlloc来生成。然后使用GlobalLock就可以得到该对象的内存地址,继而往里面写 数据。实际上在Win32中由于进程拥有独立的内存空间,因而常规的内存分配已经不需要GlobalLock了,看看MSDN就知道该函数主要就是为DDE和剪贴板服务的。
根据前面的知识,要想让其他程序识别出我们的剪切/拷贝动作我们必须往剪贴板中放两项数据,现在就让我们来为DropEffect准备数据吧,同样我们需要先注册该数据格式:
uDropEffect=RegisterClipboardFormat("Preferred DropEffect");然后分配内存对象并得到指针:
hGblEffect=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE,sizeof(DWORD)); dwDropEffect=(DWORD*)GlobalLock(hGblEffect);注意往剪贴板中放的数据必须使用GMEM_MOVEABLE标志,最后我们设置数据并解除锁定:
if(COPY) *dwDropEffect=DROPEFFECT_COPY; else *dwDropEffect=DROPEFFECT_MOVE; GlobalUnlock(hGblEffect);这样我就为DropEffect准备还数据了,等一会儿我们连同文件拖放对象一起放入剪贴板。建立文件拖放对象的方法与DropEffect基本相同,只是文件拖放对象有特殊的数据结构 而不象DropEffect那样简单,该对象数据结构如下:
+----------------------------+ | DROPFILES | Files List | +----------------------------+DROPFILES是拖放对象的头数据,该结构在shlobj.h中定义:
typedef struct _DROPFILES { DWORD pFiles; POINT pt; BOOL fNC; BOOL fWide; } DROPFILES, FAR * LPDROPFILES;pFiles指针是以对象首地址为参照的文件列表(上图中的Files List项)的offset量。通常该值等于DROPFILES结构的长度(我还没见过例外);pt表明文件拖放的位置坐标,在这个例子里我们忽略为0; fNC表明pt值是否为客户区坐标(FALSE表明是屏幕坐标);fWide表明Files List是否包含unicode,作为中国人,我们当然要设其为TRUE。DROPFILES结构之后紧跟Files List,Files List是一组宽字符串,之间以0相隔,比如:"文件1/0文件2/0..."
我们可以通过MultiByteToWideChar函数将常规的字符串转换成宽字符串。下面就是生成拖放对象的代码:
uDropFilesLen=sizeof(DROPFILES); dropFiles.pFiles =uDropFilesLen; dropFiles.pt.x=0; dropFiles.pt.y=0; dropFiles.fNC =FALSE; dropFiles.fWide =TRUE; uGblLen=uDropFilesLen+uBufLen<<1+8; //uBufLen是文件名字符传组的长度,由于要转换成宽字符,因此长度要乘2 hGblFiles= GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE, uGblLen); szData=(char*)GlobalLock(hGblFiles); memcpy(szData,(LPVOID)(&dropFiles),uDropFilesLen); //将DROPFILES copy到头部 szFileList=szData+uDropFilesLen; //得到存放文件列表的首地址 MultiByteToWideChar(CP_ACP,MB_COMPOSITE, lpBuffer,uBufLen,(WCHAR *)szFileList,uBufLen); GlobalUnlock(hGblFiles);现在我们就可以将上面两组数据放入剪贴板中了,注意在写数据前应先清空剪贴板。为了方便大家使用,下面我给出实现此功能的独立的函数:
VOID CutOrCopyFiles(char * lpBuffer,UINT uBufLen,BOOL bCopy)lpBuffer是包括所有准备剪切/拷贝的文件名称的缓冲区;uBufLen是lpBuffer的长度;bCopy决定该操作是Copy还是Cut,TRUE为Copy,FALSE为Cut。例如我们可以这样调用该函数:
char szFiles[]="c://1.txt/0c://2.txt/0"; CutOrCopyFiles(szFiles,sizeof(szFiles),FALSE);来剪切文件,或者使用:
CutOrCopyFiles(szFiles,sizeof(szFiles),TRUE);来拷贝文件。
#include <Shellapi.h> #include <Shlobj.h> #include <oleidl.h>
...... VOID CutOrCopyFiles(char *lpBuffer,UINT uBufLen,BOOL bCopy) { UINT uDropEffect; DROPFILES dropFiles; UINT uGblLen,uDropFilesLen; HGLOBAL hGblFiles,hGblEffect; char *szData,*szFileList; DWORD *dwDropEffect; uDropEffect=RegisterClipboardFormat("Preferred DropEffect"); hGblEffect=GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE,sizeof(DWORD)); dwDropEffect=(DWORD*)GlobalLock(hGblEffect); if(bCopy) *dwDropEffect=DROPEFFECT_COPY; else *dwDropEffect=DROPEFFECT_MOVE; GlobalUnlock(hGblEffect); uDropFilesLen=sizeof(DROPFILES); dropFiles.pFiles =uDropFilesLen; dropFiles.pt.x=0; dropFiles.pt.y=0; dropFiles.fNC =FALSE; dropFiles.fWide =TRUE; uGblLen=uDropFilesLen+uBufLen*2+8; hGblFiles= GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE, uGblLen); szData=(char*)GlobalLock(hGblFiles); memcpy(szData,(LPVOID)(&dropFiles),uDropFilesLen); szFileList=szData+uDropFilesLen; MultiByteToWideChar(CP_ACP,MB_COMPOSITE, lpBuffer,uBufLen,(WCHAR *)szFileList,uBufLen); GlobalUnlock(hGblFiles); if( OpenClipboard(NULL) ) { EmptyClipboard(); SetClipboardData( CF_HDROP, hGblFiles ); SetClipboardData(uDropEffect,hGblEffect); CloseClipboard(); } }希望以上内容对你有所帮助。
本文附上一个Demo工程,编译后生成CutCopy.exe程序,该程序的使用方法如下:
启动程序后,可使用Windows 资源管理器等程序剪切/拷贝文件,然后点程序中的[CheckClipboard],Demo程序将分析剪贴板中的内容,并弹出消息框告知是Copy Files还是Cut Files,并给出文件列表.用户点[OK]关闭消息框后,文件列表 将被放入文本框中,此时用户可以通过[Cut]/[Copy]按钮来改变剪贴板中的属性。
同时,用户可以通过[Browser]来选择若干文件到文本框中,然后点[Cut]/[Copy]进行操作,之后,用户既可以通过[CheckClipboard]检查剪贴板中的内容也可以通过在Windows 资源管理器等程序中进行粘贴(Paste)来检查其是否正确。
VC中一些控件的小技巧
用SetExtendedStyle方法可以设置,看代码:
(CListCtrl m_ListCtrl;)
DWORD dwStyle = m_ListCtrl.GetStyle();
dwStyle |= LVS_EX_CHECKBOXES;
m_ListCtrl.SetExtendedStyle(dwStyle);
2.让List Box有Check Box
首先,声明Control变量的时候用CCheckListBox代替CListBox。
然后,将List Box的Has Strings属性改为True;把Ower Draw属性改为Fixed。
3.Spin Control与Edit Control的绑定
首先,要让Spin Control的Tap Order紧跟着Edit Control(就是说,Spin Control的Tap Order是Edit Control的Tap Order加1)。
然后,设置Spin Control的Auto Buddy和Set Buddy Integer属性为True。
4.可以设置背景和文字颜色的Static控件
从CStatic类继承一个自己的Static类,相应WM_CTLCOLOR消息。下面是代码:
.h文件:
class ClxStatic : public CStatic
{
DECLARE_DYNAMIC(ClxStatic)
public:
ClxStatic();
virtual ~ClxStatic();
afx_msg HBRUSH CtlColor(CDC* /*pDC*/, UINT /*nCtlColor*/);
void SetBackColor(COLORREF clrBack);
void SetTextColor(COLORREF clrText);
protected:
DECLARE_MESSAGE_MAP()
CBrush m_brushBack;
COLORREF m_clrBack;
COLORREF m_clrText;
};
.cpp文件:
IMPLEMENT_DYNAMIC(ClxStatic, CStatic)
ClxStatic::ClxStatic()
{
m_clrBack = ::GetSysColor(COLOR_BTNFACE);
m_clrText = ::GetSysColor(COLOR_BTNTEXT);
}
ClxStatic::~ClxStatic()
{
}
void ClxStatic::SetBackColor(COLORREF clrBack)
{
m_clrBack = clrBack;
}
void ClxStatic::SetTextColor(COLORREF clrText)
{
m_clrText = clrText;
}
BEGIN_MESSAGE_MAP(ClxStatic, CStatic)
ON_WM_CTLCOLOR_REFLECT()
END_MESSAGE_MAP()
HBRUSH ClxStatic::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
{
// TODO: Change any attributes of the DC here
m_brushBack.Detach();
m_brushBack.CreateSolidBrush(m_clrBack);
pDC->SetBkColor(m_clrBack);
pDC->SetTextColor(m_clrText);
// TODO: Return a non-NULL brush if the parent's handler should not be called
//return NULL;
return (HBRUSH)m_brushBack.GetSafeHandle();
}
5.在Static控件中显示BMP
首先,给Static控件添加一个Control变量(ID要改了以后才能添加变量,也就是说ID不能为IDC_STATIC),本例为m_staticTest。
然后,用ModifyStyle函数修改Static控件的Style,让它可以显示图片:
m_staticTest.ModifyStyle(0, SS_BITMAP | SS_CENTERIMAGE);
最后,就是Load文件显示出来:
CRect rect;
m_staticTest.GetWindowRect(&rect);
// 下面的方法是按照Static控件的大小显示bmp,如果要安装图片实际大小显示,用这个方法Load图片:
// HBITMAP hBmp = (HBITMAP)::LoadImage(0, _T("D://test.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP hBmp = (HBITMAP)::LoadImage(0, _T("D://test.bmp"), IMAGE_BITMAP, rect.Width(), rect.Height(), LR_LOADFROMFILE);
m_staticTest.SetBitmap(hBmp);
DeleteObject(hBmp);
显示BMP图像文件
1、通过点击浏览按钮选择BMP图像文件
点击浏览按钮打开文件对话框选择BMP图像文件,得到文件所在的路径目录。
关键代码如下:
char szFilter[] = "BMP Files (*.bmp)|*.bmp|All Files (*.*)|*.*||";
CFileDialog dlg( TRUE,"BMP",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,szFilter );
if(dlg.DoModal() == IDOK)
{
CString strPathName = dlg.GetPathName();
}
2、加载BMP文件到内存
通过得到的BMP图像文件路径目录,加载BMP图像文件到内存中。
关键代码如下:
BOOL CShowBMPDlg::LoadShowBMPFile(const char *pPathname)
{
CFile file;
if( !file.Open( pPathname, CFile::modeRead) )
return FALSE;
DWORD m_nFileLen;
m_nFileLen = file.GetLength();
m_pBMPBuffer = new char[m_nFileLen + 1];
if(!m_pBMPBuffer)
return FALSE;
if(file.ReadHuge(m_pBMPBuffer,m_nFileLen) != m_nFileLen)
return FALSE;
return TRUE;
}
3、将内存中的BMP文件内容转换到HBITMAP
将内存中的BMP文件内容转换成位图句柄。
关键代码如下:
HBITMAP CShowBMPDlg::BufferToHBITMAP()
{
HBITMAP hShowBMP;
LPSTR hDIB,lpBuffer = m_pBMPBuffer;
LPVOID lpDIBBits;
BITMAPFILEHEADER bmfHeader;
DWORD bmfHeaderLen;
bmfHeaderLen = sizeof(bmfHeader);
strncpy((LPSTR)&bmfHeader,(LPSTR)lpBuffer,bmfHeaderLen);
if (bmfHeader.bfType != (*(WORD*)"BM")) return NULL;
hDIB = lpBuffer + bmfHeaderLen;
BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)hDIB ;
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
lpDIBBits=(lpBuffer)+((BITMAPFILEHEADER *)lpBuffer)->bfOffBits;
CClientDC dc(this);
hShowBMP = CreateDIBitmap(dc.m_hDC,&bmiHeader,CBM_INIT,lpDIBBits,&bmInfo,DIB_RGB_COLORS);
return hShowBMP;
}
4、在屏幕上显示BMP图像
双缓冲实现BMP位图显示在屏幕上。
关键代码如下:
void CShowBMPDlg::DrawImage(int x, int y, CDC *pDC)
{
HBITMAP OldBitmap;
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
OldBitmap=(HBITMAP)MemDC.SelectObject(m_hBitmap);
CRect rect;
GetClientRect(&rect);
pDC->BitBlt(x,y,rect.Width(),rect.Height(),&MemDC,0,0,SRCCOPY);
MemDC.SelectObject(OldBitmap);
}
自己动手制作一款简洁实用的图片浏览器
我想要DIY的,是一款简洁实用的图片浏览器。众所周知,ACDSee是最流行的图片浏览器,确实很不错。但作为一名程序员,我想,要是我也能制作出一款简洁实用的图片浏览器,可以在我开发的软件中有图片浏览功能,那该多好。
而我确实DIY出了这么一个图片浏览器,她简洁实用,小巧玲珑,取名为:SimpleBrowse。现将制作过程介绍如下,与大家分享,并期望能起到抛砖引玉的作用。
第一步:定规格
1.样子要象ACDSee一样,左边是目录树,右边是文件列表,显示图片文件的缩图。
2.缩图要好看,浏览速度要快,能浏览的图片格式要多。
3.简洁实用,制作难度不要太大。
4.在Win98,WinNT下都能用。
第二步:选材料
由于界面主要分为两大部分,即左边的目录树和右边的文件列表,故材料也就主要是这两大件。
1.左边目录树
从http://www.codejockeys.com/kstowell/上,我们可以得到一个免费的MFC扩展类库CJ60Lib.dll,这个类库包含有许多用于界面设计的类,其中有一个CShellTree类,可以显示和Windows Explorer左边目录树一样的效果,正好符合我想要的,选定了它。
2.右边文件列表
这是关键的部分,它要求能创建、显示、管理图片文件的缩图,要求能浏览多种格式的图片文件,要求有较精美的缩图显示效果和较快的浏览速度,要求易于使用难度不大。泰来影像科技有限公司在图像处理应用软件开发方面有较深的造诣,推出了一个MFC扩展类库thl.dll,其中有一个CThumbListCtrl类,正是用来创建、显示图片缩图用的,选定了它,从http://www.thalia.com.cn/上获取之。
第三步:生成程序框架
象开发其他程序一样,用VC++6.0 AppWizard生成程序框架。
1.选菜单项File->New,到Projects面板,选取MFC AppWizard(exe),Project name为SimpleBrowse。OK确定后,进入一个向导中,共有6步。
2.Step 1,选single document,其它不动,用缺省值。
3.Step 2 of 6,不动,用缺省值。
4.Step 3 of 6,不动,用缺省值。
5.Step 4 of 6,选Internet Explorer ReBars,其它不动,用缺省值。
6.Step 5 of 6,选Windows Explorer,其它不动,用缺省值。
7.Step 6 of 6,不动,用缺省值。Finish确定后,即生成程序框架。
第四步:使用类库、组件
1.左边的目录树对应的类是CLeftView,修改之。
class CLeftView : public CView/*CTreeView*/
{
...
// Attributes
public:
CShellTree m_TreeCtrl;// use shell tree control
...
// Generated message map functions
protected:
//{{AFX_MSG(CLeftView)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
...
};
(1)将其父类由CTreeView改为CView,原因后述。
(2)加入CShellTree类的成员变量m_TreeCtrl,目录树的具体内容就是由它实现的。
(3)增加消息响应函数OnCreate(),在其中把m_TreeCtrl创建起来。
(4)增加消息响应函数OnSize(),使m_TreeCtrl总是占满CLeftView的区域。
(5)增加消息响应函数OnItemexpanding(),在此响应展开目录的操作。如果CLeftView的父类是CTreeView的话,将不能得到希望的结果,这就是(1)中把父类改为CView的原因。
(6)增加消息响应函数OnSelchanged(),在此响应点击目录的操作。
具体修改请看源文件leftview.h和leftview.cpp,都很简单。
2.右边的文件列表对应的类是CSimpleBrowseView,修改之。
class CSimpleBrowseView : public CView/*CListView*/
{
...
// Attributes
public:
CThumbListCtrl m_ThumbListCtrl;
// use thumb list control
// Operations
public:
void FormatList(CString csPath);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSimpleBrowseView)
protected:
virtual void OnInitialUpdate();
// called first time after construct
//}}AFX_VIRTUAL
...
// Generated message map functions
protected:
//{{AFX_MSG(CSimpleBrowseView)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
...
};
(1)将其父类由CListView改为CView,原因和上面的类似。
(2)加入CThumbListCtrl类的成员变量m_ThumbListCtrl,文件列表的具体内容就是由它实现的。
(3)增加消息响应函数OnCreate(),在其中把m_ThumbListCtrl创建起来,并初始化为缩图显示风格。
(4)增加消息响应函数OnSize(),使m_ThumbListCtrl总是占满CSimpleBrowseView的区域。
(5)在OnInitialUpdate()中创建文件列表的栏目,调用CThumbListCtrl::BuildColumns()。
(6)增加函数FormatList(),它被CLeftView::OnSelchanged()调用,它则转而调用CThumbListCtrl::BrowseFolder()。点击左边的目录树,右边的文件列表跟着改变,就是通过这一个函数来实现的。
具体修改请看源文件simplebrowseview.h和simplebrowseview.cpp,都很简单。
3.其它事项
CShellTree和CThumbListCtrl都是在MFC扩展类库中实现的,要使用它们,必须:在编译阶段要有相应的.h文件,在连接阶段要有相应的.lib文件,在运行阶段要有相应的.dll文件。因此还要做一些配置:在leftview.h中加入#include "ShellTree.h",在simplebrowseview.h中加入#include "ThumbListCtrl.h";选菜单项Project->Settings,转到Link面板,在Object/library modules中加入CJ60Lib.lib和thl.lib;将CJ60Lib.dll,thl.dll和simplebrowse.exe放在同一目录下,注意thl.dll又使用到其它dll如Convert20.dll,JPEG.dll,TIFF60.dll等,也要放在同一目录下。
第五步:编译、运行
Rebuild All,Execute SimpleBrowse.exe,一款简洁实用的图片浏览器浮出水面...
大功告成!
(注意:一开始,我编译的是SimpleBrowse的Debug版本,发现不能正确运行,后来改为编译Release版本,就能正确运行了。可能是因为CJ60Lib.lib和thl.lib是Release版本的MFC扩展类库,需要配套的缘故。)
在对话框显示图片的多种方法
(一) 非动态显示图片(即图片先通过资源管理器载入,有一个固定ID)
(二) 动态载入图片(即只需要在程序中指定图片的路径即可载入)
为方便说明,我们已经建好一个基于对话框的工程,名为Ttest.
对话框类为CTestDlg
(一) 非动态载入图片.
方法1.先从最简单的开始,用picture 控件来实现.
步骤:
先在资源里Import一张图片,ID为IDB_BITMAP2
然后在对话框上添加一个picture控件,右键点击打开属性,
将type下拉框选择BITMAP,紧跟着下面就出现一个Image下拉框,
拉开就会看到所有已经载入好的图片,
选择你要的图片.运行程序即可看到.
方法2.通过背景图
同样如上,先载入一张图片,ID为IDB_BITMAP2
TestDlg.h中
CBrush m_brBk;//在public中定义
TestDlg.cpp中
在初始化函数OnInitDialog()中加入:
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP2);
m_brBk.CreatePatternBrush(&bmp);
bmp.DeleteObject();
.
.
.
return TRUE; // return TRUE unless you set the focus to a control
}
在打开类向导,找到WM_CTLCOLOR消息,重载得对应函数OnCtlColor(),添加如下:
HBRUSH CTestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if (pWnd == this)
{
return m_brBk;
}
return hbr;
}
(二) 动态载入图片.
方法3 图像控件(本例用KoDak 图像编辑控件)
1. 首先应该保证系统中有这个控件。注意,它不能单独使用,必须和其他几个控件(特别是Imgcmn.dll)一同使用。如果没有,从别的机器上copy过来即可。这几个文件是Imgadmin.ocx,Imgcmn.dll,Imgedit.ocx,Imgscan.ocx,Imgshl.dll,Imgthumb.ocx,Imgutil.dll,把它们copy到windows/system目录下,然后用regsvr32.exe将它们分别注册。
2. 打开工程,进入资源管理器,在对话框上单击右键,单击Insert Activex control… 选择Kodak图象编辑控件,大小任意。
3. 在对话框上选中该控件,为其添加变量:m_ctrlPicture。。
4. 在BOOL CTestDlg::OnInitDialog()添加如下:
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_ctrlPicture.SetImage("aa.jpg"); //保证图像在工程目录下,也可以写绝对路径
m_ctrlPicture.Display();
.
;
;
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
编译运行就OK了,此种方法的好处就是可能针对多种图像格式.
方法4 通过CBitmap,HBITMAP,直接用OnPaint()绘制
首先在CTestDlg类中声明一个变量: CBitmap m_bmp;
然后我们在对话框中加入一个picture 标签,名为IDC_STATIC1
然后:
BOOL CDisplayPic::OnInitDialog()
{
CDialog::OnInitDialog();
if( m_bmp.m_hObject != NULL )//判断
m_bmp.DeleteObject();
/载入图片
HBITMAP hbmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
"c://aaa.bmp", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE);
if( hbmp == NULL )
return FALSE;
///该断程序用来取得加载的BMP的信息
m_bmp.Attach( hbmp );
DIBSECTION ds;
BITMAPINFOHEADER &bminfo = ds.dsBmih;
m_bmp.GetObject( sizeof(ds), &ds );
int cx=bminfo.biWidth; //得到图像宽度
int cy=bminfo.biHeight; //得到图像高度
///
/得到了图像的宽度和高度后,我们就可以对图像大小进行适应,即调整控件的大小,让它正好显示一张图片///
CRect rect;
GetDlgItem(IDC_STATIC1)->GetWindowRect(&rect);
ScreenToClient(&rect);
GetDlgItem(IDC_STATIC1)->MoveWindow(rect.left,rect.top,cx,cy,true);//调整大小
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
图片加载成功了,标签大小也适应了,下面就是绘制绘制图像了,打开类向导,重载WM_PAINT消息
void CDisplayPic::OnPaint()
{
//以下三种情况任选一种会是不同效果(只能一种存在)///
//CPaintDC dc(this); //若用此句,得到的是对话框的DC,图片将被绘制在对话框上.
CPaintDC dc(GetDlgItem(IDC_STATIC1)); //用此句,得到picture控件的DC,图像将被绘制在控件上
// CDC dc;
// dc.m_hDC=::GetDC(NULL); //若用此两句,得到的是屏幕的DC,图片将被绘制在屏幕上///
CRect rcclient;
GetDlgItem(IDC_STATIC1)->GetClientRect(&rcclient);
CDC memdc;
memdc.CreateCompatibleDC(&dc);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc, rcclient.Width(), rcclient.Height());
memdc.SelectObject( &bitmap );
CWnd::DefWindowProc(WM_PAINT, (WPARAM)memdc.m_hDC , 0);
CDC maskdc;
maskdc.CreateCompatibleDC(&dc);
CBitmap maskbitmap;
maskbitmap.CreateBitmap(rcclient.Width(), rcclient.Height(), 1, 1, NULL);
maskdc.SelectObject( &maskbitmap );
maskdc.BitBlt( 0, 0, rcclient.Width(), rcclient.Height(), &memdc,
rcclient.left, rcclient.top, SRCCOPY);
CBrush brush;
brush.CreatePatternBrush(&m_bmp);
dc.FillRect(rcclient, &brush);
dc.BitBlt(rcclient.left, rcclient.top, rcclient.Width(), rcclient.Height(),
&memdc, rcclient.left, rcclient.top,SRCPAINT);
brush.DeleteObject();
// Do not call CDialog::OnPaint() for painting messages
}
以上四种方法唯有KoDak可以支持多种图像,其它的只支持BMP
快捷菜单
>
按Insert按钮。弹出Poup Menu对话框,在Add popup menu to下拉列表框中选择CMainFrame,点OK按钮,关闭Popup Menu对话框。按Close按钮关闭Component and Controls Gallery对话框。编译运行Hello,弹出窗口后按右键,就弹出如图3-16所示的快捷菜单。菜单中包含三项:cut、copy、paste。因为没有对应的消息矗立函数,所有这些菜单都是灰色的、非活动的。
按Insert按钮。弹出Poup Menu对话框,在Add popup menu to下拉列表框中选择CMainFrame,点OK按钮,关闭Popup Menu对话框。按Close按钮关闭Component and Controls Gallery对话框。编译运行Hello,弹出窗口后按右键,就弹出如图3-16所示的快捷菜单。菜单中包含三项:cut、copy、paste。因为没有对应的消息矗立函数,所有这些菜单都是灰色的、非活动的。
>
现在,我们看看Component Gallery是如何实现快捷菜单的。首先看资源视图的菜单资源,Component Gallery在其中增加了一个ID为CG_IDR_POPUP_MAIN_FRAME的菜单,菜单中包含了刚才我们看到的三个菜单项:cut、copy、paste。切换到类视图,浏览CMainFrame类,可以看到CMainFrame增加了一个OnContextMenu的成员函数,它是CWnd的一个方法,用于处理鼠标右键单击消息,原型如下:
afx_msg void OnContextMenu(CWnd* pWnd,CPoint point);
其中pWnd指向右键单击的窗口,它可以是一个本窗口的一个子窗口。比如,我们在工具条上单击右键时也弹出同样的菜单,工具条就是框架窗口的一个子窗口。OnContextMenu函数定义如清单3.6所示。
清单3.6 右键菜单
void CMainFrame::OnContextMenu(CWnd*, CPoint point)
{
// CG: This block was added by the Pop-up Menu component
{
if (point.x == -1 && point.y == -1){
//如果是键盘激活的快捷菜单,则在窗口左上角5,5的位置显示快捷菜单
CRect rect;
GetClientRect(rect);
ClientToScreen(rect);
point = rect.TopLeft();
point.Offset(5, 5);
}
//载入快捷菜单资源
CMenu menu;
VERIFY(menu.LoadMenu(CG_IDR_POPUP_MAIN_FRAME));
//取得本菜单的第一个子菜单
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CWnd* pWndPopupOwner = this;
//如果当前窗口是一个子窗口,取其父窗口作为弹出菜单的拥有者
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
//在point.x,point.y处显示弹出式菜单并跟踪其选择项
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,pWndPopupOwner);
}
}
一般的,我们都可以使用Component Gallery的Popup menu构件为某个窗口、对话框、视图等增加快捷菜单而无需手工编程。我们要做的只是编辑修改缺省的菜单为我们自己的快捷菜单,并用ClassWizard生成必要的成员函数,在加入自己的代码。如果确实要手工做的话,首先应当用菜单编辑器增加一个菜单,然后为对应的窗口添加OnContextMenu方法,OnContextMenu的定义可以参考上面的程序。
Component Gallery的功能远不止向程序添加快捷菜单这一项,它还可以增加启动画面(Splash Window)、多页式对话框、口令检查对话框等多种功能。读者可以试着往Hello程序中添加Splash Window和口令对话框,体验一下Component Gallery的强大功能。
如何在vc对话框中加菜单
在CMyDialog的函数OnInitDialog()中加入如下几行,IDR_MENU_MYMENU为你在资源管理器中设置好的menu资源的ID
CMenu * Menu=new CMenu();
Menu->LoadMenu(IDR_MENU_MYMENU);
SetMenu(Menu);
menu.Detach是将C++对象与菜单分离,使得menu对象析构时,菜单不被销毁。
类与头文件
CAnimateCtrl afxcmn.h
CArchive afx.h
CArchiveException afx.h
CArray afxtempl.h
CAsyncMonikerFile afxole.h
CAsyncSocket afxsock.h
CBitmap afxwin.h
CBitmapButton afxext.h
CBrush afxwin.h
CButton afxwin.h
CByteArray afxcoll.h
CCachedDataPathProperty afxctl.h
CCheckListBox afxwin.h
CClientDC afxwin.h
CCmdTarget afxwin.h
CCmdUI afxwin.h
CColorDialog afxdlgs.h
CComboBox afxwin.h
CComboBoxEx afxcmn.h
CCommandLineInfo afxwin.h
CCommonDialog afxdlgs.h
CConnectionPoint afxdisp.h
CControlBar afxext.h
CCriticalSection afxmt.h
CCtrlView afxwin.h
CDaoDatabase afxdao.h
CDaoException afxdao.h
CDaoFieldExchange afxdao.h
CDaoQueryDef afxdao.h
CDaoRecordset afxdao.h
CDaoRecordView afxdao.h
CDaoTableDef afxdao.h
CDaoWorkspace afxdao.h
CDatabase afxdb.h
CDataExchange afxwin.h
CDataPathProperty afxctl.h
CDateTimeCtrl afxdtctl.h
CDBException afxdb.h
CDBVariant afxdb.h
CDC afxwin.h
CDHtmlDialog afxdhtml.h
CDialog afxwin.h
CDialogBar afxext.h
CDocItem afxole.h
CDockState afxadv.h
CDocObjectServer afxdocob.h
CDocObjectServerItem afxdocob.h
CDocTemplate afxwin.h
CDocument afxwin.h
CDragListBox afxcmn.h
CDumpContext afx.h
CDWordArray afxcoll.h
CEdit afxwin.h
CEditView afxext.h
CEvent afxmt.h
CException afx.h
CFieldExchange afxdb.h
CFile afx.h
CFileDialog afxdlgs.h
CFileException afx.h
CFileFind afx.h
CFindReplaceDialog afxdlgs.h
CFont afxwin.h
CFontDialog afxdlgs.h
CFontHolder afxctl.h
CFormView afxext.h
CFrameWnd afxwin.h
CFtpConnection afxinet.h
CFtpFileFind afxinet.h
CGdiObject afxwin.h
CGopherConnection afxinet.h
CGopherFile afxinet.h
CGopherFileFind afxinet.h
CGopherLocator afxinet.h
CHeaderCtrl afxcmn.h
CHotKeyCtrl afxcmn.h
CHtmlEditCtrl afxhtml.h
CHtmlEditCtrlBase afxhtml.h
CHtmlEditDoc afxhtml.h
CHtmlEditView afxhtml.h
CHtmlStream afxisapi.h
CHtmlView afxhtml.h
CHttpArgList afxisapi.h
CHttpConnection afxinet.h
CHttpFile afxinet.h
CHttpFilter afxisapi.h
CHttpFilterContext afxisapi.h
CHttpServer afxisapi.h
CHttpServerContext afxisapi.h
CImageList afxcmn.h
CInternetConnection afxinet.h
CInternetException afxinet.h
CInternetFile afxinet.h
CInternetSession afxinet.h
CIPAddressCtrl afxcmn.h
CLinkCtrl afxcmn.h
CList afxtempl.h
CListBox afxwin.h
CListCtrl afxcmn.h
CListView afxcview.h
CLongBinary afxdb_.h
CMap afxtempl.h
CMapPtrToPtr afxcoll.h
CMapPtrToWord afxcoll.h
CMapStringToOb afxcoll.h
CMapStringToPtr afxcoll.h
CMapStringToString afxcoll.h
CMapWordToOb afxcoll.h
CMapWordToPtr afxcoll.h
CMDIChildWnd afxwin.h
CMDIFrameWnd afxwin.h
CMemFile afx.h
CMemoryException afx.h
CMenu afxwin.h
CMetaFileDC afxext.h
CMiniFrameWnd afxwin.h
CMonikerFile afxole.h
CMonthCalCtrl afxdtctl.h
CMultiDocTemplate afxwin.h
CMultiLock afxmt.h
CMultiPageDHtmlDialog afxdhtml.h
CMutex afxmt.h
CNotSupportedException afx.h
CObArray afxcoll.h
CObject afx.h
CObList afxcoll.h
COccManager afxocc.h
COleBusyDialog afxodlgs.h
COleChangeIconDialog afxodlgs.h
COleChangeSourceDialog afxodlgs.h
COleClientItem afxole.h
COleCmdUI afxdocob.h
COleControl afxctl.h
COleControlContainer afxocc.h
COleControlModule afxctl.h
COleControlSite afxocc.h
COleConvertDialog afxodlgs.h
COleCurrency afxdisp.h
COleDataObject afxole.h
COleDataSource afxole.h
COleDBRecordView afxoledb.h
COleDialog afxodlgs.h
COleDispatchDriver afxdisp.h
COleDispatchException afxdisp.h
COleDocObjectItem afxole.h
COleDocument afxole.h
COleDropSource afxole.h
COleDropTarget afxole.h
COleException afxdisp.h
COleInsertDialog afxodlgs.h
COleIPFrameWnd afxole.h
COleLinkingDoc afxole.h
PtInRect(point)
// CCDCView message handlers
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
char str[100];
int temp=10;
sprintf(str, "There are %d", temp);
if(m_position.PtInRect(point))
{
SetCapture();
m_oldPoint=point;
dc.TextOut(100,100, str);
}
CView::OnLButtonDown(nFlags, point);
}
{
// TODO: Add your message handler code here and/or call default
if(GetCapture()==this)
{
CRect validRect=m_position;
CSize size=point-m_oldPoint;
m_position.OffsetRect(size);
m_oldPoint=point;
validRect.UnionRect(&validRect, &m_position);
InvalidateRect(&validRect);
}
if(m_position.PtInRect(point))
::SetCursor(AfxGetApp()->LoadCursor(IDC_CROSS ));
CView::OnMouseMove(nFlags, point);
}
{
// TODO: Add your message handler code here and/or call default
if(GetCapture()==this)
::ReleaseCapture();
CView::OnLButtonUp(nFlags, point);
}
测试分析报告(GB8567——88)
1.1编写目的
说明这份测试分析报告的具体编写目的,指出预期的阅读范围。
1.2背景
说明:
a. 被测试软件系统的名称;
b. 该软件的任务提出者、开发者、用户及安装此软件的计算中心,指出测试环境与实际运行环境 之间可能存在的差异以及这些差异对测试结果的影响。
1.3定义
列出本文件中用到的专问术语的定义和外文首字母组词的原词组。
1.4参考资料
列出要用到的参考资料,如:
a. 本项目的经核准的计划任务书或合同、上级机关的批文;
b. 属于本项目的其他已发表的文件;
c. 本文件中各处引用的文件、资料,包括所要用到的软件开发标准。列出这些文件的标题、文件编号、发表日期和出版单位,说明能够得到这些文件资料的来源。
2测试概要
用表格的形式列出每一项测试的标识符及其测试内容,并指明实际进行的测试工作内容与测试计划中预先设计的内容之间的差别,说明作出这种改变的原因。
3测试结果及发现
3.1测试1(标识符)
把本项测试中实际得到的动态输出(包括内部生成数据输出)结果同对于动态输出的要求进行比较,陈述其中的各项发现。
3.2测试2(标识符)
用类似本报告3.1条的方式给出第 2项及其后各项测试内容的测试结果和发现。
4对软件功能的结论
4.1功能1(标识符)
4.1.1能力
简述该项功能,说明为满足此项功能而设计的软件能力以及经过一项或多项测试已证实的能力。
4.1.2限制
说明测试数据值的范围(包括动态数据和静态数据),列出就这项功能而言,测试期间在该软件中查出的缺陷、局限性。
4.2功能2(标识符)
用类似本报告4.l的方式给出第2项及其后各项功能的测试结论。
......
5分析摘要
5.1能力
陈述经测试证实了的本软件的能力。如果所进行的测试是为了验证一项或几项特定性能要求的实现,应提供这方面的测试结果与要求之间的比较,并确定测试环境与实际运行环境之间可能存在的差异 对能力的测试所带来的影响。
5.2缺陷和限制
陈述经测试证实的软件缺陷和限制,说明每项缺陷和限制对软件性能的影响,并说明全部测得的性能缺陷的累积影响和总影响。
5.3建议
对每项缺陷提出改进建议,如:
a. 各项修改可采用的修改方法;
b. 各项修改的紧迫程度;
c. 各项修改预计的工作量;
d. 各项修改的负责人。
5.4评价
说明该项软件的开发是否已达到预定目标,能否交付使用。
6测试资源消耗
总结测试工作的资源消耗数据,如工作人员的水平级别数量、机时消耗等。
关于软件文档
|
软件测试
1 软件测试和VSTS 测试工具
1.1 从测试设计的方法分类
1.2 功能测试
测试名称
|
测试内容
|
Unit Test
|
单元测试 – 在最低的功能/参数上验证程序的正确性
|
Functional Test
|
功能测试 – 验证模块的功能
|
Integration Test
|
集成测试 – 验证几个互相有依赖关系的模块的功能
|
Scenario Test
|
场景测试 – 验证几个模块是否能够完成一个用户场景
|
System Test
|
系统测试 – 对于整个系统功能的测试
|
Alpha/Beta Test
|
外部软件测试人员(Alpha/Beta 测试员)在实际用户环境中对软件进行全面的测试。
|
|
|
|
|
|
|
1.3 非功能测试
测试名称
|
测试内容
|
Stress/load test
|
测试软件在负载情况下能否正常工作
|
Performance test
|
测试软件的效能
|
Accessibility test
|
测试软件辅助功能测试 – 测试软件是否向残疾用户提供足够的辅助功能
|
Localization/Globalization Test
|
本地化/全球化测试
|
Compatibility Test
|
兼容性测试
|
Configuration Test
|
配置测试 – 测试软件在各种配置下能否正常工作
|
Usability Test
|
可用性测试 – 测试软件是否好用
|
Security Test
|
软件安全性测试
|
1.4 Unit Test单元测试
1.4.1 用VSTS写 单元测试
1.4.2 好的单元测试的标准
1.4.2.1 单元测试应该在最低的功能/参数上验证程序的正确性
1.4.2.2 单元测试必须由最熟悉代码的人(程序的作者)来写
1.4.2.3 单元测试过后,机器状态保持不变
1.4.2.4 单元测试要快 (一个测试运行时间是几秒钟, 而不是几分钟)
1.4.2.5 单元测试应该产生可重复,一致的结果
1.4.2.6 独立性,单元测试的运行/通过/失败不依赖于别的测试,可以人为构造数据,以保持单元测试的独立性。
1.4.2.7 单元测试应该覆盖所有代码路径,包括错误处理路径,为了保证单元测试的代码覆盖率,单元测试必须测试公开的和私有的函数/方法。
1.4.2.8 单元测试应该集成到自动测试的框架中
1.4.2.9 单元测试必须和产品代码一起保存和维护
1.5 BVT 构建验证测试 (Build Verification Test)
1.6 功能测试 (functional test)
场景ID
|
场景名
|
测试结果
|
Bug/小强id
|
3024
|
用户登录
|
成功
|
|
3026
|
用户按价格排序
|
失败
|
5032
|
3027
|
用户按名字搜索
|
失败
|
5033
|
…
|
…
|
…
|
…
|
1.7 Ad hoc Test, Exploratory Test “探索式”的测试
1.8 Regression Test回归测试
1.9 Scenario/integration/System Test 场景/集成/系统测试
1.10 Performance Test 效能测试
服务质量的细化 – 有些请求,是要对数据作“写”操作,可以要求慢一些,比如“用户购买商品”,这一服务质量请求可以放宽为3秒钟。
1.11 Stress Test压力测试
- 内存/资源泄露,在压力下这会导致程序可用的资源枯竭,最后崩溃。
- 一些平时认为“足够大/足够好”的算法实现会出现问题。
- 进程/线程的同步死锁问题,在压力下一些小概率事件会发生,看似完备的程序逻辑也出现了问题。
1.12 Alpha Test, Beta Test
1.13 Usability Test可用性测试
1.14 Bug Bash
- 鼓励大家做探索试的测试,开阔思路。
- 鼓励测试队伍学习并应用新的测试方法,例如在做完“软件安全性测试”培训后,立马做一个针对“安全性”的小强大扫除.
- 找到很多小强,让开发人员忙一阵子
- 扰乱正常的测试工作
- 如果过分重视奖励,会导致一些数量至上,滥竽充数的做法。
2 总结和思考
2.1 十八般兵器
2.2 构建的质量
2.3 问题
2.3.1 如果连续几天都不能产生“可测”版本,怎么办?
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 ); //编辑控件的大小和位置都改变
以上方法也适用于各种窗口。
VC学习笔记4:什么时候设定视中控件的初始尺寸?
我在CFormView的视中加入了一个编辑控件,在运行时使它充满客户区,当窗口改变大小时它也跟着改变。
改变控件尺寸可以放在OnDraw()函数中,也可放在CalcWindowRect()函数中,当窗口尺寸发生变化时,它们都将被执行,且CalcWindowRect()函数先于OnDraw()函数,下例是在CalcWindowRect()函数中修改控件尺寸。
重载VIEW类的CalcWindowRect函数,把设定控件的尺寸的语句加入这个函数中。
例:
void CMyEditView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
{
// TODO: Add your specialized code here and/or call the base class
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是为了让出状态条位置。
CFormView::CalcWindowRect(lpClientRect, nAdjustType);
}
VC学习笔记5:单选按钮控件(Ridio Button)的使用
一、对单选按钮进行分组:
每组的第一个单选按钮设置属性:Group,Tabstop,Auto;其余按钮设置属性Tabstop,Auto。
如:
Ridio1、Ridio2、Ridio3为一组,Ridio4、Ridio5为一组
设定Ridio1属性:Group,Tabstop,Auto
设定Ridio2属性:Tabstop,Auto
设定Ridio3属性:Tabstop,Auto
设定Ridio4属性:Group,Tabstop,Auto
设定Ridio5属性:Tabstop,Auto
二、用ClassWizard为单选控件定义变量,每组只能定义一个。如:m_Ridio1、m_Ridio4。
三、用ClassWizard生成各单选按钮的单击消息函数,并加入内容:
void CWEditView::OnRadio1()
{
m_Ridio1 = 0; //第一个单选按钮被选中
}
void CWEditView::OnRadio2()
{
m_Ridio1 = 1; //第二个单选按钮被选中
}
void CWEditView::OnRadio3()
{
m_Ridio1 = 2; //第三个单选按钮被选中
}
void CWEditView::OnRadio4()
{
m_Ridio4 = 0; //第四个单选按钮被选中
}
void CWEditView::OnRadio5()
{
m_Ridio4 = 1; //第五个单选按钮被选中
}
四、设置默认按钮:
在定义控件变量时,ClassWizard在构造函数中会把变量初值设为-1,只需把它改为其它值即可。
如:
//{{AFX_DATA_INIT(CWEditView)
m_Ridio1 = 0; //初始时第一个单选按钮被选中
m_Ridio4 = 0; //初始时第四个单选按钮被选中
//}}AFX_DATA_INIT
VC学习笔记6:旋转控件(Spin)的使用
当单击旋转控件上的按钮时,相应的编辑控件值会增大或减小。其设置的一般步骤为:
一、在对话框中放入一个Spin控件和一个编辑控件作为Spin控件的伙伴窗口,
设置Spin控件属性:Auto buddy、Set buddy integer、Arrow keys
设置文本控件属性:Number
二、用ClassWizard为Spin控件定义变量m_Spin,为编辑控件定义变量m_Edit,定义时注意要把m_Edit设置为int型。
三、在对话框的OnInitDialog()函数中加入语句:
BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_Spin.SetBuddy( GetDlgItem( IDC_EDIT1 ) ); //设置编辑控件为Spin控件的伙伴窗口
m_Spin.SetRange( 0, 10 ); //设置数据范围为0-10
return TRUE;
}
四、用ClassWizard为编辑控件添加EN_CHANGE消息处理函数,再加入语句:
void CMyDlg::OnChangeEdit1()
{
m_Edit = m_Spin.GetPos(); //获取Spin控件当前值
}
OK!
VC学习笔记7:程序结束时保存文件问题
在文档-视图结构中,用串行化自动保存文件在各种VC书上都有介绍。现在的问题是我不使用串行化,而是自己动手保存,当点击窗口的关闭按钮时,如何提示并保存文档。
用ClassWizard在文档类(CxxDoc)中添加函数CanCloseFrame(),再在其中加入保存文件的语句就可以了。
注:要保存的数据应放在文档类(CxxDoc)或应用程序类(CxxApp)中,不要放在视图类中。
例:
//退出程序
BOOL CEditDoc::CanCloseFrame(CFrameWnd* pFrame)
{
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.Open(m_PathName,CFile::modeCreate | CFile::modeWrite);
file.Write(m_Text,m_TextLen); //数据写入文件
file.Close();
}
}
return CDocument::CanCloseFrame(pFrame);
}
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 CEditView::OnChangeEdit1()
{
UpdateData(true);
}
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文件。
13, Visual C++ 6.0如何进入调试状态,在调试状态下能够显示哪些调试窗口,列举三个,其作用分别是什么?
启动调试后,在View菜单的Debug Window子菜单下可以打开一些辅助调试的窗口
Watch:显示察看当前语句和前面语句中变量值的窗口
Call Stack:显示察看调用堆栈的窗口
Memory:显示察看内存中内容的窗口
14, 说明位图资源的创建及显示过程的步骤,并给出相应的Windows API函数名。
首先定义位图句柄HBITMAP hBitmap;第二步使用LoadBitMap加载位图;第三步,调用CreateCompatibleDC向系统申请内存设备环境句柄,并调用函数SelectObject把位图选入内存设备环境;第四步,调用BitBlt函数将位图从内存设备环境输出到指定的窗口设备环境中,从而实现显示位图。
15, 如何获取字体句柄从而实现字体的输出,并给出相应的Windows API函数名。
首先定义字体句柄变量HFONT hF;然后调用函数GetStockObject获取系统的字体句柄,或者调用CreateFont得到自定义的字体句柄;最后调用SelectObject把字体句柄选入设备环境。
16, 列举三种按钮的类型,并说明其作用和创建方法之间的不同之处。
常用的按钮有普通按钮、单选按钮、复选框,和组框。普通按钮作用是帮助用户触发指定动作;单选按钮一般各选项之间存在互斥性;复选框用来显示一组选项供用户选择,各选项之间不存在互斥;组框主要用于把控件分成不同的组并加以说明.
17, 要使一个静态控件显示一个位图并能接受用户输入,应该注意什么问题。
要使静态控件显示位图,必须设定其风格包含SS_BITMAP,并在创建静态控件窗口,即调用CreateWindow时指定并加载位图;要使静态控件能够接收用户输入,必须设定其风格包含SS_NOTIFY。
c++异常处理
#include<iostream.h>
#include<stdlib.h>
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();
}
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替换。
VC实现BMP位图文件结构及平滑缩放
用普通方法显示BMP位图,占内存大,速度慢,在图形缩小时,失真严重,在低颜色位数的设备上显示高颜色位数的图形图形时失真大。本文采用视频函数显示BMP位图,可以消除以上的缺点。 | |||||||||||
一、BMP文件结构
3. 位图信息头
4. 颜色表 颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:
5. 位图数据
二、BMP位图一般显示方法 1. 申请内存空间用于存放位图文件 GlobalAlloc(GHND,FileLength); 用CreateDIBitmap()创建显示用位图,用CreateCompatibleDC()创建兼容DC, 用SelectBitmap()选择显示位图。 用DrawDib视频函数来显示位图,内存占用少,速度快,而且还可以对图形进行淡化(Dithering)处理。淡化处理是一种图形算法,可以用来在一个支持比图像所用颜色要少的设备上显示彩色图像。BMP位图显示方法如下:
3. 位图文件读入所申请内存空间中
4. 在OnPaint等函数中用DrawDibRealize(),DrawDibDraw()显示位图 以上方法的优点是: 1)显示速度快; 2) 内存占用少; 3) 缩放显示时图形失真小,4) 在低颜色位数的设备上显示高颜色位数的图形图形时失真小; 5) 通过直接处理位图数据,可以制作简单动画。
1. 在CViewBimap类中添加视频函数等成员
2. 在CViewBimap类构造函数中添加打开视频函数
3. 在CViewBimap类析构函数中添加关闭视频函数
4. 在CViewBimap类图形显示函数OnPaint中添加GraphicDraw()
五、使用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。
并在该程序的头部添加#include "bitmap0.h",然后编译运行。 1. 在客户区中带有水平和垂直滚动条。在位图大小大于显示客户区时,可以使用滚动条;在位图大小小于显示客户区或全屏显示时,滚动条无效。
|