MFC程序设计常用技巧汇总
本文实例总结了MFC程序设计常用技巧。分享给大家供大家参考。具体如下:
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),创建成功后在该类里创建要增加的控件的对象,如:
CComboBoxm_wndMyCombo; CStaticm_wndCategory,m_wndCategoryPath; CButtonm_wndOpenButton; Ceditm_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. (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的SDIProject(在第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); }