使用集锦

来源:互联网 发布:收费视频教程网站源码 编辑:程序博客网 时间:2024/04/27 13:37
使用枚举类型
必须使用手工加入。例如:
protected:
enum{font,pens,brushes} m_display
这是一个匿名的枚举。

使用方法:
m_display=fonts;
好处是防止使用非法的数字,而且可以很简要的表达所有的元素。


鼠标操作
当鼠标移动的时候,窗口(指整个窗口,包括客户和非客户区域)会收到WM_NCHITTEST消息,通过他程序可以计算鼠标的位置,通常这些都由缺省的窗口函数计算。如果需要认为的改变计算结果,可以先让父类的窗口函数计算,然后再改变结果。例如:拖动一个没有标题栏的窗口,假设按住SHIFT表示拖动,没有按住的时候表示普通处理。所以具体的处理如下:
afx_msg UINT CMyWnd::OnNcHitTest(CPoint point)
{
UINT nCode=CWnd::OnNcHitTest(point);
if((nCode==HTCLIENT)&&((GetAsyncKeyState(VK_SHIFT)&0x8000)==0x8000))
nCode=HTCAPTION;
return nCode;
}
随后窗口会收到WM_SETCURSOR消息,窗口函数可以通过这个函数改变鼠标。
处理客户区域鼠标移动,使用消息WM_MOUSEMOVE。
如果只处理非客户区域,使用消息WM_NCMOUSEMOVE。


最高窗口的实现
VC++中对基于SDI、MDI的运用程序,要实现最高窗口,只要在框架窗口类CMainFrame中的PreCreateWindow()函数中加入“cs.dwExStyle =WS_EX_TOPMOST;”即可。
    而对基于对话框的运用程序,如何实现最高窗口却很少论及,以下便是一种实现方法。
    重载要实观最高窗口的对话框的OnInitDialog()函数,方法是进入ClassWizard,在Object ID列表框中选择该对话框的ID,在Message列表框中选择WM_INITDIALOGG,单击Add Function按钮后,即对onlnitDialog函数进行了重载。再按下Edit code按钮,加入以下语句:
const CWnd * pWndInsertAfter;
pWndInsertAfter = &wndTopMost;
SetWindowPos(pWndInsertAfter,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE);
函数SetWindowPos原型为BOOL SetWindowPos(const CWnd * pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags);
pWndInsertAfter为指向标识窗口类型的CWnd对象的指针。
x,y为窗口左上角的坐标。
cx,cy为窗口的宽与高。
nFlags确定窗口的大小及位置。当为SWP_NOSIZE时,忽略cx,cy。当为SWP_NOMOVE时,忽略x,y。


改变程序的窗口设置
可以在视图类的PRECREATEWINDOW中加入语句改变程序的窗口设置。程序在生成窗口之前调用这个函数。此函数接受CREATESTRUCT结构的引用,这个结构的字段存放生成窗口时MFC指定的窗口特性。如果赋值这个结构的一个或几个字段,则MFC用所赋值而不是缺省值。CREATESTRUCT结构的IpszClass字段存放WINDOWS窗口类名,这是WINDOWS系统维护的数据结构,存放窗口生成时一组一般特性。加入的AfxRegisterWndClass生成新的WINDOWS窗口类,然后将类名赋予结构的IpszClass字段,使视图窗口用存放在这个WINDWOS窗口类中的用户化特性生成。AfxRegisterWndClass是MFC提供的全局函数。
BOOL CminiDrawView::PreCreateWindow(CREATESTRUCT &cs)
{
M_Class=AfxRegisterWndClass
(CS_HREDRAW|CS_VREDRAW,
0,
(HBRUSH)::GetStockObject(WHITE_BRUSH);
0);
cs.lpszClass=m_ClassName;
returen cview::precreatewindow(cs);
}
第一个参数指定类样式。第二个参数指定WINDOWS在窗口内自动显示的鼠标光标,赋值为0则是不准备显示光标。第三个参数提供标准的白色刷笔。最后一个参数指定窗口图标,由于视图窗口不显示图标,他赋值为0。


纯资源DLL的编写
     下面的例子是一个纯资源DLL的源程序
纯资源的DLL就是只包含资源的DLL,例如:图标,位图,字符串,声音,视频,对话框等。使用纯资源DLL可以节约可执行文件的大小,可以被所有的应用程序所共享,从而提高系统性能。纯资源DLL的编写比普通的DLL要简单的多,首先创建一个WIN32
DLL工程,不是MFC的DLL,然后创建一个资源文件 *.RC,添加到资源DLL的工程中去。然后添加一个初始化DLL的原文件。
#include <windows.h>
extern "C"
BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID )
{
    return 1;
}
这是纯资源DLL所必须需的代码,保存这个文件为*.CPP。编译这个资源DLL。

在应用程序显示的调用这个DLL,使用LoadLibrary函数装入资源DLL,FindResource和LoadResource来装入各种资源,或者使用下列的特定的资源装入函数:
  FormatMessage
  LoadAccelerators
  LoadBitmap
  LoadCursor
  LoadIcon
  LoadMenu
  LoadString
当资源使用结束,你的应用程序须调用FreeLibrary函数来释放资源。
下面就讲一下如何调用编写好的资源DLL
首先在应用程序中声明一个DLL的句柄,HINSTANCE m_hLibrary;在OnCreate( )函数中调用LoadLirbrary(
),在OnDestory( )中调用FreeLibrary()。


空心字
在开始一个路径前,我们先调用CDC类的成员函数BeginPath,然后调用一系列的输出函数,在完成绘制之后,我们可以调用CDC类的成员函数EndPath。在完成一个路径之后,我们可以调用StrokePath来绘制该路径。为了简单起见,我们仅给出应用程序的OnPaint成员函数如下:
// 应用程序主窗口的重绘函数
void CMyWnd::OnPaint()
{
// 获得窗口的客户区设备上下文句柄
CPaintDC dc(this);
// 更改当前字体
LOGFONT lf;
dc.GetCurrentFont()->GetLogFont(&lf);
CFont font;
CFont *pOldFont; // 保存设备上下文最初使用的字体对象
lf.lfCharSet=134;
lf.lfHeight=-150;
lf.lfWidth=0;
strcpy(lf.lfFaceName, "隶书");
font.CreateFontIndirect(&lf);
pOldFont=dc.SelectObject(&font);
dc.SetBkMode(TRANSPARENT);
// 更改当前画笔
CPen pen(PS_SOLID, 1, RGB(255, 0, 0));
CPen *pOldPen;
pOldPen=dc.SelectObject(&pen);
// 开始一个路径
dc.BeginPath();
dc.TextOut(10, 10, "空心字");
dc.EndPath();
// 绘制路径
dc.StrokePath();
// 恢复设备上下文的原有设置
dc.SelectObject(pOldFont);
dc.SelectObject(pOldPen);
}
函数FillPath可以使用当前刷子填充路径的内部。按下面的代码修改前面的OnPaint成员函数:
// 应用程序主窗口的重绘函数
void CMyWnd::OnPaint()
{
// 获得窗口的客户区设备上下文句柄
CPaintDC dc(this);
// 更改当前字体
LOGFONT lf;
dc.GetCurrentFont()->GetLogFont(&lf);
CFont font, *pOldFont;
lf.lfCharSet=134;
lf.lfHeight=-150;
lf.lfWidth=0;
strcpy(lf.lfFaceName, "隶书");
font.CreateFontIndirect(&lf);
pOldFont=dc.SelectObject(&font);
dc.SetBkMode(TRANSPARENT);
// 更改当前画笔
CPen pen(PS_SOLID, 1, RGB(255, 0, 0)), *pOldPen;
pOldPen=dc.SelectObject(&pen);
// 更改当前刷子
CBrush br(HS_DIAGCROSS, RGB(0, 255, 255)), *pOldBrush;
pOldBrush=dc.SelectObject(&br);
// 开始一个路径
dc.BeginPath();
dc.TextOut(10, 10, "空心字");
dc.EndPath();
// 绘制路径
dc.StrokeAndFillPath();
// 恢复设备上下文的原有设置
dc.SelectObject(pOldFont);
dc.SelectObject(pOldPen);
dc.SelectObject(pOldBrush);
}


渐变字
在完成一个路径之后,如前所述,我们可以调用CDC类的成员函数FillPath、StrokePath或StrokeAndFillPath来绘制和填充路径。这只是最初级的技巧。更进一步,我们可以使用成员函数SelectClipPath将路径选入当前剪辑区域,这样,所有的绘制操作都将只作用于这个剪辑区域。
使用此技巧可以绘制具有渐变颜色效果的字体。如下面的OnPaint成员函数所示:
// 应用程序主窗口的重绘函数
void CMyWnd::OnPaint()
{
// 获得窗口的客户区设备上下文句柄
CPaintDC dc(this);
// 更改当前字体
LOGFONT lf;
dc.GetCurrentFont()->GetLogFont(&lf);
CFont font, *pOldFont;
lf.lfCharSet=134;
lf.lfHeight=-150;
lf.lfWidth=0;
strcpy(lf.lfFaceName, "隶书");
font.CreateFontIndirect(&lf);
pOldFont=dc.SelectObject(&font);
dc.SetBkMode(TRANSPARENT);
// 更改当前画笔为空
CPen pen(PS_NULL, 1, RGB(255, 0, 0)), *pOldPen;
pOldPen=dc.SelectObject(&pen);
// 更改当前刷子
CBrush br(0), *pOldBrush;
pOldBrush=dc.SelectObject(&br);
// 开始一个路径
dc.BeginPath();
dc.TextOut(10, 10, "渐变字");
dc.EndPath();
// 绘制渐变效果
dc.SelectClipPath(RGN_COPY);
for (int i=255; i>0; i--)
{
int iRadius=(600*i)/255;
dc.SelectObject(pOldBrush);
br.DeleteObject();
br.CreateSolidBrush(RGB(255, i, 0));
dc.SelectObject(&br);
dc.Ellipse(-iRadius, -iRadius/3, iRadius, iRadius/3);
}
// 恢复设备上下文的原有设置
dc.SelectObject(pOldFont);
dc.SelectObject(pOldPen);
dc.SelectObject(pOldBrush);
}
在上面的示例中,我们以RGN_COPY方式将路径选作当前剪辑区域,然后,在该剪辑区域上进行一系列的绘制操作,这些绘制操作以不同的颜色绘制了一系列的同心椭圆,这些同心椭圆有视觉上给用户以渐变的感觉。上面的程序的运行结果如图。


测试ALT键是否按下:
GetKeyState(VK_MENU);
GetAlt();


元文件
用于记录和回放GDI函数调用。首先通过CMetaFileDC:Create来创建新的对象,如果有文件名,则保存到文件内,如果没有则建立在内存中。完毕后,用Close()关闭。
可以调用PlayMetaFile()来回放元文件。还可以用CopyMetaFile()将文件存盘。当结束元文件的时候,用DeleteMetaFile()从内存中删除。
另外有增强型元文件。
CMetaFileDC    dc;
BOOL bCreate=dc.CeeateEnblanced(pDC,”metaest,wmf/0”,0,vectosd/0 this is l/0/0”);
if(!bCreated) return;
(具体的绘制内容……)
//关闭文件,并返回文件句柄
HENHMETAFILE    hemf=dc.CloseEnhanced();
//播放文件
pDC->SaveDC();
pDC->SetMapMode();
pDC->PlayMetaFile(hemf,&rc);
pDC->RestoreDC(-1);
//当文件不再需要
if(hemf)
    ::DeleteEnhMetaFile(hemf);


如何将窗口的大小限制为特定值:
Windows发送一个WM_GETMAXMININFO消息来确定窗口的位置、大小以及跟踪尺寸,下面将窗口的追踪尺寸限制为1/4屏幕大小:
void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR *LPmmI)
{
lpMMI->ptMaxTrackSize.x=GetSystemMetrics(SM_CXSCREEN)/2;
lpMMI->ptMaxTrackSize.Y=GetSystemMetrics(SM_CYSCREEN)/2;
CMDIFrameWnd::OnGetMinMaxInfo(lpMMI);
}


字符串太长的时候如果用省略号显示
调用CDC::DrawText并指定DT_END_ELLIPSIS标志,就可以用省略号代替末尾的字符来适合指定的边界矩形,如果要显示路径信息,指定DT_PATH_ELLIPSIS标志来取代中间的字符。
    CClientDC dc(this);
    dc.DrawText(CString("This is a long string."),
        CRect(10,10,80,30),DT_LEFT|DT_END_ELLIPSIS);
    dc.DrawText(AfxGetApp()->m_pszHelpFilePath,
        CRect(10,40,200,60),DT_LEFT|DT_PATH_ELLIPSIS);


WINDOWS异常分支
异常分支是WINDOWS消息处理路径中的点,子例程根据这一路径被注入或附加,以在某些类型的消息到达某目的地之前将其过滤。一旦这些消息被捕获了,就可以被修改,记录或者简单的放弃。子例程本身被称为过滤器。他们按照正在过滤的事件的类型进行分类。
为了设置一个异常分支,必须调用SetWindowsHookEx()函数。
SetWindowsHookEX(int idHook,HOOKPROC lpfn,HINSTANCE hMod,DWORD dwThreadld);
第一个参数,代表了一个常量,标识了正要设置的异常分支的类型。
第二个参数,指向一个函数类型为HOOKPROC的指针。对于键盘异常分支,必须要如下的形式:
LRESULT CALLBACK KeyboardProc(int code ,WPARAM,LPARAM);
第三个参数,是包含过滤函数的DLL的HINSTANCE。
第四个参数允许程序指定要为之设置异常分支的线程。
为了把一个异常分支从链中去掉,必须调用函数:
BOOL    UnhookWindowsHookEx(HHOOK hHook);


文档模板字符串处理
文档类包含了GetDocString(),可以接受CString对象的引用以及一个索引,该函数可以用来查询已经注册的字符串资源的值。方式如下:
virtual BOOL GetDocString(CString &rString,enum DocStringIndex intex)const;
具体参数索引的有效值:
CDocTemplate::windowTitle 应用程序窗口标题栏的文本,只对SDI程序很重要
CDocTemplate::docName
CDocTemplate::fileNewName
CDocTemplate::filterName
CDocTemplate::filterExt          
CDocTemplate::regFileTypeId   注册表数据库内部名称,由OLE和FILE MANAGER使用
CDocTemplate::regFileTypeName 注册表数据库文档名称,由所有OLE应用程序使用并且对用户可见


简单的打印
void Print2()
{
HDC hDC;
DOCINFO di;
hDC=CreateDC(“WINSPOOL”,”HP Laser Printer”,NULL,NULL);
memset(&di,sizeof(DOCINFO));
di.cbSize=sizeof(DOCINFO);
di.lpszDocName=”Sample Document”;
if(StartDoc(hDC,&di)!=SP_ERROR)
{
StartPage(hDC);
TextOut(hDC,10,10,”This is on Page 1.”,18);
EndPage(hDC);
StartPage(hDC);
TextOut(hDC,10,10,”This is on Page 2.”,18);
EndPage(hDC);
EndDoc(hDC);
}
DeleteDC(hDC);
}


时间控制函数
传统的方法使用WM_TIMER(),精度最低。
在要求不大于1毫秒的情况下,可以采用GetTickCount()函数,该函数的返回值是DWORD型,表示以毫秒为单位的计算机启动后经历的时间间隔。实现50毫秒精确定时方法:
DWORD dwstart,dwstop;
dwstop=GetTickCount();
while(TRUE)
{
dwstart=dwstop;
    do{
        dwstop=GetTickCount();
        }while(dwstop-50<dwstart);
}
仅供WIN9X使用的高精度定时器:QueryPerformanceFrequency()和QueryPerformanceCounter(),    要求计算机从硬件上支持高精度定时器。函数的原形是:BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter (LARGE_INTEGER *lpCount);
数据类型LARGEINTEGER既可以是一个作为8字节长的整数,也可以是作为两个4字节长的整数的联合结构,其具体用法根据编译器是否支持64位而定。该类型的定义如下:typeef union _ LARGE_INTEGER
{
    struct
    {
        DWORD LowPart;
        LONG  HighPart;
    };
    LONGLONG QuadPart;
} LARGE_INTEGER;
在定时前应该先调用QueryPerformanceFrequency()函数获得机器内部计时器的时钟频率。接着在需要严格计时的事件发生前和发生之后分别调用QueryPerformanceCounter(),    利用两次获得的计数之差和时钟频率,    就可以计算出事件经历的精确时间。测试函数SLEEP(100)的精确持续时间方法:
LARGE_INTEGER litmp;
LONGLONG qt1,qt2;
double dft,dff,dfm;
QueryPerformanceFrequency(&litmp);//获得时钟频率
dff=(double)litmp.QuadPart;
QueryPerformanceCounter(&litmp);//获得初始值
qt1=litmp.QuadPart;Sleep(100);
QueryPerformanceCounter(&litmp);//获得终止值
qt2=litmp.QuadPart;
dfm=(double)(qt2-qt1);
dft=dfm/dff;//获得对应的时间值
需要注意的是DFT计算的结果单位是秒。


文本绘制函数
DrawText()      在文本被绘制时,提供一些文本格式编排。将一个字符串放入一个矩形区域使之格式化。
CRect rectangle;
GetClientRect(rectangle);
pDC->DrawText("Hello",-1,&rectangle,
DT_CENTER|DT_SINGLELINE|DT_VCENTER);
ExtTextOut()        使用三个新增特性绘制一行文本。首先可以指定一个剪取矩形以将文本限制在矩形内。其次可以指定一个不透明的矩形,它涉及使用背景文本颜色填充矩形。第三,可以通过提供一组字符单元宽度值,控制字符间距。
GrayString()        创建虚化的文本。类似于使用在菜单中显示被禁用的菜单项的文本。
TabbedTextOUt()  绘制一行文本,类似TextOut()。区别是支持制表符。
TextOut()       绘制单行文本。其坐标只能识别16位,在NT中才可以识别32。


文本坐标的计算
GetCharWidth(0   为当前选入DC中的字体的一系列字符获取默认字符宽度值的副本。
GetDeviceCaps()  获取特定于具体设备的数据的各种位。
GetTextExtent()  当使用当前选入DC中的字体绘图时,获得给定字符串将占据的空间宽度和高度。
GetTabbedTextExtent()类似于GetTextExtent(),当使用当前选入DC中的字体绘图时,此函数获取字符串将占据的空间宽度和高度。也考虑了制表设置。
GetTextMetrics() 为当前选入DC中的字体获取数据副本。包含基本的字体测量信息。


使用定时器
定时器的时间单位是毫秒,数值是1-32位整数,最大的数字是49.5天左右。虽然可以设定间隔,但是因为硬件定时器是54.9毫秒为基准,所以设定的定时器都是每55秒发送一个定时消息,有时定时就是近似的,并不完全精确。


鼠标操作
1.非客户鼠标事件:
非客户区域包括客户区域以外的所有窗口部分,包括标题栏、菜单栏、滚动条等。
在客户鼠标的事件前面加上NC的内容是非客户事件,行为之间的差别是根据鼠标按钮被单击时的鼠标位置决定的。例如:WM_NCLBUTTONDOWN
2.俘获和释放鼠标
调用CWND成员函数SETCAPTURE抓住鼠标,即所有后续鼠标信息都发送到视图窗口,直到放开命令::ReleaseCapture(),此函数是WIN32 API函数。
3.限制鼠标移动区域
将鼠标光标限制在视图窗口内,使用户不会到窗口外去画线,调用CWND::GETCLENTRECT()取得视图窗口的当前坐标,然后调用CWND::CLIENTTOSCREEN将坐标换算成屏幕坐标,最后调用::CLIPCURSOR将鼠标光标限定在指定的屏幕坐标内,从而保证光标在视图窗口内,使用命令::CLIPCURSOR(NULL)则可以使鼠标移动到屏幕的任何位置。
::ClipCursor是WIN32 API提供的函数,而不是MFC提供的。
4.鼠标处理函数的参数NFLAGS的位的位屏蔽:
MK_CONTROL      按下CTRL键时设置
MK_LBUTTON      按下鼠标左键时设置
MK_MBUTTON    按下鼠标中键时设置
MK_RUBUTTON    按下鼠标右键时设置
MK_SHIFT        按下SHIFT时设置
使用下面的语句检测SHIFT键是否按下:
if(nFlags&MK_SHIFT)
{
    ...
}
5.更改鼠标光标:
::SetCursor(::LoadCursor(AfxGetInstanceHandle(),IDC_ARROW));


指针数组:
CTypedPtrArray<CObArray,CLine*>m_linearray;
新数据成员m_LineArray是MFC类样板CTyped PrtArray的实例。CTyped PtrArray生成一族类,各由第一个样板参数指定的派生,各用于存放第二个参数指定类型的数据项。这样m_LineArray是CObArray派生的类的对象,存放CLine对象的指针。使用派生类的原因是他的编译器能进行更广泛的类型检查,帮助减少错误,并减少使用类对象时需要的校正操作。
为了使用CTypedPtrArray或者其他的任何MFC类样板,必须包含AfxTempl.h头文件,将其加入到StdAfx.h文件中。
删除数据的时候,必须先用DELETE命令删除对象,然后使用类的删除命令,删除对象的指针。


如何使程序保持极小状态?
在恢复程序窗体大小时, Windows会发送WM_QUERY-OPEN消息, 用 ClassWizard设置成员函数 OnQueryOpen() ,add following code:
Bool CMainFrame:: OnQueryOpen( )
{
Return false;
}


如何获取有关窗口正在处理的当前消息的信息
调用CWnd: : GetCurrentMessage可以获取一个MSG指针。例如,可以使用ClassWizard将几个菜单项处理程序映射到一个函数中,然后调用GetCurrentMessage来确定所选中的菜单项。
viod CMainFrame : : OnCommmonMenuHandler ( )
{
//Display selected menu item in debug window .
TRACE ("Menu item %u was selected . /n" ,
GetCruuentMessage ( ) -> wParam );
}


检查是否按下鼠标左键
if((nFlags&MK_LBUTTON)==MK_LBUTTON)


检查键盘输入
1.在OnKeyDown中的参数nChar是一个数值,当显示的时候,需要转换成字符,使用如下的命令:
char lsChar;
lsChar=char(nChar);
if(lsChar=='A');
{
.......
}
2.调用另一个函数::GetKeyState(),用一个特定的键代码来确定法键是否被按下。如果::GetKeyState函数的返回值是负的,表示该键被按下。如果返回值是非负的,表示该留未被按下。例如:如果要确定shift键是否被按下,可以使用下面的代码:
if(::GetKeyState(VK_SHIFT)<O)
{
    AfxMessageBox("shift is pressed");
}
原创粉丝点击