vc实用小技巧(感觉挺有用,搞过来方便看,)
一、 一次只运行一个程序实例下列两种方式都可以实现,
建议采用第二种方式:
1、 if( FindWindow(NULL,"程序标题"))
exit(0);
2、BOOL CDemoTBarEApp::InstanceIsRun()
{ HANDLE m_hMutex;
m_hMutex = ::CreateMutex(NULL, TRUE, _T("YourApplication"));
ASSERT(m_hMutex);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
m_hMutex = NULL;
return TRUE;//实例已经运行
} return FALSE;//实例未运行}
二、 装载光标SetCursor(AfxGetApp()->LoadStandardCursor(IDC_WAIT)); 其中::SetCursor()是全局函数,用来设置整个例程的光标参数是宏定义光标句柄。AfxGetApp ()是一个系统函数,它返回当前的一个CWinApp对象。其成员函数LoadStandardCursor()用来读取一个系统指针,每一种系统指针的具体宏定义如下:IDC_APPSTARTING 带小沙漏的标准箭头IDC_ARROW 标准箭头IDC_CROSS 十字光标(用于定位)IDC_HAND Windows 2000:手型IDC_HELP 带问号的箭头IDC_IBEAM I型标IDC_ICON Obsolete for applications marked version 4.0 or later. IDC_NO 禁止符号IDC_SIZE Obsolete for applications marked version 4.0 or later. Use IDC_SIZEALL. IDC_SIZEALL 十字箭头IDC_SIZENESW 指向东北和西南的双向箭头IDC_SIZENS 指向南和北的双向箭头IDC_SIZENWSE 指向西北和东南的双向箭头IDC_SIZEWE 指向东西的双向箭头IDC_UPARROW 上箭头IDC_WAIT 沙漏获得主框架: CM pMainframe = (CMainFrame *) AfxGetApp()->m_pMainWnd;.获取应用程序的实例句柄: Example: HANDLE hInstance=AfxGetInstanceHandle();获得应用程序主窗口的指针: Example: AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程序最大化
四、重新建立字体的代码 if(m_fontLogo.m_hObject) m_fontLogo.Detach(); m_fontLogo.CreateFont(nHeight, 0, 0, 0, nWeight, bItalic, bUnderline,0,0,0,0,0,0, Name);
五、用指定颜色填充区域 dc.FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
六、绘制立体字体效果的字体,很值得一看void CTestView::OnPaint() { CPaintDC dc(this); // device context for painting CRect rect; GetWindowRect(rect); CFont m_fontLogo; m_fontLogo.CreateFont(24, 0, 0, 0, FW_BOLD, true, FALSE,0,0,0,0,0,0, "Arial"); CString m_LogoText; m_LogoText=_T("Benlux Pro3D System"); dc.SetBkMode(TRANSPARENT); CFont * OldFont = dc.SelectObject(&m_fontLogo); // draw text in DC COLORREF OldColor = dc.SetTextColor( ::GetSysColor( COLOR_3DHILIGHT)); rect.right = rect.Width(); rect.bottom = rect.Height(); rect.left = rect.top = 0; dc.FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE)); dc.DrawText( m_LogoText, rect + CPoint(1,1), DT_SINGLELINE | DT_LEFT | DT_VCENTER); dc.SetTextColor( ::GetSysColor( COLOR_3DSHADOW)); dc.DrawText( m_LogoText, rect, DT_SINGLELINE | DT_LEFT | DT_VCENTER); // restore old text color dc.SetTextColor( OldColor); // restore old font dc.SelectObject(OldFont); // Do not call CView::OnPaint() for painting messages}
七、简单的消息检索和抽取函数,能够让系统响应其它操作BOOL PeekAndPump(){ static MSG msg; while (::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) { if (!AfxGetApp()->PumpMessage()) { ::PostQuitMessage(0); return FALSE; } } return TRUE;}
八、在你的程序中用动画光标替换默认的等待光标 (ANI光标的使用) HCURSOR m_hAniCursor=NULL; BeginWaitCursor(); //begin wait cursor for api function //load ani cursor from file in current path TCHAR cursorPath[MAX_PATH]; GetModuleFileName(NULL,cursorPath,MAX_PATH); char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath(cursorPath, drive, dir, fname, ext ); sprintf(cursorPath,"%s%s/wait.ani",drive,dir); //ani cursor file name is wait.ani m_hAniCursor= LoadCursorFromFile(cursorPath); HCURSOR oldCursor; if(m_hAniCursor != NULL) oldCursor=SetCursor(m_hAniCursor); for(long i=0;i<1000;i++) Sleep(5); oldCursor=NULL; m_hAniCursor=NULL; EndWaitCursor(); //end wait cursor for api function
九、如何限制编辑框中的准许字符 如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指定新的创建标志ES_NUMBERS,它是Windows 95新增加的标志,该标志限制 编辑控件只按收数字字符。如果用户需要复杂的编辑控件,可以使用Microsoft 的屏蔽编辑控件,它是一个很有用的OLE定制控件。 如果希望不使用OLE 定制控件自己处理字符,可以派生一个CEdit 类并处理WM_CHAR消息,然后从编辑控件中过滤出特定的字符。首先,使用ClassWizard 建立一个 CEdit的派生类,其次,在对话类中指定一个成员变量将编辑控件分类在OnInitdialog 中调用CWnd: : SubclassDlgItem .//In your dialog class declaration (.H file )private : CMyEdit m_wndEdit ; // Instance of your new edit control .//In you dialog class implementation (.CPP file )BOOL CSampleDialog : : OnInitDialog ( ){ //Subclass the edit lontrod . m_wndEdit .SubclassDlgItem (IDC_EDIT,this ); …} 使用ClassWizard处理WM_CHAR消息,计算nChar参量并决定所执行的操作,用户可以确定是否修改、传送字符。下例说明了如何显示字母字符,如果字符是字母字符,则调用CWnd ; OnChar,否则不调用OnChar.//Only display alphabetic dharacters .void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags ){ //Determine if nChar is an alphabetic character . if (: : IsCharAlpha ( ( TCHAR) nChar ) ) CEdit : : OnChar (nChar, nRepCnt , nFlags );} 如果要修改字符,则不能仅仅简单地用修改过的nChar调用CEdit : : OnChar。要修改一个字符,需要首先修改nChar,然后用修改过的nChar调用CWnd: : DefWindowProc。下例说明了如何将字符转变为大写://Make all characters uppercasevoid CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags ){ //Make sure character is uppercase . if (: : IsCharAlpha ( .( TCHAR) nChar) nChar=: : CharUpper (nChar ) ; //Bypass default OnChar processing and directly call default window proc. DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt , nFlags )) ;}
十、串太长时如何在其末尾显示一个省略号 调用CDC:: DrawText并指定DT_END_ELLIPSIS标志,这样就可以用小略号取代串末尾的字符使其适合于指定的边界矩形。如果要显示路径信息,指定DT_END_ELLIPSIS标志并省略号取代串中间的字符。void CSampleView:: OnDraw (CDC* pDC){ CTestDoc* pDoc=GetDocument (); ASSERT_VALID (pDoc); //Add ellpsis to end of string if it does not fit pDC->Drawtext (CString ("This is a long string"), CRect (10, 10, 80, 30), DT_LEFT | DT_END_ELLIPSIS); //Add ellpsis to middle of string if it does not fit pDC->DrawText (AfxgetApp () ->m_pszhelpfilePath, CRect (10, 40, 200, 60), DT_LEFT | DT_PATH_ELLIPSIS);}
十一、如何实现一个橡皮区矩形(具有踪迹矩形并可移动、缩放的矩形) CRectTracker是一个很有用的类,可以通过调用CRectTracker:: TrackRubberBand响应WM_LBUTTONDOWN消息来创建一个橡皮区矩形。下例表明使用CRectTracker移动和重置视窗中的蓝色椭圆的大小是很容易的事情。 首先,在文档类中声明一个CRectTracker数据成员:class CTestDoc: Public CDocument{…public: CRectTracker m_tracker;…}; 其次,在文档类的构造函数中初始化CRectTracker 对象:CTestDoc::CTestDoc(){ m_tracker.m_rect.SetRect (10, 10, 300, 300); m_tracker.m_nStyle=CRectTracker:: resizeInside | CRectTracker:: dottedLine; } 然后,在视图类的OnDraw函数中画椭圆和踪迹矩形:void CTestView::OnDraw(CDC* pDC){ CTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);//Select blue brush into device context. CBrush brush (RGB (0, 0, 255)); CBrush* pOldBrush=pDC->SelectObject (&brush); //draw ellipse in tracking rectangle. CRect rcEllipse; pDoc->m_tracker.GetTrueRect (rcEllipse); pDC->Ellipse (rcEllipse); //Draw tracking rectangle. pDoc->m_tracker.Draw (pDC); //Select blue brush out of device context. pDC->SelectObject(pOldBrush);} 最后,视图类中处理WM_LBUTTONDOWN消息,并增加下述代码。该段代码根据鼠标击键情况可以拖放、移动或者重置椭圆的大小。void CTestView::OnLButtonDown(UINT nFlags, CPoint point) { //Get pointer to document. CTestDoc* pDoc=GetDocument(); ASSERT_VALID (pDoc); //If clicked on ellipse, drag or resize it. Otherwise create a //rubber-band rectangle nd create a new ellipse. BOOL bResult=pDoc->m_tracker.HitTest (point)!= CRectTracker::hitNothing; //Tracker rectangle changed so update views. if (bResult) { pDoc->m_tracker.Track (this,point,TRUE); pDoc->SetModifiedFlag (); pDoc->UpdateAllViews (NULL); } else pDoc->m_tracker.TrackRubberBand (this,point,TRUE); CView::OnLButtonDown(nFlags, point);}
十二、如何在临时目录创建一个临时文件如果你要在临时目录下创建临时文件,下面的代码能帮到你的忙。bool GetuniqueTempName (CString& strTempName){ strTempName=""; //Get the temporary files directory. TCHAR szTempPath [MAX_PATH]; DWORD dwResult=:: GetTempPath (MAX_PATH, szTempPath); if (dwResult==0) return false; //Create a unique temporary file. TCHAR szTempFile[MAX_PATH]; UINT nResult=GetTempFileName (szTempPath, _T ("~ex"),0,szTempFile); if (dwResult==0) return false; strTempName=szTempFile; return true;}
十三、如何限制窗口的最小范围要限制窗体的大小,下面的代码能帮到你的忙。在CMainFrame中增加WM_GETMAXMININFO消息的处理函数,然后在这个函数中写代码如下://限制主窗体的最小高度和宽度void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { lpMMI->ptMinTrackSize.x=600; lpMMI->ptMinTrackSize.y=400; CNewFrameWnd::OnGetMinMaxInfo(lpMMI);}
十四、怎样删除文件到回收站中 要删除文件到回收站,很简单。只要用SHFileOperation函数就行了,下面的代码我将为你演示了这一个函数的用法。当然你可以直接拷贝到你的项目中。//删除文件到回收站中//pszPath : 待删除的全路径文件名//bDelete : TRUE 删除,不移到回收站,FALSE:移到回收站一、 //返回 : TRUE 删除成功 FALSE 删除失败BOOL CDelFileToRecycleDlg::Recycle(LPCTSTR pszPath, BOOL bDelete/*=FALSE*/){ SHFILEOPSTRUCT shDelFile; memset(&shDelFile,0,sizeof(SHFILEOPSTRUCT)); shDelFile.fFlags |= FOF_SILENT; // don't report progress shDelFile.fFlags |= FOF_NOERRORUI; // don't report errors shDelFile.fFlags |= FOF_NOCONFIRMATION; // don't confirm delete // Copy pathname to double-NULL-terminated string. // TCHAR buf[_MAX_PATH + 1]; // allow one more character _tcscpy(buf, pszPath); // copy caller's pathname buf[_tcslen(buf)+1]=0; // need two NULLs at end // Set SHFILEOPSTRUCT params for delete operation shDelFile.wFunc = FO_DELETE; // REQUIRED: delete operation shDelFile.pFrom = buf; // REQUIRED: which file(s) shDelFile.pTo = NULL; // MUST be NULL if (bDelete) { // if delete requested.. shDelFile.fFlags &= ~FOF_ALLOWUNDO; // ..don't use Recycle Bin } else { // otherwise.. shDelFile.fFlags |= FOF_ALLOWUNDO; // ..send to Recycle Bin } return SHFileOperation(&shDelFile); // do it!}
十五、内存泄漏检查 也许你已经知道,在C++和C语言中指针问题也就是内存申请与释放是一个令人头疼的事情,假如你申请了内存,但没有释放,并且你的程序需要长时间地运行,那么,系统的资源将逐渐减少,当系统的资源全部被用完时,系统将会崩溃。所以在开发程序的过程中一定要保证资源的完全释放。下面我们来介绍内存漏洞的检查。示例如下:// do your memory allocations and deallocations... CString s = "This is a frame variable";#ifdef _DEBUG CMemoryState oldMemState, newMemState, diffMemState; oldMemState.Checkpoint();#endif // the next object is a heap object CString* p = new CString( "Smith Alan 581_0215" ); delete p; p=NULL;#ifdef _DEBUG newMemState.Checkpoint(); BOOL b=diffMemState.Difference(oldMemState, newMemState); if (b) { AfxMessageBox( "Memory leaked!/n" ); }#endif
根据试验,由于我们无法释放掉象int CString char 申请的变量。只能释放指针型的变量。而检测内存时,照样会出现内存泄漏现象。所以,这种内存检测方式局限性还是很大。因为我们无法释放非指针型变量。
CString,string,char*的综合比较
(一) 概述string和CString均是字符串模板类,string为标准模板类(STL)定义的字符串类,已经纳入C++标准之中;CString(typedef CStringT<TCHAR, StrTraitMFC<TCHAR>> CString)为Visual C++中最常用的字符串类,继承自CSimpleStringT类,主要应用在MFC和ATL编程中,主要数据类型有char(应用于ANSI),wchar_t(unicode),TCHAR(ANSI与unicode均可);char*为C编程中最常用的字符串指针,一般以'{post.abstract}'为结束标志;
(二) 构造 string是方便的,可以从几乎所有的字符串构造而来,包括CString和char*; CString次之,可以从基本的一些字符串变量构造而来,包括char*等; char*没有构造函数,仅可以赋值; 举例:char* psz = "joise";CString cstr( psz );string str( cstr );
(三) 运算符重载a) operator= string是最方便的,几乎可以直接用所有的字符串赋值,包括CString和char*; CString次之,可以直接用些基本的字符串赋值,包括char*等; char*只能由指针赋值,并且是极危险的操作,建议使用strcpy或者memcpy,而且char*在声明的时候如未赋初值建议先设为NULL,以避免野指针,令你抓狂; 举例:char *psz = NULL;psz = new char[10]; //当然,以上的直接写成char *psz = new char[10];也是一样memset( psz, 0, 10 );strcpy( psz, "joise" ); CString cstr;cstr = psz;string str;str = psz;str = cstr;delete []psz;b) operator+string与CString差不多,可以直接与char*进行加法,但不可以相互使用+运算符,即string str = str + cstr是非法的,须转换成char*;char*没有+运算,只能使用strcat把两个指针连在一起; 举例:char* psz = "joise";CString cstr = psz;cstr = cstr + psz;string str = psz;str = str + str + psz;strcat( psz, psz );strcat( psz, cstr );//合法strcat( psz, str );//非法,由此可见,CString可自动转换为const char*,而string不行c) operator += string是最强大的,几乎可以与所有的字符串变量+=,包括CString和char*; CString次之,可以与基本的一些字符串变量进行+=而来,包括char*等;char*没有+=运算符,只能使用strcat把两个指针连在一起;d) operator[] CString最好,当越界时会抛出断言异常; string与char*下标越界结果未定义;举例:char* psz = "joise";CString cstr = psz;cout << cstr[8];string str = psz;cout << str[8];cout << psz[8];e) operator== 、operator!=、operator> 、operator< 、operator>= 、perator<= CString与string之间不可以进行比较,但均可以与char*进行比较,并且比较的是值,而不是地址;cout << ( psz == cstr );cout << ( psz == str );cout << ( str == psz );cout << ( cstr == psz );//以上代码返回均为1
(四) 常用算法a) 查找作用 char* string CString 查找指定值 strchrstrstrstrrstrstrspn find Find 第一个匹配的值 fild_first_of FindOneOf 从后面开始查找 ReserveFind 指定匹配方式 find_if 注:find_if中是把范围内的值挨个代入匹配函数直至返回trueb) 比较作用 char* string CString 查找指定值(区分大小写) strcmpstrncmpstrcoll_strncoll operator<operator>operator<= operator>=operator==operator!= CollateCompare 查找指定值(不区分大小写) _stricmp_strnicmp_stricoll_strnicoll CollateNoCaseCompareNoCas 注:返回值如果<0则前面的值小于后面的值,反之亦然c) 替换作用 char* string CString 查找指定值 _strset_strnset replacereplace_copyreplace_copy_ifreplace_if Replace d) 插入作用 char* string CString 查找指定值 insert Insert e) 增加作用 char* string CString 动态增加值 strcat pushappend AppendAppendCharAppendFormat f) 截取作用 char* string CString 得到部分值 用下标操作 substr LeftMidRightTruncate g) 移除作用 char* string CString 移除部份值 remove Remove 移除空白值 RemoveBlanks注:此为ATL提供,非C函数 remove_if TrimTrimLeftTrimRig h) 转换大小写作用 char* string CString 转换大小写 _strlwr_strupr MakeLowerMakeUpper i) 与其他类型转换作用 char* string CString 转化为数字 atoiatodatof Format 转化为char* c_str GetBufferGetBufferSetLen j) 格式化作用 char* string CString 格式化 sprintf Format k) 得到长度作用 char* string CString 得到长度 strlen length GetLength 得到大小 size GetAllocLength l) 判断为空作用 char* string CString 判断是否为空 判断是否==NULL或者第一个字符是否是'{post.abstract}' empty IsEmpty m) 重定义大小作用 char* string CString 重定义大小 reallocnew resize GetBufferSetLength n) 释放资源作用 char* string CString 释放 freedelete (delete[]) ReleaseBufferReleaseBufferSetLength
(五) 安全性>CString > string > char*;
(六) 灵活性CString > string >char*;
(七) 可移植性char* = string > CString
(八) MFC中常用字符串结构图(此非比较,但为了方便查阅就一并算在这儿了)
九) 总结综上所述,我个人认为,在MFC、ATL中使用字符串尽量使用CString,毕竟都是微软的孩子,各方面都比其它更有优势,而在非微软平台上或对移植性要求较高的场合推荐使用string,标准模板库提供了那么强大的泛型算法,没必要再自己去造车轮。
vc常用技巧总结
如何通过代码获得应用程序主窗口的 指针?主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现。AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED)//使程序最大化.
(2) 确定应用程序的路径Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。Example:TCHARexeFullPath[MAX_PATH] // MAX_PATH在API中定义了吧,好象是128GetModuleFileName(NULL,exeFullPath,MAX_PATH)
(3) 如何在程序中获得其他程序的 图标?两种方法:(1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle,(2) SDK函数 SHGetFileInfo 获得有关文件的很多信息,如大小图标,属性, 类型等.Example(1):在程序窗口左上角显示 NotePad图标.void CSampleView:OnDraw(CDC * pDC){if( :: SHGetFileInfo(_T("c:/pwin95/notepad.exe"),0,&stFileInfo,sizeof(stFileInfo),SHGFI_ICON)){pDC ->DrawIcon(10,10,stFileInfo.hIcon)}}Example(2):同样功能,Use ExtractIcon Functionvoid CSampleView:: OnDraw(CDC *pDC){HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T("NotePad.exe"),0)if (hIcon &&hIcon!=(HICON)-1)pDC->DrawIcon(10,10,hIcon)}说明: 获得notepad.exe的路径正规上来说用GetWindowsDirectory函数得到, 如果是调用 win95下的画笔,应该用访问注册表的方法获得其路径,要作成一个比较考究的程序,考虑应该全面点.
(4) 获得各种目录信息Windows目录: Use "GetWindowsDirectory"Windows下的system目录: Use "GetSystemDirectory"temp目录: Use "GetTempPath"当前目录: Use "GetCurrentDirectory"请注意前两个函数的第一个参数为目录变量名,后一个为缓冲区后两个相反.
(5) 如何自定义消息1) 手工定义消息,可以这么写#define WM_MY_MESSAGE(WM_USER+100),MS 推荐的至少是 WM_USER+100(2)写消息处理函数,用WPARAM,LPARAM返回LRESULT.LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam){temp目录: Use "GetTempPath"//加入你的处理函数 irectory"}
(6) 如何改变窗口的图标?向窗口发送 WM_SECTION消息。Example:HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON)ASSERT(hIcon)AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM)hIcon)
(7) 如何改变窗口的缺省风格?重载 CWnd:: PreCreateWindow 并修改CREATESTRUCT结构来指定窗口风格和其他创建信息.Example: Delete "Max" Button and Set OriginalWindow's Position and SizeBOOL CMainFrame:: PreCreateWindow(CREATESTRUCT &cs){cs.style &=~WS_MAXINIZEMOXcs.x=cs.y=0cs.cx=GetSystemMetrics(SM_CXSCREEN/2)cs.cy=GetSystemMetrics(SM_CYSCREEN/2)return CMDIFramewnd ::PreCreateWindow(cs)}
(8) 如何将窗口居中显示?Call Function CWnd::Center WindowsExample(1):Center Window( ) //Relative to it's parent// Relativeto ScreenExample(2):Center Window(CWnd:: GetDesktopWindow( ))//Relative toApplication's MainWindowAfxGetMainWnd( ) ->Center Window( )
(9) 如何让窗口和 MDI窗口一启动就最大化和最小化?先说窗口。在 InitStance 函数中设定 m_nCmdShow的取值.m_nCmdShow=SW_SHOWMAXMIZED //最大化m_nCmdShow=SW_SHOWMINMIZED //最小化m_nCmdShow=SW_SHOWNORMAL //正常方式MDI窗口:如果是创建新的应用程序,可以用MFC AppWizard 的Advanced 按钮并在MDI子窗口风格组中检测最大化或最小化还可以重载 MDI Window 的PreCreateWindow函数,设置WS_MAXMIZE or WS_MINMIZE如果从 CMDIChildWnd派生,调用 OnInitialUpdate函数中的 CWnd::Show Window来指定 MDI Child Window的风格。
(10) 如何限制窗口的大小?也就是 FixedDialog形式。 Windows发送 WM_GETMAXMININFO消息来跟踪, 响应它,在 OnGetMAXMININFO 中写代码:
(11) 如何使窗口不可见?很简单,用SW_HIDE 隐藏窗口,可以结合 FindWindow,ShowWindow控制.
(12) 如何创建一个字回绕的CEditView重载CWnd : : PreCreateWindow和修改CREATESTRUCT结构,关闭CEditView对象的ES_AUTOHSCROLL和WS_HSCROLL风格位, 由于CEditView : : PreCreateWindow显示设置cs. style,调用基类函数后要修改cs . style。BOOL CSampleEDitView : : PreCreateWindow (CREATESTRUCT&cs){//First call basse class function .BOOL bResutl =CEditView : : PreCreateWindow (cs)// Now specify the new window style .cs.style &= ~ (ES_AUTOHSCROLL |WS_HSCROLL)return bResult}
(13) 如何使程序保持极小状态?这么办: 在恢复程序窗体大小时,Windows会发送WM_QUERY-OPEN消息,用 ClassWizard设置成员函数OnQueryOpen() ,add following code:Bool CMainFrame:: OnQueryOpen( ){Return false}
(14) 移动窗口调用CWnd : : SetWindowPos并指定SWP_NOSIZE标志。目的位置与父窗口有关(顶层窗口与屏幕有关)。调用CWnd : : MoveWindow时必须要指定窗口的大小。//Move window to positoin 100 , 100 of its parent window .SetWindowPos (NULL, 100 , 100 , 0 , 0 , SWP_NOSIZE |SWP_NOAORDER)
(15) 通用控件的显示窗口MFC提供了几个CView派生的视窗类, 封装了通用控件的功能,但仍然使用工作框文档显示窗口体系结构:CEditView封装了编辑控件,CTreeView保持了树列表控件,CListView封装了列表显示窗口控件,CRichEditView可以处理多种编辑控件。
(16) 重置窗口的大小调用CWnd: : SetWindowPos并指定SWP_NOMOVE标志, 也可调用CWnd : : MoveWindow 但必须指定窗口的位置。// Get the size of the window .Crect reWindowGetWindowRect (reWindow )//Make the window twice as wide and twice as tall .SetWindowPos (NULL , 0 , 0 , reWindow . Width ( ) *2,reWindow . Height () * 2,SWP_NOMOVE |SWP_NOZORDER )
(17) 如何单击除了窗口标题栏以外的区域使窗口移动当窗口需要确定鼠标位置时Windows向窗口发送WM_NCHITTEST信息,可以处理该信息使Windows认为鼠标在窗口标题上。对于对话框和基于对话的应用程序,可以使用ClassWizard处理该信息并调用基类函数, 如果函数返回HTCLIENT 则表明鼠标在客房区域,返回HTCAPTION表明鼠标在Windows的标题栏中。UINT CSampleDialog : : OnNcHitTest (Cpoint point ){UINT nHitTest =Cdialog: : OnNcHitTest (point )return (nHitTest = =HTCLIENT)? HTCAPTION : nHitTest}上述技术有两点不利之处,其一是在窗口的客户区域双击时,窗口将极大;其二, 它不适合包含几个视窗的主框窗口。还有一种方法,当用户按下鼠标左键使主框窗口认为鼠标在其窗口标题上,使用ClassWizard在视窗中处理WM_LBUTTODOWN信息并向主框窗口发送一个WM_NCLBUTTONDOWN信息和一个单击测试HTCAPTION。void CSampleView : : OnLButtonDown (UINT nFlags , Cpoint point){CView : : OnLButtonDow (nFlags , pont )//Fool frame window into thinking somene clickedonits caption bar .GetParentFrame ( ) -> PostMessage (WM_NCLBUTTONDOWN ,HTCAPTION , MAKELPARAM (poitn .x , point .y) )}该技术也适用于对话框和基于对的应用程序,只是不必调用CWnd: :GetParentFrame 。void CSampleDialog : : OnLbuttonDown (UINT nFlags, Cpoint point ){Cdialog : : OnLButtonDow (nFlags, goint )//Fool dialog into thinking simeone clicked on itscaption bar .PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x, point. y) )}
(18) 如何改变视窗的背景颜色Windows向窗口发送一个WM_ERASEBKGND消息通知该窗口擦除背景,可以使用ClassWizard重载该消息的缺省处理程序来擦除背景(实际是画),并返回TRUE以防止Windows擦除窗口。//Paint area that needs to be erased.BOOL CSampleView : : OnEraseBkgnd (CDC* pDC){// Create a pruple brush.CBrush Brush (RGB (128 , 0 , 128) )// Select the brush into the device context .CBrush* pOldBrush = pDC->SelcetObject (&brush)// Get the area that needs to be erased .CRect reClippDC->GetCilpBox (&rcClip)//Paint the area.pDC-> PatBlt (rcClip.left , rcClip.top , rcClip.Width ( ) , rcClip.Height( ) , PATCOPY )//Unselect brush out of device context .pDC->SelectObject (pOldBrush )// Return nonzero to half fruther processing .return TRUE}
(19) 如何改变窗口标题调用CWnd : : SetWindowText可以改变任何窗口(包括控件)的标题。//Set title for application's main frame window .AfxGetMainWnd ( ) -> SetWindowText (_T("Application title") )//Set title for View's MDI child frame window .GetParentFrame ( ) -> SetWindowText ("_T ("MDI Child Frame new title"))//Set title for dialog's push button control.GetDigitem (IDC_BUTTON) -> SetWindowText (_T ("Button new title ") )如果需要经常修改窗口的标题(注:控件也是窗口),应该考虑使用半文档化的函数AfxSetWindowText。该函数在AFXPRIV.H中说明,在WINUTIL.CPP中实现,在联机帮助中找不到它,它在AFXPRIV.H中半文档化, 在以后发行的MFC中将文档化。AfxSetWindowText的实现如下:voik AFXAPI AfxSetWindowText (HWND hWndCtrl , LPCTSTR IpszNew ){itn nNewLen= Istrlen (Ipaznew)TCHAR szOld [256]//fast check to see if text really changes (reducesflash in thecontrols )if (nNewLen >_contof (szOld)|| : : GetWindowText (hWndCrtl, szOld , _countof (szOld) !=nNewLen|| Istrcmp (szOld , IpszNew)! = 0{//change it: : SetWindowText(hWndCtrl , IpszNew )}}
(20) 如何防止主框窗口在其说明中显示活动的文档名创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位,如果不希望在说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs){//Turn off FWS_ADDTOTITLE in main frame .cs.styel & = ~FWS_ADDTOTITLE return CMDIFrameWnd : : PreCreateWindow (cs )}关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南
(21) 如何获取有关窗口正在处理的当前消息的信息调用CWnd: : GetCurrentMessage可以获取一个MSG指针。例如,可以使用ClassWizard将几个菜单项处理程序映射到一个函数中,然后调用GetCurrentMessage来确定所选中的菜单项。viod CMainFrame : : OnCommmonMenuHandler ( ){//Display selected menu item in debug window .TRACE ("Menu item %u was selected . /n" ,
(22) 如何在代码中获取工具条和状态条的指针缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针://Get pointer to status bar .CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( )-> GetDescendantWindow(AFX_IDW_STUTUS_BAR)//Get pointer to toolbar .CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( )-> GetDescendantWindow(AFX_IDW_TOOLBAR)
(23) 如何使能和禁止工具条的工具提示如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者禁止工具提示,需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle和CControlBar : : SetBarStyle建立一个完成此功能的成员函数:void CMainFrame : : EnableToolTips ( BOOL bDisplayTips ){ASSERT_VALID (m_wndToolBar)DWORD dwStyle = m _wndToolBar.GetBarStyle ( )if (bDisplayTips) dwStyle |=CBRS_TOOLTIPSelsedwStyle & = ~CBRS_TOOLTIPSm_wndToolBar.SetBarStyle (dwStyle )}(24) 如何创建一个不规则形状的窗口可以使用新的SDK函数SetWindowRgn。该函数将绘画和鼠标消息限定在窗口的一个指定的区域,实际上使窗口成为指定的不规则形状。 使用AppWizard创建一个基于对的应用程序并使用资源编辑器从主对话资源中删除所在的缺省控件、标题以及边界。给对话类增加一个CRgn数据成员,以后要使用该数据成员建立窗口区域。Class CRoundDlg : public CDialog{…private :Crgn m_rgn : // window region…}修改OnInitDialog函数建立一个椭圆区域并调用SetWindowRgn将该区域分配给窗口:BOOL CRoundDlg : : OnInitDialog ( ){CDialog : : OnInitDialog ( )//Get size of dialog .CRect rcDialogGetClientRect (rcDialog )// Create region and assign to window .m_rgn . CreateEllipticRgn (0 , 0 , rcDialog.Width( ) , rcDialog.Height ( ) )SetWindowRgn (GetSafeHwnd ( ) , (HRGN) m_ rgn ,TRUE )return TRUE}通过建立区域和调用SetWindowRgn,已经建立一个不规则形状的窗口,下面的例子程序是修改OnPaint函数使窗口形状看起来象一个球形体。voik CRoundDlg : : OnPaint ( ){CPaintDC de (this) // device context for painting.//draw ellipse with out any borderdc. SelecStockObject (NULL_PEN)//get the RGB colour components of the sphere colorCOLORREF color= RGB( 0 , 0 , 255)BYTE byRed =GetRValue (color)BYTE byGreen = GetGValue (color)BYTE byBlue = GetBValue (color)// get the size of the view windowCrect rectGetClientRect (rect)// get minimun number of unitsint nUnits =min (rect.right , rect.bottom )//calculate he horiaontal and vertical step sizefloat fltStepHorz = (float) rect.right /nUnitsfloat fltStepVert = (float) rect.bottom /nUnitsint nEllipse = nUnits/3 // calculate how many todrawint nIndex// current ellipse that is being drawCBrush brush// bursh used for ellipse fill colorCBrush *pBrushOld // previousbrush that was selected into dc//draw ellipse , gradually moving towards upper-rightcornerfor (nIndex = 0 nIndes < + nEllipse nIndes++){//creat solid brushbrush . CreatSolidBrush (RGB ( ( (nIndex*byRed ) /nEllipse ).( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue)/nEllipse ) ) )//select brush into dcpBrushOld= dc .SelectObject (&brhsh)//draw ellipsedc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex ,rect. right -( (int) fltStepHorz * nIndex )+ 1,rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1)//delete the brushbrush.DelecteObject ( )}}最后,处理WM_NCHITTEST消息,使当击打窗口的任何位置时能移动窗口。UINT CRoundDlg : : OnNchitTest (Cpoint point ){//Let user move window by clickign anywhere on thewindow .UINT nHitTest = CDialog : : OnNcHitTest (point)rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest}
(25) 如何获取应用程序的 实例句柄?应用程序的实例句柄保存在CWinApp m_hInstance 中,可以这么调用AfxGetInstancdHandle获得句柄.Example: HANDLE hInstance=AfxGetInstanceHandle()
(26) 如何编程结束应用程序?这是个很简单又是编程中经常要遇到的问题.向窗口发送 WM_CLOSE消息,调用 CWnd::OnClose成员函数.允许对用户提示是否保存修改过的数据.Example: AfxGetMainWindow()->SendMessage(WM_CLOSE)还可以创建一个自定义的函数 Terminate Windowvoid Terminate Window(LPCSTR pCaption){CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption)if (pWnd)pWnd ->SendMessage(WM_CLOSE)}说明: FindWindow函数不是提倡的做法,因为它无法处理标题栏自动改变,比如我们要检测 Notepad是不是已运行而事先不知道Notepad的标题栏,这时FindWindow就无能为力了,可以通过枚举 windows任务列表的办法来实现。在机械出版社"Windows 95 API开发人员指南"一书有比较详细的介绍,这里就不再多说乐。
(27) 如何创建和使用无模式对话框MFC将模式和无模式对话封装在同一个类中,但是使用无模式对话需要几个对话需要几个额处的步骤。首先,使用资源编辑器建立对话资源并使用ClassWizard创建一个CDialog的派生类。模式和无模式对话的中止是不一样的:模式对话通过调用CDialog : : EndDialog 来中止,无模式对话则是调用CWnd: : DestroyWindow来中止的,函数CDialog : : OnOK和CDialog : : OnCancel调用EndDialog ,所以需要调用DestroyWindow并重置无模式对话的函数。void CSampleDialog : : OnOK ( ){// Retrieve and validate dialog data .if (! UpdateData (TRUE) ){// the UpdateData rountinewill set focus to correct item TRACEO (" UpdateData failed during dialog termination ./n")return}//Call DestroyWindow instead of EndDialog .DestroyWindow ( )}void CSampleDialog : : OnCancel ( ){//Call DestroyWindow instead of EndDialog .DestroyWindow ( )}其次,需要正确删除表示对话的C++对象。对于模式对来说,这很容易,需要创建函数返回后即可删除C++对象;无模式对话不是同步的,创建函数调用后立即返回,因而用户不知道何时删除C++对象。撤销窗口时工作框调用CWnd : : PostNcDestroy,可以重置该函数并执行清除操作,诸如删除this指针。void CSampleDialog : : PostNcDestroy ( ){// Declete the C++ object that represents this dialog.delete this最后,要创建无模式对话。可以调用CDialog : : DoModal创建一个模式对放,要创建一个无模式对话则要调用CDialog: : Create。下面的例子说明 了应用程序是如何创建无模式对话的: 象;无模式对话不是同步的,创建函数调用后立即返回,void CMainFrame : : OnSampleDialog ( ){//Allocate a modeless dialog object .CSampleDilog * pDialog =new CSampleDialogASSERT_VALID (pDialog) Destroy ( )//Create the modeless dialog . represents this dialog.BOOL bResult = pDialog -> Creste (IDD_IDALOG)ASSERT (bResult )} (28) 如何防止主框窗口在其说明中显示活动的文档名创建主框窗口和MDI子窗口进通常具有FWS_ADDTOTITLE风格位,如果不希望在说明中自动添加文档名, 必须禁止该风格位, 可以使用ClassWizard重置CWnd: : PreCreateWindow并关闭FWS_ADDTOTITLE风格。BOOL CMainFrame : : PreCreateWindow (CREATESTRUCT&cs){//Turn off FWS_ADDTOTITLE in main frame .cs.styel & = ~FWS_ADDTOTITLE return CMDIFrameWnd : : PreCreateWindow (cs )}关闭MDI子窗口的FWS _ADDTOTITLE风格将创建一个具有空标题的窗口,可以调用CWnd: : SetWindowText来设置标题。记住自己设置标题时要遵循接口风格指南。(29) 如何在代码中获取工具条和状态条的指针缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针://Get pointer to status bar .CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( )-> GetDescendantWindow(AFX_IDW_STUTUS_BAR)//Get pointer to toolbar .CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( )-> GetDescendantWindow(AFX_IDW_TOOLBAR)(30) 怎样加载其他的应用程序?三个SDK函数 winexec, shellexecute,createprocess可以使用。WinExec最简单,两个参数,前一个指定路径,后一个指定显示方式.后一个参数值得说一下,比如泥用 SW_SHOWMAXMIZED方式去加载一个无最大化按钮的程序,就是Neterm,calc等等,就不会出现正常的窗体,但是已经被加到任务列表里了。ShellExecute较 WinExex灵活一点,可以指定工作目录,下面的Example就是直接打开 c:/temp.txt,而不用加载与 txt文件关联的应用程序,很多安装程序完成后都会打开一个窗口,来显示Readme or Faq,我猜就是这么作的啦.ShellExecute(NULL,NULL,_T("1.txt"),NULL,_T("c:/temp"),SW_SHOWMAXMIZED)CreateProcess最复杂,一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等.来看个很简单的Example:STARTUPINFO stinfo//启动窗口的信息PROCESSINFO procinfo //进程的信息CreateProcess(NULL,_T("notepad.exe"),NULL,NULL.FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL, &stinfo,&procinfo)(31) 如何在代码中获取工具条和状态条的指针缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条有一个AFX_IDW_STATUS_BAR标识符,工具条有一个AFX_IDW_TOOLBAR标识符,下例说明了如何通过一起调用CWnd: : GetDescendantWindow和AfxGetMainWnd来获取这些子窗口的指针://Get pointer to status bar .CStatusBar * pStatusBar = (CStatusBar *) AfxGetMainWnd ( )-> GetDescendantWindow(AFX_IDW_STUTUS_BAR)(32) 如何使能和禁止工具条的工具提示如果设置了CBRS_TOOLTIPS风格位,工具条将显示工具提示,要使能或者禁止工具提示,需要设置或者清除该风格位。下例通过调用CControlBar : : GetBarStyle和CControlBar : : SetBarStyle建立一个完成此功能的成员函数:void CMainFrame : : EnableToolTips ( BOOL bDisplayTips ){ASSERT_VALID (m_wndToolBar)DWORD dwStyle = m _wndToolBar.GetBarStyle ( )if (bDisplayTips) dwStyle |=CBRS_TOOLTIPSelsedwStyle & = ~CBRS_TOOLTIPSm_wndToolBar.SetBarStyle (dwStyle )}//Get pointer to toolbar .CToolBar * pToolBar = (CToolBar * ) AfxGetMainWnd ( )-> GetDescendantWindow(AFX_IDW_TOOLBAR)(33) 如何设置工具条标题工具条是一个窗口,所以可以在调用CWnd : : SetWindowText来设置标题,例子如下:int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct ){…// Set the caption of the toolbar .m_wndToolBar.SetWindowText (_T "Standdard")(34) 如何使窗口始终在最前方?BringWindowToTop(Handle)SetWindowPos函数,指定窗口的 最顶风格,用WS_EX_TOPMOST扩展窗口的风格Example:void ToggleTopMost(CWnd *pWnd){ASSERT_VALID(pWnd)pWnd ->SetWindowPos(pWnd-> GetStyle( ) &WS_EX_TOPMOST)?&wndNoTopMOST: &wndTopMost,0,0,0,0,SSP_NOSIZE|WSP_NOMOVE)}(35) 如何在对话框中显示一个位图这要归功于Win 32先进的静态控件和Microsoft的资源编辑器,在对话框中显示位图是很容易的, 只需将图形控件拖到对话中并选择适当属性即可,用户也可以显示图标、位图以及增强型元文件。(36) 如何改变对话或窗体视窗的背景颜色调用CWinApp : : SetDialogBkColor可以改变所有应用程序的背景颜色。第一个参数指定了背景颜色,第二个参数指定了文本颜色。下例将应用程序对话设置为蓝色背景和黄色文本。BOOL CSampleApp : : InitInstance ( ){…//use blue dialog with yellow text .SetDialogBkColor (RGB (0, 0, 255 ), RGB ( 255 ,255 , 0 ) )…}需要重画对话(或对话的子控件)时,Windows向对话发送消息WM_CTLCOLOR,通常用户可以让Windows选择绘画背景的刷子,也可重置该消息指定刷子。下例说明了创建一个红色背景对话的步骤。首先,给对话基类增加一人成员变量CBursh :class CMyFormView : public CFormView{…private :CBrush m_ brush // background brush…}其次, 在类的构造函数中将刷子初始化为所需要的背景颜色。CMyFormView : : CMyFormView ( ){// Initialize background brush .m_brush .CreateSolidBrush (RGB ( 0, 0, 255) )}最后,使用ClassWizard处理WM_CTLCOLOR消息并返回一个用来绘画对话背景的刷子句柄。注意:由于当重画对话控件时也要调用该函数,所以要检测nCtlColor参量。HBRUSH CMyFormView : : OnCtlColor (CDC* pDC , CWnd*pWnd , UINT nCtlColor){// Determine if drawing a dialog box . If we are, return +handle to//our own background brush . Otherwise let windows handle it .if (nCtlColor = = CTLCOLOR _ DLG )return (HBRUSH) m_brush.GetSafeHandle ( )return CFormView : : OnCtlColor (pDC, pWnd , nCtlColor)}(37) 如何获取一个对话控件的指针有两种方法。其一,调用CWnd: : GetDlgItem,获取一个CWnd*指针调用成员函数。下例调用GetDlgItem,将返回值传给一个CSpinButtonCtrl*以便调用CSpinButtonCtrl : : SetPos 函数:BOOL CSampleDialog : : OnInitDialog ( ){CDialog : : OnInitDialog ( )//Get pointer to spin button .CSpinButtonCtrl * pSpin - ( CSpinButtonCtrl *) GetDlgItem(IDC_SPIN)ASSERT _ VALID (pSpin)//Set spin button's default position .pSpin -> SetPos (10)return TRUE}其二, 可以使用ClassWizard将控件和成员变量联系起来。在ClassWizard中简单地选择Member Variables标签,然后选择Add Variable …按钮。如果在对话资源编辑器中,按下Ctrl键并双击控件即可转到Add Member Variable对话。(38) 如何禁止和使能控件控件也是窗口,所以可以调用CWnd : : EnableWindow使能和禁止控件。//Disable button controls .m_wndOK.EnableWindow (FALSE )m_wndApply.EnableWindow (FALSE )(39) 如何改变控件的字体由于控件是也是窗口,用户可以调用CWnd: : SetFont指定新字体。该函数用一个Cfont指针,要保证在控件撤消之前不能撤消字体对象。下例将下压按钮的字体改为8点Arial字体://Declare font object in class declaration (.H file ).private : Cfont m_font// Set font in class implementation (.Cpp file ). Note m_wndButton is a//member variable added by ClassWizard.DDX routines hook the member//variable to a dialog button contrlo.BOOL CSampleDialog : : OnInitDialog ( ){…//Create an 8-point Arial fontm_font . CreateFont (MulDiv (8 , -pDC-> GetDeviceCaps(LOGPIXELSY) ,72). 0 , 0 , 0 , FW_NORMAL , 0 , 0,0, ANSI_CHARSER, OUT_STROKE_PRECIS ,CLIP_STROKE _PRECIS , DRAFT _QUALITYVARIABLE_PITCH |FF_SWISS, _T("Arial") )//Set font for push button .m_wndButton . SetFont (&m _font )…}(40) 如何在OLE控件中使用OLE_COLOR数据类型诸如COleControl : : GetFortColor和COleControl : : GetBackColor等函数返回OLE _COLOR数据类型的颜色,而GDI对象诸如笔和刷子使用的是COLORREF数据类型,调用COleControl : : TranslateColor可以很容易地将OLE_COLOR类型改为COLORREF类型。下例创建了一个当前背景颜色的刷子:void CSampleControl : : OnDraw (CDC* pdcconst Crect& rcBounds , const Crect& rcInvalid){//Create a brush of the cuttent background color.CBrush brushBack (TranslateColor (GetBackColor () ) )//Paint the background using the current backgroundcolor .pdc-> FilllRect (rcBounds , &brushBack)//other drawign commands…}(41) 在不使用通用文件打开对话的情况下如何显示一个文件列表调用CWnd: : DlgDirList或者CWnd: : DlgDirListComboBox,Windows 将自动地向列表框或组合框填充可用的驱动器名或者指定目录中的文件,下例将Windows目录中的文件填充在组合框中:BOOL CSampleDig : : OnInitDialog ( ){CDialog : : OnInitDialog ( )TCHAR szPath [MAX_PATH] = {"c:/windows"}int nReslt = DlgDirListComboBox (szPath, IDC_COMBO , IDC_CURIDIR, DDL_READWRITE |DDL_READONLY|DDL_HIDDEN| DDL_SYSTEM|DDL_ARCHIVE)return TRUE}(42) 为什么旋转按钮控件看起来倒转需要调用CSpinCtrl : : SetRange 设置旋转按钮控件的范围,旋转按钮控件的缺省上限为0,缺省下限为100,这意味着增加时旋转按控件的值由100变为0。下例将旋转按钮控件的范围设置为0到100:BOOL CAboutDlg : : OnInitDialog ( ){CDialog : : OnInitDialog ( )//set the lower and upper limit of the spin buttonm_wndSpin . SetRange ( 0 ,100 )return TRUE}Visual C++ 4.0 Print对话中的Copise旋转按钮控件也有同样的问题:按下Up按钮时拷贝的数目减少,而按下Down 按钮时拷贝的数目增加。(43) 为什么旋转按钮控件不能自动地更新它下面的编辑控件如果使用旋转按钮的autu buddy特性, 则必须保证在对话的标记顺序中buddy窗口优先于旋转按钮控件。从Layout菜单中选择Tab Order菜单项(或者按下Crtl+D)可以设置对话的标签顺序。(44) 如何用位图显示下压按钮Windows 95按钮有几处新的创建风格,尤其是BS_BITMAP和BS_ICON,要想具有位图按钮,创建按钮和调用CButton : : SetBitmap或CButton : : SetIcon时要指定BS_BITMAP或BS_ICON风格。首先,设置按钮的图标属性。然后,当对话初始化时调用CButton: : SetIcon。注意:下例用图标代替位图,使用位图时要小心,因为不知道背景所有的颜色--并非每个人都使用浅灰色。BOOL CSampleDlg : : OnInitDialog ( ){CDialog : : OnInitDialog ( )//set the images for the push buttons .BOOL CSampleDlg : : OnInitDialog ( ){CDialog : : OnInitDialog ( )//set the images for the push buttons .m_wndButton1.SetIcon (AfxGetApp ( ) -> LoadIcon (IDI _ IPTION1))m_wndButton2.SetIcon (AfxGetApp ( ) -> LoadIcon (IDI _ IPTION2))m_wndButton3.SetIcon (AfxGetApp ( ) -> LoadIcon (IDI _ IPTION3))return TRUE}(45) 如何一个创建三态下压按钮可以使用新的BS_PUSHBUTTON 风格位和检测框以及按钮来创建一个三态下压按钮。这很容易,只需将检测框和按钮拖拉到对话中并指定属性Push-like即可。不用任何附加程序就可以成为三态下压按钮。(46) 如何动态创建控件分配一个控件对象的实例并调用其Create成员函数。开发者最容易忽略两件事:忘记指定WS_VISBLE标签和在栈中分配控件对象。下例动态地创建一个下压按钮控件://In class declaration (.H file ).private : CButton* m _pButton//In class implementation (.cpp file ) .m_pButton =new CButtonASSERT_VALID (m_pButton)m_pButton ->Create (_T ("Button Title ") , WS_CHILD |WS_VISIBLE |BS_PUSHBUTTON. Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON )(47) 如何限制编辑框中的准许字符如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指定新的创建标志ES_NUMBERS,它是Windows 95新增加的标志,该标志限制 编辑控件只按收数字字符。如果用户需要复杂的编辑控件,可以使用Microsoft 的屏蔽编辑控件,它是一个很有用的OLE定制控件。如果希望不使用OLE 定制控件自己处理字符,可以派生一个CEdit类并处理WM_CHAR消息,然后从编辑控件中过滤出特定的字符。首先,使用ClassWizard建立一个 CEdit的派生类,其次,在对话类中指定一个成员变量将编辑控件分类在OnInitdialog 中调用CWnd: : SubclassDlgItem .//In your dialog class declaration (.H file )private : CMyEdit m_wndEdit // Instance of your new edit control .//In you dialog class implementation (.CPP file )BOOL CSampleDialog : : OnInitDialog ( ){…//Subclass the edit lontrod .m_wndEdit .SubclassDlgItem (IDC_EDIT,this)…}使用ClassWizard处理WM_CHAR消息,计算nChar参量并决定所执行的操作,用户可以确定是否修改、传送字符。下例说明了如何显示字母字符,如果字符是字母字符,则调用CWnd OnChar,否则不调用OnChar.//Only display alphabetic dharacters .void CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UITN nFlags ){//Determine if nChar is an alphabetic character.if (: : IsCharAlpha ( ( TCHAR) nChar ) )CEdit : : OnChar (nChar, nRepCnt , nFlags )}如果要修改字符,则不能仅仅简单地用修改过的nChar调用CEdit: : OnChar,然后CEdit: : OnChar调用CWnd: : Default获取原来的wParam 和lParam 的值,这样是不行的。要修改一个字符,需要首先修改nChar,然后用修改过的nChar调用CWnd: : DefWindowProc。下例说明了如何将字符转变为大写://Make all characters uppercasevoid CMyEdit : : OnChar (UINT nChar , UINT nRepCnt , UINT nFlags ){//Make sure character is uppercase .if (: : IsCharAlpha ( .( TCHAR) nChar)nChar=: : CharUpper(nChar )//Bypass default OnChar processing and directly call//default window proc.DefWindProc (WM_CHAR, nChar , MAKELPARAM (nRepCnt, nFlags ))} VC常用技巧总结2 (48) 如何改变控件的颜色有两种方法。其一,可以在父类中指定控件的颜色,或者利用MFC4.0新的消息反射在控件类中指定颜色。 当控件需要重新着色时,工作框调用父窗口(通常是对话框)的CWnd: : OnCrtlColor,可以在父窗口类中重置该函数并指定控件的新的绘画属性。例如,下述代码将对话中的所有编辑控件文本颜色改为红色:HBRUSH CAboutDig : : OnCtlColor (CDC * pDCM , CWnd * pWnd , UINT nCtlColor){HBRUSH hbr = CDialog : : OnCtlColor (pDC, pWnd , nCtlColor )//Draw red text for all edit controls .if (nCtlColor= = CTLCOLOR_EDIT )pDC -> SetTextColor (RGB (255, 0 , 0 , ) )return hbr}然而,由于每个父窗口必须处理通知消息并指定每个控件的绘画属性,所以,这种方法不是完全的面向对象的方法。控件处理该消息并指定绘画属性更合情合理。消息反射允许用户这样做。通知消息首先发送给父窗口,如果父窗口没有处理则发送给控件。创建一个定制彩色列表框控件必须遵循下述步骤。首先,使用ClassWizard 创建一个CListBox 的派生类并为该类添加下述数据成员。class CMyListBox publilc CListBox{…privateCOLORREF m_clrFor // foreground colorCOLORREF m_clrBack //background colorCbrush m_brush //background brush…}其次,在类的构造函数中,初始化数据中。CMyListBox : : CMyListBox (){//Initialize data members .m_clrFore =RGB (255 , 255 , 0) //yellow textm_clrBack=RGB (0 , 0 , 255) // blue backgroundm_brush . CreateSolidBrush (m _clrBack )}最后,使用ClassWizard处理反射的WM_CTLCOLOR(=WM_CTLCOLOR)消息并指定新的绘画属性。HBRUSH CMyListBox : : CtlColor (CDC* pDC, UINT nCtlColor ){pDC->SetTextColor (m_clrFore)pDC->SetBkColor (m_clrBack)return (HBRUSH) m_brush.GetSafeHandle ()}现在,控件可以自己决定如何绘画,与父窗口无关。(49) 当向列表框中添加多个项时如何防止闪烁调用CWnd::SetRedraw 清除重画标志可以禁止CListBox(或者窗口)重画。当向列表框添加几个项时,用户可以清除重画标志,然后添加项,最后恢复重画标志。为确保重画列表框的新项,调用SetRedraw (TRUE) 之后调用CWnd::Invalidate。//Disable redrawing.pListBox->SetRedraw (FALSE)//Fill in the list box gere//Enable drwing and make sure list box is redrawn.pListBox->SetRedraw (TRUE)pListBox->Invalidate ()(50) 如何向编辑控件中添加文本由于没有CEdit:: AppendText函数,用户只好自己做此项工作。调用CEdit:: SetSel移动到编辑控件末尾,然后调用CEdit:: ReplaceSel添加文本。下例是AppendText 的一种实现方法:void CMyEdit:: AppendText (LPCSTR pText){int nLen=GetWindowTextLength ()SetFocus ()SetSel (nLen, nLen)ReplaceSel (pText)}(51) 如何访问预定义的GDI对象可以通过调用CDC:: SlectStockObject使用Windows的几个预定义的对象,诸如刷子、笔以及字体。下例使用了Windows预定义的笔和刷子GDI对象在视窗中画一个椭圆。//Draw ellipse using stock black pen and gray brush.void CSampleView:: OnDraw (CDC* pDC){//Determine size of view.CRect rcViewGetClientRect (rcView)//Use stock black pen and stock gray brush to draw ellipse.pDC->SelectStockObject (BLACK_PEN)pDC->SelectStockObject (GRAY_BRUSH)//Draw the ellipse.pDC->Ellipse (reView)}也可以调用新的SDK函数GetSysColorBrush获取一个系统颜色刷子,下例用背景色在视窗中画一个椭圆:void CsampleView:: OnDraw (CDC* pDC){//Determine size of view.CRect rcViewGetClientRect (rcView)//Use background color for tooltips brush.CBrush * pOrgBrush=pDC->SelectObject ( CBrush ::FromHandle( ::GetSysColorBrush (COLOR_INFOBK)))//Draw the ellipse.pDC->Ellipse (rcView)//Restore original brush.pDC->SelectObject (pOrgBrush)}(52) 如何获取GDI对象的属性信息可以调用GDIObject:: GetObject。这个函数将指定图表设备的消息写入到缓冲区。下例创建了几个有用的辅助函数。//Determine if font is bold.BOOL IsFontBold (const CFont&font){LOGFONT stFontfont.GetObject (sizeof (LOGFONT), &stFont)return (stFont.lfBold)? TRUE: FALSE}//Return the size of a bitmap.CSize GetBitmapSize (const CBitmap&bitmap){BITMAP stBitmapbitmap.GetObject (sizeof (BITMAP), &stBitmap)return CSize (stBitmap.bmWidth, stBitmap.bmHeight)}//Create a pen with the same color as a brush.BOOL CreatePenFromBrush (Cpen&pen, cost Cbrush&brush){LOGBRUSH stBrushbrush.Getobject (sizeof (LOGBRUSH), &stBrush)return pen. Createpen (PS_SOLID, 0, stBrush.ibColor)}(53) 如何实现一个橡皮区矩形CRectTracker是一个很有用的类,可以通过调用CRectTracker::TrackRubberBand 响应WM_LBUTTONDOWN消息来创建一个橡皮区矩形。下例表明使用CRectTracker移动和重置视窗中的蓝色椭圆的大小是很容易的事情。首先,在文件档中声明一个CRectTracker数据成员:class CSampleView : Public CView{…public :CrectTracker m_tracker…}其次,在文档类的构造函数中初始化CRectTracker 对象:CSampleDoc:: CSampleDOC (){//Initialize tracker position, size and style.m_tracker.m_rect.SetRect (0, 0, 10, 10)m_tracker.m_nStyle=CRectTracker:: resizeInside | CRectTracker ::dottedLine}然后,在OnDraw函数中画椭圆和踪迹矩形:void CSampleView:: OnDraw (CDC* pDC){CSampleDoc* pDoc=GetDocument ()ASSERT_VALID (pDoc)//Select blue brush into device context.CBrush brush (RGB (0, 0, 255))CBrush* pOldBrush=pDC->SelectObject (&brush)//draw ellipse in tracking rectangle.Crect rcEllipsepDoc->m_tracker.GetTrueRect (rcEllipse)pDC->Ellipse (rcEllipse)//Draw tracking rectangle.pDoc->m_tracker.Draw (pDC)//Select blue brush out of device context.pDC->Selectobject (pOldBrush)}最后,使用ClassWizard处理WM_LBUTTONDOWN消息,并增加下述代码。该段代码根据鼠标击键情况可以拖放、移动或者重置椭圆的大小。void CSampleView::OnLButtonDown (UINT nFlags, CPoint point){//Get pointer to document.CSampleDoc* pDoc=GetDocument ()ASSERT_VALID (pDoc)//If clicked on ellipse, drag or resize it.Otherwise create a//rubber-band rectangle nd create a new ellipse.BOOL bResult=pDoc->m_tracker.HitTest (point)!= CRectTracker::hitNothing//Tracker rectangle changed so update views.if (bResult){pDoc->m_tracker.Track (this,point,TRue)pDoc->SetModifiedFlag ()pDoc->UpdateAllViews (NULL)}elsepDoc->m-tracker.TrackRubberBand(this,point,TRUE)CView:: onLButtonDown (nFlags,point)}(54) 如何更新翻转背景颜色的文本调用CDC:: SetBkmode并传送OPAQUE用当前的背景颜色填充背景,或者调用CDC::SetBkMode并传送TRANSPAARENT使背景保持不变,这两种方法都可以设置背景模式。下例设置背景模式为TRANSPARENT,可以两次更新串,用花色带黑阴影更新文本。黑色串在红色串之后,但由于设置了背景模式仍然可见。void CSampleView:: OnDraw (CDC* pDC){//Determint size of view.CRect rcViewGetClientRect (rcVieew)//Create sample string to display.CString str (_T ("Awesome Shadow Text..."))//Set the background mode to transparent.pDC->SetBKMode (TRANSPARENT)//Draw black shadow text.rcView.OffsetRect (1, 1)pDc->SetTextColor (RGB (0, 0, 0))pDC->DrawText (str, str.GetLength (), rcView, DT_SINGLELINE | DT_CENTER | DT_VCENTER)//Draw red text.rcView.OffsetRect (-1,-1)pDc->SetTextColor (RGB (255, 0, 0))pDC->DrawText (str, str.GetLength (), rcView, DT_SINGLELINE | DT_CENTER | DT_VCENTER)}(55) 如何创建一个具有特定点大小的字体可以指定字体逻辑单位的大小,但有时指定字体的点的大小可能会更方便一些。可以如下将字体的点转换为字体的高度:int nHeigth=mulDiv (nPointSize, -dc.GetDeviceCaps (LOGPIXELSY), 72)下例创建了一个8点的Apial字体:…CClientDC dc (AqfxGetMainWnd ())m_font. CreateFont (MulDiv (8, -dc.GetDeviceCaps (LOGPIXELSY), 72), 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS, DRAFT_QUALITY, VARIABLE_PITCH | FF-SWISS,_T("Arial"))(56) 如何计算一个串的大小函数CDC:: Det text Extent 根据当前选择的字体计算一个串的高度和宽度。如果使用的不是系统字体而是其他字体,则在调用GetTextExtent之前将字体选进设备上下文中是很重要的,否则计算高度和宽度时将依据系统字体,由此得出的结果当然是不正确的。下述样板程序当改变下压按钮的标题时动态调整按钮的大小,按钮的大小由按钮的字体和标题的大小而定。响应消息WM_SETTEXT时调用OnSetText,该消息使用ON_MESSAE宏指令定义的用户自定义消息。LRESULT CMyButton:: OnSettext (WPARAM wParam, LPARAM lParam){//Pass message to window procedure.LRESULT bResult=CallWindowProc (*GetSuperWndProcAddr(), m_hWnd, GetCurrentMessage() ->message,wParam,lParam)//Get title of push button.CString strTitleGetWindowText (strTitle)//Select current font into device context.CDC* pDC=GetDc ()CFont*pFont=GetFont ()CFont*pOldFont=pDC->SelectObject (pFont)//Calculate size of title.CSize size=pDC->GetTextExent (strTitle,strTitle.GetLength())//Adjust the button's size based on its title.//Add a 5-pixel border around the button.SetWindowPos (NULL, 0, 0, size.cx+10, size.cy+10, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE)//Clean up.pDC->SelectFont (pOldFont)ReleaseDC (pDC)return bResult}(57) 如何显示旋转文本只要用户使用TrueType或者GDI笔或字体就可以显示旋转文本(有些硬件设备也支持旋转光栅字体)。LOGFONT结构中的ifEscapement成员指定了文本行和x轴的角度,角度的单位是十分之一度而不是度,例如,ifEscapement为450表示字体旋转45度。为确保所有的字体沿坐标系统的同一方向旋转,一定要设置ifEscapement成员的CLIP_LH_ANGLES位,否则,有些字体可能反向旋转。下例使用了14点Arial字体每间隔15度画一个串。void CSampleView:: OnDraw (CDC* pDC){//Determine the size of the window.CRect rcClientGetClientRect (rcClient)//Create sample string.CString str (_T ("Wheeee...I am rotating!"))//Draw transparent, red text.pDC->SetBkMode (TRANSPARENT)pDC->SetTextColor (RGB (255,0,0))CFont font//font objectLOGFONT stFont //font definition//Set font attributes that will not change.memset (&stFont, 0, sizeof (LOGFONT))stFont.ifheight=MulDiv (14, -pDC->GetDeviceCaps(LOGPIXELSY), 72)stFont.ifWeight=FW_NORMALstFont.ifClipPrecision=LCIP_LH_ANGLESstrcpy (stFont.lfFaceName, "Arial")//Draw text at 15degree intervals.for (int nAngle=0 nAngle<3600 nAngle+=150){//Specify new angle.stFont.lfEscapement=nAngle//Create and select font into dc.font.CreateFontIndirect(&stfont)CFont* pOldFont=pDC ->SelectObject(&font)//Draw the text.pDC->SelectObject(pOldFont)font.DelectObjext()}}(58) 如何正确显示包含标签字符的串调用GDI文本绘画函数时需要展开标签字符,这可以通过调用CDC:: TabbedTextOut或者CDC:: DrawText并指定DT_EXPANDTABS标志来完成。TabbedTextOut函数允许指定标签位的数组,下例指定每20设备单位展开一个标签:void CSampleView:: OnDraw (CDC* pDC){CTestDoc* pDoc=GetDocument ()ASSERT_VALID (pDoC)CString strstr.Format (_T ("Cathy/tNorman/tOliver"))int nTabStop=20 //tabs are every 20 pixelspDC->TabbedtextOut (10, 10, str, 1, &nTabStop, 10)}(59) 如何快速地格式化一个CString对象调用CString:: Format,该函数和printf函数具有相同的参数,下例说明了如何使用Format函数://Get size of window.CRect rcWindowGetWindowRect (rcWindow)//Format message string.CString strMessagestrMessage.Format (_T ("Window Size (%d, %d)"),rcWindow.Width (), rcWindow.Height ())//Display the message.MessageBox (strmessage)(60) 串太长时如何在其末尾显示一个省略号调用CDC:: DrawText并指定DT_END_ELLIPSIS标志,这样就可以用小略号取代串末尾的字符使其适合于指定的边界矩形。如果要显示路径信息,指定DT_END_ELLIPSIS标志并省略号取代串中间的字符。void CSampleView:: OnDraw (CDC* pDC){CTestDoc* pDoc=GetDocument ()ASSERT_VALID (pDoc)//Add ellpsis to end of string if it does not fitpDC->Drawtext (CString ("This is a long string"), CRect (10, 10, 80, 30), DT_LEFT | DT_END_ELLIPSIS)//Add ellpsis to middle of string if it does not fitpDC->DrawText (AfxgetApp () ->m_pszhelpfilePath, CRect (10, 40, 200, 60), DT_LEFT | DT_PATH_ELLIPSIS)}(61) 为什么即使调用EnableMenuItem菜单项后,菜单项还处于禁止状态需要将CFrameWnd:: m_bAutomenuEnable设置为FALSE,如果该数据成员为TRUE(缺省值),工作框将自动地禁止没有ON_UPDATE_COMMAND_UI或者ON_COMMAND的菜单项。//Disable MFC from automatically disabling menu items.m_bAuoMenuEnable=FALSE//Now enable the menu item.CMenu* pMenu=GetMenu ()ASSERT_VALID (pMenu)pMenu->EnableMenuItem (ID_MENU_ITEM,MF_BYCOMMAND | MF_ENABLED)(62) 如何给系统菜单添加一个菜单项给系统菜单添加一个菜单项需要进行下述三个步骤:首先,使用Resource Symbols对话(在View菜单中选择Resource Symbols...可以显示该对话)定义菜单项ID,该ID应大于0x0F而小于0xF000;其次,调用CWnd::GetSystemMenu获取系统菜单的指针并调用CWnd:: Appendmenu将菜单项添加到菜单中。下例给系统菜单添加两个新的int CMainFrame:: OnCreate (LPCREATESTRUCT lpCreateStruct){…//Make sure system menu item is in the right range.ASSERT (IDM_MYSYSITEM &0xFFF0)==IDM_MYSYSITEM)ASSERT (IDM-MYSYSITEM<0xF000)//Get pointer to system menu.CMenu* pSysmenu=GetSystemmenu (FALSE)ASSERT_VALID (pSysMenu)//Add a separator and our menu item to system menu.CString StrMenuItem (_T ("New menu item"))pSysMenu->Appendmenu (MF_SEPARATOR)pSysMenu->AppendMenu (MF_STRING, IDM_MYSYSITEM, strMenuitem)…}现在,选择系统菜单项时用户应进行检测。使用ClassWizard处理WM_SYSCOMMAND消息并检测用户菜单的nID参数:void CMainFrame:: OnSysCommand (UINT nID,LPARAM lParam){//Determine if our system menu item was selected.if ( (nID & 0xFFF0)==IDM_MYSYSITEM){//TODO-process system menu item}elseCMDIFrameWnd ::OnSysCommand (nID, lParam)}最后,一个设计良好的UI应用程序应当在系统菜单项加亮时在状态条显示一个帮助信息,这可以通过增加一个包含系统菜单基ID的串表的入口来实现。(63) 如何确定顶层菜单所占据的菜单行数这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度;最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代码实现。int CMainFrame:: GetMenuRows (){CRect rcFrame,rcClientGetWindowRect (rcFrame)GetClientRect (rcClient)return (rcFrame.Height () -rcClient.Height () - :: GetSystemMetrics(SM_CYCAPTION) - (:: getSystemMetrics(SM_CYFRAME) *2)) / :: GetSystemMetrics(SM_CYMENU)}(64) 在用户环境中如何确定系统显示元素的颜色调用SDK函数GetSysColor可以获取一个特定显示元素的颜色。下例说明了如何在MFC函数CMainFrameWnd:: OnNcPaint中调用该函数设置窗口标题颜色。void CMiniFrameWnd:: OnNcPaint (){…dc.SetTextColor (:: GetSysColor (m_bActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT))…(65) 如何查询和设置系统参数在Windows 3.1 SDK中介绍过SDK函数SystemParametersInfo,调用该函数可以查询和设置系统参数,诸如按键的重复速率设置、鼠标双击延迟时间、图标字体以及桌面覆盖位图等等。//Create a font that is used for icon titles.LOGFONT stFont∶: SystemParametersInfo (SPIF_GETICONTITLELOGFONT, sizeof (LOGFONT), &stFont, SPIF_SENDWININICHANGE)m_font.CreateFontIndirect (&stFont)//Change the wallpaper to leaves.bmp.∶ : SystemParametersInfo (SPI_SETDESKWALLPAPER, 0, _T (" forest.bmp"), SPIF_UPDATEINIFILE)(66) 如何确定当前屏幕分辨率调用SDK函数GetSystemMetrics,该函数可以检索有关windows显示信息,诸如标题大小、边界大小以及滚动条大小等等。//Initialize CSize object with screen size.CSize sizeScreen (GetSystemMetrics (SM_CXSCREEN),GetSystemMetrics (SM_CYSCREEN))(67) 如何使用一个预定义的Windows光标调用CWinApp:: LoadStandardCursor并传送光标标识符。BOOL CSampleDialog:: OnSetCursor (CWnd* pWnd,UINT nHitTest, UINTmessage){//Display wait cursor if busy.if (m_bBusy){SetCursor (AfxGetApp () ->LoadStandardCursor (IDC_WAIT))return TRUE}return CDialog:: OnSetCursor (pWnd. nHitTest,message)}(68) 如何检索原先的Task Manager应用程序使用的任务列表原先的Task Manager应用程序显示顶层窗口的列表。为了显示该列表,窗口必须可见、包含一个标题以及不能被其他窗口拥有。调用CWnd:: GetWindow可以检索顶层窗口的列表,调用IsWindowVisible、GetWindowTextLength以及GetOwner可以确定窗口是否应该在列表中。下例将把TaskManager窗口的标题填充到列表中。void GetTadkList (CListBox&list){CString strCaption//Caption of window.list.ResetContent ()//Clear list box.//Get first Window in window list.ASSERT_VALID (AfxGetMainWnd ())CWnd* pWnd=AfxGetMainWnd () ->GetWindow (GW_HWNDFIRST)//Walk window list.while (pWnd){// I window visible, has a caption, and does not have an owner?if (pWnd ->IsWindowVisible()&& pWnd ->GetWindowTextLength ()&&! pWnd ->GetOwner ()){//Add caption o window to list box.pWnd ->GetWindowText (strCaption)list.AddString (strCaption)}//Get next window in window list.pWnd=pWnd ->GetWindow(GW_HWNDNEXT)}}(69) 如何确定Windows和Windows系统目录有两个SDK函数可以完成该功能。GetWindowsDirectory和GetSystemDirectory,下例说明了如何使用这两个函数:TCHAR szDir [MAX_PATH]//Get the full path of the windows directory.∶ : GetWindowsDirectory (szDir, MAX_PATH)TRACE ("Windows directory %s/n", szDir)//Get the full path of the windows system directory.∶ : GetSystemDirectory (szDir, MAX_PATH)TRACE ("Windows system directory %s/n", szDir)(70) 在哪儿创建临文件调用SDK函数GetTemPath可以确定临时文件的目录,该函数首先为临时路径检测TMP环境变量:如果没有指定TMP,检测TMP环境变量,然后返回到当前目录。下例说明了如何创建一个临时文件。…//get unique temporary file.CString strFileGetUniqueTempName (strFile)TRY{//Create file and write data.Note that file is closed//in the destructor of the CFile object.CFile file (strFile,CFile ::modeCreate | CFile:: modeWrite)//write data}CATCH (CFileException, e){//error opening file}END_CATCH…Void GetuniqueTempName (CString& strTempName){//Get the temporary files directory.TCHAR szTempPath [MAX_PATH]DWORD dwResult=:: GetTempPath (MAX_PATH, szTempPath)ASSERT (dwResult)//Create a unique temporary file.TCHAR szTempFile [MAX_PATH]UINT nResult=GetTempFileName (szTempPath, _T ("~ex"),0,szTempfile)ASSERT (nResult)strTempName=szTempFile}(71) 我怎样才能建立一个等待光标?调 用 BeginWaitCursor 函 数 来 启 动 等 待 光 标,调 用 EndWaitCursor 函 数 来 结 束 等 待 光 标。要 注 意,二 者 都 要 调 用 app 的 成 员 函 数,如 下 所 示:AfxGetApp()->BeginWaitCursor();// 要做的事AfxGetApp()->EndWaitCursor();(72) 我在MDI框架中有个 form 视窗。它有个取消按钮,我需要当用户按取消按钮时可关闭form视窗。我应该如何关闭该文档?调 用 OnCloseDocument 函 数。(73) 如何访问桌面窗口静态函数CWnd:: GetDesktopWindow 返回桌面窗口的指针。下例说明了MFC函数CFrameWnd::BeginModalStae是如何使用该函数进入内部窗口列表的。void CFrameWnd::BeginModalState (){…//first count all windows that need to be disabledUINT nCount=0HWND hWnd= :: GetWindow (:: GetDesktopWindow(), GW_CHILD)while (hWnd!=NULL){if (:: IsWindowEnabled (hwnd)&& CWnd::FromHandlePermanent (hWnd)!=NULL&& AfxIsDescendant (pParent->m_hWnd, hWnd)&& :: SendMessage (hWnd, WM_DISABLEMODAL, 0, 0)==0){++nCount}hWnd=:: GetWindow (hWnd, GW_HWNDNEXT)}…(74) 什么是COLORREF? 我该怎样用它?COLORREF 是 一 个 32-bit 整 型 数 值,它 代 表 了 一 种 颜 色。你 可 以 使 用 RGB 函 数 来 初 始 化 COLORREF。例 如:COLORREF color = RGB(0, 255, 0);RGB 函 数 接 收 三 个 0-255 数 值,一 个 代 表 红 色, 一 个 代 表 绿 色, 一 个 代 表 蓝 色。在 上 面的 例 子 中, 红 色 和 蓝 色 值 都 为 0,所 以 在 该 颜 色 中 没 有 红 色 和 蓝 色。绿 色 为 最 大 值 255。所 以 该 颜 色 为 绿 色。0,0,0 为 黑 色,255,255,255 为 白 色。另 一 种 初 始 化 COLORREF 的 方 法 如 下 所 示:CColorDialog colorDialog;COLORREF color;if( colorDialog.DoModal() == IDOK ){color = colorDialog.GetColor();}这 段 代 码 使 用 了 MFC 中 的 颜 色 对 话 框,它 需 要 文 件。(75) AppWizard所产生的STDAFX文件是干什么用的?它 主 要 是 协 助 产 生 预 编 译 头 文 件 的。通 常 你 是 不 需 要 修 改 它 的。(76) 我在我的程序中是了CDWordArray。我向它添加了约10,000个整数,这使得它变得非常非常慢。为什么会这么糟?CDWordArray 是 很 好 用 的,只 是 因 为 你 没 有 指 定 数 组 的最大尺寸。因 此,当 你 添 加 新 元 素 时,该 类 会 从 堆 中 重 新 分 配 空 间。不 幸 的 是,该 类 会 在 每 次 插 入 新 元 素 时 都 为 数 组 重 新 分 配 空 间。如 果 你 向 它 添 加 了 很 多 新 元 素,所 有 这 些 分 配 和 复 制 数 组 的 操 作 会 就 会 使 它 变 慢。解 决 该 问 题 的 方 法 是,你 可 以 使 用 SetSize 函 数 的 第 二 个 参 数 来 改 变 这 种 重 新 分 配 的 频 率。例 如,如 果 你 把 该 参 数 设 置 为 500,则 每 次 数 组 空 间 超 出 时 它 才 重 新 分 配 并 添 加 500 个 新 空 间,而 不 是 1 个。这 样 一 来,你 就 可 以 不 用 重 新 分 配 而 添 加 了 另 外 499 个 元 素 空 间,这 也 会 大 大 提 高 程 序 的 运 行 速 度。(77) 我该如何改变MDI框架窗口的子窗口的大小以使在窗口以一定的大小打开?在 视 中 的 OnInitialUpdate 函 数 中 调 用 GetParentFrame 函 数。GetParentFrame 会 返 回 一 指 向 一 保 存 有 该 视 的 框 架 窗 口 的 指 针。然 后 调 用 在 框 架 窗 口 上 调 用 MoveWindow。(78) 在我的程序的某些部分,我可以调用 MessageBox 函数来建立一个信息对话框,例如在视类中。但是,在其它部分我却不能,如文档类中。为什么?我怎样才能在我的应用程序类中建立一个信息对话框?MessageBox 函 数 来 自 CWnd 类,所 以 你 只 能 在 从 CWnd 继 承 的 类 ( 如 CView ) 中 调 用 它。但 是,MFC 也 提 供 了 AfxMessageBox 函 数,你 可 以 在 任 何 地 方 调 用 它。(79) 我需要在我的程序中设置全局变量,以使文档中的所有类都能访问。我应该吧它放到哪儿?把 该 变 量 放 到 该 应 用 程 序 类 的 头 文 件 中 的 attribute 处。然 后,在 程 序 的 任 何 地 方,你 都 可 以 用 下 面 的 方 法 来 访 问 该 变 量:CMyApp *app = (CMyApp *)AfxGetApp();app->MyGlobalVariable = ...(80) 我听说MFC可以发现内存漏洞,我怎样使用该特性?如 果 你 在 Debug 菜 单 中 的 Go 选 项 ( 不 是 Project 菜 单 中 的 Execute 选 项 ) 来 运 行 你 的 应 用 程 序,MFC 应 该 在 程 序 终 止 时 报 告 内 存 漏 洞。如 果 没 有,那 么 试 试 运 行 MFC Tracer 工 具 程 序 ( 在 VC++ 程 序 组 中 ),并 启 动 跟 踪。然 后 返 回 应 用 程 序。(81) 我怎样才能在我的应用程序中循环浏览已经打开的文档?使用CDocTemplate中未公开的GetFirstDocPosition()和GetNextDoc()函数。 (82)才能在我的应用程序中循环浏览已经打开的视?使 用 CDocument 中 未 公 开 的 GetFirstViewPosition() 和 GetNextView() 函 数。(83)数PreCreateWindow是干什么用的?PreCreateWindow 允 许 你 在 调 用 CreateWindow 之 前 来 改 变 窗 口 属 性。(84)该怎样防止MFC在窗口标题栏上把文档名预置成应用程序名?在 PreCreateWindow 函 数 中 删 除 FWS_PREFIXTITLE 标 志 的 窗 口 样 式:cs.style &= ~FWS_PREFIXTITLE;(85) 我应该怎样防止MFC在窗口标题栏上添加文档名?在 PreCreateWindow 函 数 中 删 除 FWS_ADDTOTITLE 标 志 的 窗 口 样 式:cs.style &= ~FWS_ADDTOTITLE ;(86) 我应该如何改变视窗口的大小?因 为 视 窗 口 实 际 上 是 框 架 窗 口 的 子 窗 口,所 以 你 必 须 改 变 框 架 窗 口 的 大 小,而 不 是 改 变 视 窗 口。使 用 CView 类 中 的 GetParentFrame() 函 数 获 得 指 向 框 架 窗 口 的 指 针,然 后 调 用 MoveWindow() 函 数 来 改 变 框 架 的 大 小。这 会 使 变 尺 寸 的 视 充 满 框 架 窗 口。(87) 我有一无模式对话框。我怎样才能在窗口退出时删除CDialog对象?把"delete this"加 到 PostNcDestroy 中。这 主 要 用 在 需 要 自 动 删 除 对 象 的 场 合。(88) 为什么把"delete this"放在PostNcDestroy中而不是OnNcDestroy?OnNcDestroy 只 被 已 建 立 的 窗 口 调 用。如 果 建 立 窗 口 失 败 ( 如 PreCreateWindow ),则 没 有 窗 口 处 来 发 送 WM_NCDESTROY 消 息。PostNcDestroy 是 在 对 象 窗 口 被 完 全 删 除,在 OnNcDestroy 后,甚 至 在 窗 口 建 立 失 败 之 后 调 用 的。(89) File菜单中的MRU列表是从哪儿来的?列表中的名字放在哪儿了?我怎样才能改变列表中项目的最大值?在 应 用 程 序 类 的 InitInstance 函 数 中 对 LoadStdProfileSettings 的 调 用 中。该 调 用 接 受 一 个 参 数 ( 在 缺 省 情 况 下 如 果 没 有 传 递 值 则 为 4 )。MRU 文 件 名 是 从 INI 文 件 中 调 用 的。如 果 你 有 带 有 ID_FILE_MRU_FILE1 的 ID 的 菜 单 选 项,它 会 为 调 入 的 MRU 列 表 所 替 换。如 果 你 改 变 传 递 给 LoadStdProfileSettings 的 数 值 ( 最 大 为 16 ),则 你 就 改 变 了 所 装 如 文 件 名 的 最 大 值。(90) 我在菜单中添加了新的项。但是,当我选该项时,在状态栏上没有出现任何提示信息。为什么?打 开 资 源 文 件 中 的 菜 单 模 板。打 开 新 菜 单 选 项 的 属 性 对 话 框。在 对 话 框 的 底 部 的 Prompt 编 辑 框 中 ,你 可 以 如 下 指 定 状 态 栏 上 的 提 示 信 息 和 工 具 栏 上 的 提 示 信 息 ( 如 果 你 已 经 建 立 的 工 具 栏 按 钮 ):Status bar string/nFlying tag(91) 我怎样才能在应用程序的缺省系统菜单中加上一些东西?系 统 菜 单 与 其 它 菜 单 类 似,你 可 以 添 加 或 删 除 项 目,这 需 要 使 用 CMenu 类 的 成 员 函 数。下 面 的 代 码 在 你 的 系 统 菜 单 后 面 添 加 一 个 新 菜 单 项:CMenu *sysmenu;sysmenu = m_pMainWnd->GetSystemMenu(FALSE);sysmenu->AppendMenu(MF_STRING, 1000, "xxx");参 见 MFC 帮 助 文 件 中 的 CMenu 类。(92) 我建立了一个对话框。但是当我显示该对话框时,第一个编辑框总是不能获得焦点,我必须单击它来使它获得焦点。我怎样才能使第一个编辑框在对话框打开时就获得焦点?打 开 资 源 编 辑 器 中 的 对 话 框 模 板。在 Layout 菜单 中 选 择 Tab Order 选 项。按 你 的 需 求 单 击 对 话 框 中 的 控 制 来 重 新 排 列 这 些 控 制 的 tab 顺 序。(93) 我怎样才能使一个窗口具有"always on top"特性?在 调 用 OnFileNew 后,在 你 的 InitInstance 函 数 中 加 上 下 面 的 代 码:m_pMainWnd->SetWindowPos(&CWnd::wndTopMost,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);(94) 我要为我的form view添加文档模板。我先建立了对话框模板,然后使用ClassWizard建立了基于CFormView的新类,它也是从CDocument继承来的。我还建立了相应的资源并在InitInstance中添加了新的文档模板。但是,当我试图运行该程序时,出现了Assertion信息。为什么?form 的 对 话 框 模 板 需 要 些 特 殊 设 置 以 便 可 用 于 CFromView。确 保 这 些 设 置 的 最 简 单 方 法 是 使 用 AppWizard 来 建 立 CFormView 应 用 程 序,并 查 看 AppWizard 所 建 立 的 对 话 框 模 板 所 选 择 的Styles Properties。你 会 发 现 该 对 话 框 模 板 具 有 下 列 样 式:没 有 标 题 栏、不 可 见 和"Child"。把 你 的 form view 的 对 话 框 属 性 变 成 这 样 就 可 以 了。(95) 我在一对话框中有一列表框,我需要tabbed列表框中的项目。但是,当我处理含有tab字符(用AddString添加的)的列表项时,tab被显示成小黑块而没有展开。哪儿出错了?在 对 话 框 模 版 中,打 开 列 表 框 的 属 性。确 保 选 择 了"Use Tabstops" 样 式。然 后,确 保 在 对 话 框 类 中 OnInitDialog 函 数 中 调 用 SetTabStops。(96) 我建立了一个应用程序,并使用了CRecordset类。但是,当我运行该程序时,它试图要访问数据库,并给出"Internal Application Error"对话框。我应该怎样做?通 常 情 况 下,当 你 的 程 序 中 向 数 据 库 发 送 信 息 的 SQL 语 句 出 现 问 题 时 才 出 现 该 对 话 框。例 如,参 见 下 面 的 例 子:set.m_strFilter = "(ZipCode = '27111')";如 果 ZipCode 列 被 定 义 为 字 符 串 时 不 会 出 现 问 题,如 果 定 义 为 long,则 会 出 现"Internal Application Error"对 话 框,这 是 由 于 类 型 不 匹 配 的 缘 故。如 果 你 删 除 27111 的 单 引 号,则 不 会 出 现 问 题。当 你 看 到"Internal Application Error"时,最 好 检 查 一 下 试 图 要 发 送 给 数 据 库 的 SQL 语 句。(97) 我用ClassWizard建立了一个类。但是,我把名字取错了,我想把它从项目中删除,应该如何做?在 ClassWizard 对 话 框 关 闭 后,用 文 件 管 理 器 删 除 新 类 的 H 和 CPP 文 件。然 后 打 开 ClassWizard,它 会 提 示 丢 失 了 两 个 文 件,并 询 问 你 该 如 何 做。你 可 以 选 择 从 项 目 中 删 除 这 两 个 问 的 按 钮。(98) 当我打开应用程序中的窗口时,我要传递该窗口的矩形尺寸。该矩形指定了窗口的外围大小,但是当我调用GetClientRect时,所得到的尺寸要比所希望的值要小(因为工具栏和窗口边框的缘故)。有其它方法来计算窗口的尺寸吗?参 见 CWnd::CalcWindowRect。(99) 我在文档类中设置了一个整型变量。但是,当我试图把该变量写入Serialize函数中的archive文件中时,出现了类型错误。而文档中的其它变量没有问题。为什么?archive 类 只 重 载 某 些 类 型 的 >> 和 << 操 作 符。"int"类 型 没 有 在 其 中,也 许 是 因 为 int 变 量 在 Windows 3.1 与 Windows NT/95 有 所 不 同 的 缘 故 吧。"long"类 型 得 到 了 支 持,所 以 你 可 以 把 int 类 型 改 成 long 型。参 见 MFC 帮 助 文 件 中 CArchive 类。(100) 如何控制菜单的大小?我用MFC的CMenu生成了一个动态菜单(例如File,Edit,View...Help), 我想控制这个菜单的大小(长+高).方法一:查找 WM_MEASUREITEM 和 MEASUREITEMSTRUCT.方法二:查询系统::GetSystemMetric(SM_CXMENUSIZE)./* 你可以通过如下代码来获得文本的大小:(A)获得被使用的字体 */NONCLIENTMETRICS ncm;HFONT hFontMenu;SIZE size;size.cy = size.cy = 0;memset(&ncm, 0, sizeof(NONCLIENTMETRICS));ncm.cbSize = sizeof(NONCLIENTMETRICS);if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0)){hFontMenu = CreateFontIndirect(&ncm.lfMenuFont);/*(B) 获得菜单项的文本: */char szText[_MAX_PATH];pMenu->GetMenuString(0, szText, _MAX_PATH, MF_BYPOSITION);/*然后,获得菜单项文本的高度: */HFONT hFontOld;HDC hDC;hDC = ::GetDC(NULL);hFontOld = (HFONT) ::SelectObject(hDC, hFontMenu);GetTextExtentPoint32(hDC, szText, lstrlen(szText), &size);SelectObject(hDC, hFontOld);::ReleaseDC(NULL, hDC);}/*此时,size.cy即为高度,size.cx为宽度,你可以给菜单加上自定义的高度和宽度,通过比较,我发现宽度为4比较合适。*/(101) 改变LVIS_SELECTED的状态颜色?我想将CListCtrl项和CTreeCtrl项在LVIS_SELECTED状态时的颜色变灰.方法一:查找函数CustomDraw,它是IE4提供的公共控制,允许有你自己的代码.方法二:生成一个draw控件,然后在DrawItem中处理文本颜色.(102) 如何只存储文档的某一部分?我只想存储文档的某一部分,能否象使用文件一样使用文档?(也就是有定位函数).将每个CArchive类设置为CFile类的派生类,这样你就能使用Seek等成员函数.(103) 保存工具条菜单有bug吗?使用浮动菜单条时,SaveBarState和LoadBarState出现了问题.如果菜单是浮动的,重起应用程序时它会出现在左上角,而它固定在屏幕其它位置时,下一次启动就会出现在该位置,这是什么原因?你试试这个PToolBar->Create(this,...,ID_MYTOOLBAR);你的工具条需要包括id,而不是象默认的工具条那样.(104) Tip of the day的bug我创建了一个简单的mdi应用程序,使用.BSF(自定义的文档扩展名)作为它的文档我保存一个foo.bsf文档后,可以在资源管理器中双击该文件打开mdi应用程序同时打开foo.bsf文档.但当我给mdi应用程序加上a tip of the day组件之后,从资源管理器中双击foo.bsf后,就会给我一个警告:ASSERT(::IsWindow(m_hWnd)),然后mdi应用程序就死那了.当从dde启动应用程序(例如:双击相关文档)时,"Tip of the Day"是有bug的.你可以看看函数"ShowTipAtStartup",它在"InitInstance"中调用,可以看到tip of the day作为一个模式对话框显示,在处理其它消息时它一直进行消息循环你可心修改ShowTipAtStartup使其从dde启动时不出现tip of the day.void CTipOfApp::ShowTipAtStartup(void){// CG: This function added by 'Tip of the Day' component.CCommandLineInfo cmdInfo;ParseCommandLine(cmdInfo);if (cmdInfo.m_bShowSplash &&cmdInfo.m_nShellCommand != CCommandLineInf:FileDDE){CTipDlg dlg;if (dlg.m_bStartup)dlg.DoModal();}}如果还有其它bug,你可以设定cmdInfo.m_nShellCommand的过滤.(105) 如何可以让我的程序可以显示在其它的窗口上面?让用户选择"总是在最上面"最好是在系统菜单里加入一个选项.可以通过修改WM_SYSCOMMAND消息来发送用户的选择.菜单的命令标识(id)会作为一个参数传给OnSysCommand().要定义标识(id),将如下代码加入到CMainFrame.CPP中:#define WM_ALWAYSONTOP WM_USER + 1将"总在最上面"的菜单项加入到系统菜单中,将如下代码加入到函数CMainFrame::OnCreate()中:CMenu* pSysMenu = GetSystemMenu(FALSE);pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, WM_ALWAYSONTOP,"&Always On Top");使用ClassWizard,加入对WM_SYSCOMMAND消息的处理,你应该改变消息过滤器,使用系统可以处理这个消息.void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam){switch ( nID ){case WM_ALWAYSONTOP:if ( GetExStyle() & WS_EX_TOPMOST ){SetWindowPos(&wndNoTopMost, 0, 0, 0, 0,SWP_NOSIZE | SWP_NOMOVE);GetSystemMenu(FALSE)->CheckMenuItem(WM_ALWAYSONTOP,MF_UNCHECKED);}else{SetWindowPos(&wndTopMost, 0, 0, 0, 0,SWP_NOSIZE | SWP_NOMOVE);GetSystemMenu(FALSE)->CheckMenuItem(WM_ALWAYSONTOP,MF_CHECKED);}break;default:CFrameWnd::OnSysCommand(nID, lParam);}}(106) 如何控制窗口框架的最大最小尺寸?要控制一个框架的的最大最小尺寸,你需要做两件事情.在CFrameWnd的继承类中处理消息WM_GETMINMAXINFO,结构MINMAXINFO设置了整个窗口类的限制,因此记住要考虑工具条,卷动条等等的大小.// 最大最小尺寸的象素点 - 示例#define MINX 200#define MINY 300#define MAXX 300#define MAXY 400void CMyFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI){CRect rectWindow;GetWindowRect(&rectWindow);CRect rectClient;GetClientRect(&rectClient);// get offset of toolbars, scrollbars, etc.int nWidthOffset = rectWindow.Width() - rectClient.Width();int nHeightOffset = rectWindow.Height() - rectClient.Height();lpMMI->ptMinTrackSize.x = MINX + nWidthOffset;lpMMI->ptMinTrackSize.y = MINY + nHeightOffset;lpMMI->ptMaxTrackSize.x = MAXX + nWidthOffset;lpMMI->ptMaxTrackSize.y = MAXY + nHeightOffset;}第二步,在CFrameWnd的继承类的PreCreateWindow函数中去掉WS_MAXIMIZEBOX消息,否则在最大化时你将得不到预料的结果.BOOL CMyFrameWnd::PreCreateWindow(CREATESTRUCT& cs){cs.style &= ~WS_MAXIMIZEBOX;return CFrameWnd::PreCreateWindow(cs);}(107) 如何改变窗口框架的颜色?MDI框架的客户区被另一个窗口的框架所覆盖.为了改变客户区的背景色,你需要重画这个客户窗口.为了做到这点,你要处理消息WM_ERASEBKND产生一个新类,从CWnd继承,姑且称之为CMDIClient.给它加上一个成员变量,#include "MDIClient.h"class CMainFrame : public CMDIFrameWnd{...protected:CMDIClient m_wndMDIClient;}在CMainFrame中重载CMDIFrameWnd::OnCreateClientBOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext){if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) ){m_wndMDIClient.SubclassWindow(m_hWndMDIClient);return TRUE;}elsereturn FALSE;}然后就可以加入对消息WM_ERASEBKGND的处理了.(108) 如何将应用程序窗口置于屏幕正中?要将你的应用程序窗口放置在屏幕正*,只须在MainFrame的OnCreate函数中加入:CenterWindow( GetDesktopWindow() );阅读全文(26次) / 评论 / 丢小纸条 / 文件夹: VC学习 收藏: QQ书签 del.icio.us / 订阅: Google 抓虾
在VC中链接动态链接库(DLL)的方法痞子 @ 2007-03-16 10:18
方法一:windows提供了一套函数,用于加载动态链接库中的符号(函数和变量),调用这些函数去加载:1. HINSTANCE LoadLibrary( LPCTSTR lpLibFileName);2. FARPROC GetProcAddress( HMODULE hModule, LPCWSTR lpProcName);3. BOOL FreeLibrary( HMODULE hLibModule);这最直观的一种方法,同时也是最麻烦的一种办法。方法二:让调用者的工程依赖于动态链接库工程。步骤如下:1. 让调用者的工程处于active状态下。2. 打依赖设置对话框:Project-->dependencies。3. 选择动态链接库工程。这种方法比较方便,但要求有DLL的项目文件。方法三:直接把动态链接库产生的.lib文件加入到调用者的工程中。方法四:进入Link设置:Project-->settings-->Link,选择Categery中的Input,在object/library modules里输入的动态链接库对应的.lib文件名,在Additional library path中输入动态链接库对应的.lib的路径。方法五:#pragma (lib, "filename.lilb")
阅读全文(24次) / 评论 / 丢小纸条 / 文件夹: VC学习 收藏: QQ书签 del.icio.us / 订阅: Google 抓虾
vc读写文本文件痞子 @ 2007-03-14 16:52一. CStdioFile (MFC类库) 该类由CFile继承而来 (1)打开文本文件 virtual BOOL Open( LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL ); lpszFileName: 路径名 nOpenFlags: 打开方式 ( 常用打开方式: CFile::modeRead Opens the file for reading only. CFile::modeReadWrite Opens the file for reading and writing. CFile::modeWrite Opens the file for writing only. CFile::modeCreate Directs the constructor to create a new file. If the file exists already, it is truncated to 0 length. ) (2)读取文本行 BOOL ReadString(CString& rString); 将读取的文本放在rString.(注意:此时已除去字符串结尾处的换行符'/n') 如果为文件结尾,则返回FALSE (3)写文本行 void WriteString( LPCTSTR lpsz ); (4)获得当前位置(按字节算,即当前指到哪个字节) virtual DWORD GetPosition( ) const; (5)文本定位(按字节算,即当前指到哪个字节) virtual LONG Seek( LONG lOff, UINT nFrom ); ( nFrom: CFile::begin Move the file pointer lOff bytes forward from the beginning of the file. CFile::current Move the file pointer lOff bytes from the current position in the file. CFile::end Move the file pointer lOff bytes from the end of the file. Note that lOff must be negative to seek into the existing file; positive values will seek past the end of the file. ) (6)例子: 输出文本内容 CStdioFile f; CString GFilePath="D:/GeneratorInfo.txt" f.Open(GFilePath,CFile::modeReadWrite); while(f.ReadString(str)) { cout<<(LPCTSTR)str<); //输出格式的设定 file.WriteString(datas); //写数据 file.WriteString("/n"); file.Close(); //写完数据后要将文件关闭 假如z=0,w=10,i=0,jfcha[z][w]=0.00345; 运行程序后,就能在工程目录下,找到一个名为test.txt的文本文件,打开一看,就能看到 jfcha[0][10][0]=3.45*E-3 --------------------------------------vc++的编程不容易,有时候想实现打开一个文本文件这么简单的功能都挺麻烦的(相对DELPHI),在网上找到一个例子,经修正后列出来。void CMainFrame::OnFileOpen(){//显示文件打开对话框CFileDialog dlg(TRUE, "SQL", "*.txt",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"Text Files(*.txt)|*.txt|SQL Files(*.sql)|*.sql|All Files(*.*)|*.*||");if ( dlg.DoModal()!=IDOK ) return;//获取文件的绝对路径CString sFileName=dlg.GetPathName();//打开文件CStdioFile out;out.Open(sFileName, CFile::modeRead);CString sSql="",s;//读取文件do{out.ReadString(s);sSql=sSql+s+(char)10;}while (out.GetPosition()!=out.GetLength());out.Close();AfxMessageBox(sSql); }另外还有一个保存的例子,不过还没经过亲自测试:/************************************************** 写文本文件**************************************************///显示文件保存对话框CFileDialog dlg(FALSE, "SQL", "*.txt",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"Text Files(*.txt)|*.txt|SQL Files(*.sql)|*.sql|All Files(*.*)|*.*||"); if ( dlg.DoModal()!=IDOK ) return;//获取文件的绝对路径CString sFileName=dlg.GetPathName();CStdioFile out;//打开文件out.Open(sFileName, CFile::modeCreate | CFile::modeWrite);//保存文件CString sSql="文本文件内容";out.WriteString(sSql);out.Close();-----------------------------------------如何用VC将文本文件中的一列数字读取到数组中 我用下边的程序打开了存有数据的文本文件CFileDialog dlg(TRUE,"txt","*.txt", //TRUE为"打开文件"窗口 OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, "信号数据文件(*.txt)|*.txt|所有文件(*.*)|*.*||",NULL); if(dlg.DoModal()==IDOK){ CString FileName=""; FileName=dlg.GetPathName(); //取文件所在的完整路径 CFile file; file.Open(FileName,Cfile::modeReadWrite); //以读写方式打开文件 buf1=new char [file.GetLength()]; //为指针动态分配堆栈 file.Read(buf1,file.GetLength()); //将数据读取到内存 m_nData1Len=file.GetLength(); //获取文件长度 file.Close(); //关闭文件能不能用其中定义的指针char*buf1读出数据我用A[i]=atof(buf1[i])为什么不能运行提示错误为 error C2664: 'atof' : cannot convert parameter 1 from 'char' to 'const char *' Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast请帮忙看看怎么把buf1[i]中的数据读出来.阅读全文(331次) / 评论 / 丢小纸条 / 文件夹: VC学习 收藏: QQ书签 del.icio.us / 订阅: Google 抓虾
MSFlexGrid控件使用摘要痞子 @ 2007-03-09 16:34l ActiveX空件 ActiveX空件是一个软件组件,建立在COM技术上,在说明ActiveX原理之前不得不提提vtable. MFC的消息与函数也是有类似的vtable.如: WM_PAINT ---àOnPaint(); WM_QUIT-----àOnOK(); ……….to be more………. 这个vtable里每一个消息就对应一个处理函数.ActiveX的vtable叫IDispatch vtable.这个vtable存了对应的接口id和处理函数。ActiveX伟大之处就在于这个接口连接工作是自动化的。 使用ActiveX空件最终就是为了实现"嵌入"。如:Excel 嵌入到 Word里面。媒介是COM技术。 l ActiveX容器与ActiveX服务器 这两个概念很容易搞乱,上例中Excel就是服务器,Word就是容器。ActiveX使用方法很简单,深入研究其原理,似乎没有必要。ActiveX空件最麻烦的一件事就是使用前要注册该ActiveX空件。 l ActiveX空件的注册 首先给WINDOWS注册:运行-àregsvr32 c:/windows/system32/msflxgrd.ocx 接着给VC++6.0注册:选择工程,再选增加到工程(工程已经存在的情况下),再选components and control,再选Registered ActiveX Controls目录,再选msflexgrid。点ok。 l ActiveX的自设成员变量 出于保护ActiveX空件,只能有一个对象型的,或者讲空件型的自设成员变量。 l MSFlexGrid控件使用摘要SetRows及SetCols: 设置控件的行列数,如果你不往各行列中插入数据,表格将为指定行列数的空表. 大多数情况下,在往表格中插入数据时必须先确保表格的行列数能容纳你要插入的行列数, 不过当你用的是AddItem方法时,你可以不必手工增加行数(列数还是要先设置好的),因为 它会增加控件的行列数.GetRows及GetCols:获取控件的行列数。SetRow及SetCol:设置控件的当前格(由行号及列号指定)SetText:设置控件的当前格的内容.SetTextMatrix:设置指定格(由行号及列号指定)中的内容SetTextArray:功能与SetTextMatrix相同,但指定格的位置的方式与SetTextMatrix不同, SetTextMatrix是 通过二维表中的行列索引来表示,而SetTextArray用一维索引来表示,其原理与C语言中访问 二维数组的方式相同,如:对于Table[N][M], Table[3][2]以一维方式表示为Table[3*M+2]. (我未实验:不完全可信)AddItem:在控件中增加一行,行中各字段以tab字符相隔,不能用本方法来增加控件的第一行(固定行或表头), 它将导致控件的行数自动加一.Clear:清除控件中的所有内容(不改变控件的原有行列数)GetRowSel及GetColSel:获取控件的当前行、列,没有当前行(即表格为空)时,返回值为-1。 l 看了上边的东西包你不会用,哈哈,我们来看些实际点的东西. Id 学生名字 性别 年龄
200501 老鼠 男 22
200502 美女 女 22
200503 小强 男 22
我们将会以这个表作为假设MSFlexGrid控件的使用方法,因为这个空件的使用太重要了,必须要掌握.这个表行数有0',0,1,2 ; 列数有 0',0,1,2 . 0' 行是字段行,第一点我们要学会计算格子,这里有9个格子(字段行除外),每个格子都有它们自己的"ID",比喻说"200502"是5号格子, 老鼠是2号格子. 我们自然会想到,这些格子与"行"标和"列"标有何关系呢.?看公式: cell()=(行标x 4 +列标). 由于上面一大堆函数它们直接操作对象是格子(cell),比如说其中最重要的一个成员函数SetTextArray(格子,字符串或值)向表格填入数据.另外有些以Get字头的空参数函数,这使用起来的确很方便,不过还得知道它们是什么意思. 这里还介绍多两三个函数如:GetFixedRow()这个是获得字段行标,如这里的第0' 行. SetMergeCol(行标,值)这个函数则是用来合拼单元格的,同一列中邻近的格子具有相同的值的合拼.如上表,3个人的年龄都系22岁.那么我们可以这么做: SetMergeCol(0,true); SetMergeCol(1,true); SetMergeCol(2,true); l 随即函数 看这行代码:"Srand( (unsigned) time(NULL) )"这个语句会产生一些数值以参数形式传递给rand()函数.看msdn的一个例子: ///////////////////////////////////////////////////////////////// #include <stdlib.h> #include <stdio.h> #include <time.h> void main( void ) { int i; srand( (unsigned)time( NULL ) ); for( i = 0; i < 10;i++ ) printf( " %6d/n", rand() ); }//这里会输出10个随即数 /////////////////////////////////////////////////////////////////// l 今天的题设: 画一个对话框MyDlg,添加一个ActiveX控件msflexgrid,并为它设置如下属性: ID标式符: IDC_MYGRID Rows行数: 20 Cols列数:4 MergeCells:2-Restric Rows Format:<Region|<Product|<Emploee|>Sales //这里是添加字段名,就好比为第0' 行赋值。这4个英文单词的意思是地区、产品、销售员、卖出,假如你喜欢写成中文吧。 最后就是为控件添加成员变量m_ctlMygrid l 我们首先为单元格计算公式,创建一个函数Mycell() cell()=(行标x 4 +列标),不过我们改一改,改成cell()=(行标x 总列数 +列标),这样就更一般了。这条公式是我们先前讨论过的,View面版选MyDlg类,右击选插入函数,函数返回值填int , 函数声明Mycell(int m_iRow,int m_iCol)成了,,现在写代码: /////////////////////////////////////// Int MyDlg:: Mycell(int m_iRow,int m_iCol) { int i; i=m_ctlMygrid.GetCols(); //获得当前总列数。 return m_iRow*i+m_iCol ; } //////////////////////////////////////////////////////////////////////// l 接下来书上创建了一个函数,把随即数填入表格。 这里主要是一个SetTextArray(单元格,值)函数的运用。 如: m_ctlMygrid.SetTextArray(7,"baby"),这样就向7号单元格填入了baby字样。 这里相信好理解。 l 获得当前单元格 打开精灵class winzard,选IDC_MYGRID,消息选Click.然后填加函数 代码如下: //////////////////////////////////////////////////////////////////////// int i,j; i=m_ctlMygrid.GetMouseRow ; j=m_ctlMygrid_GetMouseCol; Mycell(i,j ); m_flexManage.Clear();//清空 m_flexManage.SetRows(tatalrow);//设置总函数 m_flexManage.SetColWidth(0l,600);//设置第零列的宽度 m_flexManage.SetTextMatrix(0,0L,"test");//设置0列0行的内容 m_flexManage.SetRow(rowcount); //定位到rowcount行 m_flexManage.SetCol(colcount); //定位到colcount列 m_flexManage.SetCellAlignment(0);//对齐方式 //一般要用到此控件的Click消息函数 OnClickMsflexgrid1(); CString str=(char*)_bstr_t(m_flexManage.GetRow());//得到当前行 m_flexManage.SetTopRow(toprow);//设置top row,可以实现自动滚动 阅读全文(91次) / 评论 / 丢小纸条 / 文件夹: VC学习 收藏: QQ书签 del.icio.us / 订阅: Google 抓虾
VC常用数据类型使用转换详解痞子 @ 2007-03-09 11:18我们先定义一些常见类型变量借以说明 int i = 100; long l = 2001; float f=300.2; double d=12345.119; char username[]="女侠程佩君"; char temp[200]; char *buf; CString str; _variant_t v1; _bstr_t v2; 一、其它数据类型转换为字符串 短整型(int) itoa(i,temp,10);///将i转换为字符串放入temp中,最后一个数字表示十进制 itoa(i,temp,2); ///按二进制方式转换 长整型(long) ltoa(l,temp,10); 二、从其它包含字符串的变量中获取指向该字符串的指针 CString变量 str = "2008北京奥运"; buf = (LPSTR)(LPCTSTR)str; BSTR类型的_variant_t变量 v1 = (_bstr_t)"程序员"; buf = _com_util::ConvertBSTRToString((_bstr_t)v1); 三、字符串转换为其它数据类型 strcpy(temp,"123"); 短整型(int) i = atoi(temp); 长整型(long) l = atol(temp); 浮点(double) d = atof(temp); 四、其它数据类型转换到CString 使用CString的成员函数Format来转换,例如: 整数(int) str.Format("%d",i); 浮点数(float) str.Format("%f",i); 字符串指针(char *)等已经被CString构造函数支持的数据类型可以直接赋值 str = username; 五、BSTR、_bstr_t与CComBSTR CComBSTR、_bstr_t是对BSTR的封装,BSTR是指向字符串的32位指针。 char *转换到BSTR可以这样: BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上头文件comutil.h 反之可以使用char *p=_com_util::ConvertBSTRToString(b); 六、VARIANT 、_variant_t 与 COleVariant VARIANT的结构可以参考头文件VC98/Include/OAIDL.H中关于结构体tagVARIANT的定义。 对于VARIANT变量的赋值:首先给vt成员赋值,指明数据类型,再对联合结构中相同数据类型的变量赋值,举个例子: VARIANT va; int a=2001; va.vt=VT_I4;///指明整型数据 va.lVal=a; ///赋值 对于不马上赋值的VARIANT,最好先用Void VariantInit(VARIANTARG FAR* pvarg);进行初始化,其本质是将vt设置为VT_EMPTY,下表我们列举vt与常用数据的对应关系: unsigned char bVal; VT_UI1 short iVal; VT_I2 long lVal; VT_I4 float fltVal; VT_R4 double dblVal; VT_R8 VARIANT_BOOL boolVal; VT_BOOL SCODE scode; VT_ERROR CY cyVal; VT_CY DATE date; VT_DATE BSTR bstrVal; VT_BSTR IUnknown FAR* punkVal; VT_UNKNOWN IDispatch FAR* pdispVal; VT_DISPATCH SAFEARRAY FAR* parray; VT_ARRAY|* unsigned char FAR* pbVal; VT_BYREF|VT_UI1 short FAR* piVal; VT_BYREF|VT_I2 long FAR* plVal; VT_BYREF|VT_I4 float FAR* pfltVal; VT_BYREF|VT_R4 double FAR* pdblVal; VT_BYREF|VT_R8 VARIANT_BOOL FAR* pboolVal; VT_BYREF|VT_BOOL SCODE FAR* pscode; VT_BYREF|VT_ERROR CY FAR* pcyVal; VT_BYREF|VT_CY DATE FAR* pdate; VT_BYREF|VT_DATE BSTR FAR* pbstrVal; VT_BYREF|VT_BSTR IUnknown FAR* FAR* ppunkVal; VT_BYREF|VT_UNKNOWN IDispatch FAR* FAR* ppdispVal; VT_BYREF|VT_DISPATCH SAFEARRAY FAR* FAR* pparray; VT_ARRAY|* VARIANT FAR* pvarVal; VT_BYREF|VT_VARIANT void FAR* byref; VT_BYREF _variant_t是VARIANT的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。 例如: long l=222; ing i=100; _variant_t lVal(l); lVal = (long)i; COleVariant的使用与_variant_t的方法基本一样,请参考如下例子: COleVariant v3 = "字符串", v4 = (long)1999; CString str =(BSTR)v3.pbstrVal; long i = v4.lVal; 七、其它 对消息的处理中我们经常需要将WPARAM或LPARAM等32位数据(DWORD)分解成两个16位数据(WORD),例如: LPARAM lParam; WORD loValue = LOWORD(lParam);///取低16位 WORD hiValue = HIWORD(lParam);///取高16位 对于16位的数据(WORD)我们可以用同样的方法分解成高低两个8位数据(BYTE),例如: WORD wValue; BYTE loValue = LOBYTE(wValue);///取低8位 BYTE hiValue = HIBYTE(wValue);///取高8位 阅读全文(34次) / 评论 / 丢小纸条 / 文件夹: VC学习 收藏: QQ书签 del.icio.us / 订阅: Google 抓虾
VC用ADO访问数据库全攻略痞子 @ 2007-03-09 10:22介绍VC用ADO访问数据库全攻略,介绍了VC用ADO来访问数据库的各个对象及各方法,很经典,也很实用,很值得一看。 正文一、ADO概述ADO是Microsoft为最新和最强大的数据访问范例 OLE DB 而设计的,是一个便于使用的应用程序层接口。ADO 使您能够编写应用程序以通过 OLE. DB 提供者访问和操作数据库服务器中的数据。ADO 最主要的优点是易于使用、速度快、内存支出少和磁盘遗迹小。ADO 在关键的应用方案中使用最少的网络流量,并且在前端和数据源之间使用最少的层数,所有这些都是为了提供轻量、高性能的接口。之所以称为 ADO,是用了一个比较熟悉的暗喻,OLE 自动化接口。OLE DB是一组"组件对象模型"(COM) 接口,是新的数据库低层接口,它封装了ODBC的功能,并以统一的方式访问存储在不同信息源中的数据。OLE DB是Microsoft UDA(Universal Data Access)策略的技术基础。OLE DB 为任何数据源提供了高性能的访问,这些数据源包括关系和非关系数据库、电子邮件和文件系统、文本和图形、自定义业务对象等等。也就是说,OLE DB 并不局限于 ISAM、Jet 甚至关系数据源,它能够处理任何类型的数据,而不考虑它们的格式和存储方法。在实际应用中,这种多样性意味着可以访问驻留在 Excel 电子数据表、文本文件、电子邮件/目录服务甚至邮件服务器,诸如 Microsoft Exchange 中的数据。但是,OLE DB 应用程序编程接口的目的是为各种应用程序提供最佳的功能,它并不符合简单化的要求。您需要的API 应该是一座连接应用程序和OLE DB 的桥梁,这就是 ActiveX Data Objects (ADO)。 二、在VC中使用ADO(开发步骤好下:) 1、引入ADO库文件 使用ADO前必须在工程的stdafx.h头文件里用直接引入符号#import引入ADO库文件,以使编译器能正确编译。代码如下所示: 用#import引入ADO库文件#import "c:/program files/common files/system/ado/msado15.dll"no_namespaces rename("EOF", "adoEOF")这行语句声明在工程中使用ADO,但不使用ADO的名字空间,并且为了避免常数冲突,将常数EOF改名为adoEOF。现在不需添加另外的头文件,就可以使用ADO接口了。 2、初始化OLE/COM库环境必须注意的是,ADO库是一组COM动态库,这意味应用程序在调用ADO前,必须初始化OLE/COM库环境。在MFC应用程序里,一个比较好的方法是在应用程序主类的InitInstance成员函数里初始化OLE/COM库环境。BOOL CMyAdoTestApp::InitInstance(){if(!AfxOleInit())//这就是初始化COM库{AfxMessageBox("OLE初始化出错!");return FALSE;} …… }3、ADO接口简介 ADO库包含三个基本接口:_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。_ConnectionPtr接口返回一个记录集或一个空指针。通常使用它来创建一个数据连接或执行一条不返回任何结果的SQL语句,如一个存储过程。使用_ConnectionPtr接口返回一个记录集不是一个好的使用方法。对于要返回记录的操作通常用_RecordserPtr来实现。而用_ConnectionPtr操作时要想得到记录条数得遍历所有记录,而用_RecordserPtr时不需要。 _CommandPtr接口返回一个记录集。它提供了一种简单的方法来执行返回记录集的存储过程和SQL语句。在使用_CommandPtr接口时,你可以利用全局_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用连接串。如果你只执行一次或几次数据访问操作,后者是比较好的选择。但如果你要频繁访问数据库,并要返回很多记录集,那么,你应该使用全局_ConnectionPtr接口创建一个数据连接,然后使用_CommandPtr接口执行存储过程和SQL语句。 _RecordsetPtr是一个记录集对象。与以上两种对象相比,它对记录集提供了更多的控制功能,如记录锁定,游标控制等。同_CommandPtr接口一样,它不一定要使用一个已经创建的数据连接,可以用一个连接串代替连接指针赋给_RecordsetPtr的connection成员变量,让它自己创建数据连接。如果你要使用多个记录集,最好的方法是同Command对象一样使用已经创建了数据连接的全局_ConnectionPtr接口,然后使用_RecordsetPtr执行存储过程和SQL语句。 4、使用_ConnectionPtr接口_ConnectionPtr主要是一个连接接口,取得与数据库的连接。它的连接字符串可以是自己直接写,也可以指向一个ODBC DSN。_ConnectionPtr pConn;if (FAILED(pConn.CreateInstance("ADODB.Connection"))){AfxMessageBox("Create Instance failed!");return;}CString strSRC;strSRC="Driver=SQL Server;Server=";strSRC+="suppersoft";strSRC+=";Database=";strSRC+="mydb";strSRC+=";UID=SA;PWD=";CString strSQL = "Insert into student(no,name,sex,address) values(3,'aaa','male','beijing')";_variant_t varSRC(strSRC);_variant_t varSQL(strSQL);_bstr_t bstrSRC(strSRC);if (FAILED(pConn->Open(bstrSRC,"","",-1))){AfxMessageBox("Can not open Database!");pConn.Release();return;}COleVariant vtOptional((long)DISP_E_PARAMNOTFOUND,VT_ERROR);pConn->Execute(_bstr_t(strSQL),&vtOptional,-1);pConn.Release();AfxMessageBox("ok!");5、使用_RecordsetPtr接口(以连接SQL Server为例)_RecordsetPtr pPtr;if (FAILED(pPtr.CreateInstance("ADODB.Recordset"))){AfxMessageBox("Create Instance failed!");return FALSE;}CString strSRC;strSRC="Driver=SQL Server;Server=";strSRC+="210.46.141.145";strSRC+=";Database=";strSRC+="mydb";strSRC+=";UID=sa;PWD=";strSRC+="sa";CString strSQL = "select id,name,gender,address from personal";_variant_t varSRC(strSRC);_variant_t varSQL(strSQL);if(FAILED(pPtr->Open(varSQL,varSRC,adOpenStatic,adLockOptimistic,adCmdText))){AfxMessageBox("Open table failed!");pPtr.Release();return FALSE;}while(!pPtr->GetadoEOF()){_variant_t varNo;_variant_t varName;_variant_t varSex;_variant_t varAddress;varNo = pPtr->GetCollect ("id");varName = pPtr->GetCollect ("name");varSex = pPtr->GetCollect ("gender");varAddress = pPtr->GetCollect ("address");CString strNo =(char *)_bstr_t(varNo);CString strName =(char *)_bstr_t(varName);CString strSex =(char *)_bstr_t(varSex);CString strAddress =(char *)_bstr_t(varAddress);strNo.TrimRight();strName.TrimRight();strSex.TrimRight();strAddress.TrimRight();int nCount = m_list.GetItemCount();int nItem = m_list.InsertItem (nCount,_T(""));m_list.SetItemText (nItem,0,strNo);m_list.SetItemText (nItem,1,strName);m_list.SetItemText (nItem,2,strSex);m_list.SetItemText (nItem,3,strAddress);pPtr->MoveNext();}pPtr->Close();pPtr.Release();阅读全文(37次) / 评论 / 丢小纸条 / 文件夹: VC学习 收藏: QQ书签 del.icio.us / 订阅: Google 抓虾
ADO数据库访问举例痞子 @ 2007-03-09 10:20在VC中使用ADO的开发步骤:1,引入ADO库文件 在工程的stdafx.h里用#import引入ADO库文件。 #import "C:/Program Files/Common Files/System/ado/msado15.dll" no_namespace rename("BOF","adoBOF") rename("EOF","adoEOF") 2, 初始化COM环境 ::CoInitialize(NULL); //初始化OLE/COM库环境 ::CoUninitialize(); //关闭OLE/COM库环境,释放资源 AfxOleInit();//初始化OLE/COM库环境(MFC自带的)3,使用ADO库的三个基本接口 ADO库包含三个基本接口:_ConnectionPtr接口、_RecordsetPtr接口和_CommandPtr接口。其分别对应Connection对象(完成应用程序对数据源的访问连接)、Recordset对象(将查询的结果以记录集的方式存储)和Command对象(对已连接的数据源进行命令操作)。定义对象并创建对象实例:方法一:_ConnectionPtr m_pConnection;_RecordsetPtr m_pRecordset;_CommandPtr m_pCommand;m_pConnection.CreateInstance(__uuidof(Connection));m_pRecordset.CreateInstance(__uuidof(Recordset));m_pCommand.CreateInstance(__uuidof(Command));方法二:_ConnectionPtr m_pConnection("ADODB.Connection");_RecordsetPtr m_pRecordset("ADODB.Recordset");_CommandPtr m_pCommand("ADODN.Command");方法三:_ConnectionPtr m_pConnection;_RecordsetPtr m_pRecordset;_CommandPtr m_pCommand;m_pConnection.CreateInstance("ADODB.Connection");m_pRecordset.CreateInstance("ADODB.Recordset");m_pCommand.CreateInstance("ADODN.Command");这三种方法都是一样的,关键看你喜好。 分别举例简单说明一下:Connection对象: _ConnectionPtr m_pConnection; m_pConnection.CreateInstance(__uuidof(Connection)); try{ // 打开本地Access库ChatLog.mdb m_pConnection->Open ("Provider=Microsoft.Jet.OLEDB.4.0;DataSource=ChatLog.mdb","","",adModeUnknown); //SQL Server连接方法 _bstr_t strConnect = "Provider=SQLOLEDB; Server=billgates;Database=HrMan; uid=sa; pwd=sa;"; m_pConnection->Open(strConnect,"","",adModeUnknown); } catch(_com_error e){ AfxMessageBox(e.Description()); } Recordset对象: _RecordsetPtr m_pRecordset; m_pRecordset.CreateInstance(__uuidof(Recordset)); CString sql; sql.Format("SELECT DISTINCT name FROM table1"); try{ m_pRecordset->Open(sql.GetBuffer(sql.GetLength()), _variant_t((IDispatch *)m_pConnection,true), adOpenDynamic, adLockOptimistic, adCmdText); } catch(_com_error *e){ AfxMessageBox(e->ErrorMessage()); } CString strName; while (!m_pRecordset->adoEOF) { strName.Format("%s",(char*)(_bstr_t)m_pRecordset->Fields->GetItem(_variant_t("Name"))->Value); m_listbox.AddString(strName); m_pRecordset->MoveNext(); }Command对象: _CommandPtr m_pCommand; HRESULT hr = m_pCommand.CreateInstance(__uuidof(Command)); if(FAILED(hr)) { AfxMessageBox("创建Command对象实例失败!"); } CString strP_mailid; _ParameterPtr param; param=m_pCommand->CreateParameter("p_mailid",adVarChar,adParamOutput,strP_mailid.GetLength()+1,_variant_t(strP_mailid)); m_pCommand->Parameters->Append(param); m_pCommand->ActiveConnection = m_pConnection; m_pCommand->CommandType = adCmdStoredProc; m_pCommand->CommandText = _bstr_t("P_MAIL_SEND"); try{ cmd->Execute(NULL,NULL,adCmdStoredProc); } catch (...) { AfxMessageBox("调用存储过程P_MAIL_SEND有错!"); } try{ strP_mailid = (char*)(_bstr_t)m_pCommand->Parameters->GetItem(_variant_t("p_mailid"))->GetValue(); }catch (...) { strP_mailid = ""; } m_pCommand.Detach();阅读全文(39次) / 评论 / 丢小纸条 / 文件夹: VC学习 收藏: QQ书签 del.icio.us / 订阅: Google 抓虾
VC使用ActiveX控件常见问题痞子 @ 2007-03-08 17:01一方面,它表示将你联系到Microsoft、Internet和业界的新技术的小型快速的可重用组件。它与开发语言无关,任何支持 ActiveX控件的软件开发平台(如VB、VC++、Access、VFP、Delphi、PowerBuilder等)上,都可以使用ActiveX控件,程序员可以像使用Windows标准控件一样使用不同厂商开发的ActiveX控件。这样就实现了软件开发的工业化,大大地提高了软件的生产效率。 另一方面,它代表Internet与应用程序的一种集成策略。用户可以从Internet上下载ActiveX控件,也可以通过网络在本地机上调用远程机上的ActiveX控件,还可以将ActiveX控件加入到Internet主页上。 既然ActiveX控件对程序员是如此地重要,那么如何用好ActiveX控件也就成为软件开发者所关心的问题。本文以VC++5.0为开发工具,以一个项目名为Test的应用程序为例,就笔者在控件使用中遇到的一些问题加以讨论。 要想在应用程序中使用ActiveX控件,必须使你的应用程序成为ActiveX控件包容器。ActiveX 控件包容器就是完全支持ActiveX控件,并能把控件组合进自己的窗口或对话框的父应用程序。利用MFC的AppWizard,你可以很方便地创建你的包容器程序。事实上,在用AppWizard创建新的应用程序时,你的应用程序就被缺省设置为控件包容器,即在第3步选中支持ActiveX Controls的复选框。如果你在创建过程中没有选择这项技术支持,以后也可以手动地加入这项支持。 步骤如下: 1. 在项目的应用类的.cpp文件(本例中为test.cpp)的Initinstance函数中加入对函数AfxEnableControlContainer()的调用,如下所示: BOOL CTestApp::InitInstance() { AfxEnableControlContainer(); ... } 在使用一个已注册的ActiveX控件之前,必须先用组件廊将该控件添加到应用程序中,步骤如下: 1.从Project菜单选择Add To Project下的Components and Controls。 2.在弹出的对话框中双击Registered ActiveX Control子目录,打开此目录。 3.选择你需要的控件,点击Insert按钮,弹出Confirm Classes对话框。 4.在列出的类名中选择需要的类(缺省为全选中,最好接受缺省设置),点击OK,关闭Confirm Classes对话框。 5.点击Close关闭组件廊,该控件的图标即加入到对话框编辑器的控件面板上。 这样,我们就可以在对话框中像使用Windows标准控件那样使用该控件了。但在某些应用中,你可能需要在非对话框容器(如应用程序的窗口)中嵌入ActiveX控件。这时没有对话框编辑器,我们应怎样在非对话框容器中使用ActiveX控件呢? 当组件廊将ActiveX控件添加到你的应用程序后,组件廊会创建一些包裹类(即在Confirm Classes对话框中列出的那些类)。其中有一个类的基类是CWnd,该类是控件的包裹类,它被用作控件与控件包容器之间的接口,有两个公有的Create成员函数: virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL) 和BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CFile* pPersist = NULL, BOOL bStorage = FALSE, BSTR bstrLicKey = NULL) 我们就可以使用该控件的包裹类的Create函数在非对话框容器中动态地创建此控件的实例。 步骤如下:(本例中欲加入的控件名为MSFlexGrid ,CMSFlexGrid是控件的包裹类,msflexgrid.h是包裹类的头文件) 1.在视类头文件(本例中为TestView.h)中的类定义前加上 #include "msflexgrid.h" 2. 在TestView.h中CTestView类定义的protected部分加上控件包裹类类型的成员变量声明: class CTestView : public CView { ... protected: CMSFlexGrid m_fgrid; ... }; 3. 用ClassWizard为类CTestView 添加消息WM_CREATE的处理函数CTestView::OnCreate,在此函数中,调用控件类CMSFlexGrid的Create函数: int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // ****** Add your code below this line ********** // m_fgrid.Create(NULL, WS_VISIBLE, CRect(50,50,100,100), this, 0); //用this指针作为指向父窗口的指针 m_fgrid.SetCols(2); m_fgrid.SetRows(10); m_fgrid.SetTextMatrix(0,0,"序号"); m_fgrid.SetTextMatrix(0,1,"姓名"); // ****** Add your code above this line ********** // return 0; } 4.重新链接工程,运行。可以看到当应用程序的视窗生成时,控件也动态地生成了。 5.如果你以后还想改变控件的位置和大小,可以继承CWnd::MoveWindow()函数。例如,若想使控件充满整个窗口,并在父窗口移动和缩放时也随之移动和缩放,可以添加消息WM_SIZE的处理函数OnSize,并加入如下代码: void CTestView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); // TODO: Add your message handler code here m_fgrid.MoveWindow(0,0,cx,cy); } 通常情况下,我们可以用两种方法来存取对话框中的控件:1、将控件与对话框的成员变量相关联,通过对话框数据交换DDX来实现控件和对应的成员变量之间的数据交换(详情请参阅VC联机帮助ActiveX Control Containers: Connecting an ActiveX Control to a Member Variable);2、调用函数CWnd::GetDlgItem来取得指向控件的指针。 有些ActiveX控件没有用户界面,在运行时不可见。如果你在对话框中加入了运行时不可见的ActiveX控件,并想用CWnd::GetDlgItem来存取此控件,此控件将不能正常工作。要得到代表此控件的对象指针,可采取以下两种方法之一: 1. 在ClassWizard的成员变量标签中,选择此控件的ID,点击Add Variable,然后输入一个成员变量名,在Category中选择"Control",在Variable type中选择控件类。 2. 声明一个此控件类型的局部变量,并将它作为一个对话框项。加入类似如下所列的代码(其中CmyCtrl是控件类,IDMYCTRL1是控件ID): CMyCtrl myCtrl; myCtrl.SubclassDlgItem(IDC_MYCTRL1, this); // ... 使用控件myCtrl ... myCtrl.UnsubclassWindow(); 下面举一个例子加以说明。本例将在对话框中加入一个运行时不可见的计时控件Timer Object。该控件在一个的预定的时间间隔过去之后引发 Timer 事件,该时间间隔储存于该控件的 Interval 属性中,它以千分之一秒为单位指定时间的长度。本例用一个成员变量m_num来计数,每隔Interval时间递增1,当m_num计到10时,重置为0,并将时间间隔m_Interval增加200毫秒,并分别在两个静态框中显示当前的m_num和m_Interval。 步骤如下: 1.用组件廊将Timer控件加入到项目Test中。 2.在项目中插入一个新的对话框,类名为CTestDlg。 3.在对话框模板中加入控件Timer Object(包裹类为CIeTimer),如图2的右下角。打开属性对话框,设置ID为IDC_TIMER1。再切换至All属性页,设置Interval为200。 4.在对话框模板中添加静态控件,Caption为"The current interval is:"。 5.添加一个不带Caption的静态控件,打开属性对话框,设置ID为IDC_STATIC1。再切换至Extended Styles属性页,选中Static edge复选框。 6.按下Ctrl键的同时双击静态控件IDC_STATIC1,弹出Add Member Variable对话框,第一项中填写变量名m_text1,Category项中选择Control,Variable type项中选择CStatic。 7.添加静态控件"The current number is:"。 8.重复步骤5到步骤6,添加一个不带Caption的静态控件(ID为IDC_STATIC2),变量名为m_text2。 9.运行ClassWizard并选择Message Map属性页,在Class name 中选择CTestDlg,Object IDs中选择IDC_TIMER1,在Messages中选择Timer,点击Add Function…按钮,加入OnTimerTimer1()处理函数。若采用第一种方法,则按前面所述方法用ClassWizard给此控件类添加一个成员变量m_timer,并在OnTimerTimer1函数中添加如下代码: void CTestDlg::OnTimerTimer1() { // TODO: Add your control notification handler code here char buf[10]; m_num++; if(m_num>=10) { m_num=0; m_interval+=200; m_timer.SetInterval(m_interval); } _itoa(m_interval,buf,10); m_text1.SetWindowText (buf); _itoa(m_num,buf,10); m_text2.SetWindowText (buf); } 若采用第二种方法,不需要添加此控件类的成员变量,只需将加灰显示的语句用下列语句代替即可: CIeTimer m_timer; m_timer.SubclassDlgItem(IDC_TIMER1,this); m_timer.SetInterval(m_interval); m_timer.UnsubclassWindow(); 运行之后可以看到计数的步调越来越慢了(时间间隔越来越大了)