您的位置:首页 > 其它

MFC知识点总结

2015-11-30 20:00 176 查看
1、数据更新、刷新

UpdateData(true); //将edit box中看到的内容传给系统

UpdateData(false); //将系统中的变量传出来,显示在edit box

控件和变量关联(可使用ClassWizard)之后:当修改了变量的值,而希望对话框控件更新显示,就应该在修改变量后调用UpdateData(FALSE);如果你希望知道用户在对话框中到底输入了什么,就应该在访问变量前调用UpdateData(TRUE)。

InvalidateRect(NULL,true); //将窗口置为无效区,告诉系统重绘指定矩形区域,不会引发WM_PAINT消息

UpdateWindow(); //引发WM_PAINT消息,立即进行重绘操作,于是界面将会立即刷新,等价于临时性地提高WM_PAINT消息的优先级。

(1)Invalidate

Invalidate标记一个需要重绘的无效区域,并不意味着调用该函数后就立刻进行重绘。类似于PostMessage(WM_PAINT),需要处理 到WM_PAINT消息时才真正重绘。以为您Invalidate之后还有其他的语句正在执行,程序没有机会去处理WM_PAINT消息,但当函数执行完 毕后,消息处理才得以进行。

Invalidate只是放一个WM_PAINT消息在队列里,不做别的,所以只有当当前函数返回后,进入消息循环,取出WM_PAINT,才执行 PAINT,所以不管Invalidate放函数哪个地方,(作用相当于)都是(放在)最后的(但并不是推荐你一律放在函数最后一行)。

Invalidate()之后:OnPaint()->OnPrepareDC()->OnDraw(),所以只是刷新在OnPaint()和OnDraw()函数中的绘图语句。其它地方没有影响。

(2)InvalidateRect

InvalidateRect只是增加重绘区域,在下次WM_PAINT的时候才生效,InvalidateRect函数中的参数TRUE表示系统会在你画之前用背景色将所选区域覆盖一次,默认背景色为白色,可以通过设置BRUSH来改变背景色。

InvalidateRect(hWnd,&rect,TRUE);将hWnd窗体的rect区域标记为无效,此区域外的客户区域不被重绘,这样 防止客户区域的一个局部的改动,而导致整个客户区域重绘而导致闪烁,如果最后的参数为TRUE,则还向窗体发送WM_ERASEBKGND消息,使背景重 绘,当然在客户区域重绘之前。

(3)UpdateWindow

UpdateWindow向窗体发送WM_PAINT消息,在发送之前判断GetUpdateRect(hWnd,NULL,TRUE)看有无可绘制的客 户区域,如果没有,则不发送WM_PAINT。如果希望立即刷新无效区域,可以在调用InvalidateRect之后调用UpdateWindow,如 果客户区的任一部分无效,则UpdateWindow将导致Windows用WM_PAINT消息调用窗口过程(如果整个客户区有效,则不调用窗口过 程)。这一WM_PAINT消息不进入消息队列,直接由WINDOWS调用窗口过程。窗口过程完成刷新以后立刻退出,WINDOWS将控制返回给程序中
UpdateWindow调用之后的语句。

Invalidate()会导致整个窗口图象重画,需要时间比较长,而InvalidateRect()仅仅重画Rect区域内内容,所需时间会少一些。

2、#include不在当前工程文件夹下的头文件

#include ".//fader_window//FaderWnd.h"

3、全局变量的定义

工程名.h中extern CDatabase theDB; //在函数体之外

工程名.cpp中CDatabase theDB; //在函数函数体之外

4、全局函数的定义

同上

//较好的全局变量和全局函数定义

(1)、添加一个没有基类的新类,设类名起为CPublic

(2)、包含公用类的头文件,使各个类都能访问它

#include “Public.h” //在应用程序类(APP)的头文件中包含此公用类头文件

(3)、在公用类中定义全局变量和全局函数,均使用static修饰,静态变量还必须在类外定义和初始化!!

Public.h:(公用类头文件)

class CPublic

{

public:

CPublic();

virtual ~CPublic();

public:

static int x; //全局变量

static int time; //全局变量

static int f(int y); //全局函数

}

Public.cpp:(公用类程序文件)

int CPublic::x = 0; //初始化全局变量

int CPublic::time; //定义全局变量

int CPublic::f(int y)

{

y++;

return y;

}

(4)、全局量的使用

void CTestView::xyz()

{

CPublic::x = 0; //访问变量x

CPublic::time = CPublic::f(1); //访问函数f()

}

(5)、几点注意:

   ① 由于静态量可独立于类存在,不需要生成CPublic类的实例。

   ② 静态数据成员的定义和初始化必须在类外进行,如例中x的初始化;变量time虽然没有初始化,但也必须

在类外进行定义 。由于没有生成CPublic类的实例,所以它的构造函数和析构函数都不会被执行,在里面

做什么工作都没有什么意义。

   ③ 如果静态函数需要访问CPublic类内的变量,这些变量也必须为静态的。因为非静态量在不生成实例时都

不会存在。

5、定义一组按键消息函数

在头文件中:

private:

afx_msg void OnNumberKey(UINT nID); //数字键

afx_msg void OnOperationKey(UINT nID); //运算键

在源文件中://在BEGIN_MESSAGE_MAP(HYJCalculatorDLG, CDialog)和END_MESSAGE_MAP()之间

ON_COMMAND_RANGE(ID_NUM0,ID_NUM9,OnNumberKey) //自定义(一组按键)消息函数,将一组按钮映射到一个函数

ON_COMMAND_RANGE(IDC_OPERATION1,IDC_OPERATION17,OnOperationKey)

//ID_NUM0,ID_NUM9和IDC_OPERATION1,IDC_OPERATION17是按钮ID范围,且必需是一组连续的ID

6、ACCESS数据库的表中有自动编号字段,追加时需要给出目标表的字段列表^=^

strsql.Format("insert into message([提醒内容],[提醒时间],[是否提醒]) values('%s','%s',%d)",m_message,showtime,0);

7、SQL常用语句一览

(1)、数据记录筛选:

sql="select * from 数据表 where 字段名=字段值 order by 字段名 [desc]"

sql="select * from 数据表 where 字段名 like '%字段值%' order by 字段名 [desc]"

sql="select top 10 * from 数据表 where 条件表达式 order by 字段名 [desc]"

sql="select * from 数据表 where 字段名 in ('值1','值2','值3')"

sql="select * from 数据表 where 字段名 between 值1 and 值2"

(2)、更新数据记录:

sql="update 数据表 set 字段名=字段值 where 条件表达式"

sql="update 数据表 set 字段1=值1,字段2=值2……字段n=值n where 条件表达式"

(3)、删除数据记录:

sql="delete from 数据表 where 条件表达式"

sql="delete from 数据表"(将数据表所有记录删除)

(4)、添加数据记录:

sql="insert into 数据表(字段1,字段2,字段3…)values(值1,值2,值3…)"

sql="insert into 目标数据表 select * from 源数据表"(把源数据表的记录添加到目标数据表)

(5)、数据记录统计函数:

AVG(字段名) 得出一个表格栏平均值

COUNT(*|字段名) 对数据行数的统计或对某一栏有值的数据行数统计

MAX(字段名) 取得一个表格栏最大的值

MIN(字段名) 取得一个表格栏最小的值

SUM(字段名)把数据栏的值相加

引用以上函数的方法:

sql="select sum(字段名) as 别名 from 数据表 where 条件表达式"

set rs=conn.excute(sql)

用rs("别名")获取统的计值,其它函数运用同上。

(6)、数据表的建立和删除:

CREATE TABLE 数据表名称(字段1 类型1 (长度),字段2 类型 2(长度)……)

例:CREATE TABLE tab01 (namevarchar (50), datetimedefaultnow ())

DROP TABLE数据表名称(永久性删除一个数据表)

(7)、外连接查询(表名1:a 表名2:b)  

select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c

(8)、四表联查问题:  

select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....

8、关于绘图

OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函 数,并且没有响应消息的功能。这就是为什么你用VC成的程序代码时,在视图类只有OnDraw没有OnPaint的原因。当视图变得无效时(包括大小的改 变,移动,被遮盖等等),Windows 将 WM_PAINT 消息发送给它。该视图的 OnPaint 处理函数通过创建 CPaintDC 类的DC对象来响应该消息并调用视图的 OnDraw 成员函数。OnPaint最后也要调用OnDraw,因此我们一般会在OnDraw函数中进行绘制。因此我们一般用OnPaint维护窗口的客户区(例如
我们的窗口客户区加一个背景图片),用OnDraw维护视图的客户区(例如我们通过鼠标在视图中画图)。

载入位图

OnDraw(CDC* pDC)

{

CBitmap bitmap;

bitmap.LoadBitmap(IDB_BITMAP1);

CDC *pdcm=new CDC;

pdcm->CreateCompatibleDC(pDC);

pdcm->SelectObject(&bitmap);

pDC->BitBlt(100,100,54,96,pdcm,0,0,SRCCOPY);

delete pdcm;

}

双缓冲机制:

把电脑屏幕看作一块黑板。首先我们在内存环境中建立一个“虚拟”的黑板,然后在这块黑板上绘制复杂的图形,等图形全部绘制完毕的时候,再一次性的把内存中绘制好的图形“拷贝”到另一块黑板(屏幕)上。采取这种方法可以提高绘图速度,极大的改善绘图效果。

建立一个缓存bufferDC,将要画的图像先画在内存中,等画完之后再与前台内容交换,能有效的消除图像闪烁

CBitmap bmp; //定义一个位图对象

CDC bufferDC; //定义一个显示设备对象建立一个缓存bufferDC建立一个缓存bufferDC

bufferDC.CreateCompatibleDC(pDC); //为屏幕pDC创建兼容的内存显示设备bufferDC.CreateCompatibleDC(NULL);

bmp.CreateCompatibleBitmap(pDC,500,500); //创建位图bmp,可以用窗口的大小nWidth,nHeight

bufferDC.SelectObject(&bmp); //把位图bmp选入设备环境,可以理解为选择画布

bufferDC.FillSolidRect(0,0,500,500,RGB(255,255,255)); //用背景色将位图清除干净,这里用白色作为背景

//*** 绘图 ***//

DrawClock(&bufferDC); //画在缓存bufferDC中

//*** 绘图 ***//

pDC->BitBlt(0,0,500,500,&bufferDC,0,0,SRCCOPY); //将缓存中的内容复制到前台,把绘制好的图形拷贝到屏幕上

bufferDC.DeleteDC(); //绘图完成后的清理,善后工作^=^

bmp.DeleteObject();

9、对话框在屏幕中央渐渐出现

/*

在StdAfx.h中

#undef WINVER

#define WINVER 0X500

*/

OnInitDialog()

{

CenterWindow(); //使窗口运行时居于屏幕正中央

AnimateWindow(GetSafeHwnd(),1000,AW_CENTER); //GetSafeHwnd()用来得到窗口句柄

SetTimer(1,1000,NULL);

}

OnCancel()

{

CDialog::OnCancel();

AnimateWindow(GetSafeHwnd(),1000,AW_HIDE|AW_CENTER);

KillTimer(1); //销毁定时器

}

10、程序运行、最小化后图标在右下角,类似QQ

在头文件MainFrm.h中声明NOTIFYICONDATA nid;

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

//***** 初始化系统托盘图标 *****//

nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);

nid.hWnd=this->m_hWnd;

nid.uID=IDR_MAINFRAME;

nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP ;

nid.uCallbackMessage=WM_USER+1;//自定义的消息名称

nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));

strcpy(nid.szTip,"双击打开多功能电子钟");//信息提示条

Shell_NotifyIcon(NIM_ADD,&nid);//在托盘区添加图标

//***** 初始化系统托盘图标 *****//

//CenterWindow();

}

LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)

{

switch(message){

case WM_USER+1: //如果是用户定义的消息

if(lParam==WM_LBUTTONDOWN) //WM_LBUTTONDBLCLK不怎么灵

{

//鼠标单击时主窗口出现

::SetForegroundWindow(this->m_hWnd); //::SetWindowPos(this->m_hWnd,HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);

AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW);

WindowIsHide=false;

return 0;

}

else if(lParam==WM_RBUTTONDOWN) // && WindowIsHide

{

::SetForegroundWindow(this->m_hWnd); //将主框架窗口置前,左击其他地方,菜单消失

//鼠标右键单击弹出菜单

CMenu menu;

menu.LoadMenu(IDR_MAINFRAME);

CMenu* pMenu=menu.GetSubMenu(0);

CPoint point;

GetCursorPos(&point);

pMenu->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,AfxGetMainWnd());

::PostMessage(this->m_hWnd, WM_NULL, 0,0); //左击其他地方,菜单消失

menu.DestroyMenu();

return 0;

}

break;

case WM_SYSCOMMAND: //如果是系统消息

if(wParam==SC_MINIMIZE||wParam==SC_CLOSE||wParam==SC_MAXIMIZE||wParam==SC_SIZE)

{

//主窗口隐藏

AfxGetApp()->m_pMainWnd->ShowWindow(SW_HIDE);

WindowIsHide=true;

return 0;

}

break;

}

return CFrameWnd::WindowProc(message, wParam, lParam);

}

void CMainFrame::OnDestroy()

{

CFrameWnd::OnDestroy();

::Shell_NotifyIcon(NIM_DELETE,&nid);

}

11、主框架风格设置

/*

CWnd是MFC的类(class类型),HWND是Win32的句柄(UINT类型)

CWnd是MFC类库的窗口基类。具有很多的成员函数和成员变量。

CWnd::m_hWnd里面就保存着一个HWND类型的句柄。其中公用变量m_hWnd是窗口句柄,就是本窗口的HWND。

在MFC中,有几种典型的窗口对象,CWnd描述的一般窗口对象,CView描述的视图对象,CFrameWnd描述的SDI框窗对象,CMDIFrameWnd描述的MDI框窗对象等等。

HWND是一个窗口的句柄,可以理解为一个极大的整数,可以唯一识别系统中的所有窗口,用于标识、访问窗口对象。

*/

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

......

SetWindowText(name); //改名称

ShowWindow(SW_SHOWMAXIMIZED);

//最大化窗口,在SuperClock.cpp中m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);有从小到大的过程

......

}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

if( !CFrameWnd::PreCreateWindow(cs) )

return FALSE;

//获得窗体风格

LONG style = ::GetWindowLong(m_hWnd,GWL_STYLE);

/*

假如style从右边数第四个bit控制窗口的最大化(我是随便说的,具体是第几位我也不知道,可以到MSDN里查),

那么WS_MAXIMIZEBOX就是0x08(也就是二进制的1000)。

于是cs.style &= ~WS_MAXIMIZEBOX;就把style中代表最大化的那个bit给清空了(置成0了),

而同时又能保持style中的其他bit位不变,因为其它bit位有其他的用处。

*/

cs.style &=~WS_MAXIMIZEBOX; //把WS_MAXIMIZEBOX从cs.style中去掉

cs.style &= ~FWS_ADDTOTITLE ; //防止在标题栏上预置应用程序名SuperClock

cs.style &= WS_DLGFRAME; //对话框边框样式,不带标题框,无法拖动大小

cs.style = cs.style & (~WS_THICKFRAME); //WS_THICKFRAME表示边框可以调大小

::SetWindowLong(m_hWnd,GWL_STYLE,style);

return TRUE;

}

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)

{

//设置WS_DLGFRAME对话框边框样式后,处理窗口最大化时覆盖任务栏的情况

MINMAXINFO FAR* pmmi = (MINMAXINFO FAR*)lpMMI;

pmmi->ptMaxSize.y = GetSystemMetrics(SM_CYFULLSCREEN);

CFrameWnd::OnGetMinMaxInfo(lpMMI);

}

12、右击弹出菜单

void CSuperClockView::OnRButtonDown(UINT nFlags, CPoint point)

{

CMenu menu;

menu.LoadMenu(IDR_MAINFRAME);

CMenu* pMenu=menu.GetSubMenu(2);

/*

不要直接使用

pMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);

TrackPopupMenu使用的是屏幕坐标,而OnRButtonDown函数中参数point是当前窗口客户区坐标系,

*/

//需要将坐标进行转换一下

ClientToScreen(&point);

pMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);

/* 或者

CPoint pt;

GetCursorPos(&pt);

pMenu->TrackPopupMenu(TPM_LEFTALIGN,pt.x,pt.y,this);

*/

/*

TPM_CENTERALIGN:若设置此标志,函数将按参数x指定的坐标水平居中放置快捷菜单。

TPM_LEFTALIGN:若设置此标志,函数使快捷菜单的左边界与由参数X指定的坐标对齐。

TPM_RIGHTALIGN:若设置此标志,函数使快捷菜单的右边界与由参数X指定的坐标对齐。

TPM_BOTTOMALIGN:若设置此标志,函数使快捷菜单的下边界与由参数y指定的坐标对齐。

TPM_TOPALIGN:若设置此标志,函数使快捷菜单的上边界与由参数y指定的坐标对齐。

TPM_VCENTERALIGN;若设置此标志,函数将按参数y指定的坐标垂直居中放置快捷菜单。

TPM_NONOTIFY:若设置此标志,当用户单击菜单项时函数不发送通知消息。

TPM_RETURNCMD;若设置此标志;函数将用户所选菜单项的标识符返回到返回值里。

(补充:当TrackPopupMenu的返回值大于0,就说明用户从弹出菜单中选择了一个菜单。以返回的ID号为参数wParam的值,程序给自己发送了一个WM_SYSCOMMAND消息)

TPM_LEFTBUTTON:若设置此标志,用户只能用鼠标左键选择菜单项。

TPM_RIGHTBUTTON:若设置此标志,用户能用鼠标左、右键选择菜单项。

*/

CRecordView::OnRButtonDown(nFlags, point);

}

13、鼠标在非客户区的操作

/*

Nc开头代表的是非客户区,标题栏、边框等

在ClassWizard中把class info的message filter选成window,就可以在消息表里找到WM_NCLBUTTONDBLCLK、WM_NCHITTEST等消息

*/

//禁止双击改变窗体大小

void CMainFrame::OnNcLButtonDblClk(UINT nHitTest, CPoint point)

{

if(nHitTest != HTCAPTION)

CFrameWnd::OnNcLButtonDblClk(nHitTest, point);

}

//禁止鼠标拖动窗体边框改变窗体大小

UINT CMainFrame::OnNcHitTest(CPoint point)

{

/*

通过判断CWnd::OnNcHitTest()的返回值是否为

HTRIGHT,HTLEFT,HTTOP,HTBOTTOM,HTTOPLEFT,

HTTOPRIGHT,HTBOTTOMLEFT,HTBOTTOMRIGHT(4条边、4个角),

如果是,说明用户此时已点击了四个边框之一,此时我们应该返回HTCLIENT(静态客户区)那么,系统以为鼠标还在客户区,其形状就不会变成水平或垂直的双向箭头,用户就不可能依靠拖动边框来改变窗口大小了。

*/

//用于屏蔽双击改变窗体大小

if(CWnd::OnNcHitTest(point) == HTCAPTION)return HTCLIENT; //HTCAPTION标题栏区域

if(CWnd::OnNcHitTest(point) == HTRIGHT || CWnd::OnNcHitTest(point) == HTLEFT ||

CWnd::OnNcHitTest(point) == HTTOP || CWnd::OnNcHitTest(point) == HTBOTTOM ||

CWnd::OnNcHitTest(point) == HTTOPLEFT || CWnd::OnNcHitTest(point) == HTTOPRIGHT

||CWnd::OnNcHitTest(point)==HTBOTTOMLEFT||CWnd::OnNcHitTest(point)

== HTBOTTOMRIGHT)

return HTCLIENT;

return CFrameWnd::OnNcHitTest(point);

}

14、关于SetTimer

先请看SetTimer这个API函数的原型

UINT_PTR SetTimer(

HWND hWnd, // 窗口句柄

UINT_PTR nIDEvent, // 定时器ID,多个定时器时,可以通过该ID判断是哪个定时器

UINT uElapse, // 时间间隔,单位为毫秒

TIMERPROC lpTimerFunc // 回调函数

);

例如

SetTimer(m_hWnd,1,1000,NULL); //一个1秒触发一次的定时器

在MFC程序中SetTimer被封装在CWnd类中,调用就不用指定窗口句柄了

于是SetTimer函数的原型变为:

UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT*

lpfnTimer)(HWND,UINT ,YINT ,DWORD))

当使用SetTimer函数的时候,就会生成一个计时器。函数中nIDEvent指的是计时器的标识,也就是名字。 nElapse指的是时间间隔,也就是每隔多长时间触发一次事件。第三个参数是一个回调函数,在这个函数里,放入你想要做的事情的代码,你可以将它设定为 NULL,也就是使用系统默认的回调函数,系统默认认的是onTime函数。这个函数怎么生成的呢?你需要在需要计时器的类的生成onTime函数:在 ClassWizard里,选择需要计时器的类,添加WM_TIME消息映射,就自动生成onTime函数了。然后在函数里添加代码,让代码实现功能。每
隔一段时间就会自动执行一次。

例如:

SetTimer(1,1000,NULL);

1:计时器的名称;

1000:时间间隔,单位是毫秒;

NULL:使用onTime函数。

当不需要计时器的时候调用KillTimer(nIDEvent);

例如:KillTimer(1);

调用回调函数

void CALLBACK TimerProc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime);

然后再用SetTimer(1,100,TimerProc)函数来建一个定时器,第三个参数就是回调函数地址。

或许你会问:如果我要加入两个或者两个以上的 timer怎么办?

继续用SetTimer函数吧,上次的timer的ID是1,这次可以是2,3,4。。。。

SetTimer(2,1000,NULL);

SetTimer(3,500,NULL);

WINDOWS会协调他们的。当然onTimer函数体也要发生变化,要在函数体内添加每一个timer的处理代码:

onTimer(nIDEvent)

{

switch(nIDEvent)

{

case 1:........;

break;

case 2:.......;

break;

case 3:......;

break;

}

15、库冲突

选择Project -> Setting,出现Project Setting对话框,单击Link标签,在Category下拉菜单中选择Input,在下方的Ignore libraries: 输入框中输入“被忽略的library”框中对应的libs。注意:当前Build的是什么版本(Debug或者Release),libs之间用“,” 隔开。“Ingore all default libraries”不能勾选。

.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: