vc++经典技巧总结

1."属性页的添加:

创建对话框的类,该类要从CpropertyPage继承;然后在要添加该对话框为属性页的类(头文件)里创建CpropertySheet类的一个对象m_tabsheet和新创建的对话框类的对象m_skatch;最后,在.cpp文件里的OnInitDialog()之类的函数里实现如下代码:
m_tabsheet.Create(this,WS_CHILD|WS_VISIBLE,0);
"//使选项卡的按钮在下面
"if(m_tabsheet.m_hWnd)
"m_tabsheet.ShowWindow(SW_MAXIMIZE);//显示选项卡
//加入标签,标签名由各个子对话框的标题栏决定
"m_tabsheet.AddPage(&m_skatch);
"//用Create来创建一个属性页
"m_tabsheet.Create(this,WS_CHILD|WS_VISIBLE,WS_EX_CONTROLPARENT);
"
RECTrect;
"m_tabsheet.GetWindowRect(&rect);
"intwidth=rect.right-rect.left;
"intheight=rect.bottom-rect.top;
"
"//调整属性页的大小和位置
"m_tabsheet.SetWindowPos(NULL,225,225,width-82,height,SWP_NOACTIVATE);
属性页的添加完成。如果要添加多个属性页,则只需要增加多个对象,如下:m_tabsheet.AddPage(&m_skatch1);
  m_tabsheet.AddPage(&m_skatch2);
......

2."ListControl中标题栏(Column)的添加:

创建一个ListControl,其ID为IDC_LIST,在其Styles属性项下的View项里选择Report、Align项里选择Top、Sort项里选择None.
然后在该List所在对话框的类(头文件)里创建ClistCtrl的一个对象m_list然后在.cpp文件的OnInitDialog()之类的函数里实现如下代码:
CStringstrname[3];
strname[0]="ScreenName";
strname[1]="FormID";
strname[2]="CategoryPath";
for(inti=0;i<3;i++)
{
m_List.InsertColumn(i,strname[i],LVCFMT_LEFT,130);
}
在这之前也要将ListControl的ID与ClistCtrl的对象m_list在DoDataExchange(CDataExchange*pDX)函数里绑定,如下:
DDX_Control(pDX,IDC_LIST,m_List);

3."ToolBar和StatusBar中控件的添加:

方法⑴.只能在ToolBar里创建控件:首先,在ToolBar中创建一个Button,其ID为ID_TOOL_COMBO(我们要将创建的控件放在该Button的位置上).
其次,新创建一个类CMainToolBar,要从CToolBar继承(创建过程大概如下:选择工程/增加到工程/新的类;也可以选择工程的根,然后点击右键,选择新的类;或者CTL+W,选择增加类/新的类---然后在classtype里选择GenericClass,在Name栏里输入新类的名字,Baseclass里输入CToolBar),创建成功后在该类里创建要增加的控件的对象,如:
CComboBox""m_wndMyCombo;
CStatic""m_wndCategory,m_wndCategoryPath;
CButton""m_wndOpenButton;
Cedit"""m_wndEdit;
然后在构造函数里初始化如:
m_wndMyCombo.m_hWnd=NULL;
m_wndCategory.m_hWnd=NULL;
m_wndCategoryPath.m_hWnd=NULL;
m_wndOpenButton.m_hWnd=NULL;
m_wndEdit.m_hWnd=NULL;
接着在CMainframe的头文件里创建CMainToolBar的一个对象m_wndToolBar,最后在.cpp文件的OnCreate函数的最后实现如下:
"intindex=0;
"CRectrect; //可定义在头文件当中
"// ComboBox
"{
""//找到指定的工具项
""while(m_wndToolBar.GetItemID(index)!=ID_TOOL_COMBO)
"""index++;
""//设置指定工具项的宽度并获取新的区域 120是宽度
""m_wndToolBar.SetButtonInfo(index,ID_TOOL_COMBO,TBBS_SEPARATOR,120);
""m_wndToolBar.GetItemRect(index,&rect);
""
""//设置位置
""rect.top+=1;
""rect.bottom+=200;
""
""//创建并显示控件
""if(!m_wndToolBar.m_wndMyCombo.Create(WS_CHILD|WS_VISIBLE|CBS_AUTOHSCROLL|
"""CBS_DROPDOWNLIST|CBS_HASSTRINGS,rect,&m_wndToolBar,ID_TOOL_COMBO))
""{ 
"""TRACE0("Failedtocreatecombo-box\n");
"""returnFALSE;
""}
""m_wndToolBar.m_wndMyCombo.ShowWindow(SW_SHOW);
""
""//填充内容"
""m_wndToolBar.m_wndMyCombo.AddString("25%");
""m_wndToolBar.m_wndMyCombo.AddString("50%");
""m_wndToolBar.m_wndMyCombo.AddString("75%");
"
""//选择默认项
""m_wndToolBar.m_wndMyCombo.SetCurSel(0);
""
""//获取到内容并MSGBOX显示出来
""CStringstrContent;
""m_wndToolBar.m_wndMyCombo.GetWindowText(strContent);

""index=0;
"}
其他控件都类似创建(只需要注意一下各自的Create函数的参数即可)。
方法⑵.这种方法创建不太容易控制:直接在CMainframe的头文件中创建要增加的控件的对象,如CButton"的对象m_wndAboutButton,然后创建CToolBar或者CstatusBar的对象,如:CstatusBar的对象_wndStatusBar;再增加几个函数如下:
Protected:
virtualvoidRecalcLayout(BOOLbNotify=TRUE);
"afx_msgvoidCMainFrame::OnViewStatusBar();
接着在.cpp文件中将StatusBar的ID和OnViewStatusBar函数绑定在一起,如下所示:BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)
"  // {{AFX_MSG_MAP(CMainFrame)
"  ON_COMMAND(ID_VIEW_STATUS_BAR,OnViewStatusBar)
"  ON_WM_CREATE()
"  // }}AFX_MSG_MAP
END_MESSAGE_MAP()
然后Create函数的最后(返回值之前)实现如下代码:
CRectrc;
"VERIFY(m_wndAboutButton.Create(_T("MyAbout"),
"" WS_VISIBLE,rc,this,ID_APP_ABOUT));

"//TODO:Removethisifyoudon'twanttooltipsoraresizeabletoolbar
"m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle()|
"CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC);
再在RecalcLayout函数里实现:
CRectrc;
if(m_wndStatusBar.m_hWnd)
{
""m_wndStatusBar.GetWindowRect(&rc);
""ScreenToClient(&rc);
""rc.right-=50;
""m_wndStatusBar.SetWindowPos(NULL,rc.left,rc.top,rc.Width(),rc.Height(),
"""SWP_NOZORDER);

""rc.left=rc.right;
""rc.right+=50;
""m_wndAboutButton.SetWindowPos(NULL,rc.left,rc.top,rc.Width(),rc.Height(),
"""SWP_NOZORDER);
"}
最后在OnViewStatusBar()里实现:
BOOLbShow=m_wndStatusBar.GetStyle()&WS_VISIBLE;
"m_wndAboutButton.SetWindowPos(NULL,0,0,0,0,
SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
(bShow?SWP_SHOWWINDOW:SWP_HIDEWINDOW));
ToolBar中的创建与此相同,只需更改一下句柄即可。

4."通过Control创建的控件,对其属性的动态控制:

在对话框类的头文件里创建所要改变属性的控件的对象,如要改变一个Button(其ID为IDC_MyButton)的属性,则需创建Cbutton的对象m_button。然后在.cpp中的DoDataExchange函数里将Button的ID和创建的对象绑定在一起:
//{{AFX_DATA_MAP(CPrintDlg)
""//NOTE:theClassWizardwilladdDDXandDDVcallshere
"DDX_Control(pDX,IDC_MyButton,m_button);
"//}}AFX_DATA_MAP
然后可以在该函数的最后进行初始化:
"m_button.EnableWindow(FALSE);
到这里已经实现了改变属性。如果要动态改变其属性,可如下实现(通过两个Button的点击改变起属性):
//RadioAllButton的点击响应函数
voidCPrintDlg::OnRadioAll()
{
""//TODO:Addyourcontrolnotificationhandlercodehere
""m_button.EnableWindow(TRUE);
}

//RadioSelectButton的点击响应函数
voidCPrintDlg::OnRadioSelect()
{
""//TODO:Addyourcontrolnotificationhandlercodehere
""m_button.EnableWindow(FALSE);
}
也可以通过一个CheckButton的点击来改变,在其点击响应函数里实现:
m_button.EnableWindow(!m_button.IsWindowEnabled());
其余控件属性的改变都如此。

5."窗口的分割与停靠:                        
一、新建一个类CMySplitter,基类为CSplitterWnd
二、重载该类的OnMouseMove函数:
voidCMySplitter::OnMouseMove(UINTnFlags,CPointpoint)
{
"//限制切分条的运动范围。
"if(point.x<228||point.x>600)
"{
""CWnd::OnMouseMove(nFlags,point);
"}
"else
"{
""CSplitterWnd::OnMouseMove(nFlags,point);
"}
}
三、然后就可以跟一般的窗口分割那样去做了,if(point.x<228||point.x>600)这里的范围可以随你去设置了^_^,够简单吧。
四、切分窗口
在MaiFram.h建立切分条对象:
protected:
CMySplitterm_wndSplitter;//切分窗口对象
//在MaiFram.cpp中实现窗口切分:
BOOLCMainFrame::OnCreateClient(LPCREATESTRUCT/*lpcs*/,CCreateContext*pContext)
{
"//创建拆分器窗口
if(!m_wndSplitter.CreateStatic(this,1,2))
""returnFALSE;
if(!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CLeftView),CSize(228,100),pContext)||!m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CDataEditView), CSize(100,100),pContext))
"{
""m_wndSplitter.DestroyWindow();
""returnFALSE;
"}

"returnTRUE;
}


6. ①怎样在程序开始的时候让它最大化?
②vc++做出来的exe文件在窗体的右上方是没有最大化和最小化按钮的,怎样实现这一功能?
③如何在显示窗口时,使最大化按钮变灰?

①在App类里的C…App::InitInstance()中把m_pMainWnd->ShowWindow(SW_SHOW)改成m_pMainWnd->ShowWindow(SW_MAXIMIZE);
②在CreateWidnow时用WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX风格.
  ③第一种方法:
BOOLCMainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
if(!CFrameWnd::PreCreateWindow(cs))
returnFALSE;
//TODO:ModifytheWindowclassorstylesherebymodifying
// theCREATESTRUCTcs
//disablethemaxminibox
cs.style&=~WS_MAXIMIZEBOX;
returnTRUE;
}
第二种方法:
CMenu*pMenu=AfxGetApp()->m_pMainWnd->GetSystemMenu(FALSE);
    intx=pMenu->GetMenuItemCount();
    UINTpID=pMenu->GetMenuItemID(x-1);
    pMenu->EnableMenuItem(pID,MF_DISABLED);
第三种方法:
ModifyStyle(WS_MAXIMIZEBOX,0);
这个函数也可以是最大化按钮失效!
并且可以在程序中动态的改变窗口的风格

7.更改属性页标题

voidCProSheet::SetPageTitle(intnPage,intnImage,CStringstrTitle)
{
 TC_ITEMitem;
 //item.mask=TCIF_TEXT|TCIF_IMAGE;  //设置图标+文字
 item.mask=TCIF_IMAGE;    //只设置图标
 item.iImage=nImage;
//item.pszText=strTitle.GetBuffer(0);  //设置文字
 GetTabControl()->SetItem(nPage,&item);
//要设置文字时就将上面2行有注释符的代码前的注释符去掉
}

8.创建动态菜单

voidCMainFrame::OnSelectState(NMTOOLBAR*pnmtb,LRESULT*plr)
{
"CMenumenu;
"if(!menu.CreateMenu())
"return;
"menu.AppendMenu(MF_STRING,0,"开始");
"menu.AppendMenu(MF_STRING,0,"结束");
"CRectrc;
"m_wndToolBar.SendMessage(TB_GETRECT,pnmtb->iItem,(LPARAM)&rc); 
"m_wndToolBar.ClientToScreen(&rc);
"menu.TrackMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL,
"""rc.left,rc.bottom,this,&rc);
//"menu.DestroyMenu();
"menu.detach();
}
9.关于打印

1.要打印哪个视就
((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.SetActivePane(...)
//要打印的那个视对应的Pane

2.有一个单文档工程,文档窗口被切分:左视图由CTreeView的派生类管理,右视图由CListView的派生类CMyListView(其为风格为LVS_REPORT)管理,我想为右视图添加打印和打印预览,我在MyListView.cpp中添加了
  ON_COMMAND(ID_FILE_PRINT,CListView::OnFilePrint)
  ON_COMMAND(ID_FILE_PRINT_PREVIEW,CListView::OnFilePrintPreview)还有
  BOOLCMyListView::OnPreparePrinting(CPrintInfo*pInfo)
  {
    //TODO:callDoPreparePrintingtoinvokethePrintdialogbox

    //returnCListView::OnPreparePrinting(pInfo);
    pInfo->SetMaxPage(2);
    BOOLbret=DoPreparePrinting(pInfo);
    pInfo->m_nNumPreviewPages=2;
    returnbret;
  }
3.下面是从MSDN中摘出来的一段,是用来改变消息路由的。用了这段代码之后,CView中的消息(菜单,控件,子窗口)将先被CMyShape类来处理。不知道你要的是不是这样的效果。

  //Thisexampleillustratesextendingtheframework'sstandardcommand
  //routefromtheviewtoobjectsmanagedbytheview. Thisexample
  //isfromanobject-orienteddrawingapplication,similartothe
  //DRAWCLIsampleapplication,whichdrawsandedits"shapes".

  BOOLCMyView::OnCmdMsg(UINTnID,intnCode,void*pExtra,
   AFX_CMDHANDLERINFO*pHandlerInfo)
  {
     //Extendtheframework'scommandroutefromtheviewto
     //theapplication-specificCMyShapethatiscurrentlyselected
     //intheview.m_pActiveShapeisNULLifnoshapeobject
     //iscurrentlyselectedintheview.
     if((m_pActiveShape!=NULL)
        &&m_pActiveShape->OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))
      returnTRUE;

     //Iftheobject(s)intheextendedcommandroutedon'thandle
      //thecommand,thenletthebaseclassOnCmdMsghandleit.
      returnCView::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);
     }

     //ThecommandhandlerforID_SHAPE_COLOR(menucommandtochange
     //thecolorofthecurrentlyselectedshape)wasaddedto
     //themessagemapofCMyShape(note,notCMyView)usingClassWizard. 

     //Themenuitemwillbeautomaticallyenabledordisabled,depending
     //onwhetheraCMyShapeiscurrentlyselectedintheview,thatis,
     //dependingonwhetherCMyView::m_pActiveViewisNULL. Itisnot
     //necessarytoimplementanON_UPDATE_COMMAND_UIhandlertoenable
     //ordisablethemenuitem. 

   BEGIN_MESSAGE_MAP(CMyShape,CCmdTarget)
   //{{AFX_MSG_MAP(CMyShape)
   ON_COMMAND(ID_SHAPE_COLOR,OnShapeColor)
   //}}AFX_MSG_MAP
   END_MESSAGE_MAP()

如果你只是想调用OnFilePrint()函数,可以试一试下面的代码,就和调用其它类中的函数一样。

CMDIFrameWnd*pFrame=
      (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;

//GettheactiveMDIchildwindow.
CMDIChildWnd*pChild=
      (CMDIChildWnd*)pFrame->GetActiveFrame();

//orCMDIChildWnd*pChild=pFrame->MDIGetActive();

//GettheactiveviewattachedtotheactiveMDIchild
//window.
CMyView*pView=(CMyView*)pChild->GetActiveView();

pView->OnFilePrint();


4.
voidCMyReportView::OnFileOpen()
{
charFilter[]="CrystalReportfiles(*.rpt)|*.rpt|Allfiles(*.*)|*.*||";
CRectrect;
CFileDialogOpenDlg(TRUE,0,0,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,(LPCTSTR)Filter,NULL);
if(OpenDlg.DoModal()!=IDOK)///显示文件对话框
return;
CStringm_fName=OpenDlg.GetPathName();///取得文件名
if(m_CrystalReport)
m_CrystalReport.DestroyWindow();
GetClientRect(rect);
///创建控件///
if(!m_CrystalReport.Create(AfxRegisterWndClass(0,AfxGetApp()->LoadStandardCursor(IDC_ARROW)),WS_CHILD|WS_VISIBLE,rect,this,IDC_CRYSTALREPORT1))
{
AfxMessageBox("控件创建失败!");
return;
}
m_CrystalReport.SetWindowParentHandle((long)(this->m_hWnd));///设置父窗口
m_CrystalReport.SetWindowBorderStyle(0);///设置为没有边框
m_CrystalReport.SetWindowLeft(0);///左空间
m_CrystalReport.SetWindowTop(0);///顶部空间
m_CrystalReport.SetWindowControls(FALSE);///不显示工具条
m_CrystalReport.SetReportFileName(m_fName);///设置报表文件
m_CrystalReport.SetWindowWidth(rect.Width());///设置窗口宽度
m_CrystalReport.SetWindowHeight(rect.Height());///设置窗口高度
m_CrystalReport.SetFormulas(0,"Company=\"VC知识库\"");///将报表中的Company变量的值设置为VC知识库
m_CrystalReport.SetDestination(0);///设置输出对象是屏幕
m_CrystalReport.PrintReport();///显示报表
}
voidCMyReportView::OnFilePrint()
{
if(m_CrystalReport&&m_CrystalReport.GetReportFileName()!="")
{
m_CrystalReport.SetDestination(1);///设置输出对象是打印机
m_CrystalReport.PrintReport();///打印
}

10.Scroll

创建一个基于CScrollview的SDI Project(在第6步中选CScrollview)
若你已创建了,这步可以省略。
然后:
改为如
voidCTestView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();

CSizesizeTotal;
//TODO:calculatethetotalsizeofthisview
sizeTotal.cx=1024; //改这两个
sizeTotal.cy=768; //
SetScrollSizes(MM_TEXT,sizeTotal);
}

11.修改主窗口风格

AppWizard生成的应用程序框架的主窗口具有缺省的窗口风格,比如在窗口标题条中自动添加文档名、窗口是叠加型的、可改变窗口大小等。要修改窗口的缺省风格,需要重载CWnd::PreCreateWindow(CREATESTRUCT&cs)函数,并在其中修改CREATESTRUCT型参数cs。
CWnd::PreCreateWindow函数先于窗口创建函数执行。如果该函数被重载,则窗口创建函数将使用CWnd::PreCreateWindow函数返回的CREATESTRUCTcs参数所定义的窗口风格来创建窗口;否则使用预定义的窗口风格。
CREATESTRUCT结构定义了创建函数创建窗口所用的初始参数,其定义如下:

typedefstructtagCREATESTRUCT{
LPVOIDlpCreateParams;//创建窗口的基本参数
HANDLEhInstance;//拥有将创建的窗口的模块实例句柄
HMENUhMenu;//新窗口的菜单句柄
HWNDhwndParent;//新窗口的父窗口句柄
intcy;//新窗口的高度
intcx;//新窗口的宽度
inty;//新窗口的左上角Y坐标
intx;//新窗口的左上角X坐标
LONGstyle;//新窗口的风格
LPCSTRlpszName;//新窗口的名称
LPCSTRlpszClass;//新窗口的窗口类名
DWORDdwExStyle;//新窗口的扩展参数
}CREATESTRUCT;

CREATESTRUCT结构的style域定义了窗口的风格。比如,缺省的MDI主窗口的风格中就包括FWS_ADDTOTITLE(在标题条中显示当前的工作文档名)、FWS_PREFIXTITLE(把文档名放在程序标题的前面)、WS_THICKFRAME(窗口具有可缩放的边框)等风格。由于多种风格参数由逻辑或(“|”)组合在一起的,因此添加某种风格,就只需用“|”把对应的参数加到CREATESTRUCT结构的style域中;删除已有的风格,则需用“&”连接CREATESTRUCT结构的style域与该风格的逻辑非值。
CREATESTRUCT结构的x、y、cx、cy域分别定义了窗口的初始位置和大小,因此,在CWnd::PreCreateWindow函数中给它们赋值,将能定义窗口的初始显示位置和大小。
下例中的代码将主框窗口的大小将固定为1/4屏幕,标题条中仅显示窗口名,不显示文档名。

BOOLCMainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
//TODO:ModifytheWindowclassorstylesherebymodifying
//theCREATESTRUCTcs

//修改主窗风格
cs.style&=~FWS_ADDTOTITLE;//去除标题条中的文档名
cs.style&=~WS_THICKFRAME;//去除可改变大小的边框
cs.style|=WS_DLGFRAME;//增加不能改变大小的边框

//确定主窗的大小和初始位置
intcxScreen=::GetSystemMetrics(SM_CXSCREEN);//获得屏幕宽
intcyScreen=::GetSystemMetrics(SM_CYSCREEN);//获得屏幕高
cs.x=0;//主窗位于左上角
cs.y=0;
cs.cx=cxScreen/2;//主窗宽为1/2屏幕宽
cs.cy=cxScreen/2;//主窗高为1/2屏幕高
returnCMDIFrameWnd::PreCreateWindow(cs);
}

12.控制滚动条

BOOLCDiagramShowView::PreTranslateMessage(MSG*pMsg)
{
"CFileTreeDoc*pDoc=(CFileTreeDoc*)GetDocument();
"CPointpoint=GetScrollPosition();
"
"if(pMsg->message==WM_KEYDOWN)
"{
""switch(pMsg->wParam)
""{
""caseVK_LEFT:
"""if(point.x>10)
"""{
""""EndPoint.x=EndPoint.x-10;
""""EndPoint.y=EndPoint.y;
"""}
"""else
"""{
""""EndPoint.x=0;
""""EndPoint.y=EndPoint.y;
"""}
"""ScrollToPosition(EndPoint);
"""InvalidateRect(NULL,TRUE);
"""break;
""caseVK_RIGHT:
"""if(point.x<pDoc->intDiagramColumnCount*pDoc->intColumnWidth-10)
"""{
""""EndPoint.x=EndPoint.x+10;
""""EndPoint.y=EndPoint.y;
"""}
"""else
"""{
""""EndPoint.y=pDoc->intDiagramColumnCount*pDoc->intColumnWidth;
""""EndPoint.x=EndPoint.x;
"""}
"""ScrollToPosition(EndPoint);
"""InvalidateRect(NULL,TRUE);
"""break;
""caseVK_UP:
"""if(point.y>10)
"""{
""""EndPoint.y=EndPoint.y-10;
""""EndPoint.x=EndPoint.x;
"""}
"""else
"""{
""""EndPoint.y=0;
""""EndPoint.x=EndPoint.x;
"""}
"""ScrollToPosition(EndPoint);
"""InvalidateRect(NULL,TRUE);
"""break;
""caseVK_DOWN:
"""if(point.y<pDoc->intDiagramRowCount*pDoc->intRowHeight-10)
"""{
""""EndPoint.y=EndPoint.y+10;
""""EndPoint.x=EndPoint.x;
"""}
"""else
"""{
""""EndPoint.y=pDoc->intDiagramRowCount*pDoc->intRowHeight;
""""EndPoint.x=EndPoint.x;
"""}
"""ScrollToPosition(EndPoint);
"""InvalidateRect(NULL,TRUE);
"""break;
""default:
"""break;
""}
"}
"returnFALSE;
}


//通过正负号判断是向上还是向下滚动
if(zDelta==120) 
向上滚动
if(zDelta==-120)
向下滚动

BOOLCDiagramShowView::OnMouseWheel(UINTnFlags,shortzDelta,CPointpt)
{
"CFileTreeDoc*pDoc=(CFileTreeDoc*)GetDocument();
"CPointpoint=GetScrollPosition();
"
"if(zDelta==120)
"{
""if(point.y>=20)
""{
"""EndPoint.x=point.x;
"""EndPoint.y=point.y;
"""
"""EndPoint.x=EndPoint.x;
"""EndPoint.y=EndPoint.y-20;
""}
""else
""{
"""EndPoint.x=EndPoint.x;
"""EndPoint.y=0;
""}
"}
"
"if(zDelta==-120)
"{
""if(point.y<=pDoc->intDiagramRowCount*pDoc->intRowHeight-20)
""{
"""EndPoint.x=point.x;
"""EndPoint.y=point.y;
"""
"""EndPoint.x=EndPoint.x;
"""EndPoint.y=EndPoint.y+20;
""}
""else
""{
"""EndPoint.x=EndPoint.x;
"""EndPoint.y=EndPoint.y;
""}
"}
"
"ScrollToPosition(EndPoint);
"InvalidateRect(NULL,TRUE);
"returnCScrollView::OnMouseWheel(nFlags,zDelta,pt);
}

13.属性页处理通知消息

CPropertyPageImpl有一个消息映射处理WM_NOTIFY。如果通知代码是PSN_*的值,OnNotify()就会调用相应的通知处理函数。这使用了编译阶段虚函数机制,从而使得派生类可以很容易的重载这些处理函数。
由于WTL3和WTL7设计的改变,从而存在两套不同的通知处理机制。在WTL3中通知处理函数返回的值与PSN_*消息的返回值不同,例如,WTL3是这样处理PSN_WIZFINISH的:

casePSN_WIZFINISH:
lResult=!pT->OnWizardFinish();
break;
OnWizardFinish()期望返回TRUE结束向导,FALSE阻止关闭向导。这个方法很简陋,但是IE5的通用控件对PSN_WIZFINISH处理的返回值添加了新解释,他返回需要获得焦点的窗口的句柄。WTL3的程序将不能使用这个特性,因为它对所有非0的返回值都做相同的处理。
在WTL7中,OnNotify()没有改变PSN_*消息的返回值,处理函数返回任何文档中规定的合法数值和正确的行为。当然,为了向前兼容,WTL3仍然使用当前默认的工作方式,要使用WTL7的消息处理方式,你必须在中includingatldlgs.h一行之前添加一行定义:
#define_WTL_NEW_PAGE_NOTIFY_HANDLERS
编写新的代码没有理由不使用WTL7的消息处理函数,所以这里就不介绍WTL3的消息处理方式。
CPropertyPageImpl为所有消息提供了默认的通知消息处理函数,你可以重载与你的程序有关的消息处理函数完成特殊的操作。默认的消息处理函数和相应的行为如下:
intOnSetActive()-允许页面成为激活状态
BOOLOnKillActive()-允许页面成为非激活状态
intOnApply()-返回PSNRET_NOERROR表示应用操作成功完成
voidOnReset()-无相应的动作
BOOLOnQueryCancel()-允许取消操作
intOnWizardBack()-返回到前一个页面
intOnWizardNext()-进行到下一个页面
INT_PTROnWizardFinish()-允许向导结束
voidOnHelp()-无相应的动作
BOOLOnGetObject(LPNMOBJECTNOTIFYlpObjectNotify)-无相应的动作
intOnTranslateAccelerator(LPMSGlpMsg)-返回PSNRET_NOERROR表示消息没有被处理
HWNDOnQueryInitialFocus(HWNDhWndFocus)-返回NULL表示将按TabOrder顺序的第一个控件设为焦点状态
14.使工具条上的按钮点击一次为按下,再点击才弹起
bCheck=m_RtfEditToolBar.GetToolBarCtrl().IsButtonChecked(ID_TB_BOLD);
m_RtfEditToolBar.GetToolBarCtrl().CheckButton(ID_TB_BOLD,!bCheck);
15.VC中基于Windows的精确定时
  
在工业生产控制系统中,有许多需要定时完成的操作,如定时显示当前时间,定时刷新屏幕上的进度条,上位机定时向下位机发送命令和传送数据等。特别是在对控制性能要求较高的实时控制系统和数据采集系统中,就更需要精确定时操作。
  众所周知,Windows是基于消息机制的系统,任何事件的执行都是通过发送和接收消息来完成的。这样就带来了一些问题,如一旦计算机的CPU被某个进程占用,或系统资源紧张时,发送到消息队列中的消息就暂时被挂起,得不到实时处理。因此,不能简单地通过Windows消息引发一个对定时要求严格的事件。另外,由于在Windows中已经封装了计算机底层硬件的访问,所以,要想通过直接利用访问硬件来完成精确定时,也比较困难。所以在实际应用时,应针对具体定时精度的要求,采取相适应的定时方法。
  VC中提供了很多关于时间操作的函数,利用它们控制程序能够精确地完成定时和计时操作。本文详细介绍了VC中基于Windows的精确定时的七种方式.
  方式一:VC中的WM_TIMER消息映射能进行简单的时间控制。首先调用函数SetTimer()设置定时间隔,如SetTimer(0,200,NULL)即为设置200ms的时间间隔。然后在应用程序中增加定时响应函数OnTimer(),并在该函数中添加响应的处理语句,用来完成到达定时时间的操作。这种定时方法非常简单,可以实现一定的定时功能,但其定时功能如同Sleep()函数的延时功能一样,精度非常低,最小计时精度仅为30ms,CPU占用低,且定时器消息在多任务操作系统中的优先级很低,不能得到及时响应,往往不能满足实时控制环境下的应用。只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况。如示例工程中的Timer1。
  方式二:VC中使用sleep()函数实现延时,它的单位是ms,如延时2秒,用sleep(2000)。精度非常低,最小计时精度仅为30ms,用sleep函数的不利处在于延时期间不能处理其他的消息,如果时间太长,就好象死机一样,CPU占用率非常高,只能用于要求不高的延时程序中。如示例工程中的Timer2。
  方式三:利用COleDateTime类和COleDateTimeSpan类结合WINDOWS的消息处理过程来实现秒级延时。如示例工程中的Timer3和Timer3_1。以下是实现2秒的延时代码:
   COleDateTime   start_time=COleDateTime::GetCurrentTime();
   COleDateTimeSpan end_time=COleDateTime::GetCurrentTime()-start_time;
   while(end_time.GetTotalSeconds()<2)//实现延时2秒
  {
       MSG msg;
       GetMessage(&msg,NULL,0,0);
       TranslateMessage(&msg);
       DispatchMessage(&msg);
       
      //以上四行是实现在延时或定时期间能处理其他的消息,
      //虽然这样可以降低CPU的占有率,
      //但降低了延时或定时精度,实际应用中可以去掉。
      end_time=COleDateTime::GetCurrentTime()-start_time;
   }//这样在延时的时候我们也能够处理其他的消息。   
  方式四:在精度要求较高的情况下,VC中可以利用GetTickCount()函数,该函数的返回值是 DWORD型,表示以ms为单位的计算机启动后经历的时间间隔。精度比WM_TIMER消息映射高,在较短的定时中其计时误差为15ms,在较长的定时中其计时误差较低,如果定时时间太长,就好象死机一样,CPU占用率非常高,只能用于要求不高的延时程序中。如示例工程中的Timer4和Timer4_1。下列代码可以实现50ms的精确定时:
   DWORDdwStart=GetTickCount();
   DWORDdwEnd =dwStart;
   do
   {
     dwEnd=GetTickCount()-dwStart;
   }while(dwEnd<50);
为使GetTickCount()函数在延时或定时期间能处理其他的消息,可以把代码改为:
   DWORDdwStart=GetTickCount();
   DWORDdwEnd =dwStart;
   do
   {
       MSG msg;
       GetMessage(&msg,NULL,0,0);
       TranslateMessage(&msg);
       DispatchMessage(&msg);
       dwEnd=GetTickCount()-dwStart;
   }while(dwEnd<50);
虽然这样可以降低CPU的占有率,并在延时或定时期间也能处理其他的消息,但降低了延时或定时精度。
  方式五:与GetTickCount()函数类似的多媒体定时器函数DWORDtimeGetTime(void),该函数定时精度为ms级,返回从Windows启动开始经过的毫秒数。微软公司在其多媒体Windows中提供了精确定时器的底层API持,利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一个事件、函数或过程的调用。不同之处在于调用DWORDtimeGetTime(void)函数之前必须将Winmm.lib 和Mmsystem.h添加到工程中,否则在编译时提示DWORDtimeGetTime(void)函数未定义。由于使用该函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。如示例工程中的Timer5和Timer5_1。
  方式六:使用多媒体定时器timeSetEvent()函数,该函数定时精度为ms级。利用该函数可以实现周期性的函数调用。如示例工程中的Timer6和Timer6_1。函数的原型如下:
   MMRESULTtimeSetEvent(UINTuDelay,
               UINTuResolution,
               LPTIMECALLBACKlpTimeProc,
               WORDdwUser,
               UINTfuEvent)
  该函数设置一个定时回调事件,此事件可以是一个一次性事件或周期性事件。事件一旦被激活,便调用指定的回调函数,成功后返回事件的标识符代码,否则返回NULL。函数的参数说明如下:
   uDelay:以毫秒指定事件的周期。
   Uresolution:以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms。
   LpTimeProc:指向一个回调函数。
   DwUser:存放用户提供的回调数据。
   FuEvent:指定定时器事件类型:
   TIME_ONESHOT:uDelay毫秒后只产生一次事件
   TIME_PERIODIC:每隔uDelay毫秒周期性地产生事件。   
  具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在LpTimeProc回调函数中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是,任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后,应及时调用timeKillEvent()将之释放。
  方式七:对于精确度要求更高的定时操作,则应该使用QueryPerformanceFrequency()和QueryPerformanceCounter()函数。这两个函数是VC提供的仅供Windows95及其后续版本使用的精确时间函数,并要求计算机从硬件上支持精确定时器。如示例工程中的Timer7、Timer7_1、Timer7_2、Timer7_3。
QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下:
   BOOL QueryPerformanceFrequency(LARGE_INTEGER*lpFrequency);
   BOOL QueryPerformanceCounter(LARGE_INTEGER*lpCount);
  数据类型ARGE_INTEGER既可以是一个8字节长的整型数,也可以是两个4字节长的整型数的联合结构,其具体用法根据编译器是否支持64位而定。该类型的定义如下:
   typedefunion_LARGE_INTEGER
   {
     struct
     {
       DWORDLowPart;//4字节整型数
       LONG HighPart;//4字节整型数
     };
     LONGLONGQuadPart;//8字节整型数
     
    }LARGE_INTEGER;
  在进行定时之前,先调用QueryPerformanceFrequency()函数获得机器内部定时器的时钟频率,然后在需要严格定时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数,利用两次获得的计数之差及时钟频率,计算出事件经历的精确时间。下列代码实现1ms的精确定时:
   LARGE_INTEGERlitmp;
   LONGLONGQPart1,QPart2;
   doubledfMinus,dfFreq,dfTim;
   QueryPerformanceFrequency(&litmp);
   dfFreq=(double)litmp.QuadPart;//获得计数器的时钟频率
   QueryPerformanceCounter(&litmp);
   QPart1=litmp.QuadPart;//获得初始值
   do
   {
     QueryPerformanceCounter(&litmp);
     QPart2=litmp.QuadPart;//获得中止值
     dfMinus=(double)(QPart2-QPart1);
     dfTim=dfMinus/dfFreq;//获得对应的时间值,单位为秒
   }while(dfTim<0.001);
  其定时误差不超过1微秒,精度与CPU等机器配置有关。下面的程序用来测试函数Sleep(100)的精确持续时间:
   LARGE_INTEGERlitmp;
   LONGLONGQPart1,QPart2;
   doubledfMinus,dfFreq,dfTim;
   QueryPerformanceFrequency(&litmp);
   dfFreq=(double)litmp.QuadPart;//获得计数器的时钟频率
   QueryPerformanceCounter(&litmp);
   QPart1=litmp.QuadPart;//获得初始值
   Sleep(100);
   QueryPerformanceCounter(&litmp);
   QPart2=litmp.QuadPart;//获得中止值
   dfMinus=(double)(QPart2-QPart1);
   dfTim=dfMinus/dfFreq;//获得对应的时间值,单位为秒  
  由于Sleep()函数自身的误差,上述程序每次执行的结果都会有微小误差。下列代码实现1微秒的精确定时:
   LARGE_INTEGERlitmp;
   LONGLONGQPart1,QPart2;
   doubledfMinus,dfFreq,dfTim;
   QueryPerformanceFrequency(&litmp);
   dfFreq=(double)litmp.QuadPart;//获得计数器的时钟频率
   QueryPerformanceCounter(&litmp);
   QPart1=litmp.QuadPart;//获得初始值
   do
   {
     QueryPerformanceCounter(&litmp);
     QPart2=litmp.QuadPart;//获得中止值
     dfMinus=(double)(QPart2-QPart1);
     dfTim=dfMinus/dfFreq;//获得对应的时间值,单位为秒
   }while(dfTim<0.000001);
其定时误差一般不超过0.5微秒,精度与CPU等机器配置有关。

16.为对话框中的控件增加提示的简单方法

我学VC从VC知识库中得到不少好处,相来都是一些热心朋友们的帮助,在此表示感谢!本工程可分五步:
1、建一个基于对话框的程序TipTest,在CTipTestDlg中增加成员变量:CToolTipCtrlm_tip[2],CWnd*m_pSub[2];
2、在CTipTestDlg::OnInitDialog()函数中增加如下代码:
    pSub[0]=GetDlgItem(IDC_RADIO1);  //得到单选按钮的指针
    pSub[1]=GetDlgItem(IDC_BUTTON1);

"m_tip[0].Create(pSub[0],TTS_ALWAYSTIP); //创建CToolTipCtrl
"m_tip[0].AddTool(pSub[0]);       //将CToolTipCtrl与相应的控件对应起来

"m_tip[1].Create(pSub[1],TTS_ALWAYSTIP);
"m_tip[1].AddTool(pSub[1]);

"m_tip[0].SetTipTextColor(RGB(0,0,255)); //设定文字的颜色
    m_tip[0].SetDelayTime(150);       //设定提示文字在控件上停留的时间

3、重载CTipTestDlg::PreTranslateMessage(MSG*pMsg)函数,增加如下代码:
   if(m_tip[0].m_hWnd!=NULL)
    m_tip[0].RelayEvent(pMsg);  //如果m_tip[0]句柄不为空,就从主窗口中捕获消息,如WM_MOUSEMOVE,WM_LBUTTONDOWN等消息
   if(m_tip[1].m_hWnd!=NULL)
    m_tip[1].RelayEvent(pMsg); 
4、捕获主窗口的WM_MOUSEMOVE消息,在CTipTestDlg::OnMouseMove(UINTnFlags,CPointpoint)函数中增加如下代码:
    m_tip[0].UpdateTipText("VC知识库欢迎你!",pSub[0]);    //鼠标在相应的控件上移动时显示提示文字
"m_tip[1].UpdateTipText("http://vckbase.com",pSub[1]);

17.删除文件夹

//删除文件夹及其所有内容
voidCBaseDoc::RemoveFolder(constCString&strPathName)
{
  CStringpath=strPathName;
  if(path.Right(1)!=_T("\\"))
    path+=_T("\\");
  path+=_T("*.*");

  CFileFindff;
  BOOLres=ff.FindFile(path);
  while(res)
  {
    res=ff.FindNextFile();
    //是文件时直接删除
    if(!ff.IsDots()&&!ff.IsDirectory())
      DeleteFile(ff.GetFilePath());
    elseif(ff.IsDots())
      continue;
    elseif(ff.IsDirectory())
    {
      path=ff.GetFilePath();
      //是目录时继续递归,删除该目录下的文件
      RemoveFolder(path);
      ::RemoveDirectory(path);
    }
  }
}

18.消息映射

有对话框A,B
从A中发消息给B然后B处理。
准备工作,先定义消息,如下
#defineWM_B_NOTIFYWM_USER+300

首先,必须将B的对话框句柄传送给A,暂时叫m_hWndB;

在A的发送消息的地方这样写:
::SendMessage(m_hWndB,WM_B_NOTIFY,TRUE,NULL);

这样A中的处理就完了,下面说B中的
首先定义消息处理函数,如下
voidB::ModiNotify(WPARAMwParam,LPARAMlParam)
{
  MessageBox("小样,我就不信,搞不定你!");
}

然后加消息隐射,如下:
BEGIN_MESSAGE_MAP(CB,CDialog)
  //{{AFX_MSG_MAP(CRPServerDlg)

  ON_MESSAGE(WM_B_NOTIFY,ModiNotify)

  //}}AFX_MSG_MAP
END_MESSAGE_MAP()

19.给从CWnd派生的窗口添加滚动条
ModifyStyle(0,WS_VSCROLL);

20.SetWindowPos
函数功能:该函数改变一个子窗口,弹出式窗口式顶层窗口的尺寸,位置和Z序。子窗口,弹出式窗口,及顶层窗口根据它们在屏幕上出现的顺序排序、顶层窗口设置的级别最高,并且被设置为Z序的第一个窗口。 
  
     函数原型:BOOL SetWindowPos(HWN hWnd,HWND hWndlnsertAfter,int X,int Y,int cx,int cy,UNIT.Flags); 
  
     参数: 
  
     hWnd:窗口句柄。 
  
     hWndlnsertAfter:在z序中的位于被置位的窗口前的窗口句柄。该参数必须为一个窗口句柄,或下列值之一: 
  
     HWND_BOTTOM:将窗口置于Z序的底部。如果参数hWnd标识了一个顶层窗口,则窗口失去顶级位置,并且被置在其他窗口的底部。 
  
     HWND_DOTTOPMOST:将窗口置于所有非顶层窗口之上(即在所有顶层窗口之后)。如果窗口己经是非顶层窗口则该标志不起作用。 
  
     HWND_TOP:将窗口置于Z序的顶部。 
  
     HWND_TOPMOST:将窗口置于所有非顶层窗口之上。即使窗口未被激活窗口也将保持顶级位置。 
  
     查g看该参数的使用方法,请看说明部分。 
  
     x:以客户坐标指定窗口新位置的左边界。 
  
     Y:以客户坐标指定窗口新位置的顶边界。 
  
     cx:以像素指定窗口的新的宽度。 
  
     cy:以像素指定窗口的新的高度。 
  
     uFlags:窗口尺寸和定位的标志。该参数可以是下列值的组合: 
  
     SWP_ASNCWINDOWPOS:如果调用进程不拥有窗口,系统会向拥有窗口的线程发出需求。这就防止调用线程在其他线程处理需求的时候发生死锁。 
  
     SWP_DEFERERASE:防止产生WM_SYNCPAINT消息。 
  
     SWP_DRAWFRAME:在窗口周围画一个边框(定义在窗口类描述中)。 
  
     SWP_FRAMECHANGED:给窗口发送WM_NCCALCSIZE消息,即使窗口尺寸没有改变也会发送该消息。如果未指定这个标志,只有在改变了窗口尺寸时才发送WM_NCCALCSIZE。 
  
     SWP_HIDEWINDOW;隐藏窗口。 
  
     SWP_NOACTIVATE:不激活窗口。如果未设置标志,则窗口被激活,并被设置到其他最高级窗口或非最高级组的顶部(根据参数hWndlnsertAfter设置)。 
  
     SWP_NOCOPYBITS:清除客户区的所有内容。如果未设置该标志,客户区的有效内容被保存并且在窗口尺寸更新和重定位后拷贝回客户区。 
  
     SWP_NOMOVE:维持当前位置(忽略X和Y参数)。 
  
  SWP_NOOWNERZORDER:不改变z序中的所有者窗口的位置。 
  
  SWP_NOREDRAW:不重画改变的内容。如果设置了这个标志,则不发生任何重画动作。适用于客户区和非客户区(包括标题栏和滚动条)和任何由于窗回移动而露出的父窗口的所有部分。如果设置了这个标志,应用程序必须明确地使窗口无效并区重画窗口的任何部分和父窗口需要重画的部分。 
  
  SWP_NOREPOSITION;与SWP_NOOWNERZORDER标志相同。 
  
  SWP_NOSENDCHANGING:防止窗口接收WM_WINDOWPOSCHANGING消息。 
  
  SWP_NOSIZE:维持当前尺寸(忽略cx和Cy参数)。 
  
  SWP_NOZORDER:维持当前Z序(忽略hWndlnsertAfter参数)。 
  
  SWP_SHOWWINDOW:显示窗口。 
  
  返回值:如果函数成功,返回值为非零;如果函数失败,返回值为零。若想获得更多错误消息,请调用GetLastError函数。 
  
  备注:如果设置了SWP_SHOWWINDOW和SWP_HIDEWINDOW标志,则窗口不能被移动和改变大小。如果使用SetWindowLoog改变了窗口的某些数据,则必须调用函数SetWindowPos来作真正的改变。使用下列的组合标志:SWP_NOMOVEISWP_NOSIZEISWP_FRAMECHANGED。 
  
 有两种方法将窗口设为最顶层窗口:一种是将参数hWndlnsertAfter设置为HWND_TOPMOST并确保没有设置SWP_NOZORDER标志;另一种是设置窗口在Z序中的位置以使其在其他存在的窗口之上。当一个窗口被置为最顶层窗口时,属于它的所有窗口均为最顶层窗口,而它的所有者的z序并不改变。 
  
  如果HWND_TOPMOST和HWND_NOTOPMOST标志均未指定,即应用程序要求窗口在激活的同时改变其在Z序中的位置时,在参数hWndinsertAfter中指定的值只有在下列条件中才使用: 
  
  在hWndlnsertAfter参数中没有设定HWND_NOTOPMOST和HWND_TOPMOST标志。 
  
  由hWnd参数标识的窗口不是激活窗口。 
  
  如果未将一个非激活窗口设定到z序的顶端,应用程序不能激活该窗口。应用程序可以无任何限制地改变被激活窗口在Z序中的位置,或激活一个窗口并将其移到最高级窗口的顶部或非最高级窗口的顶部。 
  
  如果一个顶层窗口被重定位到z序的底部(HWND_BOTTOM)或在任何非最高序的窗口之后,该窗口就不再是最顶层窗口。当一个最顶层窗口被置为非最顶级,则它的所有者窗口和所属者窗口均为非最顶层窗口。 
  
  一个非最顶端窗口可以拥有一个最顶端窗口,但反之则不可以。任何属于顶层窗口的窗口(例如一个对话框)本身就被置为顶层窗口,以确保所有被属窗口都在它们的所有者之上。 
  
  如果应用程序不在前台,但应该位于前台,就应调用SetForegroundWindow函数来设置。 
  
  Windows CE:如果这是一个可见的顶层窗口,并且未指定SWP_NOACTIVATE标志,则这个函数将激活窗口、如果这是当前的激活窗口,并且指定了SWP_NOACTIVATE或SWP_HIDEWINDOW标志,则激活另外一个可见的顶层窗口。 
  
  当在这个函数中的nFlags参数里指定了SWP_FRAMECHANGED标志时,WindowsCE重画窗口的整个非客户区,这可能会改变客户区的大小。这也是重新计算客户区的唯一途径,也是通过调用SetwindowLong函数改变窗口风格后通常使用的方法。 
  
  SetWindowPos将使WM_WINDOWPOSCHANGED消息向窗口发送,在这个消息中传递的标志与传递给函数的相同。这个函数不传递其他消息。 
  
  Windows CE 1.0不支持在hWndlnsertAber参数中的HWND_TOPMOST和HWND_NOTOPMOST常量。 
  
  Windows CE1.0不支持在fuFags参数中的SWP_DRAWFRAME和SWP_NOCOPYBITS标志。 
  
  速查:Windows NT:3.1以上版本;Windows:95以上版本;Windows CE:1.0以上版本;头文件:winuser.h库文件:eser32lib

21.介绍函数过程中一种任意键退出同时能处理消息的实现方法

1.设置定时器,用于使::GetMessage(...)函数总能快速取到消息.
2.在函数处理中加入:

函数每执行完一步后执行下面的代码.
if(::GetMessage(&msg,0,0,0))
{
  if(msg.message>=WM_KEYFIRST&&msg.message<=WM_KEYLAST)return;
  ::TranslateMessage(&msg);
  ::DispatchMessage(&msg);
}
else::PostQuitMessage(0);

22.如何隐藏工具栏

添加如下两个函数
隐藏:
voidCMainFrame::OnHide()
{
  if(m_wndToolBar.IsWindowVisible())
    m_wndToolBar.ModifyStyle(WS_VISIBLE,0);
  SendMessage(WM_SIZE);
}

显示:
voidCMainFrame::OnShow()
{
  if(!m_wndToolBar.IsWindowVisible())
    m_wndToolBar.ModifyStyle(0,WS_VISIBLE);
  SendMessage(WM_SIZE);
}

23.如何动态获取工具条指针并给工具条加标题?

[问题提出]
工具条也是窗口,是窗口就有标题,如何给工具条加标题?
[程序实现]
不想动态改变工具条的标题就在CMainFrame::OnCreate()中:
intCMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct)
{
......
m_wndToolBar.SetWindowText(_T("Standdard"));
return0;
}
若想动态改变工具条的标题,如下:
声明一个菜单,并响应事件,如响应:OnMyToolBar()函数
voidCMainFrame::OnMyToolBar()
{
//TODO:Addyourcommandhandlercodehere
CToolBar*pToolBar=(CToolBar*)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_TOOLBAR);
pToolBar->SetWindowText(_T("Standdard"));
}
不要在TooBar悬浮时做OnMyToolBar()会出错的.
顺便提一下如何获得状态条的指针:
CStatusBar*pStatusBar=(CStatusBar*)AfxGetMainWnd()->GetDescendantWindow(AFX_IDW_STATUS_BAR);

24.在状态条中显示鼠标的设备坐标与逻辑坐标

显示器的设备坐标系的原点在客户区的左上角,x轴向右增长,y轴向下增长。我们要设置的逻辑坐标系的原点则在客户区的中心,x轴向右增长,y轴向上增长,如一个笛卡尔坐标系一般。

为CChildView添加一个成员函数voidOnPrepareDC(CDC*pDC,CPrintInfo*pInfo=NULL);

voidOnPrepareDC(CDC*pDC,CPrintInfo*pInfo){
 CRectrect;

 //设置映射模式为LOMETRIC(0.1mm),右上为增长方向
 pDC->SetMapMode(MM_LOMETRIC);

 //将坐标原点定在客户区的中心
 GetClientRect(rect);
 pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);
}
为CChildView响应鼠标移动消息,并在状态条中显示鼠标的坐标值。m_ptMouse数据成员是原打算做十字交叉线用的,在此使用没有实际意义。

voidCChildView::OnMouseMove(UINTnFlags,CPointpoint){
 CClientDCdc(this);
 CStringstr;
 
 OnPrepareDC(&dc);

 //要访问类CMainFrame,需要将mainfrm.h文件引入
 CMainFrame*pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;

 //要访问CMainFrame的数据成员m_wndStatusBar,需要手工修改mainfrm.h,public这个数据成员
 CStatusBar*pStatus=(CStatusBar*)&pFrame->m_wndStatusBar;
 
 m_ptMouse=point;
 str.Format("设备坐标X=%ipixel,Y=%ipixel",m_ptMouse.x,m_ptMouse.y);
 pStatus->SetPaneText(1,str);
 
 dc.DPtoLP(&m_ptMouse);
 str.Format("逻辑坐标X=%i*0.1mm,Y=%i*0.1mm",m_ptMouse.x,m_ptMouse.y);
 pStatus->SetPaneText(2,str);
}

25.如何用VC++动态修改应用程序菜单

 [问题提出]
  本文将介绍一些使用CMenu的方法,如查找指定菜单,在指定选项前添加菜单项.....

 [解决方法]
  使用CWnd::GetMenu()访问主菜单,GetMenu()返回指向CMenu对象的指针,它有一些成员函数,允许我们修改一个菜单。
  1)如何实现找到一个菜单项:
  步骤如下:
  {
    //动态修改菜单:
    //GettheMainMenu
    CMenu*pMainMenu=AfxGetMainWnd()->GetMenu();
    CMenu*pSubMenu=NULL;
    inti;
    for(i=0;i<(int)pMainMenu->GetMenuItemCount();i++)
    {
      pSubMenu=pMainMenu->GetSubMenu(i);
      if(pSubMenu&&pSubMenu->GetMenuItemID(0)==ID_FILE_NEW)
       break;
    }
    CStrings;
    s.Format("%d",i);//菜单项的位数.
    AfxMessageBox(s);
    ASSERT(pSubMenu);
  }

  2)动态编辑菜单:
  步骤如下(可以用上例的pSubMenu,要加的菜单你自己定义.):
  1)添加一个称为Wzd2,命令ID为IDC_NAME_NEW1的菜单命令到该菜单中,可以用:
    pSubMenu->AppendMenu(0,IDC_NAME_NEW1,"New&1");

  2)在New1前插入New2,可以用:
    pSubMenu->InsertMenu(IDC_NAME_NEW1,MF_BYCOMMAND,IDC_NAME_NEW2,"New&2");

  3)把New1改变成New3,可以用:
    pSubMenu->ModifyMenu(IDC_NAME_NEW1,MF_BYCOMMAND,IDC_NAME_NEW3,"New&3");

  4)删除该菜单中第二项,可以用:
    pSubMenu->RemoveMenu(1,MF_BYPOSITION);

26.VC++中的3D按钮的编程

运行AppWizard生成一个基于对话框的test工程,在对话框中加入一个CButton控件。在CButton控件的General属性页将控件的ID改为IDC_3DTEXTBTN,Caption改为“谁与争疯”,在控件Styles属性页选中OwnerDraw,其余设置保持默认。
  用classwizard创建一个新类:C3dTextButton,基类为CButton。为C3dTextButton类添加一个protected的函数voidDraw(CDC*pDC,constCRect&rect,UINTstate)。如下所示编写代码:
  voidC3dTextButton::Draw(CDC*pDC,constCRect&rect,UINTstate)
  {
   CStringtext;GetWindowText(text);
   intl=text.GetLength();
   CRectrectClient=rect;
 
   //获得控件的字体
   CFont*pFont=GetFont();
 
   //确定所选字体有效高度和宽度
   LOGFONTlogfont;
   pFont->GetObject(sizeof(LOGFONT),&logfont);
   if(logfont.lfHeight==0)logfont.lfHeight=20;
   logfont.lfWidth=0;//宽度设为0,宽度值由高度确定
   logfont.lfWeight=1000;
   logfont.lfEscapement=logfont.lfOrientation=0;
   CFonttryfont;VERIFY(tryfont.CreateFontIndirect(&logfont));
   CFont*pFontOld=pDC->SelectObject(&tryfont);
 
   //根据控件大小,调整字体的高度,使文本与控件协调
   CSizetextSizeClient=pDC->GetTextExtent(text,l);
   if(rectClient.Width()*textSizeClient.cy>rectClient.Height()*textSizeClient.cx)
   {
    logfont.lfHeight=::MulDiv(logfont.lfHeight,rectClient.Height(),textSizeClient.cy);
   }
   else{
    logfont.lfHeight=::MulDiv(logfont.lfHeight,rectClient.Width(),textSizeClient.cx);
   }
 
   //创建并选择协调后的字体
   CFontfont;font.CreateFontIndirect(&logfont);
   pDC->SelectObject(&font);
   textSizeClient=pDC->GetTextExtent(text,l);
   //确定文本与控件边界的距离minx,miny
   intminx=rectClient.left+(rectClient.Width()-textSizeClient.cx)/2;
   intminy=rectClient.top+(rectClient.Height()-textSizeClient.cy)/2;
   intoldBkMode=pDC->SetBkMode(TRANSPARENT);
   COLORREFtextcol=::GetSysColor(COLOR_BTNTEXT);
   COLORREFoldTextColor=pDC->SetTextColor(textcol);
   intcx=minx;
   intcy=miny;
   ints=(state&ODS_SELECTED)?-1:+1;
   cx+=3;cy+=3;
 
   //实现3D效果
   pDC->SetTextColor(::GetSysColor(COLOR_3DDKSHADOW));
   pDC->TextOut(cx-s*2,cy+s*2,text);
   pDC->TextOut(cx+s*2,cy-s*2,text);
   pDC->TextOut(cx+s*2,cy+s*2,text);
   pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT));
   pDC->TextOut(cx+s*1,cy-s*2,text);
   pDC->TextOut(cx-s*2,cy+s*1,text);
   pDC->TextOut(cx-s*2,cy-s*2,text);
   pDC->SetTextColor(::GetSysColor(COLOR_3DSHADOW));
   pDC->TextOut(cx-s*1,cy+s*1,text);
   pDC->TextOut(cx+s*1,cy-s*1,text);
   pDC->TextOut(cx+s*1,cy+s*1,text);
   pDC->SetTextColor(::GetSysColor(COLOR_3DLIGHT));
   pDC->TextOut(cx,cy-s*1,text);
   pDC->TextOut(cx-s*1,cy,text);
   pDC->TextOut(cx-s*1,cy-s*1,text);
   pDC->SetTextColor(textcol);
 
   //输出标题
   pDC->TextOut(cx,cy,text);
 
   //恢复设备描述表
   pDC->SetTextColor(oldTextColor);
   pDC->SetBkMode(oldBkMode);
   pDC->SelectObject(pFontOld);
  }

  用classwizard重载C3dTextButton类的DrawItem函数。编写代码如下所示:
  voidC3dTextButton::DrawItem(LPDRAWITEMSTRUCTlpDrawItemStruct)
  {
   CDC*pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
   ASSERT_VALID(pDC);
   CRectrectClient=lpDrawItemStruct->rcItem;
   Draw(pDC,rectClient,lpDrawItemStruct->itemState);
  }
  用classwizard为IDC_3DTEXTBTN建立一个C3dTextButton控件变量m_3dTextButton1。

把“3dTextButton.h”加入testDlg头文件。编译并测试应用程序。

27.如何正确的得到ComBox的指针

CComboBox*mComb=(CComboBox*)GetDlgItem(IDC_DuanCB);
CComboBox*mComb=(CComboBox*)::GetDlgItem(m_hWnd,IDC_DuanCB);

28.如何让对话框中的CEdit控件类接收对话框的消息


//如何让对话框中的CEdit控件类接收对话框的消息

1、在对话框中增加一个ID为IDC_EDIT1的CEdit1控件

2、通过ClassWizard生成一个基于CEdit的新类CMyEdit,

CMyEdit m_wndEdit;

3、在对话框OnInitDialog()中,将m_wndEdit子类化,使其能够接受对话框的消息。

m_wndEdit.SubclassDlgItem(IDC_EDIT1,this);

29.利用WM_CTLCOLOR消息实现编辑控制(EditControl)的文本与背景色的改变

首先要明白:WM_CTLCOLOR是一个由控制(Control)发送给它父窗口的通知消息(Notificationmessage)。

实现步骤:
生成一个标准的单文档应用程序框架,假设应用程序的名称为Color。我将利用它的About对话框做示范。在Aboutdialog中添加两个Editcontrol,设定其ID为IDC_EDIT1与IDC_EDIT2。

第一种方法(对应于IDC_EDIT1):按照标准的Windows编程,由其父窗口的消息处理函数负责处理WM_CTLCOLOR消息。

1.在CAboutDlg中添加一个数据成员:HBRUSHm_brMine;
2.利用向导映射AboutDlg的WM_CTLCOLOR消息,产生函数:HBRUSHCAboutDlg::OnCtlColor(CDC*pDC,CWnd*pWnd,UINTnCtlColor);
pDC是AboutDlg的设备上下文,pWnd是AboutDlg中发送该消息的control指针,nCtlColor市Control的类型编码。对其进行如下修改:

HBRUSHCAboutDlg::OnCtlColor(CDC*pDC,CWnd*pWnd,UINTnCtlColor)
{
 if((pWnd->GetDlgCtrlID()==IDC_EDIT1)&&(nCtlColor==CTLCOLOR_EDIT))
 {
   COLORREFclr=RGB(255,0,0);
   pDC->SetTextColor(clr); //设置红色的文本
   clr=RGB(0,0,0);
   pDC->SetBkColor(clr);  //设置黑色的背景
   m_brMine=::CreateSolidBrush(clr);
   returnm_brMine; //作为约定,返回背景色对应的刷子句柄
 }
 else
 {
   HBRUSHhbr=CDialog::OnCtlColor(pDC,pWnd,nCtlColor);
   returnhbr;
 }
}

第二种方法(对应于IDC_EDIT2):
利用MFC4.0的新特性:Messagereflection。

1.利用向导添加一个新的类:CColorEdit,基类为CEdit;
2.在CColorEdit中添加一个数据成员:HBRUSHm_bkBrush;
3.利用向导映射CColorEdit的"=WM_CTLCOLOR"消息,产生函数:

HBRUSHCColorEdit::CtlColor(CDC*pDC,UINTnCtlColor);

对其进行如下修改:

HBRUSHCColorEdit::CtlColor(CDC*pDC,UINTnCtlColor)
{
 COLORREFclr=RGB(0,0,0);
 pDC->SetTextColor(clr); //设置黑色的文本
 clr=RGB(255,0,0);
 pDC->SetBkColor(clr);  //设置红色的背景
 m_bkBrush=::CreateSolidBrush(clr);
 returnm_bkBrush; //作为约定,返回背景色对应的刷子句柄
}

4.利用向导为IDC_EDIT2生成一个数据成员CColorEditm_coloredit;
5.在定义CAboutDlg的color.cpp文件中加入:#include"coloredit.h"

30.如何防止密码被非法获取?

 [问题提出]
  这两天大家比较专注在获取Edit密码框的密码.在盗取时,我们如何防范呢?
 
 [解决方法]
  此方法针对于通过SendMessage向此窗口发送WM_GETTEXT或EM_GETLINE消息来取得密码.跟我来.
 
 [程序实现]
  方法很简单,用CWnd::DefWindowProc函数拦截得到的消息(向Edit发的).
  建立名为My的对话框工程.建立一个Edit控件ID=IDC_EDIT1.建一个新类名为CMyProtectEdit,派生于CEdit.
  在MyDlg.cpp中声明全局变量:BOOLg_bIdentity;
  BOOLg_bIdentity;

  在MyProtecEdit.cpp中:
  externBOOLg_bIdentity;

  响应CMyProtectEdit的DefWindowProc函数:
  LRESULTCMyProtectEdit::DefWindowProc(UINTmessage,WPARAMwParam,LPARAMlParam)
  {
   //TODO:Addyourspecializedcodehereand/orcallthebaseclass
   //对Edit的内容获取必须通过以下两个消息之一,不对其采用默认的处理:
   if((message==WM_GETTEXT)||(message==EM_GETLINE))
   { //检查是否为合法
     if(!g_bIdentity)
     { //非法获取,显示非法信息
      AfxMessageBox(_T("不能让你看我的密码,:(!"));
      return0;
     )
     g_bIdentity=FALSE;//合法获取
   }
    
   returnCEdit::DefWindowProc(message,wParam,lParam);
  }

  然后在MyDlg.cpp中
  voidCMyDlg::DoDataExchange(CDataExchange*pDX)
  {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CGetPasswordDlg)
    //NOTE:theClassWizardwilladdDDXandDDVcallshere
   if(pDX->m_bSaveAndValidate)
   {
     g_bIdentity=TRUE;
   }   
   //}}AFX_DATA_MAP
  }
  即可.找个程序(盗取)的试试.

31.如何在编辑控件中以追加的方式添入字符?

 [问题提出]
  SetDlgItemText可以向Edit控件中输入字符,发送更新的消息也可是Edit控件显示与其关联的变量的值,但若是向已有的Edit字符后追加字符,该如何做?
 [程序实现]
  建立名为My的对话框工程,添加一个Edit和一个Button控件.Edit的ID=IDC_EDIT1,Button的ID=IDC_BUTTON1.建立和IDC_BUTTON1的响应函数:OnButton1()
  voidCMyDlg::OnButton1()
  {
   CStringpText="你好";
   CEdit*m_Edit=(CEdit*)GetDlgItem(IDC_EDIT1);
   intnLen=m_Edit->GetWindowTextLength();
   m_Edit->SetFocus();
   m_Edit->SetSel(nLen,nLen);
   m_Edit->ReplaceSel(pText);
  }
  在Edit控件中输入字符,想追加时按IDC_BUTTON1按钮.看看效果.

32.属性页标题改名

我用CPropertySheet创建属性页,用的CPropertyPage对象只有一个,也就是每个属性页的内容一样.现在的问题是:这样每个属性页的标题都是一样的,是对话框的标题!怎样动态的改变这个标题,使每个属性页的标签的名称都不同??


CTabCtrl*pCtrl=pSheet->GetTabControl();
TCITEMtc;
tc.mask=TCIF_TEXT;
tc.pszText="新标题";
pCtrl->SetItem(0,&tc);//0即是你要改的TAb的索引

33.怎样去掉属性页的Apply与Help按钮?

//去掉Help
  m_psh.dwFlags|=PSH_HASHELP;
  m_psh.dwFlags&=~PSH_HASHELP;
//除掉应用按钮 m_psh.dwFlags|=PSH_NOAPPLYNOW;

34.如何给树控件加入工具提示

1.首先给树控件加入TVS_INFOTIP属性风格,如下所示:

if(!m_ctrlTree.Create(WS_CHILD|WS_VISIBLE|
 TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT|TVS_SHOWSELALWAYS|TVS_INFOTIP,//加入提示TVS_INFOTIP,jingzhouxu(树控件ID:100)
   CRect(0,0,0,0),&m_wndTreeBar,100))
 {
   TRACE0("Failedtocreateinstantbarchild\n");
   return-1;
 }

2.其次加入映射消息声明,如下所示:

afx_msgvoidOnGetInfoTip(NMHDR*pNMHDR,LRESULT*pResult);   //树控件上加入提示消息,jingzhouxu  

ON_NOTIFY(TVN_GETINFOTIP,100,OnGetInfoTip)       //树控件条目上加入提示,jingzhouxu

3.最后加入呼应涵数处理:

voidCCreateTreeDlg::OnGetInfoTip(NMHDR*pNMHDR,
                  LRESULT*pResult)
 {
 *pResult=0;
 NMTVGETINFOTIP*pTVTipInfo=(NMTVGETINFOTIP*)pNMHDR;
 LPARAMitemData=(DWORD)pTVTipInfo->lParam;
 //对应每个条目的数据
 HTREEITEMhItem=pTVTipInfo->hItem;
 CStringtip;
 HTREEITEMhRootItem=m_chassisTree.GetRootItem();
 if(hRootItem!=pTVTipInfo->hItem)
 {
  tip="树结点的提示";
 }
 else
 {
  tip="树根上的提示";
 }
 strcpy(pTVTipInfo->pszText,(LPCTSTR)tip);
}

35.如何在TreeList中加图标?

 [问题提出]
 请问treeview控件和treectrl控件的用法有何不同呢?向如何imagelist控件中加图象呀?
 [解决方法]
 1)
  HICONhicon[8];
  m_imageList.Create(16,16,0,8,8);
  hicon[0]=AfxGetApp()->LoadIcon(IDI_ICON0);
  hicon[1]=AfxGetApp()->LoadIcon(IDI_ICON1);
  hicon[2]=AfxGetApp()->LoadIcon(IDI_ICON2);
  hicon[3]=AfxGetApp()->LoadIcon(IDI_ICON3);
  hicon[4]=AfxGetApp()->LoadIcon(IDI_ICON4);
  hicon[5]=AfxGetApp()->LoadIcon(IDI_ICON5);
  hicon[6]=AfxGetApp()->LoadIcon(IDI_ICON6);
  hicon[7]=AfxGetApp()->LoadIcon(IDI_ICON7);
  for(intn=0;n<8;n++)
    m_imageList.Add(hicon[n]);

  CTreeCtrl*pTree=(CTreeCtrl*)GetDlgItem(IDC_TREE);
  pTree->SetImageList(&m_imageList,TVSIL_NORMAL);

 2)
  CImageListcil1;
  cil1.Create(32,32,TRUE,2,2);
  cil1.Add(pApp->LoadIcon(IDI_DAO1));
  cil1.Add(pApp->LoadIcon(IDI_DAO2));
  cil1.Add(pApp->LoadIcon(IDI_DAO3));
  cil1.Add(pApp->LoadIcon(IDI_DAO4));
  cil1.Add(pApp->LoadIcon(IDI_DAO5));
  cil1.Add(pApp->LoadIcon(IDI_DA

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值