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”不能勾选。