VC++编程通用技巧范例大全2010版


VC++通用技巧范例大全 2011 最新版 (适用于 VC6-VC2010) 经典 VC 编程网站 .................................................................................................................................... 7 设置窗口最大最小 ................................................................................................................................... 7 设置窗口标题 ........................................................................................................................................... 7 去掉主菜单 ............................................................................................................................................... 7 修改应用程序图标 ................................................................................................................................... 7 系统只能允许一个程序运行 ................................................................................................................... 7 在状态栏中添加时间 ............................................................................................................................... 7 研究调用存储过程 ................................................................................................................................... 8 得到本机的 IP 地址 .................................................................................................................................. 9 vc 调用 chm 文件 .................................................................................................................................... 10 最高窗口的实现 ..................................................................................................................................... 10 防止 Edit 框中的 Password 不保密 ........................................................................................................ 11 在同一系统中显示 GB 字符和 BIG5 字符 ........................................................................................... 12 改变颜色(整个窗体的控件) ............................................................................................................. 12 改变工程表头栏 ..................................................................................................................................... 13 ◆如何找开一个 DiaLog 的窗口◆ ....................................................................................................... 13 ◆得到系统中设置的窗口颜色◆ ......................................................................................................... 14 ◆如何让点下去的菜单成为 V 状态◆................................................................................................. 14 ◆如何调用 WINDOWS 的颜色板◆ .................................................................................................... 14 ◆如何产生一个 MDI 的主窗口◆ ........................................................................................................ 14 ◆如何让一个文本控件显示出值◆ ..................................................................................................... 15 ◆如何让一个控件显示出相应的值◆ ................................................................................................. 15 ◆在调试中怎么样 MESSAGEBOX 一个数字◆ ................................................................................ 16 ◆如何控制控件的焦点◆ ..................................................................................................................... 16 ◆如何对析构函数中对象进行释放◆ ................................................................................................. 16 ◆如何关闭一个模态窗口◆ ................................................................................................................. 17 ◆如何将一个提示的声音发到声卡上◆ ............................................................................................. 17 ◆如何得到打开 exe 的带的参数◆ ...................................................................................................... 17 ◆如何在框架上建立一个工具条◆ ..................................................................................................... 17 ◆如何生成一个主窗口下方的状态条◆ ............................................................................................. 18 ◆如何让 Cscrollview 类中控制其可以流动区域大小◆ .................................................................... 18 ◆MFC 中控件的一些基本控制方法◆ ................................................................................................. 19 ◆如何让一个数字型变量化为字符型变量◆ ..................................................................................... 19 ◆如何使用“拉动条”,“上下选择”◆ ............................................................................................. 19 ◆如何使用 postmessage 来异步触发某事件◆ ................................................................................... 21 ◆如何使用 Sendmessage 来异步触发某事件◆ .................................................................................. 21 ◆如何修改父类的相关控件属性◆ ..................................................................................................... 22 ◆如何在程序中得到控件的名◆ ......................................................................................................... 22 ◆如何控制菜单的事件程序◆ ............................................................................................................. 22 ◆如何使用控件中的数据录入的控制属性◆ ..................................................................................... 23 ◆哪些函数是文档、视图相互处理用的◆ ......................................................................................... 23 ◆如何建立一个基于对话框一程序◆ ................................................................................................. 23 ◆如何建立一个线程◆ ......................................................................................................................... 24 ◆如何让窗口产生一个图标(从应用程序资源中取出)◆ .............................................................. 24 ◆如何得到一个 edit 的录入的值◆ ..................................................................................................... 24 ◆如何启动 TIMER 事件◆ ................................................................................................................... 24 ◆如何使用 ctrllist 控件实现表格◆ ..................................................................................................... 25 ◆如何从 INI 文件中得到值◆ .............................................................................................................. 25 ◆如何将图标文件写到窗口中◆ ......................................................................................................... 25 ◆如何得到本机的 IP 地址◆ ................................................................................................................ 26 ◆如何使用全局变量◆ ......................................................................................................................... 26 ◆如何让一个字符加上回车、换行◆ ................................................................................................. 26 ◆如何定义、使用结构◆ ..................................................................................................................... 26 ◆如何在任意程序中显示 MessageBox◆ ............................................................................................ 27 ◆如何在程序判断出 debug 状态◆ ...................................................................................................... 27 ◆当对话框中有一个滚动条是,当滚动滚动条时的消息控制函数◆ .............................................. 27 ◆将 CWnd 指针转换成控件 ID(整数)(注意:GetDlgItem()是从控件 ID 转换成 CWnd 的指针)◆ . 28 ◆如果在对话框中自定义一个消息的方法,假设对话框名为 CXX◆ ............................................ 28 ◆消息传递◆ ......................................................................................................................................... 29 ◆在一个函数引用另外的一个对话框◆ ............................................................................................. 29 ◆全局函数的申明问题◆ ..................................................................................................................... 29 ◆在应用程序中*APP.CPP 中的 InitInstance()的事件◆ ..................................................................... 29 ◆给执行文件加一个图标◆ ................................................................................................................. 30 ◆如何在全局函数中通过传入的窗口句柄操作窗口◆...................................................................... 30 ◆如何使桌面文字背景透明?◆ ......................................................................................................... 30 ◆怎样才能在 VC 里产生一个唯一的字符串◆ .................................................................................. 30 ◆如何隐藏进程(在系统状态栏和进程列表里不可见)◆ ................................................................ 31 ◆如何得到一个确定大小的视?◆ ........................................................................................................ 31 ◆如何实现点击窗口任意地方拖动窗口?◆ ..................................................................................... 32 ◆如何在启动时阻止 MDI 应用程序创建一个新文档?◆ ................................................................ 32 ◆如何在多文档 MFC 程序中制作独立的 File|New 菜单?◆ ........................................................... 33 ◆如何检测视是否处于分割状态?◆ ................................................................................................. 34 ◆如何使程序保持极小状态?◆ ......................................................................................................... 34 ◆如何确定当前进程实例是否为唯一实例?◆ ................................................................................. 34 ◆如何向一个文档附加多个视?◆ ..................................................................................................... 35 ◆如何获得文件的图标、属性、大小、类型等参数?◆ .................................................................. 36 ◆如何得到鼠标下面的窗口?◆ ......................................................................................................... 37 ◆设置鼠标的形状◆ ............................................................................................................................. 37 ◆在对话框中设置编辑 EDIT 的值◆ .................................................................................................. 37 1. 如何获取应用程序的实例句柄? ....................................................................................................... 38 2. 如何通过代码获得应用程序主窗口的指针? ................................................................................... 38 3. 如何在程序中获得其他程序的图标? ............................................................................................... 38 4. 如何编程结束应用程序?如何编程控制 windows 的重新引导? ..................................................... 38 5.怎样加载其他的应用程序? ................................................................................................................. 39 6. 确定应用程序的路径 ........................................................................................................................ 39 7. 获得各种目录信息 ............................................................................................................................ 39 8. 如何自定义消息 ................................................................................................................................ 40 9. 如何改变窗口的图标?....................................................................................................................... 40 10. 如何改变窗口的 缺省风格? ........................................................................................................... 40 11. 如何将窗口居中显示? ................................................................................................................... 40 12. 如何让窗口和 MDI 窗口一启动就最大化和最小化? .................................................................. 40 13. 如何使程序保持极小状态? ............................................................................................................. 41 14. 如何限制窗口的 大小? ................................................................................................................... 41 15. 如何使窗口不可见? .................................................................................................................... 41 16. 如何使窗口始终在最前方? ............................................................................................................. 41 17、如何创建一个字回绕的 CEditView ............................................................................................... 41 18、通用控件的显示窗口 ..................................................................................................................... 42 19、移动窗口 ......................................................................................................................................... 42 20、重置窗口的大小 ............................................................................................................................. 42 21、如何单击除了窗口标题栏以外的区域使窗口移动...................................................................... 42 22、如何改变视窗的背景颜色 ............................................................................................................. 43 23、如何改变窗口标题 ......................................................................................................................... 44 24、如何防止主框窗口在其说明中显示活动的文档名...................................................................... 44 25、如何获取有关窗口正在处理的当前消息的信息.......................................................................... 44 26、如何创建一个不规则形状的窗口 ................................................................................................. 45 27、如何在代码中获取工具条和状态条的指针 ................................................................................. 47 28、如何使能和禁止工具条的工具提示 ............................................................................................. 47 29、如何设置工具条标题 ..................................................................................................................... 47 30、如何创建和使用无模式对话框 ..................................................................................................... 48 31、如何在对话框中显示一个位图 ..................................................................................................... 49 32、如何改变对话或窗体视窗的背景颜色 ......................................................................................... 49 33、如何获取一个对话控件的指针 ..................................................................................................... 50 34、如何禁止和使能控件 ..................................................................................................................... 50 35、如何改变控件的字体 ..................................................................................................................... 50 36、如何在 OLE 控件中使用 OLE_COLOR 数据类型 ...................................................................... 51 37、在不使用通用文件打开对话的情况下如何显示一个文件列表 .................................................. 51 38、为什么旋转按钮控件看起来倒转 ................................................................................................. 51 39 为什么旋转按钮控件不能自动地更新它下面的编辑控件 ............................................................. 52 40、如何用位图显示下压按钮 ............................................................................................................. 52 41、如何一个创建三态下压按钮 ......................................................................................................... 52 42、如何动态创建控件 ......................................................................................................................... 52 43、如何限制编辑框中的准许字符 ..................................................................................................... 53 44、如何改变控件的颜色 ..................................................................................................................... 54 45、当向列表框中添加多个项时如何防止闪烁 ................................................................................. 55 46、如何向编辑控件中添加文本 ......................................................................................................... 55 47、如何访问预定义的 GDI 对象 ........................................................................................................ 55 48、如何获取 GDI 对象的属性信息 .................................................................................................... 56 49、如何实现一个橡皮区矩形 ............................................................................................................. 56 50、如何更新翻转背景颜色的文本 ..................................................................................................... 58 51、如何创建一个具有特定点大小的字体 ......................................................................................... 58 52、如何计算一个串的大小 ................................................................................................................. 58 53、如何显示旋转文本 ......................................................................................................................... 59 54、如何正确显示包含标签字符的串 ................................................................................................. 60 55、串太长时如何在其末尾显示一个省略号 ..................................................................................... 60 56、如何快速地格式化一个 CString 对象 ........................................................................................... 61 57、为什么即使调用 EnableMenuItem 菜单项后,菜单项还处于禁止状态 .................................... 61 58、如何给系统菜单添加一个菜单项 ................................................................................................. 61 59、如何确定顶层菜单所占据的菜单行数 ......................................................................................... 62 60、在用户环境中如何确定系统显示元素的颜色.............................................................................. 62 问:如何控制窗口框架的最大最小尺寸? ............................................................................................ 62 问:如何改变窗口框架的颜色? ............................................................................................................ 63 问:如何将应用程序窗口置于屏幕正中? ............................................................................................ 64 问:VC6.0 对 VC5.0 的兼容性? ........................................................................................................... 64 问:打印和打印机的问题? .................................................................................................................... 64 问:CRichEditCtrl 滚动条的问题?........................................................................................................ 65 问:从数据库中读大于 32k 的内容? .................................................................................................... 65 问:如何获得 CRichEditCtrl 中字符的位置? ....................................................................................... 65 问:如何限制 mdi 子框架最大化时的大小?........................................................................................ 66 问:如何切换视口而不破坏它们? ........................................................................................................ 66 问:改变列表控制时发生闪烁现象? .................................................................................................... 68 问:处理列表控件可见项的问题? ........................................................................................................ 68 问:产生线程的问题?............................................................................................................................ 68 问:CFile 使用了缓冲区吗? .................................................................................................................. 69 问:DAO 的密码? .................................................................................................................................. 69 问:如何知道 CListBox 什么时候滚动了? .......................................................................................... 69 问:视口的不活动性如何处理? ............................................................................................................ 70 问:如何使用 COleClientItem 的 IDispatch 接口? ............................................................................... 70 问:关于用户自定义的消息使用? ........................................................................................................ 71 问:在打开一个文档时退出? ................................................................................................................ 71 问:在 CListCtrl 控件中多选择项的删除? ........................................................................................... 71 问:工作线程的登录状态? .................................................................................................................... 71 问:如何控制菜单的大小? .................................................................................................................... 72 问:改变 LVIS_SELECTED 的状态颜色? ........................................................................................... 73 问:如何只存储文档的某一部分? ........................................................................................................ 73 问:保存工具条菜单有 bug 吗? ............................................................................................................ 73 问:Tip of the day 的 bug ....................................................................................................................... 73 问:如何让我的 mfc 应用程序可以在最上面?.................................................................................... 74 问:如何增加视图中 ActiveX 控件的事件处理函数? ........................................................................ 74 问:如何创建一个动态的 Tree 控件? .................................................................................................. 75 问:SDI 程序开始时不打开文档? ........................................................................................................ 75 问:List 控件中整栏选择? .................................................................................................................... 75 问:如何重载 MRU 文件? .................................................................................................................... 76 问:CImageList 控件中图象橙色被显示为黄色? ................................................................................ 76 问:无法正确改变应用程序的图标? .................................................................................................... 78 问:工具条状态的问题?........................................................................................................................ 78 问:在 SDI 应用程序中使用 Active 控件? ........................................................................................... 79 问:有 RichEdit 控件的对话框无法正常显示?.................................................................................... 79 问:DLL 中的模板成员函数? ............................................................................................................... 79 问:CFormView 中的上下文帮助? ....................................................................................................... 80 问:CArchive 类的 WriteObject 函数问题?.......................................................................................... 80 问:RegisterWindowMessage 中的 BroadcastSystemMessage 如何处理? .......................................... 80 问:CListCtrl 中选择变化时如何获得通知? ........................................................................................ 81 问:如何向 ATL-COM 对象传送一个数组? ........................................................................................ 81 问:如何选择 CTreeCtrl 中的节点文本进行编辑? .............................................................................. 82 问:如何改变默认的光标形状? ............................................................................................................ 82 问:如何用键盘滚动分割的视口? ........................................................................................................ 82 问:如何在线程中处理状态条? ............................................................................................................ 83 问:如何阻止 WINDOWS 关闭? .......................................................................................................... 83 问:如何使一个按钮 Disable? ................................................................................................................. 83 问:怎样从 MFC 扩展动态链结库(DLL)中显示一个对话框? ............................................................ 84 问:想隐藏用户界面怎么办? ................................................................................................................ 85 问:如何实现 SDI 与 MDI 的转换? ...................................................................................................... 85 问:CDC 中的竖排文本? ...................................................................................................................... 86 问:如何激活变灰的弹出菜单? ............................................................................................................ 86 问:线程消息? ....................................................................................................................................... 87 问:TreeCtrl 控制的显示速度太慢? ..................................................................................................... 87 怎样使窗口总是浮现在最上面? ............................................................................................................ 88 改变拖放时的光标外形?........................................................................................................................ 89 如何定位到最新的记录上? .................................................................................................................... 89 MVC 和 Doc-View? ................................................................................................................................ 90 被禁止(Disable)的控件如何改变其文本或背景色? ............................................................................. 90 有 ODBC 的查找函数吗? ...................................................................................................................... 90 多个 MRU 菜单的问题 .......................................................................................................................... 91 校验框类问题 ......................................................................................................................................... 92 CFormView 类的 Fold 按钮 ................................................................................................................... 93 视的背景色 ............................................................................................................................................. 94 隐藏控件台程序 ..................................................................................................................................... 94 修改 SDI 窗口标题 ................................................................................................................................. 94 焦点问题 ................................................................................................................................................. 95 从一个 OCX 调用另一个 OCX 的方法。 ............................................................................................. 95 得到视 ..................................................................................................................................................... 96 字符转化时间 ......................................................................................................................................... 96 二进制还是文本方式?............................................................................................................................ 99 发送消息 ................................................................................................................................................. 99 怎样知道菜单运行时的状态 ................................................................................................................. 99 DLL 编译出错 ........................................................................................................................................ 99 通用控件的显示窗口 ........................................................................................................................... 100 如何禁止和使能控件 ........................................................................................................................... 100 如何在 OLE 控件中使用 OLE_COLOR 数据类型 ............................................................................ 100 在不使用通用文件打开对话的情况下如何显示一个文件列表 ........................................................ 100 为什么旋转按钮控件看起来倒转 ....................................................................................................... 100 为什么旋转按钮控件不能自动地更新它下面的编辑控件 ................................................................ 101 如何动态创建控件 ............................................................................................................................... 101 如何显示旋转文本 ............................................................................................................................... 101 在 TreeList 中使用 Edit 功能 ............................................................................................................... 102 TreeList control 中使用 check box ....................................................................................................... 102 有关属性对话框(property sheet )的几个提示 ..................................................................................... 108 在 MFC 加入"这是什么?"的帮助提示 ................................................................................................. 111 精通工具条 ............................................................................................................................................ 112 如何改变视窗的背景颜色 .................................................................................................................... 112 为 MFC 应用程序添加全屏幕显示功能 .............................................................................................. 112 VC 常用数据类型使用转换详解 .......................................................................................................... 114 用 Visual C++操作 INI 文件 ................................................................................................................. 117 单文档加入背景图 ................................................................................................................................ 119 更新窗体方法 ........................................................................................................................................ 119 更改窗口控件的能动和不能动(以按钮控件为例)......................................................................... 119 窗口响应键盘事件 ............................................................................................................................... 120 密码框输入受保护 ............................................................................................................................... 121 最高窗口的实现 ................................................................................................................................... 122 实现窗口动态写入汉字和改变汉字颜色形状 ................................................................................... 122 经典 VC 编程网站 http://www.vckbase.com http://www.vchome.net http://www.programfan.com http://www.codeproject.com http://www.codeguru.com http://www.csdn.net http://www.cctry.com http://msdn.microsoft.com/zh-CN/ 设置窗口最大最小 m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED); m_pMainWnd->UpdateWindow(); 设置窗口标题 AfxGetMainWnd ( ) -> SetWindowText (_T("创智流媒体计费软件 V1.0") ); 去掉主菜单 SetMenu(NULL);//去掉菜单 修改应用程序图标 去掉程序当中 ICON 中标识为 IDR_MAINFRAME 的图标 将自己的图标名称修改为 IDR_MAINFRAME 五、提示框出现自己提示要用到 MessageBox,而不是使用 AfxMessageBox; 系统只能允许一个程序运行 CString AppTitle; AppTitle.Format(_T("This is PowerSumFee,ReadOnly!)); HANDLE m_hMutex=CreateMutex(NULL,TRUE,AppTitle); if(GetLastError()==ERROR_ALREADY_EXISTS) { MessageBox(NULL,_T("该程序已经在运行!"),_T("错误!"),MB_OK|MB_ICONSTOP); return FALSE; } 在状态栏中添加时间 1)在 String Table 中添加 New String,在此定义为 ID_INDICATOR_CLOCK, 将其 Caption 设为 00:00:00(由于状态栏根据 Caption 确定时间窗格的缺 省宽度,使用此值将为时间的显示预留空间)。注 2)在 MainFrm.cpp 中 indicators 声明处添加 ID_INDICATOR_CLOCK,代 码如下: 这一步中 ID_INDICATOR_CLOCK 的插入位置将影响时间窗格在状态栏中 的显示位置。 3)安装定时器:在 MainFrm.cpp 中 OnCreate 函数处添加代码如下: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { …… SetTimer(1,1000,NULL);//安装定时器,并将其时间间隔设为 1000 毫秒 return 0; } 4)编写时间处理函数:利用 ClassWizard 为 CMainFrame 类加入 WM_TIMER 的消息处理函数 OnTimer,并添加代码如下: void CMainFrame::OnTimer(UINT nIDEvent) {// TODO: Add your message handler code here and/or call default CTime time; time=CTime::GetCurrentTime();//得到当前时间 CString s=time.Format(″%H:%M:%S″);//转换时间格式,这里格式一定要大写 m_wndStatusBar.SetPaneText(m_wndStatusBar.CommandToIn- dex(ID_INDICATOR_CLOCK),s); //显示时钟 CFrameWnd::OnTimer(nIDEvent);} 5)销毁定时器:利用 ClassWizard 为 CMainFrame 类加入 WM_CLOSE 的消息处理 函数 OnClose,并添加代码如下: void CMainFrame::OnClose() {// TODO: Add your message handler code here and/or call default KillTimer(1);//销毁定时器 研究调用存储过程 //建立自己的 commmand 指针和记录集对象 _CommandPtr CmdPriv; // command object pointer _RecordsetPtr m_pCmdRs; //记录集对象指针 _bstr_t bstrProc =( L"PRO_JudgeNo" );; //Stored procedure name _variant_t vtUserName; _variant_t vtReturn; _variant_t tResult; //建立通道 CmdPriv.CreateInstance( __uuidof( Command ) ); // creating command object CmdPriv->ActiveConnection = theApp.m_pConn; // giving the connection handle CmdPriv->CommandText = _bstr_t( bstrProc ); // passing the stored procedue CmdPriv->CommandType = adCmdStoredProc; // type CmdPriv->Parameters->Release(); // passing string value as argument to stored procedure //传入参数 vtUserName.vt=VT_BSTR; vtUserName.bstrVal=_bstr_t(strUserName); CmdPriv->Parameters->Append(CmdPriv->CreateParameter(_bstr_t(strUserName),adVarChar,adParamInput,sizeof(vtUs erName),vtUserName)); vtReturn.vt=VT_I2; vtReturn.iVal=1; CmdPriv->Parameters->Append(CmdPriv->CreateParameter(_T("nReturn"),adInteger,adParamOutput,sizeof(vtReturn),v tReturn)); CmdPriv->put_Prepared(true); m_pCmdRs = CmdPriv->Execute( NULL,NULL,adCmdStoredProc ); // executing the stored procedure and storing the recordset value vtReturn=CmdPriv->Parameters->GetItem("nReturn")->Value; if(vtReturn.iVal!=1) { AfxMessageBox(_T("%d"),vtReturn.iVal); return FALSE; } //vtReturn = theApp.m_pRs ->Fields->GetItem( _variant_t( 0L ) )->Value; // getting the first column value of the result row return TRUE; 得到本机的 IP 地址 CString CPowerClipInfoView::GetHostIP() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ return _T("172.0.0.1"); } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ WSACleanup( ); return _T("172.0.0.1"); } /* The WinSock DLL is acceptable. Proceed. */ // 得到本机的 IP 地址 char HostName[ 50 ] = ""; IN_ADDR hostIP; CString strHostIP; int len = 50; struct hostent * hostAddr; gethostname( HostName,len ); m_sHostName = CString(HostName); theApp.theHostName = CString(HostName); hostAddr = gethostbyname( HostName ); hostIP = *( (LPIN_ADDR)*hostAddr->h_addr_list ); CString strHostIP; strHostIP.Format(_T("%d.%d.%d.%d"),hostIP.S_un.S_un_b.s_b1,hostIP.S_un.S_un_b.s_b2,hostIP.S_un.S_un_b.s_b3,hostIP.S_ un.S_un_b.s_b4); return strHostIP; } vc 调用 chm 文件 HtmlHelp(this->m_hWnd,"c:\\help.chm",HH_DISPLAY_TOPIC,0); 加 hhctrl.lib, #include "htmlhelp.h" 十一、得到系统时间 CString strSysTime; CTime systemTime=CTime::GetCurrentTime(); //得到系统的具体时间 int nYear=systemTime.GetYear(); int nMonth=systemTime.GetMonth(); int nDay=systemTime.GetDay(); int nHour=systemTime.GetHour(); int nMinute=systemTime.GetMinute(); int nSecond=systemTime.GetSecond(); //格式化时间字符串 strSysTime.Format(_T("%.4d-%.2d-%.2d %.2d:%.2d:%.2d"),nYear,nMonth,nDay,nHour,nMinute,nSecond); return strSysTime; 最高窗口的实现 最高窗口就是总浮动在其他窗口上的,不会被一般窗口遮住的窗口,最高窗口技术在编程中有着很广 泛的应用。VC++中对基于 SDI、MDI 的运用程序,要实现最高窗口,只要在框架窗口类 CMainFrame 中 的 PreCreateWindow()函数中加入"cs.dwExStyle =WS_EX_TOPMOST;"即可。关于函数 PreCreateWindow() 及结构 CREATESTRUCT 的详细信息可参见 VC++的联机文档。 而对基于对话框的运用程序,如何实现最高窗口却很少论及,以下便是一种实现方法。 重载要实观最高窗口的对话框的 OnInitDialog()函数,方法是进入 ClassWizard,在 Object ID 列表框中 选择该对话框的 ID,在 Message 列表框中选择 WM_INITDIALOGG,单击 Add Function 按钮后,即对 onlnitDialog 函数进行了重载。再按下 Edit code 按钮,加入以下语句: const CWnd * pWndInsertAfter;pWndInsertAfter = &wndTopMost;SetWindowPos(pWndInsertAfter,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE);函数 SetWindowPos 原 型 为 BOOL SetWindowPos(const CWnd * pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags);pWndInsertAfter 为指向标识窗口类型的 CWnd 对象的指针。 x,y 为窗口左上角的坐标。 cx,cy 为窗口的宽与高。nFlags 确定窗口的大小及位置。当为 SWP_NOSIZE 时,忽略 cx,cy。当为 SWP_NOMOVE 时,忽略 x,y。 防止 Edit 框中的 Password 不保密 1) 创建新 CEdit 类 从 CEdit 继承一个子类 CPasswordEdit, 申明全局变量 g_bAuthorIdentity 表明消息发送者的身份: BOOL g_bAuthorIdentity; 然后响应 CWnd 的虚函数 DefWindowProc,在这个回调函数中进行身份验证: LRESULT CPasswordEdit::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // 对 Edit 的内容获取必须通过以下两个消息之一 if(( message == WM_GETTEXT) || ( message == EM_GETLINE)) { // 检查是否为合法 if( !g_bAuthorIdentity) { // 非法获取,显示信息 AfxMessageBox(_T("我的密码,可不能让你看哦!")); // return 0; } // 合法获取 g_bAuthorIdentity = FALSE; } return CEdit::DefWindowProc(message, wParam, lParam); } 2) 在数据输入对话框中做处理 在对话框中申明一个类成员 m_edtPassword: CPasswordEdit m_edtPassword; 然后在对话框的 OnInitDialog()中加入下列代码: m_edtPassword.SubclassDlgItem(IDC_EDIT_PASSWORD, this); 其目的是将控制与新类做关联。 之后在对话框的数据交换中将身份设为合法: void CDlgInput::DoDataExchange(CDataExchange* pDX) { // 如果获取数据 // 注意:对于 CPropertyPage 类这里不需要 if( pDX- >m_bSaveAndValidate) 条件 if( pDX- >m_bSaveAndValidate) { g_bAuthorIdentity = TRUE; } CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDlgInput) DDX_Text(pDX, IDC_EDIT_PASSWORD, m_sPassword); //}}AFX_DATA_MAP } 在同一系统中显示 GB 字符和 BIG5 字符 当前由于大陆和港台采用不同的内码,因此产生了两种常用的内码 GB/BIG5。以前的软件都是利用内建的字库来完成 两种内码的显示,而在这里我提供一种简便的方法用于在 Windows 程序中显示不同内码的文字。 大家可能都注意到 IE,MS Office97 等软件都可以根据不同内码使用不同的字体显示而不需要平台支持。他们利用的都 是 MS 所提供的语言开发包进行开发,下面介绍这种方法: 首先你需要安装 MS 提供的 GB 和 BIG5 字体,(可在 MS 站点免费下载)。 然后需要修改你的显示代码,对于不同的模式装入不同的字体。这种技术的核心就是指定不同的字符集和字体名称,示 范代码如下: //下面的代码将装入 BIG5 字体并显示 CFont font; LOGFONT lf; //LOGFONT 结构中的变量用于定义字体的各种特性 memset(&lf,0,sizeof(lf)); lf.lfCharSet = CHINESEBIG5_CHARSET; //设置字符集 lf.lfHeight = 20; strcpy(lf.lfFaceName,"MingLiu"); //设置字体名称 MingLiu 为 MS 提供的 BIG5 字体 font.CreateFontIndirect(&lf); //创建字体 CFont* pF = (CFont*)dc.SelectObject(&font); //保存当前字体 dc.TextOut(0,0,_T("what you want to display")); dc.SelectObject(pF); //恢复以前的字体 但是系统中安装的字体我们是不知道的,因此我们应该找出我们所需要的字体是否已经安装。Windows 中的 EnumFontFamiliesEx 可以帮助我们。该函数的说明如下: int EnumFontFamiliesEx(HDC hdc,LPLOGFONT lpLogfont, FONTENUMPROC lpEnumFontFamExProc, LPARAM lParam,DWORD dwFlags); 在调用该功能时需要在 lpLogfont 中设置相应的值,下面的代码表示列出所有 BIG5 字体。 HWND hW=::GetFocus(); HDC hdc=::GetDC(hW); LOGFONT lf; memset(&lf,0,sizeof(lf)); lf.lfCharset = CHINESEBIG5_CHARSET; //如果该值为 DEFAULT_CHARSET 将会列出所有字体 lf.lfFaceName = ""; lf.lfPitchAndFamily = 0; EmunFontFamiliesEx(hdc,&lf,myEnumFontFamExProc,0,0); 同时你还需要定义一个回调函数,在每找到一种字体时该函数都将被调用。函数原型如下: int CALLBACK myEnumFontFamExProc(ENUMLOGFONTEX *lpelfe,NEWTEXTMETRICEX *lpntme, int FontType,LPARAM lParam) { TRACE("font family name\n",lpelfe->elfLogFont.lfFaceName); //将该字体 LOGFONT 或是 FaceName 保存到自己的数据中 } 改变颜色(整个窗体的控件) ④ 点击 Class Wizard,给 testDlg 加入 WM_CTLCOLOR 事件,单击 Edit Code 按钮,然后把改函数的内容替换为如下代 码: HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); if (pWnd->GetDlgCtrlID() == IDC_CrdFavor_Time) { pDC->SetTextColor(RGB(255, 0, 0)); } // TODO: Return a different brush if the default is not desired return hbr; 改变工程表头栏 1、cs.style = WS_OVERLAPPED | WS_CAPTION |WS_THICKFRAME | WS_SYSMENU |SWP_NOMOVE; cs.dwExStyle =WS_EX_TOPMOST; 2、cs.style &=~WS_WS_MINIMIZE&~WS_MAXIMIZE; 这里去掉了最大化和最小化按钮。 ◆如何找开一个 DiaLog 的窗口◆ 区别:CDialog(IDD_DIALOG1).Create();与 CDialog(IDD_DIALOG1).DoModal(); 1。Create()创建的对话框是非模态,即它可以失去焦点 (但 仍 有效),但是对话框终止时需调用 DestroyWindow();在成员函数中创建的非模态对话框要注意其作用域和有效性. 2。DoModal()显示 一 个模 态对话框,在其有效期内不能失去焦点,调用 OnCancel(),OnOK()返回 IDOK,IDCANCEL... 例一: CDialog(IDD_DIALOG1).DoModal(); 其中 IDD_DIALOG1 为窗口名 例三:其中 WScoll 类名 WScoll *dlg; dlg = new WScoll(this); dlg->DoModal(); 例二: 打开窗口,但是该窗口并不是模态的,但又不能让其打开多次 1:定义该窗口变量 CEx07aDialog* m_pDlg; m_pDlg = new CEx07aDialog(this); 2:判断方该窗口是否已经存在,不存在则让其实例化 if (m_pDlg->GetSafeHwnd() == 0) { m_pDlg->Create(); } //该窗口隐藏,此时效果好象是 visible = flase m_pDlg->DestroyWindow(); //删除该窗口 delete m_pDlg; ◆得到系统中设置的窗口颜色◆ ===================================================== dc.SetBkColor(::GetSysColor(COLOR_WINDOW)); ::GetSysColor(COLOR_WINDOW)为系统的设置 ◆如何让点下去的菜单成为 V 状态◆ ===================================================== 1:先对事件申明一个宏 ON_UPDATE_COMMAND_UI(IDM_BLUE, OnUpdateColor) 2:在事件中写下: void CHelloWnd::OnUpdateColor(CCmdUI* pCmdUI) { pCmdUI->SetCheck(pCmdUI->m_nID == m_nIDColor); } 其中: CCmdUI 只在 ON_UPDATE_COMMAND_UI 中才用 pCmdUI->m_nID 是表示用户当前点下的菜单 m_nIDColor 是用户定义的菜单 ID 号,定义方法:UINT m_nIDColor; ◆如何调用 WINDOWS 的颜色板◆ ===================================================== 例一: void CHelloWnd::OnCustomColor() { CColorDialog dlgColor(m_clrText); if (dlgColor.DoModal() == IDOK) { m_clrText = dlgColor.GetColor(); Invalidate(); } } 其中: Invalidate()作用是让相应的窗口进行颜色的刷新,触发 ONPAINT 事件 然后在该事件中写相应的语句,m_clrText 为用户选择的颜色 COLORREF m_clrText; ◆如何产生一个 MDI 的主窗口◆ ===================================================== BOOL CTestApp::InitInstance() { Enable3dControls(); CTestWindow* pMainWnd = new CTestWindow; if (!pMainWnd->Create(NULL, "Control Test App", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL, MAKEINTRESOURCE(AFX_IDI_STD_FRAME)/*menu*/)) return FALSE; pMainWnd->m_bAutoMenuEnable = FALSE; // do manual menu enabling pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd = pMainWnd; // store in CWinApp member return TRUE; } 其中: CTestWindow 是一个标准的类产生的 class CTestWindow : public CFrameWnd AFX_IDI_STD_FRAME 是一个用户自己定义的菜单 例二:单一的主窗口建立 CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CEx03aDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CEx03aView)); //其中 SW_SHOW 是 ShowWindow 函数的一个参数 m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); ◆如何让一个文本控件显示出值◆ ===================================================== SetDlgItemInt(IDC_NUMBEROUT, m_nNumber); 其中:IDC_NUMBEROUT 是一个文本控件的 ID 号,m_nNumber 是一个数字型变量 ◆如何让一个控件显示出相应的值◆ ===================================================== 例一: SetDlgItemText(IDC_STATIC_TRACK1, strText1); 其中 strText1 是一个字符型变量 而 IDC_STATIC_TRACK1 可以是一个文本、一个按钮、一个 EDIT 等 例二: IDC_STATIC_TRACK1.SetWindowText("Delete"); 而 IDC_STATIC_TRACK1 可以是一个文本、一个按钮、一个 EDIT 等 ◆在调试中怎么样 MESSAGEBOX 一个数字◆ ===================================================== 例一: CString strMsg; strMsg.Format("%d", dlg.m_nNumber); AfxMessageBox(strMsg); 其中: dlg.m_nNumber 是一个数字型变量 strMsg.Format("%d", dlg.m_nNumber);是将该变量以某种方式显示 例二:对于很低大数值的数字可以用下列方法转换 char buf[256] ; _ltoa((long)f_file.GetLength(),buf, 10) ; MessageBox(buf); ◆如何控制控件的焦点◆ ===================================================== 例一:两个按钮 if (prevButton.IsWindowEnabled() == 0) //若 prevButton 不能得到焦点,则让 nextButton 得到焦点 nextButton.SetFocus(); else if (!nextButton.IsWindowEnabled()) prevButton.SetFocus(); 其中:IsWindowEnabled()若返回值大于 0,则可以得到焦点,否则是 enabled = false 例二:在对话框中,将让 IDC_COMBO1 得到焦点 GotoDlgCtrl(GetDlgItem(IDC_COMBO1)); 其中: GetDlgItem(IDC_COMBO1)是将 IDC_COMBO1 控件返回ID值 GotoDlgCtrl 将焦点移到该控件上 ◆如何对析构函数中对象进行释放◆ ===================================================== CNotepadView::CNotepadView() { m_pFindDialog = new CFindDlg; m_pGotoDialog = new CGotoDlg; } CNotepadView::~CNotepadView() { delete m_pGotoDialog; delete m_pFindDialog; } ◆如何关闭一个模态窗口◆ ===================================================== 让一个按钮定义一个事件,触发窗口中某函数,用 EndDialog(TRUE);来关闭该窗口 void CFindDlg::OnEditFindNext() { EndDialog(TRUE); } ◆如何将一个提示的声音发到声卡上◆ ===================================================== MessageBeep(2006); ◆如何得到打开 exe 的带的参数◆ ===================================================== //用下面两句可以将参数放到变量中 CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); //调用系统默认处理,如"/p 文件"打印该文件 if (!ProcessShellCommand(cmdInfo)) return FALSE; ◆如何在框架上建立一个工具条◆ ===================================================== 例一: 1:定义一个变量 CToolBar m_wndToolBar; 2:在框架窗口的 Oncreate 函数中,写下 //其中 this 是指框架窗口,IDR_MAINFRAME 是指工具条名 if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { //没有成功处理 TRACE0("Failed to create toolbar\n"); return -1; // fail to create } //允许在本框架窗口中工具条可以任意依靠 EnableDocking(CBRS_ALIGN_ANY); //设置初始状态工具条在窗口什么位置 DockControlBar(&m_wndToolBar,AFX_IDW_DOCKBAR_LEFT); ◆如何生成一个主窗口下方的状态条◆ ===================================================== 例一: 1:先在框架窗口的.h 文件上中声明一个数组,用来说明状态条有几列 static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; 2:在 CPP 中定义 CStatusBar m_wndStatusBar; 3:在框架窗口的 oncreate 函数中,写下 //其中 this 是指框架窗口, //indicators 是指上面定义的数组 //sizeof(indicators)/sizeof(UINT) = 4 表示状态列有几列 if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { //不成功的处理 TRACE0("Failed to create status bar\n"); return -1; // fail to create } //设置状态条的相应的状态 m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); //让状态条可以移动 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); ◆如何让 Cscrollview 类中控制其可以流动区域大小◆ ===================================================== //在该视中 OnInitialUpdate 函数中写下 void CEx04cView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal(20000, 30000); //整个区域的大小 CSize sizePage(sizeTotal.cx / 2, sizeTotal.cy / 2); //点到滚动条时,横向、纵向改变多少 CSize sizeLine(sizeTotal.cx / 50, sizeTotal.cy / 50); //点到滚动条上按钮时,横向、纵向改变多少 SetScrollSizes(MM_HIMETRIC, sizeTotal, sizePage, sizeLine); //将参数设置,其中 MM_HIMETRIC 是 说明单位为(0.01mm) } ◆MFC 中控件的一些基本控制方法◆ ===================================================== ◆如何让一个数字型变量化为字符型变量◆ ===================================================== CString strText; strText.Format("%d", pSlide->GetPos()); MessageBox(strText); 其中:pSlide->GetPos()是返回一个数字型变量,经过 format 后,strText 得到返回格式的字符型变量 ◆如何使用“拉动条”,“上下选择”◆ ===================================================== 在 VC 中系统中,当“拉动条”,“上下选择”进行动作时,会触发窗口的相应事件 如: 横向则是:OnHScroll 纵向则是:OnVScroll 程序可以根据函数中传入的当前控件来作处理 例一:处理两个横向拉动条拉动,并将其新的状态值显示出来 void CEx06bDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { //上面的三个参数分别表示:用户操作方式、控件位置、控件 ID 号 //将系统传入的控件转为“拉动条” CSliderCtrl* pSlide = (CSliderCtrl*) pScrollBar; CString strText; //因为有两个拉动条,所以判断是哪一个被拉动 switch(pScrollBar->GetDlgCtrlID()) { case IDC_TRACKBAR1: //IDC_TRACKBAR1 是一个拉动条的名 strText.Format("%d", pSlide->GetPos()); SetDlgItemText(IDC_STATIC_TRACK1, strText); break; case IDC_TRACKBAR2: //IDC_TRACKBAR2 是另一个拉动条的名 strText.Format("%3.1f", dValue[pSlide->GetPos()]); SetDlgItemText(IDC_STATIC_TRACK2, strText); break; } } ◆如何使用 LIST CONTROL 控件( 该 控 件 可 以 变 为 grid) ◆ ===================================================== 例一: //先从资源文件中引入 ICO 文件,并放到新建立的 CImageList 控件中 //好让这些 ICO 放到 LIST CONTROL 控件中 HICON hIcon[8]; int n; CImageList m_imageList; m_imageList.Create(16, 16, 0, 8, 8); // 32, 32 for large icons hIcon[0] = AfxGetApp()->LoadIcon(IDI_WHITE); //在当前应用中取 ICO 文件 hIcon[1] = AfxGetApp()->LoadIcon(IDI_BLACK); hIcon[2] = AfxGetApp()->LoadIcon(IDI_RED); hIcon[3] = AfxGetApp()->LoadIcon(IDI_BLUE); hIcon[4] = AfxGetApp()->LoadIcon(IDI_YELLOW); hIcon[5] = AfxGetApp()->LoadIcon(IDI_CYAN); hIcon[6] = AfxGetApp()->LoadIcon(IDI_PURPLE); hIcon[7] = AfxGetApp()->LoadIcon(IDI_GREEN); for (n = 0; n < 8; n++) { m_imageList.Add(hIcon[n]); } //加入一个字符型数组,让其显示在 LIST CONTROL 中 static char* color[] = {"white", "black", "red", "blue", "yellow", "cyan", "purple", "green"}; //得到将窗口中已经有的 LIST CONTROL 控件 IDC_LISTVIEW1 的指针 pList CListCtrl* pList = (CListCtrl*) GetDlgItem(IDC_LISTVIEW1); //将 ICO、与字符说明放入 LIST CONTROL 中 pList->SetImageList(&m_imageList, LVSIL_SMALL); for (n = 0; n < 8; n++) { pList->InsertItem(n, color[n], n); } //设置 LIST CONTROL 中的相应属性 pList->SetBkColor(RGB(0, 255, 255)); // UGLY! pList->SetTextBkColor(RGB(0, 255, 255)); ◆如何使用 postmessage 来异步触发某事件◆ ===================================================== 例一:让一个对话窗口在关闭时,触发主窗口视中的某一个事件 1:先定义一个主窗口中视的变量 CView* m_pView; 2:在对话框中点下 OK 按钮的事件时,写下 void CEx07aDialog::OnOK() { if (m_pView != NULL) { //若 m_pView 对象存在 UpdateData(TRUE); //触发主窗口视中的 WM_GOODBYE 消息,控件是 IDOK,参数是 12 m_pView->PostMessage(WM_GOODBYE, IDOK,12); } else { CDialog::OnOK(); // modal case } } 3:在主窗口的视的.h 文件中,相应位置写下,宣告该函数,参数不要改 afx_msg LRESULT OnGoodbye(WPARAM wParam, LPARAM lParam); 4:在主窗口的视的.cpp 文件中,相应位置写下,让该函数与消息对应起来,参数不要改 ON_MESSAGE(WM_GOODBYE, OnGoodbye) 5:在主窗口的视的.cpp 文件中,写下该函数 LRESULT CEx07aView::OnGoodbye(WPARAM wParam, LPARAM lParam) { CString ss; ss.Format("%d",lParam); MessageBox(ss) ; //此时 ss 为 12 return 0L; } ◆如何使用 Sendmessage 来异步触发某事件◆ ===================================================== 例一:有一个对话窗口是从 CFileDialog 从继承出来的,现在对话框中有一个按钮 点下实现父类的"打开"事件 GetParent()->SendMessage(WM_COMMAND, IDOK); ◆如何修改父类的相关控件属性◆ ===================================================== 例一:有一个对话窗口是从 CFileDialog 从继承出来的,现在修改父类窗口中 IDOK 按钮的 text 值 BOOL CSpecialFileDialog::OnInitDialog() { BOOL bRet = CFileDialog::OnInitDialog(); if (bRet == TRUE) { //用 GetParent()来找到父类,因为 IDOK 在父类中 GetParent()->GetDlgItem(IDOK)->SetWindowText("Delete"); } return bRet; } ◆如何在程序中得到控件的名◆ ===================================================== 例一: GetDlgItem(IDC_START)->EnableWindow(FALSE); 其中 IDC_START 是一个控件的 ID 号,不管它是什么控件 例二: CProgressCtrl* pBar = (CProgressCtrl*) GetDlgItem(IDC_PROGRESS1); pBar->SetPos(m_nCount * 100 / nMaxCount); ◆如何控制菜单的事件程序◆ ===================================================== 注意对待工具条方法与对待菜单方法一样,可以多个菜单对应一个函数 例一: 1:先产生菜单,点正要有事件的菜单,点右键产生向导,选正“class name”中程序要保存的位置 也就是说,只在该 class 存在时,才能进行点正事件 2:选正"messagebs"中的事件,点"function"产生函数 3:则该函数为点下菜单所触发和事件 注意:第一步中的 class name,否则你看不到菜单的角发事件程序 例二:让菜单被打上 V 1:产生生一个"ON_UPDATE_COMMAND_UI"事件 2:在该事件函 数中写下: void CEx13aView::OnUpdateDrawCircle(CCmdUI* pCmdUI) { pCmdUI->Enable(1); //控制是否的效 pCmdUI->SetCheck(m_bPattern); //是否打上 V } 其中:Enable()表控制是否被打上 V 注意:菜单是先执行 oncommand,再执行 ON_UPDATE_COMMAND_UI 可以将上面的方法改为: oncommand 修改一个变量的值 ` ON_UPDATE_COMMAND_UI 来控菜单属性 ◆如何使用控件中的数据录入的控制属性◆ ===================================================== 用:UpdateData(FALSE)来让视中所有控件中的控制属性附到控件上 用:UpdateData(TRUE)判断控件中的录入数据是否正确,不正确时为返回值为 0 ◆哪些函数是文档、视图相互处理用的◆ ===================================================== 视图: 函数一:CEx15aDoc* pDoc = GetDocument(); 可以得到视图中联接的文档指针 ◆如何建立一个基于对话框一程序◆ ===================================================== 例一:以下代码可以建立一个只有一个对话框的应用程序 在该应用程序的主文件中写下 BOOL CEx22aApp::InitInstance() { #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif //CEx22aDlg 是要打开的对话框 ,m_pMainWnd 是表示系统的主线程 CEx22aDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { //点下 OK 按钮 } else if (nResponse == IDCANCEL) { //点下了 CANCEL 按钮 } return FALSE; //让应用程序结束 } ◆如何建立一个线程◆ ===================================================== 例一:点下一个按钮后,启动一个线程 1:用向导给该按钮加上 ID 号,并给其加上触发的事件函数,如 ID:ID_STORAGE_WRITE 函数:OnStorageWrite 2:在 OnStorageWrite 函数中写下: CWinThread* pThread = AfxBeginThread(WriteThreadProc, GetSafeHwnd()); 其中: WriteThreadProc 是线程要执行的函数 GetSafeHwnd()是要带入的参数 AfxBeginThread 还要其它函数可以设置线程的级别,见书 3:写要使用线程运行的函数,其定义的格式要一定 UINT WriteThreadProc(LPVOID pParam) { //一个要运行很长时间的程序,注意线程只运行一次,只是分时运行 return 0; } 例二: 1: CWinThread* pThread = AfxBeginThread(CC, pmser); ◆如何让窗口产生一个图标(从应用程序资源中取出)◆ ===================================================== SetIcon(AfxGetApp()->LoadIcon(IDI_ICON6),TRUE); 其中该语句写在框架窗口的 oncreate 事件中,IDI_ICON6 为图标号 ◆如何得到一个 edit 的录入的值◆ ===================================================== 以下代码是从 IDC_EDIT1 有 EDIT 中取出值,记录到 HOST 中 CEdit *m_eTemp=new CEdit; m_eTemp=(CEdit*)GetDlgItem(IDC_EDIT1); CString HOST; m_eTemp->GetWindowText(HOST); ◆如何启动 TIMER 事件◆ ===================================================== 例一:让 TIMER 事件启动,并更改一个图形控件的图形 1:先调用 SetTimer 语句 m_TimerID=SetTimer(1,500,NULL); 2:启动 TIMER 事件中写下 void CConnect::OnTimer(UINT nIDEvent) { static BOOL start=TRUE; //更改一个图形控件的图形 start=!start; HICON hIcon=AfxGetApp()->LoadIcon((start)?IDI_ICON1:IDI_ICON2); m_Pic.SetIcon(hIcon); UpdateWindow(); CDialog::OnTimer(nIDEvent); } 3:关闭 timer 事件,其中 m_TimerID 是建立了事件句柄 注意在窗口删除时,一定要调用此句 KillTimer(m_TimerID); ◆如何使用 ctrllist 控件实现表格◆ ===================================================== 例一: lst_ip.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES); lst_ip.InsertColumn(1,_T("用户名称"),LVCFMT_LEFT,200); lst_ip.InsertColumn(2,_T("IP 地址"),LVCFMT_LEFT,200); BeginWaitCursor(); //显示沙漏标 Enumerate(0); GetIP(); EndWaitCursor(); ◆如何从 INI 文件中得到值◆ ===================================================== 例一:从 INI 文件中取值到 confChat 结构中 CWinApp *pTheApp = AfxGetApp(); //得到当前应用 confChat.nProxyType = pTheApp->GetProfileInt( "Network", "ProxyType", HTTP_PROXY ); confChat.szProxyIP = pTheApp->GetProfileString( "Network", "ProxyIP", "127.0.0.1" ); ◆如何将图标文件写到窗口中◆ ===================================================== 例一:将资源文件中的图标文件写到窗口中 1:定义一个图标文件变量 HICON m_hIcon; 2:取出资源文件中的图标文件 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 3:放到窗口中 SetIcon(m_hIcon, TRUE); // Set big icon ◆如何得到本机的 IP 地址◆ ===================================================== 例一:下面代码是将本机的 IP 地址放到 confChat 结构的 szLocalIP 变量中 void CChatDlg::GetLocalIP() { char buf[108]; struct hostent *ip; if( gethostname( buf, 108 ) != 0 ) return; ip = gethostbyname( buf ); if( ip != NULL ) { confChat.szLocalIP.Format("%s", inet_ntoa( *(LPIN_ADDR)(ip->h_addr_list[0]) ) ); } } ◆如何使用全局变量◆ ===================================================== 例一: 1:在全局变量中定义 CString kk; 2:在要使用的地方(*.app)文件的开头写上 extern CString kk; //关联全局变量 ◆如何让一个字符加上回车、换行◆ ===================================================== strTemp += _T("\r\n"); ◆如何定义、使用结构◆ ===================================================== 例一:定义结构方法如下: struct st_mem_index { unsigned long NO; //编号 int mark; //是否有数据 unsigned int len; //块长度 BYTE* Place; //首地址 int readonly; //是否可读 }; 使用结构可以是结构数组,也可以是变量 st_mem_index st_list[999]; st_mem_index st_list; st_list[3].NO=1 ◆如何在任意程序中显示 MessageBox◆ ===================================================== 例一:用 API 来实现 ::MessageBox(NULL,"标题","内容",MB_OK); ◆如何在程序判断出 debug 状态◆ ===================================================== 例:以下句是当程序在 DEBUG 状态时,将反馈信息显示在 debug 信息档中 CFile f; CFileException e; char* pFileName = "test.dat"; if( !f.Open( pFileName, CFile::modeCreate | CFile::modeWrite, &e ) ) { //如果是 debug 状态 #ifdef _DEBUG afxDump << "File could not be opened " << e.m_cause << "\n"; #endif } ◆当对话框中有一个滚动条是,当滚动滚动条时的消息控制函数◆ ================================================================================= enum { nMin = 0 };滚动条的最小值 enum { nMax = 100 };滚动条的最大值 在 INITOnInitDialog() 中要进行初始化: { CScrollBar* pSB = (CScrollBar*) GetDlgItem(IDC_LOYAL); //(空间名称*)GetDlgItem(控件 ID) pSB->SetScrollRange(nMin, nMax); pSB = (CScrollBar*) GetDlgItem(IDC_RELY); pSB->SetScrollRange(nMin, nMax); } 当滚动条滚动时,就会触发 WM_HSCROLL 消息——————那么与 OnHScroll 函数联系; void CEx06aDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) //水平滚动 { int nTemp1, nTemp2; nTemp1 = pScrollBar->GetScrollPos(); switch(nSBCode) { case SB_THUMBPOSITION: pScrollBar->SetScrollPos(nPos); break; case SB_LINELEFT: // left arrow button nTemp2 = (nMax - nMin) / 10; if ((nTemp1 - nTemp2) > nMin) { nTemp1 -= nTemp2; } else { nTemp1 = nMin; } pScrollBar->SetScrollPos(nTemp1); break; case SB_LINERIGHT: // right arrow button nTemp2 = (nMax - nMin) / 10; if ((nTemp1 + nTemp2) < nMax) { nTemp1 += nTemp2; } else { nTemp1 = nMax; } pScrollBar->SetScrollPos(nTemp1); break; } } ◆将一个 CWnd 指针转换成一个控件 ID(整数)注意用 GetDlgItem()函数是从一个控件 ID 转换成一个 CWnd 的指针◆ ================================================================================= int ID_XX; ID_XX = ::GetDlgCtrlID(*pSB); CDialogMy::GetSafeHwnd()==========得到指定窗口 CDialogMy(CDialog 的派生窗口)的句柄 ◆如果在对话框中自定义一个消息的方法,假设对话框名为 CXX◆ ================================================================================= 注意:自定义消息在*.h 中加入函数原型:afx_msg LRESULT OnGoodbye(WPARM wparam,LPARM lparm); 注意:自定义消息在*.cpp 中必须加在 BEGAIN_MESSAGE_MAP 语句之后,而且在 AFX_MSG_MAP 括弧之外; 如:ON_MESSAGE(WM_GOODBYE,OnGoodbye); 1、在 CXX.H 中添加:#define WM_GOODBYE WM_USER + 5(WM_GOODBYE 是自定义消息名, WM_USER + 5 是消息 ID); 2、利用 SendMessage()和 PostMessage()来发送消息; 2.1、SendMessage()表示立刻可以导致对消息控制函数的调用; 2.2、PostMessage()表示将消息放进 windows 的消息队列中;( 调用类(CView)->PostMessage(自定义消息名,对象ID)) ◆消息传递◆ ================================================================================= 在 WIN32 中,wParam 和 lParam 参数是用来传递消息数据的最主要的手段。 在自定义消息,我们只能使用 wParam 和 lParam 来传递消息数据, ◆在一个函数引用另外的一个对话框◆ ================================================================================= CTestDlg *dlg;//首先根据对话框,定义一个指针; dlg = new CTestDlg() ;//产生一个对话框对象; dlg = (CTestDlg*)((AfxGetApp()->m_pMainWnd)) ; //AfxGetApp()-----》得到应用程序指针;而 m_pMainWnd 是窗口指针,然后进行强制转换 //此后就可以应用 dlg 了!!!!如:dlg->GetDlgItem(IDC_NAME)->SetWindowText("ok"); ◆全局函数的申明问题◆ ================================================================================= 一般情况下: A:申明一个 QJ*.H 文件,在这个头文件中声明全局函数; B:在需要用此全局函数的*.h 中写“#INCLUDE QJ*.H”,那么在*.CPP 中就可以使用此全局函 数了; ◆在应用程序中*APP.CPP 中的 InitInstance()的事件◆ ================================================================================= BOOL CMeterApp::InitInstance() { #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif CMeterDlg dlg;(CMeterDlg 是对话框) m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { } return FALSE; } ◆给执行文件加一个图标◆ ================================================================================= m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME) AfxGetApp()//返回一个指针指向 CWinApp for the application. ◆如何在全局函数中通过传入的窗口句柄操作窗口◆ ================================================================================= CTestdlg* test = (CTestdlg*)CWnd::FromHandle(cwnd); test->Attach(cwnd); 或 CTestDlg *test; test=new CTestDlg; test->Attach(hWnd); http://www.vckbase.com/ http://www.programlife.com/ http://www.tomda.com.cn/jc/ http://member.netease.com/~small/bar_on_top.html http://www.chinaprogrammer.com/ ================================================================================= ◆如何使桌面文字背景透明?◆ ================================================================================= HWND hWnd; hWnd = GetDesktopWindow(); if ((hWnd = FindWindowEx(hWnd, 0, "Progman", "Program Manager")) == 0) return ; if ((hWnd = FindWindowEx(hWnd, 0, "SHELLDLL_DefView", NULL)) == 0) return ; if ((hWnd = FindWindowEx(hWnd, 0, "SysListView32", NULL)) == 0) return ; // Change icon text attributes SendMessage(hWnd, 0x1026, 0, 0xffffffff); // Turn background to transparent SendMessage(hWnd, 0x1024, 0, 0x00ffffff); // Turn foregound to white InvalidateRect(hWnd, NULL, TRUE); // Repaint return ; ================================================================================= ◆怎样才能在 VC 里产生一个唯一的字符串◆ ================================================================================= 可以用 CoCreateGUID 产生一个 128 位的 CLSID,然后用 StringFromCLSID 把它转变为 OLE 字符串。 GUID guid; CoCreateGuid(&guid); LPOLESTR lpCLSID; StringFromCLSID(guid,&lpCLSID); char lpAnsiCLSID[256]; WideCharToMultiByte(CP_ACP,0,lpCLSID,-1,lpAnsiCLSID,256,0,0); OutputDebugString(lpAnsiCLSID); ================================================================================= ◆如何隐藏进程(在系统状态栏和进程列表里不可见)◆ ================================================================================= 可以创建一个服务应用程序(Server Process)。 typedef DWORD (WINAPI Fun) (DWORD,DWORD); HINSTANCE hKernel=LoadLibrary("Kernel32.dll"); if ( hKernel != NULL ) { Fun *RegisterServerProcess=(Fun *)GetProcAddress(hKernel,"RegisterServerProcess"); ( *RegisterServerProcess)(NULL,1); FreeLibrary(hKernel); } ================================================================================= ◆如何得到一个确定大小的视?◆ ================================================================================= A:有时我们要得到创建一个特定大小的视,比如一个 400x500 的象棋棋盘视。但是我们不能直接改变视 的大小,而必须通过改变包含视的框架。当改变框架大小时,就改变了整个窗口的大小,包括非客户区。 应此,要想得到 400x500 的视,视的框架必须大于 400x500。具体要大多少,取决于几个因素。首先,非 客户区的大小取决于你使用的硬件、用户的喜好以及其它。同时视包含一个较小的非客户区。为了使视的 非客户区大小为 400x500,必须先计算出视的整个大小,包括非客户区,然后计算出多大的框架才能包含 该尺寸的视。 函数 AdjustWindowRectEx 可以根据客户区的大小计算出窗口(视也是窗口)的整个大小。你必须提 供窗口的风格和标志,并且说明窗口是否有菜单。 窗口的风格和标志可以用 GetStyle 和 GetStyleEx 函数 得到,如果你要在拥有窗口之前得到尺寸,可以用 Spy++等工具来获取风格(在不同机器上窗口尺寸可能 不同,但窗口风格不变),并把它们进行硬编码。 〖参考代码〗 //下面是创建客户区大小为 400x500 像素的视的例子代码。 CRect rcClient(0,0,400,500); CWnd *frame=(CWnd *)GetParentFrame(); ::AdjustWindowRectEx(&rcClient,GetStyle(), FALSE/*视没有菜单*/,GetExStyle()); // 得到视的大小 ::AdjustWindowRectEx(&rcClient,frame->GetStyle(), TRUE/*主框架窗口有菜单*/,GetExStyle()); // 得到包含视的框架大小 frame->SetWindowPos(NULL,0,0,rcClient.Width(),rcClient.Height(), SWP_NOACTIVE | SWP_NOMOVE | SWP_NOZORDER ); ================================================================================= ◆如何实现点击窗口任意地方拖动窗口?◆ ================================================================================= A:系统是根据 WM_NCHITTEST 消息返回的值确定鼠标在窗口什么位置的,我们可以通过修改该消息返 回值使系统认为鼠标在窗口标题上。对于对话框和基于对话的应用程序,可以使用 ClassWizard 处理该信 息并调用基类函数,如果函数返回 HTCLIENT 则表明鼠标在客户区,修改返回值为 HTCAPTION 以欺骗 系统鼠标在的标题栏中. 〖参考代码〗 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 ); // 欺骗主框架窗口单击标题栏了. GetParentFrame ( ) — > PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARAM (poitn.x , point.y) ); } 该技术也适用于对话框和基于对话的应用程序,只是不必调用 CWnd::GetParentFrame. void CSampleDialog::OnLbuttonDown (UINT nFlags, Cpoint point ) { Cdialog::OnLButtonDow (nFlags,goint ); // 欺骗对话框单击它的标题栏了. PostMessage (WM_NCLBUTTONDOWN, HTCAPTION,MAKELPARM (point.x,point.y ) ) ; } ================================================================================= ◆如何在启动时阻止 MDI 应用程序创建一个新文档?◆ ================================================================================= A:可 以在 MFC 应用程序中,命令行处理阶段控制着程序的初始表现(例如程序启动后创建一个新文档)。 下面是 APP 类的 InitInstance()函数的命令处理代码: // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); // 分析命令行参数并填充 cmdInfo // Dispatch commands specified on the command line if (!ProcessShellCommand(cmdInfo)) // 处理命令行参数 return FALSE; cmdInfo 描述命令行参数信息,有以下主要成员: 成 员 描 述 ParseParam 重载以提供定制的参数分析 m_bShowSplash 指示是否显示一个醒目的屏幕画面 m_bRunEmbeded 指示发现了命令行/Embededing 选项 m_bRunAutoMated 指示发现了命令行/Automation 选项 m_nShellCommand 指示外壳命令处理结果(取值见下表) m_strPrinterName 如果外壳命令为 Print To 则指示打印机名,否则为空 m_strFileName 指示打开或打印的文件名,如果外壳命令为 New 或 DDE 则为空 m_strDriverName 如果外壳命令为 Print To 则指示驱动器名,否则为空 m_strPortName 如果外壳命令为 Print To 则指示端口名,否则为空 m_nShellCommand 可以取以下值:FileNew、FileOpen、FilePrint、FilePrintTo、FileDDE、FileNothing 。 当 m_nShellCommand 的值为 FileNew 时将在程序开始时创建一个新文档,可以修改上面的代码以阻止创 建一个新文档。 〖参考代码〗 // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if (cmdInfo.m_nShellCommand == FileNew ) cmdInfo.m_nShellCommand=FileNothing; // Dispatch commands specified on the command line if (!ProcessShellCommand(cmdInfo)) return FALSE; ================================================================================= ◆如何在多文档 MFC 程序中制作独立的 File|New 菜单?◆ ================================================================================= A:在多文档的 MFC 应用程序中,FileNew 的缺省处理方法将创建一个包含程序模板列表中所有文档模板 的列表的对话框。但是,通常的非 MFC 应用程序采用连级菜单的方法,为每种类型的文档提供一个新建 命令。 如果你知道每种类型的文档对应的文档模板,可以为每种文档制作一个定制的菜单处理函数,然后使 用合适的文档模板调用 OpenDocumentFile 函数就可以了。 〖参考代码〗 void CLiveDoc::OnNewText() { // 历遍文档模板列表以得到合适的文档模板,也可以在创建文档模板时预先保存模板的指针 POSITION pos; pos=GetFirstDocTemplatePosition(); CDocTemplate *p=GetNextDocTemplate(&pos); while ( TRUE ) { // 假设 CLiveTextDoc 为文本文档的类名 if ( p==NULL || p->IsKindOf(RUNTIME_CLASS(CLiveTextDoc)) ) break; } if ( p != NULL ) p->OpenDocumentFile(NULL); else AfxMessageBox(_T("新建文本文档失败!"),MB_OK); } ================================================================================= ◆如何检测视是否处于分割状态?◆ ================================================================================= A:在许多时候我们都想得到一个分割视当前是否处于分割状态.下面这个函数返回 TRUE 时表示视当前处 于分割状态. 〖参考代码〗 int CMySplitterView::IsSplit(void) { CSplitterWnd * pv; pv = (CSplitterWnd * )GetParent( ); if ( pv->GetRowCount( ) > 1 || pv->GetColumnCount( ) > 1 ) return ( TRUE ) ; return FALSE; } ================================================================================= ◆如何使程序保持极小状态?◆ ================================================================================= A:在恢复程序窗口时,系统会发送 WM_QUERYOPEN 消息,可以在该消息处理函数中返回非使系统不发送 窗口恢复消息 〖参考代码〗 BOOL CMainFrame::OnQueryOpen() { return FALSE; } ================================================================================= ◆如何确定当前进程实例是否为唯一实例?◆ ================================================================================= A:在 16 位应用程序中,可以通过检查传递给 main 函数的 hPrevInstance 确定程序是否已经有一个实例在 运行了,但在 win32 程序中,传递给 WinMain 函数的 hPrevInstance(也就是 MFC 程序 theApp 对象的 m_hPrevinstance 成员变量)总是为 NULL。 我们是不是可以创建一个全局变量(或者静态变量)来保存程序的已运行的实例数呢?答案是在 16 位 应用程序中可以,但在 Win32 程序中,全局变量都是被限制在自己进程的私有地址空间中,是不能被进程 间共享的。不过我们可以通过修改编译器的参数来定义一个可以在进程间共享的数据区,在该共享数据区 中定义共享变量保存程序的已运行的实例数。 〖参考代码〗 1.定义共享变量 // // 定义一个共享数据区,方法是: // // 添加编译器参数 /section:shared,rws // 这就告诉编译器在“shared”数据段中定义的数据具有读(r)、写(w)和共享(s)属性。 // // 定义共享数据 // # pragma data_seg("shared") // shared 数据段开始 int gs_nModule=0; // 一定要初始化,否则会被编译到未初始化数据区中。 # pragma data_seg() // shared 数据段结束 2。在初始化实例时先判断共享变量: if ( gs_nModule != 0 ) { MessageBox(NULL,_T(" 该程序的一个实例已经运行!"),_T("Alarm"),MB_OK | MB_ICONINFORMATION); return FALSE; } gs_nModule++; ================================================================================= ◆如何向一个文档附加多个视?◆ ================================================================================= A:在文档视结构中,可以向一个文档附加多个视,比如你要创建一个电子表格程序,可以同时用表格或 饼图来表示的数据。 但是要完成这项工作是非常复杂的,你首先必须创建一个框架窗口,向它附加一个 视,然后通知文档它已经有了一个新视。不过可以用文档模板来完成这所有的工作。下面是具体实现方法: 1.创建或获取一个文档模板(可以在 InitInstance 中创建文档模板时保存一个指向它的指针). 2.调用合适的文档模板的 CreateNewFrame 函数,第一个参数为你想使用的文档指针,第二个参数使用 NULL.该函数返回一个指向新框架窗口的指针(该窗口已经包含一个附加在第一个参数中指定的文档的视) 3. 调 用 框 架 窗 口 的 InitialUpdateFrame 成 员 函 数 , 这 是 因 为 有 些 视 ( 如 CScrollView) 需 要 在 InitialUpdateFrame 中完成特定的工作。 〖参考代码〗 void CLiveDoc::OnNewTextView() { CMultiDocTemplate tempTemplate(IDR_DEBUGTYPE,RUNTIME_CLASS(CLiveDoc), RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CTextView)); CFrameWnd *frame=tempTemplate.CreateNewFrame(this,NULL); if ( ! frame ) AfxMessageBox("创建新窗口失败!"); else frame->InitialUpdateFrame(this,TRUE); } ================================================================================= ◆如何获得文件的图标、属性、大小、类型等参数?◆ ================================================================================= A:SDK 函数 SHGetFileInfo 可以获得文件的大小图标、属性、大小和类型等. 〖函数原型〗 SHDWORD SHGetFileInfo(LPCTSTR pszPath,DWORD dwFileAttributes,SHFILEINFO *psfi,UINT cbFileInfo,UINT uFlags); 〖参数说明〗 pszPath:要获得信息的文件路径 dwFileAttributes:要获得的文件属性 psfi:返回包含文件信息的 SHFILEINFO 结构,该结构在 Shellapi.h 中的定义: typedef struct _SHFILEINFOA { HICON hIcon; // out: icon int iIcon; // out: icon index DWORD dwAttributes; // out: SFGAO_ flags CHAR szDisplayName[MAX_PATH]; // out: display name (or path) CHAR szTypeName[80]; // out: type name } SHFILEINFOA; typedef struct _SHFILEINFOW { HICON hIcon; // out: icon int iIcon; // out: icon index DWORD dwAttributes; // out: SFGAO_ flags WCHAR szDisplayName[MAX_PATH]; // out: display name (or path) WCHAR szTypeName[80]; // out: type name } SHFILEINFOW; #ifdef UNICODE typedef SHFILEINFOW SHFILEINFO; #else typedef SHFILEINFOA SHFILEINFO; #endif // UNICODE cbFileInfo:SHFILEINFO 结构大小 uFlags:函数调用标志(在 psfi 结构中将返回什么信息),常用的标志有: SHGFI_ICON //得到文件图标句柄(hIcon) SHGFI_DISPLAYNAME //得到文件名(szDisplayName) SHGFI_TYPENAME //得到文件扩展名(szTypeName) SHGFI_ATTRIBUTES /得到文件属性(dwAttributes) SHGFI_SYSICONINDEX //得到文件图标在系统图标列表中的索引(iIcon) SHGFI_LARGEICON //得到的是大图标信息 SHGFI_SMALLICON //得到的是小图标的信息 函数返回系统图标列表的句柄地址。 〖参考代码〗 // Get system icon list handle. SHFILEINFO sfi; HIMAGELIST hSmallImageList; HIMAGELIST hLargeImageList; hSmallImageList=(HIMAGELIST)SHGetFileInfo(_T("c:\\"),NULL,&sfi,sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON ); // 小图标列表 hLargeImageList=(HIMAGELIST)SHGetFileInfo(_T("c:\\"),NULL,&sfi,sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_LARGEICON ); // 大图标列表 // 得到任意文件的图标在系统图标列表的索引号的代码 // Get file icon index SHFILEINFO sfi; int iSmallIcon; int iLargeIcon; // lpszFilePath 为要得到图标索引的文件名(全路径名) SHGetFileInfo(lpszFilePath,NULL,&sfi,sizeof(sfi),SHGFI_SYSICONINDEX | SHGFI_SMALLICON ); iSmallIcon=sfi.iIcon; // 小图标列表索引 SHGetFileInfo(lpszFilePath,NULL,&sfi,sizeof(sfi),SHGFI_SYSICONINDEX | SHGFI_LARGEICON ); iLargeIcon=sfi.iIcon; // 大图标列表索引 ================================================================================= ◆如何得到鼠标下面的窗口?◆ ================================================================================= A: 〖参考代码〗 POINT pt; GetCursorPos(&pt); HWND hWnd=WindowFromPoint(pt); // 得到鼠标下面的窗口句柄 HWND hChild=ChildWindowFromPoint(hWnd,pt); // 得到鼠标所在的子窗口句柄 ================================================================================= ◆设置鼠标的形状◆ ================================================================================= BeginWaitCursor(); (设置鼠标为沙漏行) ◆在对话框中设置编辑 EDIT 的值◆ ================================================================================= SetDlgItemInt(该控件的 ID,INT 值,TRUE/FALSE) SetDlgItemText(该控件的 ID , string 值) 1. 如何获取应用程序的实例句柄? 应用程序的实例句柄保存在 CWinAppIm_hInstance 中,可以这么调用 AfxGetInstancdHandle 获得句柄. Example: HANDLE hInstance=AfxGetInstanceHandle(); 2. 如何通过代码获得应用程序主窗口的指针? 主窗口的 指针保存在 CWinThread::m_pMainWnd 中,调用 AfxGetMainWnd 实现。 AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程序最大化. 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 Function void 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 的重新引导? 这是个很简单又是编程中经常要遇到的问题. 第一问,向窗口发送 WM_CLOSE 消息,调用 CWnd::OnClose 成员函数.允许对用户提 示是否保存修改过的数据. Example: AfxGetMainWindow()->SendMessage(WM_CLOSE); 还可以创建一个自定义的函数 Terminate Window void Terminate Window(LPCSTR pCaption) { CWnd *pWnd=Cwnd::FindWindow(NULL,pCaption); if (pWnd) pWnd ->SendMessage(WM_CLOSE); } 说明: FindWindow 函数不是提倡的做法,因为它无法处理标题栏自动改变,比如我 们要检测 Notepad 是不是已运行而事先不知道 Notepad 的标题栏,这时 FindWindow 就 无能为力了,可以通过枚举 windows 任务列表的办法来实现。 在机械出版社 "Windows 95 API 开发人员指南"一书有比较详细的介绍,这里就不再多说乐。 第二问,Use ExitWindowsEx Function 函数控制系统是重新引导,还是重启 windows. 前面已经有人讲过乐,就不再提了。 5.怎样加载其他的应用程序? 我记得这好象是出场频度很高的问题。 三个 SDK 函数 winexec, shellexecute,createprocess 可以使用。 WinExec 最简单,两个参数,前一个指定路径,后一个指定显示方式.后一个参数 值得说一下,比如泥用 SW_SHOWMAXMIZED 方式去加栽一个无最大化按钮的 程序,呵 呵就是 Neterm,calc 等等,就不会出现正常的窗体,但是已经被加到任务列表里了。 ShellExecute 较 WinExex 灵活一点,可以指定工作目录,下面的 Example 就是直接 打开 c:\temp\1.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); 6. 确定应用程序的路径 前些天好象有人问过这个问题. Use GetModuleFileName 获得应用程序的路径,然后去掉可执行文件名。 Example: TCHAR exeFullPath[MAX_PATH]; // MAX_PATH 在 API 中定义了吧,好象是 128 GetModuleFileName(NULL,exeFullPath,MAX_PATH) 7. 获得各种目录信息 Windows 目录: Use "GetWindowsDirectory“ Windows 下的 system 目录: Use "GetSystemDirectory" temp 目录: Use "GetTempPath " 当前目录: Use "GetCurrentDirectory" 请注意前两个函数的第一个参数为 目录变量名,后一个为缓冲区; 后两个相反. 8. 如何自定义消息 也有人问过的,其实不难。 (1) 手工定义消息,可以这么写 #define WM_MY_MESSAGE(WM_USER+100),MS 推荐 的至少是 WM_USER+100; (2)写消息处理函数,用 WPARAM,LPARAM 返回 LRESULT. LRESULT CMainFrame::OnMyMessage(WPARAM wparam,LPARAM lParam) { //加入你的处理函数 } (3) 在类的 AFX_MSG 处进行声明,也就是常说的"宏映射" 9. 如何改变窗口的图标? 向窗口发送 WM_SECTION 消息。 Example: HICON hIcon=AfxGetApp() ->LoadIcon(IDI_ICON); ASSERT(hIcon); AfxGetMainWnd() ->SendMessage(WM_SECTION,TRUE,(LPARAM) hIcon); 10. 如何改变窗口的 缺省风格? 重栽 CWnd:: PreCreateWindow 并修改 CREATESTRUCT 结构来指定窗口风格和其他创建信息. Example: Delete "Max" Button and Set Original Window's Position and Size BOOL CMainFrame:: PreCreateWindow (CREATESTRUCT &cs) { cs.style &=~WS_MAXINIZEMOX; cs.x=cs.y=0; cs.cx=GetSystemMetrics(SM_CXSCREEN/2); cs.cy=GetSystemMetrics(SM_CYSCREEN/2); return CMDIFramewnd ::PreCreateWindow(cs); } 11. 如何将窗口居中显示? Easy, Call Function CWnd:: Center Windows Example(1): Center Window( ); //Relative to it's parent // Relative to Screen Example(2): Center Window(CWnd:: GetDesktopWindow( )); //Relative to Application's MainWindow AfxGetMainWnd( ) -> Center Window( ); 12. 如何让窗口和 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 的 风格。 13. 如何使程序保持极小状态? 很有意思的问题 这么办: 在恢复程序窗体大小时, Windows 会发送 WM_QUERY-OPEN 消息, 用 ClassWizard 设置成员函数 OnQueryOpen() ,add following code: Bool CMainFrame:: OnQueryOpen( ) { Return false; } 14. 如何限制窗口的 大小? 也就是 FixedDialog 形式。 Windows 发送 WM_GETMAXMININFO 消息来跟踪, 响应它,在 OnGetMAXMININFO 中写代码: 15. 如何使窗口不可见? 很简单,用 SW_HIDE 隐藏窗口,可以结合 FindWindow,ShowWindow 控制. 16. 如何使窗口始终在最前方? 两种途径. 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); } 17、如何创建一个字回绕的 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 ; } 18、通用控件的显示窗口 MFC 提供了几个 CView 派生的视窗类, 封装了通用控件的功能,但仍然使用工 作框文档显示窗口体系结构:CEditView 封装了编辑控件,CTreeView 保持了树列表 控件,CListView 封装了列表显示窗口控件,CRichEditView 可以处理多种编辑控件。 19、移动窗口 调用 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); 20、重置窗口的大小 调用 CWnd: : SetWindowPos 并指定 SWP_NOMOVE 标志, 也可调用 CWnd : : MoveWindow 但必须指定窗口的位置。 // Get the size of the window . Crect reWindow ; GetWindowRect (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 ); 21、如何单击除了窗口标题栏以外的区域使窗口移动 当窗口需要确定鼠标位置时 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 clicked on its 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 its caption bar . PostMessage (WM_NCLBUTTONDOWN , HTCAPTION , MAKELPARM (point.x , point. y ) ) } 22、如何改变视窗的背景颜色 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 reClip ; pDC—>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; } 23、如何改变窗口标题 调用 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 (reduces flash in the controls ) if (nNewLen >_contof (szOld) || : : GetWindowText (hWndCrtl , szOld , _countof (szOld) !=nNewLen || Istrcmp (szOld , IpszNew )! = 0 { //change it : : SetWindowText (hWndCtrl , IpszNew ); } } 24、如何防止主框窗口在其说明中显示活动的文档名 创建主框窗口和 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 来设置标题。记住自己设置标题时要遵循接口风格指南。 25、如何获取有关窗口正在处理的当前消息的信息 调用 CWnd: : GetCurrentMessage 可以获取一个 MSG 指针。例如,可以使用 ClassWizard 将几个菜单项处理程序映射到一个函数中,然后调用 GetCurrentMessage 来确定所选中的菜单项。 viod CMainFrame : : OnCommmonMenuHandler ( ) { //Display selected menu item in debug window . TRACE ("Menu item %u was selected . \n" , GetCruuentMessage ( ) —> wParam ); } 26、如何创建一个不规则形状的窗口 可以使用新的 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 rcDialog ; GetClientRect (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 border dc. SelecStockObject (NULL_PEN); //get the RGB colour components of the sphere color COLORREF color= RGB( 0 , 0 , 255); BYTE byRed =GetRValue (color); BYTE byGreen = GetGValue (color); BYTE byBlue = GetBValue (color); // get the size of the view window Crect rect ; GetClientRect (rect); // get minimun number of units int nUnits =min (rect.right , rect.bottom ); //calculate he horiaontal and vertical step size float fltStepHorz = (float) rect.right /nUnits ; float fltStepVert = (float) rect.bottom /nUnits ; int nEllipse = nUnits/3; // calculate how many to draw int nIndex ; // current ellipse that is being draw CBrush brush ; // bursh used for ellipse fill color CBrush *pBrushOld; // previous brush that was selected into dc //draw ellipse , gradually moving towards upper-right corner for (nIndex = 0 ; nIndes < + nEllipse ; nIndes ++) { //creat solid brush brush . CreatSolidBrush (RGB ( ( (nIndex *byRed ) /nEllipse ). ( ( nIndex * byGreen ) /nEllipse ), ( (nIndex * byBlue) /nEllipse ) ) ); //select brush into dc pBrushOld= dc .SelectObject (&brhsh); //draw ellipse dc .Ellipse ( (int) fltStepHorz * 2, (int) fltStepVert * nIndex , rect. right -( (int) fltStepHorz * nIndex )+ 1, rect . bottom -( (int) fltStepVert * (nIndex *2) ) +1) ; //delete the brush brush.DelecteObject ( ); } } 最后,处理 WM_NCHITTEST 消息,使当击打窗口的任何位置时能移动窗口。 UINT CRoundDlg : : OnNchitTest (Cpoint point ) { //Let user move window by clickign anywhere on the window . UINT nHitTest = CDialog : : OnNcHitTest (point) ; rerurn (nHitTest = = HTCLIENT)? HTCAPTION: nHitTest ; } 27、如何在代码中获取工具条和状态条的指针 缺省时, 工作框创建状态条和工具条时将它们作为主框窗口的子窗口,状态条 有一个 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); 28、如何使能和禁止工具条的工具提示 如果设置了 CBRS_TOOLTIPS 风格位,工具条将显示工具提示,要使能或者禁止 工具提示,需要设置或者清除该风格位。下例通过调用 CControlBar : : GetBarStyle 和 CControlBar : : SetBarStyle 建立一个完成此功能的成员函数: void CMainFrame : : EnableToolTips ( BOOL bDisplayTips ) { ASSERT_VALID (m_wndToolBar); DWORD dwStyle = m _wndToolBar.GetBarStyle ( ) ; if (bDisplayTips) dwStyle |=CBRS_TOOLTIPS ; else dwStyle & = ~ CBRS_TOOLTIPS ; m_wndToolBar.SetBarStyle (dwStyle ); } 29、如何设置工具条标题 工具条是一个窗口,所以可以在调用 CWnd : : SetWindowText 来设置标题, 例子如下: int CMainFrame : : OnCreate (LPCREATESTRUCT lpCreateStruct ) { … // Set the caption of the toolbar . m_wndToolBar.SetWindowText (_T "Standdard"); 30、如何创建和使用无模式对话框 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 rountine will 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 CSampleDialog ; ASSERT_VALID (pDialog) ; //Create the modeless dialog . BOOL bResult = pDialog —> Creste (IDD_IDALOG) ; ASSERT (bResult ) ; } 31、如何在对话框中显示一个位图 这要归功于 Win 32 先进的静态控件和 Microsoft 的资源编辑器, 在对话框中 显示位图是很容易的, 只需将图形控件拖到对话中并选择适当属性即可,用户也 可以显示图标、位图以及增强型元文件。 32、如何改变对话或窗体视窗的背景颜色 调用 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 ); } 33、如何获取一个对话控件的指针 有两种方法。其一,调用 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 对话。 34、如何禁止和使能控件 控件也是窗口,所以可以调用 CWnd : : EnableWindow 使能和禁止控件。 //Disable button controls . m_wndOK.EnableWindow (FALSE ) ; m_wndApply.EnableWindow (FALSE ) ; 35、如何改变控件的字体 由于控件是也是窗口,用户可以调用 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 font m_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 _QUALITY VARIABLE_PITCH |FF_SWISS, _T ("Arial") ); //Set font for push button . m_wndButton . SetFont (&m _font ); … } 36、如何在 OLE 控件中使用 OLE_COLOR 数据类型 诸如 COleControl : : GetFortColor 和 COleControl : : GetBackColor 等函数 返回 OLE _COLOR 数据类型的颜色,而 GDI 对象诸如笔和刷子使用的是 COLORREF 数据类 型,调用 COleControl : : TranslateColor 可以很容易地将 OLE_COLOR 类型改为 COLORREF 类型。下例创建了一个当前背景颜色的刷子: void CSampleControl : : OnDraw (CDC* pdc const Crect& rcBounds , const Crect& rcInvalid ) { //Create a brush of the cuttent background color . CBrush brushBack (TranslateColor (GetBackColor ( ) ) ); //Paint the background using the current background color . pdc—> FilllRect (rcBounds , &brushBack) ; //other drawign commands … } 37、在不使用通用文件打开对话的情况下如何显示一个文件列表 调用 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 ; } 38、为什么旋转按钮控件看起来倒转 需要调用 CSpinCtrl : : SetRange 设置旋转按钮控件的范围,旋转按钮控件 的缺省上限为 0,缺省下限为 100,这意味着增加时旋转按控件的值由 100 变为 0。 下例将旋转按钮控件的范围设置为 0 到 100: BOOL CAboutDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //set the lower and upper limit of the spin button m_wndSpin . SetRange ( 0 ,100 ) ; return TRUE ; } Visual C++ 4.0 Print 对话中的 Copise 旋转按钮控件也有同样的问题:按下 Up 按钮时拷贝的数目减少,而按下 Down 按钮时拷贝的数目增加。 39 为什么旋转按钮控件不能自动地更新它下面的编辑控件 如果使用旋转按钮的 autu buddy 特性, 则必须保证在对话的标记顺序中 buddy 窗口优先于旋转按钮控件。从 Layout 菜单中选择 Tab Order 菜单项(或者按 下 Crtl+D)可以设置对话的标签顺序。 40、如何用位图显示下压按钮 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 ; } 41、如何一个创建三态下压按钮 可以使用新的 BS_PUSHBUTTON 风格位和检测框以及按钮来创建一个三态下 压按钮。这很容易,只需将检测框和按钮拖拉到对话中并指定属性 Push—like 即 可。不用任何附加程序就可以成为三态下压按钮。 42、如何动态创建控件 分配一个控件对象的实例并调用其 Create 成员函数。开发者最容易忽略两件 事:忘记指定 WS_VISBLE 标签和在栈中分配控件对象。下例动态地创建一个下压按 钮控件: //In class declaration (.H file ). private : CButton* m _pButton ; //In class implementation (.cpp file ) . m_pButton =new CButton ; ASSERT_VALID (m_pButton); m_pButton —>Create (_T ("Button Title ") , WS_CHILD |WS_VISIBLE | BS_PUSHBUTTON. Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON ) 43、如何限制编辑框中的准许字符 如果用户在编辑控件中只允许接收数字,可以使用一个标准的编辑控件并指 定新的创建标志 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 uppercase void 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 )) ; } 44、如何改变控件的颜色 有两种方法。其一,可以在父类中指定控件的颜色,或者利用 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 { … private; COLORREF m_clrFor ; // foreground color COLORREF m_clrBack ; //background color Cbrush m_brush ; //background brush … } ; 其次,在类的构造函数中,初始化数据中。 CMyListBox : : CMyListBox () { //Initialize data members . m_clrFore =RGB (255 , 255 , 0) ; // yellow text m_clrBack=RGB (0 , 0 , 255) ; // blue background m_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 () } 现在,控件可以自己决定如何绘画,与父窗口无关。 45、当向列表框中添加多个项时如何防止闪烁 调用 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 (); 46、如何向编辑控件中添加文本 由于没有 CEdit:: AppendText 函数,用户只好自己做此项工作。调用 CEdit:: SetSel 移动到编辑控件末尾,然后调用 CEdit:: ReplaceSel 添加文 本。下例是 AppendText 的一种实现方法: void CMyEdit:: AppendText (LPCSTR pText) { int nLen=GetWindowTextLength (); SetFocus (); SetSel (nLen, nLen); ReplaceSel (pText); } 47、如何访问预定义的 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 rcView; GetClientRect (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 rcView; GetClientRect (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); } 48、如何获取 GDI 对象的属性信息 可以调用 GDIObject:: GetObject。这个函数将指定图表设备的消息写入到 缓冲区。下例创建了几个有用的辅助函数。 //Determine if font is bold. BOOL IsFontBold (const CFont&font) { LOGFONT stFont; font.GetObject (sizeof (LOGFONT), &stFont); return (stFont.lfBold)? TRUE: FALSE; } //Return the size of a bitmap. CSize GetBitmapSize (const CBitmap&bitmap) { BITMAP stBitmap; bitmap.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 stBrush; brush.Getobject (sizeof (LOGBRUSH), &stBrush); return pen. Createpen (PS_SOLID, 0, stBrush.ibColor); } 49、如何实现一个橡皮区矩形 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 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); } 最后,使用 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); } else pDoc->m-tracker.TrackRubberBand (this,point,TRUE); CView:: onLButtonDown (nFlags,point); } 50、如何更新翻转背景颜色的文本 调用 CDC:: SetBkmode 并传送 OPAQUE 用当前的背景颜色填充背景,或者调用 CDC::SetBkMode 并传送 TRANSPAARENT 使背景保持不变,这两种方法都可以设置背景 模式。下例设置背景模式为 TRANSPARENT,可以两次更新串,用花色带黑阴影更新 文本。黑色串在红色串之后,但由于设置了背景模式仍然可见。 void CSampleView:: OnDraw (CDC* pDC) { //Determint size of view. CRect rcView; GetClientRect (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); } 51、如何创建一个具有特定点大小的字体 可以指定字体逻辑单位的大小,但有时指定字体的点的大小可能会更方便一 些。可以如下将字体的点转换为字体的高度: 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")); ... 52、如何计算一个串的大小 函数 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 strTitle; GetWindowText (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; } 53、如何显示旋转文本 只要用户使用 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 rcClient; GetClientRect (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 object LOGFONT 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_NORMAL; stFont.ifClipPrecision=LCIP_LH_ANGLES; strcpy (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 (); } } 54、如何正确显示包含标签字符的串 调用 GDI 文本绘画函数时需要展开标签字符,这可以通过调用 CDC:: TabbedTextOut 或者 CDC:: DrawText 并指定 DT_EXPANDTABS 标志来完 成。TabbedTextOut 函数允许指定标签位的数组,下例指定每 20 设备单位展 开一个标签: void CSampleView:: OnDraw (CDC* pDC) { CTestDoc* pDoc=GetDocument (); ASSERT_VALID (pDoC); CString str; str.Format (_T ("Cathy\tNorman\tOliver")); int nTabStop=20; //tabs are every 20 pixels pDC->TabbedtextOut (10, 10, str, 1, &nTabStop, 10); } 55、串太长时如何在其末尾显示一个省略号 调用 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); } 56、如何快速地格式化一个 CString 对象 调用 CString:: Format,该函数和 printf 函数具有相同的参数,下例说明了 如何使用 Format 函数: //Get size of window. CRect rcWindow; GetWindowRect (rcWindow); //Format message string. CString strMessage; strMessage.Format (_T ("Window Size (%d, %d)"), rcWindow.Width (), rcWindow.Height ()); //Display the message. MessageBox (strmessage); 57、为什么即使调用 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); 58、如何给系统菜单添加一个菜单项 给系统菜单添加一个菜单项需要进行下述三个步骤: 首先,使用 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 } else CMDIFrameWnd:: OnSysCommand (nID, lParam); } 最后,一个设计良好的 UI 应用程序应当在系统菜单项加亮时在状态条显示 一个帮助信息,这可以通过增加一个包含系统菜单基 ID 的串表的入口来实现。 59、如何确定顶层菜单所占据的菜单行数 这可以通过简单的减法和除法来实现。首先,用户需要计算主框窗口的高 度和客户区;其次,从主框窗口的高度中减去客户区、框边界以及标题的高度; 最后,除以菜单栏的高度。下例成员函数是一个计算主框菜单所占据的行数的代 码实现。 int CMainFrame:: GetMenuRows () { CRect rcFrame,rcClient; GetWindowRect (rcFrame); GetClientRect (rcClient); return (rcFrame.Height () -rcClient.Height ()- :: GetSystemMetrics (SM_CYCAPTION) - (:: getSystemMetrics (SM_CYFRAME) *2)) / :: GetSystemMetrics (SM_CYMENU); } 60、在用户环境中如何确定系统显示元素的颜色 调用 SDK 函数 GetSysColor 可以获取一个特定显示元素的颜色。下例说明了如何 在 MFC 函数 CMainFrameWnd:: OnNcPaint 中调用该函数设置窗口标题颜色。 void CMiniFrameWnd:: OnNcPaint () { … dc.SetTextColor (:: GetSysColor (m_bActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT)); … } 问:如何控制窗口框架的最大最小尺寸? 答:要控制一个框架的的最大最小尺寸,你需要做两件事情.在 CFrameWnd 的 继承类中处理消息 WM_GETMINMAXINFO,结构 MINMAXINFO 设置了整个窗口 类的限制,因此记住要考虑工具条,卷动条等等的大小. // 最大最小尺寸的象素点 - 示例 #define MINX 200 #define MINY 300 #define MAXX 300 #define MAXY 400 void 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); } 问:如何改变窗口框架的颜色? 答:MDI 框架的客户区被另一个窗口的框架所覆盖.为了改变客户区的 背景色,你需要重画这个客户窗口.为了做到这点,你要处理消息 WM_ERASEBKND 产生一个新类,从 CWnd 继承,姑且称之为 CMDIClient. 给它加上一个成员变量, #include "MDIClient.h" class CMainFrame : public CMDIFrameWnd { ... protected: CMDIClient m_wndMDIClient; } 在 CMainFrame 中重载 CMDIFrameWnd::OnCreateClient BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) ) { m_wndMDIClient.SubclassWindow(m_hWndMDIClient); return TRUE; } else return FALSE; } 然后就可以加入对消息 WM_ERASEBKGND 的处理了. 问:如何将应用程序窗口置于屏幕正中? 答:要将你的应用程序窗口放置在屏幕正中央,只须在 MainFrame 的 OnCreate 函数中加入: CenterWindow( GetDesktopWindow() ); 问:当文档被修改时,如何在标题上加上标志'*'? 答:重载 CDocument 类的虚函数 virtual SetModifiedFlag: void CTest2Doc::SetModifiedFlag(BOOL bModified) { CString strTitle = GetTitle(); CString strDirtyFlag = " *"; // note space before the '*' // so we don't break Save As dialog if (!IsModified() && bModified) { SetTitle(strTitle + strDirtyFlag); } else if ( IsModified() && !bModified ) { int nTitleLength = strTitle.GetLength(); int nDirtyLength = strDirtyFlag.GetLength(); SetTitle( strTitle.Left(nTitleLength - nDirtyLength) ); } UpdateFrameCounts(); CDocument::SetModifiedFlag(bModified); } 问:VC6.0 对 VC5.0 的兼容性? 答:很不幸,vc6.0 在调试模式对 vc5.0 不兼容,但发行模式没有问题. 原因在微软改变了调试模式所用 dll 的格式,而保留了原文件名. 因此,不要在 vc6.0 中打开 vc5.0 的调试 版本工程. 问:打印和打印机的问题? 我碰到这么一个问题:在打印方法中使用了 MM_LOMETRIC 模式,在 LOGFONT 结构中改 变了字体的大小,但不 知道 173(或者对于屏幕而言是 25)是从哪来的,它是自动的. 然而当我用另外一个打印机时 173 并不适合. 我想知道的是:我如何对所有的打印来 调整这个数字. 答:我以前也碰到过类似的问题,我让用户改变字体(大小,颜色等等).这些改变在屏幕 上看起来挺好,但 是打印时太小(我的同事在程序包中加入一个放大类).原因非常 简单:打印机的分辨率可能是 300dpi,而 屏幕的分辨率则低得多. 我是这么解决的:在获得屏幕字体信息后,我获取屏幕字体的毫米级大小(使用 LPtoDP, 然后将模式变为 MM_LOMETRIC,调用 DPtoLP),接着对打印机设定了相同的模式,再调用 LPtoDP.切换回原来 的模式之后,我调用了 DPtoLP,这样就得到了想要的字体高度和宽度. 在 LOGFONT 中使用这个值,并且带有 其它诸如下划线,斜体等字体信息,我实现了用户的要求. 问:CRichEditCtrl 滚动条的问题? 我使用了 CRichEditCtrl 控制来显示某个文件中的数据(将该控制设置为只读).我已经设置 了 ES_MULTILINE | ES_AUTOVSCROLL,但当数据内容比控制显示多的时候,滚动条并不出现, 是不是因为设置 了只读属性而引起了其它的问题? 答:ES_AUTOVSCROLL | ES_AUTOHSCROLL 属性只在控制是可编辑时有效.你可心使用下面的滚动条 风格来 使滚动条出现:WS_VSCROLL | WS_HSCROLL,但是这样一来,不管你的数据量有多大,滚动 条总是会出现. 问:从数据库中读大于 32k 的内容? 我在从数据库中读数据时碰到了问题.当数据栏包含超过 32k 的内容时,我就读不出来,我试过 ODBC::SQLGetData()也不行. 答:哪种类型的数据库?MS SQL,SYBASE... 试试设置一下大小: BOOL CGetBlobStmt::Execute(LPCTSTR stmt) { m_cbSize = 0; m_size = 0; LPBYTE lpData; lpData = (LPBYTE)GlobalLock(m_hData); m_retcode = SQLSetStmtOption(GetHandle(),SQL_MAX_LENGTH,m_dwBytesLeft); m_retcode = SQLExecDirect(GetHandle(),(UCHAR*)stmt,SQL_NTS); if (m_retcode == SQL_SUCCESS) { m_retcode = SQLFetch(GetHandle()); if (m_retcode == SQL_SUCCESS ||m_retcode == SQL_SUCCESS_WITH_INFO) { m_retcode = SQLGetData(GetHandle(),1,SQL_C_BINARY,lpData,254,&m_cbSize); while(m_retcode == SQL_SUCCESS_WITH_INFO) { lpData+= 254; m_retcode = SQLGetData(GetHandle(),1,SQL_C_BINARY,lpData,254,&m_cbSize); } GetError(); } } GlobalUnlock(m_hData); #if TESTDATA TRACE("%ld",m_size); #endif SaveFile(); return RETVALUE; } 问:如何获得 CRichEditCtrl 中字符的位置? 我想在 CRichEditCtrl 中使用右键菜单,因此想判定光标处字符的位置,请指点. 答:查看如下的帮助: IRichEditOleCallback::GetContextMenu EM_SETOLECALLBACK 问:如何限制 mdi 子框架最大化时的大小? 答:用 ptMaxTrackSize 代替 prMaxSize,如下所示: void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { // TODO: Add your message handler code here and/or call default CChildFrame::OnGetMinMaxInfo(lpMMI); lpMMI->ptMaxTrackSize.x = 300; lpMMI->ptMaxTrackSize.y = 400; } 问:如何切换视口而不破坏它们? 我创建了一个带有静态分隔区的 sdi 应用程序,左边显示工作区,右过显示左边选取 的东西.我想达到的是如果在分隔区之间进行切换,而不覆盖或破坏原来的 CView 对象. 答:以下代码是你所想要的: class CExSplitterWnd : public CSplitterWnd { // Construction public: CExSplitterWnd(); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CExSplitterWnd) //}}AFX_VIRTUAL // Implementation virtual ~CExSplitterWnd(); BOOL AttachView(CWnd* pView, int row, int col); BOOL DetachView(int row, int col); // Generated message map functions //{{AFX_MSG(CExSplitterWnd) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CExSplitterWnd::CExSplitterWnd() { } CExSplitterWnd::~CExSplitterWnd() { } BOOL CExSplitterWnd::AttachView(CWnd* pView, int row, int col) { //Make sure the splitter window was created if (!IsWindow(m_hWnd)) { ASSERT(0); TRACE(_T("Create the splitter window before attaching windows to panes")); return (FALSE); } //Make sure the row and col indices are within bounds if (row >= GetRowCount() || col >= GetColumnCount()) { ASSERT(0); return FALSE; } //Is the window to be attached a valid one if (pView == NULL || (!IsWindow(pView->m_hWnd))) { ASSERT(0); return FALSE; } pView->SetDlgCtrlID(IdFromRowCol(row, col)); pView->SetParent(this); pView->ShowWindow(SW_SHOW); pView->UpdateWindow(); return (TRUE); } BOOL CExSplitterWnd::DetachView(int row, int col) { //Make sure the splitter window was created if (!IsWindow(m_hWnd)) { ASSERT(0); TRACE(_T("Create the splitter window before attaching windows to panes")); return (FALSE); } //Make sure the row and col indices are //within bounds if (row >= GetRowCount() || col >= GetColumnCount()) { ASSERT(0); return FALSE; } CWnd* pWnd = GetPane(row, col); if (pWnd == NULL || (!IsWindow(pWnd->m_hWnd))) { ASSERT(0); return FALSE; } pWnd->ShowWindow(SW_HIDE); pWnd->UpdateWindow(); //Set the parent window handle to NULL so that this child window is not //destroyed when the parent (splitter) is destroyed pWnd->SetParent(NULL); return (TRUE); } 问:改变列表控制时发生闪烁现象? 我创建了一个简单的对话框,在对话框中设置了一个列表控件,这个控件占用了对话框的全部 客户区.对 话框是可以改变大小的,因此我要保证列表控件在对话框中维持正确的位置,在对话 框的 ONSize()事件中 我对列表控件使用了 MoveWindow(),这起到了作用,但当用户改变对话框 的大小时,列表控件不停地闪烁. 答:要解决这个问题,在用 MoveWindow 之前,先用 ShowWindow(SW_HIDE)隐藏列表控件,然后在 MoveWindow 之后用 ShowWindow(SW_SHOW)来显示列表控件. 问:处理列表控件可见项的问题? 我在一个列表控件中加入了好多条目.我通过获取某个条目是否可见或最后是哪个条目来进行 处理.我看 了 CListCtrl::GetItem()的帮助,但是没有找到如何判断一个条目是否可见的方法. 答:如果你只想处理可见的条目,你可以用 GetTopIndex.它返回最大可见条目的索引值,然后 你再用 GetCountPerPage 来得到在可见区域的条目数. 问:产生线程的问题? 我在使用 CreateThread 时碰到了问题.我想让调用的函数和被调用的函数属于同一个类,结果 在我调用 CreateThread 时得到如下错误: error C2440: 'type cast' : cannot convert from 'unsigned long (__stdcall Cdmi::*)(void *)' to 'unsigned long (__stdcall *)(void *)' A1:(1)'unsigned long (__stdcall Cdmi::*)(void *)'是指向 Cdmi 某个成员函数的指针. (2)'unsigned long (__stdcall *)(void *)'仅仅只是一个 c 形式函数的指针. 编译器无法将(1)转换为(2)是因为 c++成员函数取第一个(隐藏)参数"this pointer" 作为成员函数,但当 是一个静态的成员时则例外.可按如下方法解决. class XMyThread { public: void StartThread(void); virtual UINT ThreadFunction(void); static UINT __bogusthreadfunc(LPVOID lpparam); }; void XMyThread::StartThread() { AfxBeginThread(__bogusthreadfunc,this); } UINT XMyThread::ThreadFunction(void) { //here you do all your real work return 0; } UINT XMyThread::__bogusthreadfunc(LPVOID lpparam) { XMyThread* This = dynamic_cast(lpparam); return This->ThreadFunction(); } for the sake of clairty, I did not add StopThread and I did not save the CWinThread* returned by AfxBeginThread. If you wanted a thread that does other things, simply derive from XMyThread and override ThreadFunction() example: class XAnotherThread : public XMyThread { virtual UINT ThreadFunction(void); }; UINT XAnotherThread :: ThreadFunction(void) { //do some other work here return 0; } A2:Cdmi::MonitorFiles()是个静态的成员函数. 问:CFile 使用了缓冲区吗? 请告诉我 CFile 到底有没有使用缓冲区来处理文件? 答:CFile 没有使用运行库的 I/O 缓冲例程,从这个意义上讲 CFile 并没有使用缓冲. 但是有可能操作 系统在处理文件时使用了缓冲区,如果你完全不需要缓冲区, 你可以设置 FILE_FLAG_NO_BUFFERING.CFile 工作在这种模式下的唯一的方法 是 CFile::Attach(). 问:DAO 的密码? 我创建了一个使用数据库的 mfc 应用程序.用类模板生成 CDaoRecordset 直接打开 数据库(不通过 ODBC),但问题是我如何打开有密码保护的数据库? 答:试试下面的代码: DAODBEngine* pDBEngine = AfxDaoGetEngine(); ASSERT(pDBEngine != NULL); COleVariant varUserName (strUserName, VT_BSTRT); COleVariant varPassword (strPassword, VT_BSTRT); DAO_CHECK(pDBEngine->put_DefaultUser (V_BSTR(&varUserName)); DAO_CHECK(pDBEngine->put_DefaultPassword (V_BSTR(&varPassword)); A2:你可以使用 CDaoDatabase 的 Open 方法来打开: MyDaoDatabase->Open("C:\MyDatabaseFile.mdb",FALSE,FALSE,";PWD=MyPassWord"); btw:不要忘了 PWD=前面的;号. 问:如何知道 CListBox 什么时候滚动了? 答:每次绘制列表框都要重绘某项,通过消息 WM_CTLCOLOR 从父窗口获得 DC 颜色.因此每次列表框的 滚动 你都可以用 WM_CTLCOLOR 来检验是否滚动. HBRUSH CParentDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { // is the control _the_ list box we're interested in? if( nCtlColor == CTLCOLOR_LISTBOX && pWnd->GetDlgCtrlID() == IDC_LIST ) { // if the top index changed, the list box has been scrolled int iTop = ((CListBox*)pWnd)->GetTopIndex(); if( iTop != m_iTopOld ) { // keeps tracking of the top index changes m_iTopOld = iTop; // process scrolling ... } } HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); return hbr; } 使用这种方法可以不必为了实现这个功能而去产生一个继承类. 问:视口的不活动性如何处理? 有什么方法使 CListView 成为类似 WM_DIASBLED 的风格,或者使它和背景色一致. 答:你所要做的是处理 CListView 的 WM_SETFOCUS 消息,然后在 TreeView 中调用 SetFocus, 这 样,ListView 就永远不会获得焦点. afx_msg void CMyListView::OnSetFocus(CWnd* pOldWnd); { // assuming m_pwndTreeView points to the valid TreeView // on the left side m_pwndTreeView->SetFocus(); } A2:重载 PreTranslateMessage,然后当消息为 WM_LBUTTONDOWN 或 WM_RBUTTONDOWN 时 返回真即可 问:如何使用 COleClientItem 的 IDispatch 接口? 我创建了一个如何使用 COleClientItem 对象,我想使用它的自动化方法.有什么 方法来获得 IDispatch 的接口?我试过以 CCmdTarget 为基类的的 GetIDispatch 函数 但却出错,我用过 EnableAutomation 和 GetIDispatch,却什么也没得到. 答:MSDN 中有一篇关于这个的文章(TN039).如下的代码也可能是你所需要的: LPDISPATCH CMyClientItem::GetIDispatch() { ASSERT_VALID(this); ASSERT(m_lpObject != NULL); LPUNKNOWN lpUnk = m_lpObject; Run(); // must be running LPOLELINK lpOleLink = NULL; if (m_lpObject->QueryInterface(IID_IOleLink, (LPVOID FAR*)&lpOleLink) == NOERROR) { ASSERT(lpOleLink != NULL); lpUnk = NULL; if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR) { TRACE0("Warning: Link is not connected!\n"); lpOleLink->Release(); return NULL; } ASSERT(lpUnk != NULL); } LPDISPATCH lpDispatch = NULL; if (lpUnk->QueryInterface(IID_IDispatch, &lpDispatch) != NOERROR) { TRACE0("Warning: does not support IDispatch!\n"); return NULL; } ASSERT(lpDispatch != NULL); return lpDispatch; } 问:关于用户自定义的消息使用? 我写了一个基于 MFC应用程序的对话框,在这个程序中,我创建了等待网络传输数据 的线程,一旦该线 程接收到数据,它就传送一个用户自定义的消息到对话框,使对话 框知道有数据过来.但是为何在 CMyDialog::PreTranslateMessage(MSG* pMsg)中能 捕捉到 WM_MYCMD 这个消息,却不能和 OnMyCommand 相映射? 答:将你所有自定义消息的基类设为 WM_APP,而不是 WM_USER. 问:在打开一个文档时退出? 我有一个 mdi 程序,在打开文件的处理过程中,我想判断该文档是不是应用程序需要 处理的文档,因此,我检 测文档中的某个数字是否符合要求,如何在发现不是该文档 时出现一个错误提示,然后不打开该文档? 答:给文档设定某个标志,如果文档不是所要的就设定它.然后 OnOpenDocument 中检测, 当发现标志被设定 后返回 FALSE. 问:在 CListCtrl 控件中多选择项的删除? 如何从在 CListCtrl 中删除多个选择项? 答:按如下方法处理: 假定你的 CListCtrl 是 m_list,to_delete 是个整数数组. i=3D0; POSITION pos=3Dm_list.GetFirstSelectedItemPosition(); if(pos) while(pos) to_delete[i++]=3Dm_list.GetNextSelectedItem(pos); 然后用删除保存在 to_delete 中的项目,用 GetSelectedCount 来得到已选项的个数. 问:工作线程的登录状态? 我使用循环删除了用 AfxBeginThread 创建的线程的好几个实例.每个线程打开一个 iNET 连接,打开 一个 URL 并返回结果.我需要找出哪一个或者何时这些线程进入到登录状态. 答:按如下方法处理:(伪代码) // Start Threads for( unsigned u = 0; u < NUMBER_OF_THREADS; u++ ) { ThreadHandleArray[ u ] = AfxBeginThread( ...... )->m_hThread; } DWORD count = NUMBER_OF_THREADS DWORD dwWait; while( count ) { dwWait = ::WaitForMultipleObjects( count, ThreadHandleArray, FALSE,INFINITE ); if( dwWait >= WAIT_OBJECT_0 && dwWait < ( WAIT_OBJECT_0 + count ) ) { dwWait -= WAIT_OBJECT_0; // dwWait now has index to thread that completed do whateveryou want to do with it // set array back up for next wait if( dwWait != ( count - 1 ) ) ThreadHandleArray[ dwWait ] = ThreadHandleArray[count - 1 ]; count--; } } 问:如何控制菜单的大小? 我用 MFC 的 CMenu 生成了一个动态菜单(例如 File,Edit,View...Help), 我想控制这个菜单的大小(长 +高). 答 1:查找 WM_MEASUREITEM 和 MEASUREITEMSTRUCT. 答 2:查询系统::GetSystemMetric(SM_CXMENUSIZE). 我从新闻组得到下面一个例子: // 你可以通过如下代码来获得文本的大小: //(A)获得被使用的字体 NONCLIENTMETRICS ncm; HFONT hFontMenu; SIZE size; size.cx = 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 比较合适。 */ 问:改变 LVIS_SELECTED 的状态颜色? 我想将 CListCtrl 项和 CTreeCtrl 项在 LVIS_SELECTED 状态时的颜色变灰. A1:查找函数 CustomDraw,它是 IE4 提供的公共控制,允许自己写代码. A2:生成一个 draw 控件,然后在 DrawItem 中处理文本颜色. 问:如何只存储文档的某一部分? 我只想存储文档的某一部分,能否象使用文件一样使用文档?(也就是有定位函数). 答:将每个 CArchive 类设置为 CFile 类的派生类,这样你就能使用 Seek 等成员函数. 问:保存工具条菜单有 bug 吗? 使用浮动菜单条时,SaveBarState 和 LoadBarState 出现了问题.如果菜单是浮动 的,重起应用程序时它会出现在左上角,而它固定在屏幕其它位置时,下一次启动 就会出现在该位置,这是什么原因? 答:你试试这个 PToolBar->Create(this,...,ID_MYTOOLBAR); 你的工具条需要包括 id,而不是象默认的工具条那样. 问: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 != CCommandLineInfo::FileDDE) { CTipDlg dlg; if (dlg.m_bStartup) dlg.DoModal(); } } 如果还有其它 bug,你可以设定 cmdInfo.m_nShellCommand 的过滤. 问:如何让我的 mfc 应用程序可以在最上面? 如何可以让我的程序可以显示在其它的窗口上面? 答:让用户选择"总是在最上面"最好是在系统菜单里加入一个选项.可以通过修改 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); } } 问:如何增加视图中 ActiveX 控件的事件处理函数? 如果我在对话框中加入微软的网络浏览器,很容易通过类模板加入对事件的处理. 但我现在在视图中 用 m_pBrowser=new CWebBrowser2 加入了网络浏览器,我该如何 对事件进行处理? 答:到 www.vcdj.com(inet 章节)去看看,有一篇文章名为"Building a Webbrowser in a Afternoon". 如下的代码也可能是你所需要的: #include // For AFX_EVENT def. BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { AFX_EVENT *pEvent = (AFX_EVENT *)pExtra; //If this is a control notification event. if (nCode == CN_EVENT) { // If we have information on this event. if (pEvent) { // Event DISPID is stored at pEvent->m_dispid // Event DISPPARAMS are stored at pEvent->m_pDispParams // Handle the event from here... } } return CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); } 问:如何创建一个动态的 Tree 控件? 我想创建一个动态的 tree 控件,就象弹出窗口一样,但它并不象想象中那么容易. A1:用 CreateWindow(SDK)创建风格为 WS_POPUP,WS_CAPTION 和 WS_TICKFRAME 的窗口, 并作为父窗口. A2:创建一个包含 Tree 控件的对话框. 问:SDI 程序开始时不打开文档? 我创建了一个 SDI 应用,但每次启动时它都会打开一个文档("untitled"), 如何不让它打开该文档呢? 答:看看 InitInstance 函数中有没有关于 OnFileNew 的调用,去掉它即可. 问:List 控件中整栏选择? 我在处理 List 控件时碰到了麻烦,我想创建一个 ListView,来依据 Tree 控件的 选择同时在 ListView 和 ReportView 中显示列表的信息.以下是相关的代码: // Set full line select ListView_SetExtendedListViewStyle(m_plstCustomers->GetSafeHwnd(), LVS_EX_FULLROWSELECT); 答:按如下方法处理: // -------------------- begin of snippet -------------------------------- bool CCommCtrlUtil32::ListCtrl_ModifyExtendedStyle(CListCtrl& p_rListCtrl, const DWORD p_dwStyleEx, const bool p_bAdd) { HWND t_hWnd = p_rListCtrl.GetSafeHwnd(); DWORD t_dwStyleEx = ListView_GetExtendedListViewStyle(t_hWnd); if(p_bAdd) { if(0 == (p_dwStyleEx & t_dwStyleEx)) { // add style t_dwStyleEx |= p_dwStyleEx; } } else { if(0 != (p_dwStyleEx & t_dwStyleEx)) { // remove style t_dwStyleEx &= ~p_dwStyleEx; } } ListView_SetExtendedListViewStyle(t_hWnd, t_dwStyleEx); return true; } 问:如何重载 MRU 文件? 我创建了一个应用程序可以载入图象文件,但当我点击 FILE 菜单下 MRU 文件 列表时,却不能从磁盘载 入以前曾经打开过的文件. 答:下面是我所能想到的解决方案: (1)在文档类中定义一个成员函数(例如:CMyDoc::Reopen)来处理重新打开 这个问题,指明参数和返回值. (2)产生一个 CMultiDocTemplate 的继承类(如 CMyDocTemplate),定义一个构造 函数,取和基类相同的参数,不做任何事,只是调用基类的构造函数. (3)重载 MatchDocType: CMyDocTemplate::Confidence CMyDocTemplate::MatchDocType( LPCTSTR lpszPath, CDocument *&rpDocMatch ) { Confidence match = CMultiDocTemplate::MatchDocType(lpszPath, rpDocMatch); if(yesAlreadyOpen == match) // clear enough { ASSERT_KINDOF(CMyDoc, rpDocMatch); ((CMyDoc *) rpDocMatch)->Reopen(/* your parameters */); // you can take any other actions here... } return match; } 当这函数返回"yesAlreadyOpen"时,你的文档框架将会被激活. 问:CImageList 控件中图象橙色被显示为黄色? 我使用了一个 CImageList 控件来装入位图,用于 TREE 控件,其它的色彩都很正常 就是橙色被显示成 为黄色 . 答:你只能使用系统指定的 20 种颜色(橙色不包括在内);当然,你也可以用下面的方法 来装载位图 资源而不受颜色数的限制. HBITMAP LoadResourceBitmap(HINSTANCE hInstance, LPSTR lpString, HPALETTE FAR* lphPalette) { HRSRC hRsrc; HGLOBAL hGlobal; HBITMAP hBitmapFinal = NULL; LPBITMAPINFOHEADER lpbi; HDC hdc; int iNumColors; if (hRsrc = ::FindResource(hInstance, lpString, RT_BITMAP)) { hGlobal = ::LoadResource(hInstance, hRsrc); lpbi = (LPBITMAPINFOHEADER)LockResource(hGlobal); hdc = ::GetDC(NULL); *lphPalette = CreateDIBPalette ((LPBITMAPINFO)lpbi, &iNumColors); if (*lphPalette) { ::SelectPalette(hdc,*lphPalette,FALSE); ::RealizePalette(hdc); } hBitmapFinal = ::CreateDIBitmap(hdc,(LPBITMAPINFOHEADER)lpbi,(LONG)CBM_INIT, (LPSTR)lpbi + lpbi->biSize + iNumColors * sizeof(RGBQUAD), (LPBITMAPINFO)lpbi,DIB_RGB_COLORS ); ::ReleaseDC(NULL,hdc); // ::UnlockResource(hGlobal); // ::FreeResource(hGlobal); } return (hBitmapFinal); } // internally used by LoadResourceBitmap HPALETTE CreateDIBPalette (LPBITMAPINFO lpbmi, LPINT lpiNumColors) { LPBITMAPINFOHEADER lpbi; LPLOGPALETTE lpPal; HANDLE hLogPal; HPALETTE hPal = NULL; int i; lpbi = (LPBITMAPINFOHEADER)lpbmi; if (lpbi->biBitCount <= 8) *lpiNumColors="(1" << lpbi->biBitCount); else *lpiNumColors = 0; // No palette needed for 24 BPP DIB if (lpbi->biClrUsed > 0) *lpiNumColors = lpbi->biClrUsed; // Use biClrUsed if (*lpiNumColors) { hLogPal = GlobalAlloc (GHND, sizeof (LOGPALETTE) + sizeof (PALETTEENTRY) * (*lpiNumColors)); lpPal = (LPLOGPALETTE) GlobalLock (hLogPal); lpPal->palVersion = 0x300; lpPal->palNumEntries = *lpiNumColors; for (i = 0; i <*lpiNumColors; i++) { lpPal->pal PalEntry[i]. peRed = lpbmi->bmiColors[i].rgbRed; lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen; lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue; if (i<=10 || i>=246) lpPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE; else lpPal->palPalEntry[i].peFlags = 0; } hPal = CreatePalette (lpPal); GlobalUnlock (hLogPal); GlobalFree (hLogPal); } return hPal; } 该函数也重载了位图调色板,这个功能被 CBitmap::LoadBitmap 忽略了(它假定位图只 使用 20 种颜 色).因此要保证在 DC 中有 SelectPalette 和 RealizePalette. 问:无法正确改变应用程序的图标? 我有一个基于对话框的应用程序,在初始化时我使用了 AfxGetApp()->LoadIcon(IDI_BRIEFCASE) 来 载入自己的图标,当把程序拷贝到桌面上时,图标是我所期望的.但在 资源管理器中的图标却还是 MFC 的图标. 答:资源管理器仅使用 16x16 的小图标,可能你在资源编辑器中只修改了 32x32 的标准 图标.你需要 重建 16x16 的小图标. 问:工具条状态的问题? 在应用程序中我创建了三个工具条,我想让它们在应用程序启动的时候排成一行 正好在主菜单的下 面,我该如何去做? 答:在 VC CDs 上有一个例子: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { //other stuff here... EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar,AFX_IDW_DOCKBAR_TOP); DockControlBarLeftOf(&m_wndListToolBar,&m_wndToolBar); return 0; } void CMainFrame::DockControlBarLeftOf(CToolBar* Bar,CToolBar* LeftOf) { CRect rect; DWORD dw; UINT n; // get MFC to adjust the dimensions of all docked ToolBars // so that GetWindowRect will be accurate RecalcLayout(); LeftOf->GetWindowRect(&rect); rect.OffsetRect(1,0); dw=LeftOf->GetBarStyle(); n = 0; n = (dw & CBRS_ALIGN_TOP) ? AFX_IDW_DOCKBAR_TOP :n; n = (dw & CBRS_ALIGN_BOTTOM && n==0) ? AFX_IDW_DOCKBAR_BOTTOM :n; n = (dw & CBRS_ALIGN_LEFT && n==0) ? AFX_IDW_DOCKBAR_LEFT :n; n = (dw & CBRS_ALIGN_RIGHT && n==0) ? AFX_IDW_DOCKBAR_RIGHT :n; // When we take the default parameters on rect, DockControlBar will dock // each Toolbar on a seperate line. By calculating a rectangle, we in effect // are simulating a Toolbar being dragged to that location and docked. DockControlBar(Bar,n,&rect); } 问:在 SDI 应用程序中使用 Active 控件? 我刚了解到如何在 MFC 应用程序中使用 Active 控件,文档上说只能在视图为 CFormView 和 CDialog 时使用,但要是其它的情况该怎么办呢? 答:你可以在你应用程序的任何地方使用 Active 控件,而不仅仅局限于 CFormView 和 CDialog 为视图基类的情况.DevStudio 通过资源编辑器和对话框模板来使得在上述两个条件 下使用 Active 控件更容易.因此,你也可以在任何视图中使用 Active 控件,条件是你 直接操纵该控件,创建它并手工 的布置好它的位置(这也是 DevStudio 为你所做的事). 问:有 RichEdit 控件的对话框无法正常显示? 我在对话框中放置了一个 RichEdit 控件,但是对话框却无法正常显示. 答:在你的应用程序 InitInstance()中调用了::AfxInitRichEdit()吗? 问:DLL 中的模板成员函数? 在一个 DLL 中,我在自己创建的类中使用了模板成员函数来代替预处理宏.但出现以下错误: error C2664: 'double Dat 答::extract(double &)' : cannot convert parameter 1 from 'class CArray' to 'double &' 为什么在匹配模板定义时它要寻找一个 DOUBLE 参数? 答:我觉得你可能是在表达成员函数(内联)时出现了问题,请参照下面的示例: class AFX_EXT_CLASS Data : public CObject //This is not a template { public: Data(); Data(BYTE * buffer,int size); template Data(const CArray& array); template CArray& extract(CArray& array) { CArchive ar(&buffer, CArchive::store); ar >> array; }; double extract(double&); (...) private: CMemFile buffer; } 问:CFormView 中的上下文帮助? 我想在基于 CFormView 类的 SDI 应用程序中加入真正的上下文帮助,但没有成功. 答:你应该重载 CMyFormView 类的 OnHelpHitTest 函数: LRESULT CMyFormView::OnHelpHitTest(WPARAM, LPARAM lParam) { LRESULT lResult = (LRESULT)0x00; CWnd* pWndChild = ChildWindowFromPoint(CPoint(lParam),CWP_ALL|CWP_SKIPINVISIBLE); if (pWndChild && ::IsWindow(pWndChild->m_hWnd)) { lResult = ::GetWindowLong(pWndChild->m_hWnd, GWL_ID); if (lResult) lResult += HID_BASE_COMMAND; } if (lResult == (LRESULT)0x00) lResult = ::GetWindowLong(m_hWnd, GWL_ID) + HID_BASE_RESOURCE; return lResult; } 然后你就可以使用平时用的帮助文件了,但你要保证有正确的前缀,请参照 TN028:Context-Sensitive Help Support. 例如: ID_SOME_MENU_ITEM_OR_COMMAND_BUTTON IDR_SOME_WINDOW_OR_DIALOG IDP_PROMPT IDW_CONTROL_THAT_IS_NOT_A_COMAND_BUTTON 你要确认你所使用的控件的 ID 包含在文件 resource.hm 中. 问:CArchive 类的 WriteObject 函数问题? 谁知道在使用 CArchive 类的 WriteObject 函数时,如何避免将类名写入文件吗? 答:WriteObject 函数不仅写入了类名,而且还写入 PID(请查看 TN02),如果你只想写进 一个文本文件, 并且你也想用串行化,你可以使用文件指针(用 GetFile)来存储字符串. 或者,你可以使用 CFILE 类来 处理这个问题,如果是文本文件,你也可以用 CStdioFile 类. 问:RegisterWindowMessage 中的 BroadcastSystemMessage 如何处理? 我想用 BroadcastSystemMessage 来在两个进程之间通讯,我从一个进程发送了一个用 RegisterWindowMessage 注册过的消息,但在目的进程中却没有收到该消息. 答:我认为你应该在两个进程的最高级窗口中都注册该消息.请看下例: static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand")); BEGIN_MESSAGE_MAP( Gui_Top_Level_MainFrame, Gui_MainFrame ) ON_REGISTERED_MESSAGE( sBroadcastCommand, onBroadcastCommand ) END_MESSAGE_MAP() LRESULT Gui_MainFrame :: onBroadcastCommand( UINT aMsg, LPARAM lParam ) { your code... } 然后发送进行应该包含: While the sending process would contain: static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand")); void Someclass :: someMethod( void ) { ::PostMessage( (HWND)HWND_BROADCAST,sBroadcastCommand, 0,yourMessageId ); } 问:CListCtrl 中选择变化时如何获得通知? 我在 Report View 中使用了一个 CListCtrl(自绘制类型),我想知道什么时候选择项 发生了改变. 答:在选择项变化时,可以使用按钮有效或失效,按如下操作: 加入 LVN_ITEMCHANGED 消息处理. void CYourClassNameHere::OnItemchangedEventList(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; *pResult = 0; if (pNMListView->uChanged == LVIF_STATE) { if (pNMListView->uNewState) GetDlgItem(IDC_DELETE)->EnableWindow(TRUE); else GetDlgItem(IDC_DELETE)->EnableWindow(FALSE); } } 问:如何向 ATL-COM 对象传送一个数组? 我想创建一个函数来向 ATL-COM 对象传送数组. 答:如下代码的方法用于 ACTIVEX 中,可能对 ATL-COM 也有启发吧. CoInitialize(NULL); CLSID m_clsid; USES_CONVERSION; ::CLSIDFromString(T2OLE("ROUNDANALOG.RoundAnlgAARCtrl.1"), &m_clsid); IDispatch FAR* pObj = (IDispatch FAR*)NULL; CString str = "UpdateControl"; BSTR bstr = str.AllocSysString(); HRESULT hr = CoCreateInstance(m_clsid, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&pObj); SafeArrayAccessData(psa, (void**)&bstrArray); bstrArray[0] = str.AllocSysString(); bstrArray[1] = str.AllocSysString(); SafeArrayUnaccessData(psa); VARIANTARG* pvars = new VARIANTARG[1]; VariantInit(&pvars[0]); pvars[0].vt = VT_ARRAY|VT_BYREF|VT_BSTR; pvars[0].pparray = &psa; DISPID dispid; hr = pObj->GetIDsOfNames(IID_NULL, &bstr, 1,LOCALE_USER_DEFAULT, &dispid); DISPPARAMS disp = {pvars, &dispid, 1,1}; hr = pObj->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,DISPATCH_PROPERTYPUT,&disp,NULL, NULL, NULL); delete[] pvars; pObj->Release(); CoUninitialize(); 在你的控制中建立如下函数: void CRoundAnlgAARCtrl::SaveFunc(const VARIANT FAR& var) { // TODO: Add your dispatch handler code here ASSERT(var.vt == VT_ARRAY | VT_BYREF | VT_BSTR); SAFEARRAY* psa = *var.pparray; } 问:如何选择 CTreeCtrl 中的节点文本进行编辑? 在向 CTreeCtrl 中加入一项后,有什么方法可以编辑该节点的文本呢? 答:首先设置你的 CcompTreeCtrl 具有 TVS_EDITLABELS 属性.在设计时用控件属性来设置 在运行时 用 GetStyle()/SetStyle()成员函数来设置.然后请看下述代码: HTREEITEM CCompTreeCtrl::AddSet() { static int setCnt =3D 1; HTREEITEM hItem; CString csSet; //create text for new note: New Set 1, New Set 2 ... csSet.Format( _T( "New Set %d" ), setCnt++ ); hItem =3D InsertItem( csSet, IMG_CLOSEDFOLDER, IMG_CLOSEDFOLDER ); if( hItem !=3D NULL ) EditLabel( hItem ); return hItem; } 问:如何改变默认的光标形状? 我试着将光标改变为其它的形状和颜色,但却没有变化. 答:在对话框/窗口/你需要的地方加上对 WM_SETCURSOR 消息的处理. BOOL MyDialog::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // TODO: Add your message handler code here and/or call default ::SetCursor(AfxGetApp()->LoadCursor(IDC_MYCURSOR)); return TRUE; //return CDialog::OnSetCursor(pWnd, nHitTest, message); } 你没有成功的原因是因为窗口类光标风格不能为 NULL. 问:如何用键盘滚动分割的视口? 我的问题是当我用鼠标滚动分割窗口时,视口滚动都很正常,但用键盘时, 却什么也没有发生. 答:在你的视图继承类中加入如下两个函数,假定该类为 CScrollerView: void CScrollerView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { BOOL processed; for (unsigned int i=0;i 问:如何在线程中处理状态条? 在我的应用程序 CWnd 的继承中有指针指向状态条,用 pStatusBar->SetPaneText(0,status,TRUE) 在状态条上显示一些文本都很正常.但在第二个线程中调用该函数却不行,出现 hwnd 警告. 答:当你传送一个 CWnd 的指针到另外一个线程时,m_hWnd 将为空.我的办法是用 PostThreadMessage 传送消息到状态条的父类,让它对状态条进行处理. 问:如何阻止 WINDOWS 关闭? 我有一个应用程序会不停地工作.当该程序正常运行时,该如何避免用户关掉系统? 是不是该用 WM_QUERYENDSESSION. 答:是的,在你的主框架窗口类中使用. // in the class header afx_msg BOOL OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason ); // in the Message Map ON_MESSAGE( WM_QUERYENDSESSION, OnQueryEndSession ) // in the class body BOOL CMainFrame::OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason ) { if( lEndReason =3D=3D ENDSESSION_LOGOFF ) { // user is logging off else // Windows is going down return( bCanExit ); } 问:如何使一个按钮 Disable? 我使用下面代码来 Disable 一个为 ID_BUTTON 的按钮,为什么会没有变化. GetDlgItem(IDC_BUTTON)->EnableWindow(FALSE); 答:CWnd 类中的 EnableWindow 函数用来 Enable 或 Disable 一个窗口类的 对象,因为 CButton 类继承于类 CWnd,所以你可以使用来操作一个按钮. Enable 一个基于窗口类的对象可以用以下代码: pWnd->EnableWindow(TRUE); Disable 一个对象可用 pWnd->EnableWindow(FALSE); 其中 pWnd 为一个指向窗口对象的指针 VC++中消息 WM_ENABLE 告诉窗口它正在 Disable 或 Enable,但它并不能 使一个窗口 Enable 或 Disable. 问:怎样从 MFC 扩展动态链结库(DLL)中显示一个对话框? 问:我在过去的几天中试着在 DLL 中定义的函数中显示一个对话框,可是已 经在 DLL 中定义好的对话框资源,在常规 DLL 调用时,我可以正常的显示出来, 为什么在扩展 DLL 中同样的资源我却不能显示. 答:当你在 DLL 中使用资源时,有些小细节需要注意,首先,在 DLL 运行时, 必须保存 DLL 的实例,可以通过 AfxInitExtensionModule static AFX_EXTENSION_MODULE extensionDLL; extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID) { if (dwReason == DLL_PROCESS_ATTACH) { // Extension DLL one-time initialization if (!AfxInitExtensionModule(extensionDLL, hInstance)) return false; } return(true); } 然后,每次使用 DLL 资源时,你必须改变资源的句柄,使其指向 DLL,并保 存 exe 的资源,以便以后正确恢复 void get_DLL_resource(void) { /* this function changes the resource handle to that of the DLL */ //这个函数改变资源句柄使其指向 DLL if (resource_counter == 0) { save_hInstance = AfxGetResourceHandle(); AfxSetResourceHandle(extensionDLL.hModule); } resource_counter++; } 接着你需要其它函数来恢复资源句柄 void reset_DLL_resource(void) { /* this function restores the resource handle set by 'get_DLL_resource()' */ if (resource_counter > 0) resource_counter--; if (resource_counter == 0) AfxSetResourceHandle(save_hInstance); } 接下来一点非常重要,只要有可能就必须恢复资源句柄,否则,你将会遇到许 多问题.原因是可执行文件必须重画工具条等等,比如说,如果用户移动 DLL 的 对话框,如果资源句柄仍然为 DLL 的资源,程序就崩溃了,我发现最好恢复句柄 的时机在对话框的 OnInitDialog()中,这时对话框的模板等已经读出了. 问:想隐藏用户界面怎么办? 问:我编了一个小巧而有趣的工具,当用户使用时我不想让它显示出任何用户 界面。听听各位有办法可将视关闭。 答:你可以注册一个新的窗口类型,它拥有除了 WS_VISBLE 属性外的任何属性, 类似 CFrameWnd,在 PreCreateWindow 方法中实现。 另外,你能在 OnCreate 方法中通过设置 m_nCmdShow 为 SW_HIDE 来实现, 具体方法如下: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // hide our app AfxGetApp()->m_nCmdShow = SW_HIDE; return 0; } 问:如何实现 SDI 与 MDI 的转换? 问:我想将一个编好的 SDI 应用程序转换为 MDI,很明显要有多处的改变。 答:你可以这样做:建立一个继承于 CMDIChidWnd 的类,不防设为 CChldFrm. 在 CWinApp 中作如下变化。 InitInstance() { ...... //instead of adding CSingleDocTemplate // Add CMultiDocTemplate. pDocTemplate = new CMultiDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CSDIDoc), RUNTIME_CLASS(CChldFrm), // For Main MDI Frame change this frame window from // CFrameWnd derivative ( i.e. CMainFrame ) // to your CMDIChildWnd derived CChldFrm. RUNTIME_CLASS(CSDIView)); // After this it is required to create the main frame window // which will contain all the child windows. Now this window is // what was initially frame window for SDI. CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; ..... } 在从 CMDIFrameWnd 中继承的类 CMainFrame 代替 CFramWnd 后,所有的类都将从 CMDIFrame 继承, 而不是 CFrameWnd,编译运行后你就会发现程序已经从 SDI 变 换到 MDI。 注意:在 CMainFram 中必须将构造函数从 private 改为 public.否则会出错。 问:CDC 中的竖排文本? 在 OnDraw 成员函数中我想让文本竖直对齐,但 CDC 类似乎不支持该处理 答:如果你的竖直对齐是指旋转文本的话,下面的代码会对你有帮助: 该代码检查一个 Check box 控 制,查看文本是否需要旋转. // m_pcfYTitle is a CFont* to the selected font. // m_bTotateYTitle is a bool (==TRUE if rotated) void CPage1::OnRotateytitle() { LOGFONT lgf; m_pcfYTitle->GetLogFont(&lgf); m_bRotateYTitle= ((CButton*)GetDlgItem(IDC_ROTATEYTITLE))->GetCheck()>0; // escapement is reckoned clockwise in 1/10ths of a degree: lgf.lfEscapement=-(m_bRotateYTitle*900); m_pcfYTitle->DeleteObject(); m_pcfYTitle->CreateFontIndirect(&lgf); DrawSampleChart(); } 注意如果你从 CFontDialog 中选择了不同的字体,你应该自己设定 LOGFONT 的 lfEscapement 成员.将初始化后的 lfEscapement 值传到 CFontDialog 中. A2:还有一段代码可参考: LOGFONT LocalLogFont; strcpy(LocalLogFont.lfFaceName, TypeFace); LocalLogFont.lfWeight = fWeight; LocalLogFont.lfEscapement = Orient; LocalLogFont.lfOrientation = Orient; if (MyFont.CreateFontIndirect(&LocalLogFont)) { cMyOldFont = cdc->SelectObject(&MyFont); } 问:如何激活变灰的弹出菜单? 在设计菜单时设定为 GRAYED 的菜单项,如何在运行时激活它? 答:请看下面的示例代码: void CMyView::OnRButtonDown(UINT nFlags, CPoint point) { CScrollView::OnRButtonDown(nFlags, point); CMenu *menu, *popup; menu = new CMenu(); // load menu from resource file menu->LoadMenu( IDR_POPUPMENU ); popup = menu->GetSubMenu(0); // item 0 is DUMMY UINT nEnable; nEnable = MF_BYCOMMAND|MF_GRAYED; if( your test ) { nEnable = MF_BYCOMMAND|MF_ENABLED; } popup->EnableMenuItem( ID_YOUR_ID, nEnable ); //display menu ClientToScreen(&point); popup->TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this ); delete menu; } 问:线程消息? 如何正确地在线程之间传送消息? 答:下面的代码将会帮你的忙: void CThread::OnUserOpen( WPARAM wParm, LPARAM lParm ) { UNUSED( wParm ) ; UNUSED( lParm ) ; AfxMessageBox("User Open", MB_OK|MB_ICONEXCLAMATION); } 当然,也别忘了以下声明: class CThread : public CWinThread { DECLARE_DYNCREATE(CThread) protected: CThread(); // protected constructor used by dynamic creation afx_msg void OnUserOpen( WPARAM wParm, LPARAM lParm ); 问:TreeCtrl 控制的显示速度太慢? 我从 CTreeCtrl 继承了一个 TREE 控制类,重载主要是为了改写每个节点的文本.我在 OnPaint 函数中 写了一些代码,但这严重地影响了 TREE 控制的滚动速度. 答:OnPaint 函数 1.可见节点,对于 GetFirstVisibleItem 和 GetNextVisibleItem 来讲,是: a.根节点;b.父节点已展开的节点; 因此,"可见"意味着"没有被未展开的父节点隐藏".当节点滚动到客户外时,它对上述两 个函数来讲 仍是可见的. 2.当 TREE 的内容改变时,它默认只将变为可见的节点重绘.另外其它已经是可见的节点 没有必要重 绘,TREE 只是滚动 DC 的位图而已. 上面的意思是不要绘制你不需要看的节点,那会导致速度降低.建议,测试节点矩形是否 在客户区,使 得只有需要绘制的节点才会被绘制. void CIndentTree::OnPaint() { CPaintDC dc(this); // device context for painting HTREEITEM hItem = NULL; DRAWITEMSTRUCT dis; CRect rc; // redraw only visible items with indentation for( hItem = GetFirstVisibleItem(); hItem; hItem = GetNextVisibleItem( hItem ) ) { if( !GetItemRect( hItem, rc, FALSE ) ) continue; if( rc.top <= dc.m_ps.rcPaint.bottom && rc.bottom> dc.m_ps.rcPaint.top &&=20 rc.left <= dc.m_ps.rcPaint.right && rc.right> dc.m_ps.rcPaint.left ) { dis.hwndItem = (HWND)hItem; dis.rcItem = rc; OnDrawItem(0, &dis, &dc); } } } OnDrawItem 函数 1.删掉如下代码: IMAGEINFO* pinfo = new IMAGEINFO; ... delete pinfo; 没有必要使用动态的 IMAGEINFO 变量,你可以将其定义为堆栈变量. 2.GetItemState 和 GetItemText 都是使用的 GetItem,因此,你只需调用一次, 就可以从节点获得你要 的所有信息 怎样使窗口总是浮现在最上面? 问:我想让一个窗口浮在最上面,我用过许多函数,但都没有一个能在 98 下工作. 答:1.在 CWnd::ModifyStyleEx()函数中加入 WS_EX_TOPMOST 状态参数; 2.这是个老问题,下面的代码将会对你有所启示 #include "Windows.h" #pragma data_seg("shared") HHOOK g_hHook = NULL; HINSTANCE g_DllInst = NULL; #pragma data_seg() BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { g_DllInst = hInst; return TRUE; } LRESULT CALLBACK GetMsgProc( int code,WPARAM wParam,LPARAM lParam) { UINT nMsg = RegisterWindowMessage("Set foreground window"); MSG * pMsg; HWND hWnd; pMsg = (MSG *)lParam; if(pMsg->message==nMsg) { hWnd = (HWND)pMsg->wParam; OpenIcon(hWnd); if(IsIconic(hWnd)) OpenIcon(hWnd); else SetForegroundWindow(hWnd); } return CallNextHookEx(g_hHook, code, wParam,lParam); } BOOL __declspec(dllexport) ReallySetForegroundWindow(HWND hWnd) { int nMsg; HWND fhWnd = GetForegroundWindow(); if(IsIconic(hWnd)) OpenIcon(hWnd); else SetForegroundWindow(hWnd); if(fhWnd == GetForegroundWindow()) { if (g_hHook) UnhookWindowsHookEx(g_hHook); g_hHook = NULL; } g_hHook = SetWindowsHookEx(WH_GETMESSAGE , GetMsgProc, g_DllInst,GetWindowThreadProcessId(fhWnd, NULL)); nMsg = RegisterWindowMessage("Set foreground window"); PostMessage(fhWnd,nMsg, (WPARAM)hWnd, 0); } return TRUE; } 改变拖放时的光标外形? 问:我用 CView::OnDragEnter(), CView::OnDragOver(), CView::OnDragOver()来实现 拖放功能, 但我不想用标准的拖动光标,有没有方法将它改一下,我试过 SetCursor(). 答:有没有检查过 SetCursor()的参数,试试下面的代码,在我这儿一切正常 HCURSOR hlCursor; hlCursor = AfxGetApp()->LoadStandardCursor(IDC_WAIT); SetCursor(hlCursor); 顺便提一下,最好在 SetCursor()时设置一个断点,用来检查指针是否为 NULL 如何定位到最新的记录上? 问:我需要将最后插入 ACCESS 数据库中的记录显示出来,在 DAO 中我知道可以用 CDaoRecordset::GetLastModifiedBookmark()实现,但在 CRecordset 中不行. 答:1)试一下下面的代码 void Refresh( CRecordset* pSet) { ASSERT(pSet && pSet->CanScroll() ); if (pSet && pSet->CanBookmark()) { // CRecordset-derived object CDBVariant varCurrentRecord; pSet->GetBookmark(varCurrentRecord); pSet->SetBookmark(varCurrentRecord); } } 2).在 Update()后,使用 SetBookmark(GetLastModifiedBookmark())函数,这样你就 能得到最新的插 入或改写的记录的位置,然后使用 GetFieldValue 得到你所期望的. if(rs.CanAppend()) { rs.AddNew(); rs.SetBookmark(rs.GetLastModifiedBookmark()); } 问:我想用不同的颜色来替换缺省的颜色(检查标记区域) 答:1).你可以在 component library 中选择 MS Form checkbox2.0,里面可以通过 设置属性 "Backcolor"和"Forecolor"来改变. 2).检查框也是个按钮,可能使用自画按钮可以完成你所期望的,更多的消息 可以看 BS_OWNERDRAW 和 WM_DRAWITEM MVC 和 Doc-View? 问:谁知道 MVC(文档,视,控制)结构与 MFC(文档,视)的优异? 答:文档视比起 MVC 来少了一个控制,在 MVC 中你不可以使用一视多文档,当然文档 视结构比起 MVC 来 可能自己要做得更多些. (其实,MVC 是 BC 中采用的一种方法,但 BORLAND 公司已不再辉煌,再做比较可能已 经没有多大用处了 --译者注) 被禁止(Disable)的控件如何改变其文本或背景色? 问:能否可以改变一个已经被禁止(Disable)的文本颜色或者背景色? 答:你可以捕获 OnCrlColor 消息,然后检查控件是否在同一个函数中被禁止,接着 如果是被禁止的话 返回你的画刷,那么系统会自动照返回的颜色绘色. HBRUSH OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor ) { if (GetDlgItem (IDC_SOMECTL) == pWnd) { SetTextColor (dwReqdColor); return hReqdBrush; } return NULL; } 有 ODBC 的查找函数吗? 问:我将一个应用程序从 DAO 转换为 ODBC,但发现没有与 CDaoRecordse::Find()等价的 ODBC 函数. 答:我建议用折半查找算法.当然这只能在你的记录是按某一字段排序的情况下,而且也应该 取得记 录的总条数.请看如下示例: BOOL CMyRecordset::FindFirst_Name(const CString& value) { if (IsEOF() && IsBOF()) // recordset empty? return FALSE; ULONG ulTop = 1, ulBottom, ulMiddle; // try to determine record count - if it is possible, of course SetAbsolutePosition(-1); ulBottom = GetRecordCount(); if(ulBottom == -1) // number of records can not be determined return FALSE; do { SetAbsolutePosition(ulMiddle = (ulTop + ulBottom) >> 1); switch(value.Compare(m_sName)) { case 0: // found! return TRUE; case 1: // value is greater than m_sName ulTop = ulMiddle; break; case -1:// value is less than m_sName ulBottom = ulMiddle; } } while(ulTop != ulBottom); // not found return FALSE; } 注意:  这个函数不能保证找到的是第一个(按顺序)符合条件的记录,但很显然,你可以定制 它来满足你 的要求.  取中值时你不一定非要除以 2,例如你可以用 Fibonacci数列(1,2,3,5,8,13,21...)来改变 切分的 大小,这样或许会得到更好的性能.  我没有测试这个函数,也许无法工作. 多个 MRU 菜单的问题 问:我想象 DevStudio97 那样将不同文档类型的 MRU 子菜单分开,如分成最近的工作区和最近打开 的 文件.我在 CodeGuru 上找了找,但没有什么收获. 答:这是可以解决的.我保留了 CRecentFileList 对象,让 MFC 框架去管理默认的文档类型,然后 加入 了对第二种文档类型的处理,我准备一步一步说明这个问题: 1. 使用自定义的菜单 ID,如 ID_FILE_MRU_MYFILE1,你也应该在字符串表中加入 ID_FILE_MRU_MYFILE2, ID_FILE_MRU_MYFILE3, ... ID_FILE_MRU_MYFILE## 2. 在应用程序类中加入新成员:CRecentFileList* m_pRecentListMyFiles; 3. 在初始化 InitInstance()加入如下代码: m_pRecentListMyFiles =new CRecentFileList( 5, "My Recent File List", "MyFile%d", 5 ); m_pRecentListMyFiles->ReadList(); 4. 在 ExitInstance()加入 m_pRecentListMyFiles->WriteList(); 5. 增 加 对 ID_FILE_MRU_MYFILE1 的 UI 处理 UPDATE_COMMAND_UI:m_pRecentListMyFiles->UpdateMenu(pCmdUI); 6. 在应用程序消息映射中加入如下代 码 :ON_COMMAND_EX_RANGE(ID_FILE_MRU_MYFILE1, ID_FILE_MRU_MYFILE##,OnOpenRecentMyFile) 7. 下面是上述消息的处理函数: 8. BOOL CMyApp::OnOpenRecentMyFile(UINT nID) 9. { 10. int nIndex = nID - ID_FILE_MRU_MYFILE1; 11. if (OpenDocumentFile((*m_pRecentListMyFiles)[nIndex]) == NULL) 12. m_pRecentListMyFiles->Remove(nIndex); 13. return TRUE; 14. } 15. 重载 CWinApp::AddToRecentFileList() 16. void Ck2App::AddToRecentFileList(LPCTSTR lpszPathName) 17. { 18. // Somehow determine doc type, I used file extension 19. CString strExt; 20. CString strPathName = lpszPathName; 21. int nPos = strPathName.ReverseFind( '.' ); 22. if ( nPos != -1 ) 23. strExt = strPathName.Mid( nPos + 1 ); 24. if ( strExt.CompareNoCase( "XXX" ) == 0 ) 25. { 26. if (m_pRecentListMyFiles!= NULL) 27. { 28. // fully qualify the path name 29. TCHAR szTemp[_MAX_PATH]; 30. AfxFullPath(szTemp, lpszPathName); 31. 32. // then add to recent file list 33. m_pRecentListMyFiles->Add(szTemp); 34. } 35. } 36. else // Otherwise, let base class put it on default MRU 37. CWinApp::AddToRecentFileList(lpszPathName); 38. } 当然,也不要忘了在应用程序的析构函数中删除 m_pRecentListMyFiles 校验框类问题 问:我想创建这样一个校验框类,它的自动特性只出现在用户点击校验标记时,而不是 当文本 被点击时.在点击文本时,我只想设置焦点,就象 CheckListBox 那样. 答:在按钮类的派生类中,例如 CCheckBox,处理 WM_LBUTTONDOWN 消息: void CCheckBox::OnLButtonDown( UINT nFlags, CPoint point ) { // if the checkmark was clicked, pass the message onto the button if ( HitTest( point ) ) CButton::OnLButtonDown( nFlags, point ); else // otherwise set the focus only SetFocus(); } BOOL CCheckBox::HitTest( CPoint& point ) { CRect rcClient; GetClientRect( rcClient ); // Checkmark rect CRect rc; // Checkmark square size, hard coded here because I couldn't find any method to obtain this value from the system. // Maybe someone else knows how to do it? const int nCheckSize = 13; DWORD dwStyle = GetStyle(); if ( ( dwStyle & BS_VCENTER ) == BS_VCENTER ) rc.top = rcClient.top + ( ( rcClient.bottom - rcClient.top ) -nCheckSize ) / 2; else if ( dwStyle & BS_TOP ) rc.top = rcClient.top + 1; else if ( dwStyle & BS_BOTTOM ) rc.top = rcClient.bottom - nCheckSize - 2; else // Default rc.top = rcClient.top + ( ( rcClient.bottom - rcClient.top ) -nCheckSize ) / 2; if ( dwStyle & BS_LEFTTEXT ) rc.left = rcClient.right - nCheckSize; else rc.left = rcClient.left; rc.right = rc.left + nCheckSize; rc.bottom = rc.top + nCheckSize; return rc.PtInRect( point ); } CFormView 类的 Fold 按钮 问:我有一个 SDI 程序,视类继承 CFormView,我想实现在屏幕上一个 fold 按钮,它能 隐藏或显现 在屏幕任何适当的地方,但我不知道该怎么去做它。 答:我认为ResizeParentToFit并没有达到所期望的,通常在MS的文档说明中是用在MDI子窗口中 的, 所以我们需要自己做函数所做的事情。 #define SIZE_TO_FOLD your_dynamically_or_statically_calculated_value void CCashMachineView::OnBtnFold() { static bool bUnfolded = true; CSize sizNew; CRect rc, rcMF; GetWindowRect(&rc); AfxGetMainWnd()->GetWindowRect(&rcMF); if(bUnfolded) // fold { rc.bottom -= SIZE_TO_FOLD; rcMF.bottom -= SIZE_TO_FOLD; } else // unfold { rc.bottom += SIZE_TO_FOLD; rcMF.bottom += SIZE_TO_FOLD; } bUnfolded = !bUnfolded; sizNew.cx = rc.right - rc.left - 5; sizNew.cy = rc.bottom - rc.top - 5; SetScrollSizes(MM_TEXT, sizNew); MoveWindow(0, 0, sizNew.cx, sizNew.cy); AfxGetMainWnd()->SetWindowPos(&wndTop, 0, 0, rcMF.right - rcMF.left, rcMF.bottom - rcMF.top, SWP_NOMOVE); } 这可能会带来些付作用,比如闪烁。 视的背景色 问:我写了一个 SDI 程序,是用 vc5.0 分析 HTML 文件,并显示出来,但我不知道如何 改变程序的背 景色? 答:1)首先不知道您为什么要自己写一个 HTML 浏览器,你可以将 MS Web Browser 控件插入 你的视 中。在 6.0 中你可以使用 CHtmlView 类。5.0 中你同样可以快速建立一个自己的 CHtmlView 类(建立 一个视关于 ActiveX 控件的)。 2)在 OnCtlColor 消息句柄返回所需的画刷。 隐藏控件台程序 问:我用 MFC 写了个控件台程序,现在我想让它在启动时隐藏或最小化,使用户尽可能减 少相互交 流。 答:我认为一个方法是使用 32 位函数,你能使用 FindWindow()得到窗口的句柄, 然后就使用 ShowWindow 函数。 HWND hWnd = FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName); ShowWindow(hWnd, SW_SHOWMINIMIZED ) 修改 SDI 窗口标题 问:我们通常是用向导生成器来完成一个 SDI 框架,那么怎样才能设置窗口的标题? 答:1)试一下我程序中由向导生成的代码: GetDocument()->SetTitle(_T("Meaningful Title")); 2)我认为你可以应用类中实现它,InitInstance 函数,你有一个成员变量 m_pMainWindow,所 以 只要 m_pMainWnd->SetWindowText(_T("Ur Text"))就可以了,然后再运行 m_pMainWnd->ShowWindow(SW_SHOWNORMAL); m_pMainWnd->UpdateWindow(); 焦点问题 问:我有一个非模态属性表,其中的一页包含 7 个控件,我的问题是,如果现在焦点在一个 编辑控 件上,当我最小化窗口后又最大化,那么该控件就会失去焦点,怎样才能恢复原状? 答:在消息 WM_SHOW 中这样做: void CPropPage::OnShowWindow(BOOL bShow, UINT nStatus) { ... if( bShow ) { // restore current focused control if( m_pCurFocusWnd != NULL ) { m_pCurFocusWnd->SetFocus(); } } else { // save current focused wnd m_pCurFocusWnd = GetFocus(); } YourBaseClass::OnShowWindow(bShow, nStatus); ... } 注意:pCurFocusWnd 是一个 CWnd 指针,必须在构造函数中初始化为 NULL;你也必须声明 对话框中 的所有变量,否则调用 OnShowWindow 时,指针通过 GetFocus()所返回的值将是 非法的。希望你能满 意! 从一个 OCX 调用另一个 OCX 的方法。 问:我们能否在一个 OCX 中建立另外一个 OCX 的句柄?我想做一个 OCX,里面包含 VC 的应用 向导生 成器的 OCX,第一个 OCX 需要第二个 OCX 的支持(插入的控件需要交流)当我建立第二 个 OCX 句柄时, 总是失败。 答:将你的 initlnstance()作如下修改。 BOOL CScheduleXVer1App::InitInstance() { BOOL bInit = COleControlModule::InitInstance(); if (bInit) { AfxEnableControlContainer(); } return bInit; } 得到视 问:我写了一个 SDI 程序,怎样我才能从框架窗口中得到指向视的指针? 答:试一下 CFrameWnd 中的 GetActiveView() CView* theView = MyFrameWnd.GetActiveView(); if (CView) // do something... 字符转化时间 问:我想将字符转化为 CTime 对象。 答:这有一个非常简单的函数,您可以在此上面加入你所需要的: BOOL ScanTime ( CTime &time, // o - filled in time structure LPCTSTR lpszTime, // i - the string containing the time to be extracted LPCTSTR lpszFormat // i - the time format to extract according to ) { int nYear = 1980; // extracted time fields int nMonth = 1; int nDay = 1; int nHour = 0; int nMin = 0; int nSec = 0; int nFlag = DATE_TIME; // DATE_TIME / DATE_ONLY / TIME_ONLY CString msg; // start at the beginning char *pTime = (char *)lpszTime; char *pFmt = (char *)lpszFormat; while (*pFmt != '\0') { if (*pFmt == '%') { pFmt++; switch (*pFmt) { case 'Y' : // year with century sscanf (pTime,"%4d",&nYear); if (nYear <1980 || nYear> 2036) { msg.Format ("Invalid year (%d)",nYear); AfxMessageBox (msg); return (FALSE); } pTime+=4; break; case 'y' : // year without century (00-99) sscanf (pTime,"%2d",&nYear); nYear = nYear + (nYear > 36 ? 1900 : 2000); if (nYear <1980 || nYear> 2036) { msg.Format ("Invalid year (%d)",nYear); AfxMessageBox (msg); return (FALSE); } pTime+=2; break; case 'm' : // month (01-12) sscanf (pTime,"%2d",&nMonth); if (nMonth <1 || nMonth> 12) { msg.Format ("Invalid month (%d)",nMonth); AfxMessageBox (msg); return (FALSE); } pTime+=2; break; case 'd' : // day of month (01-31) sscanf (pTime,"%2d",&nDay); if (nDay <1 || nDay> 31) { msg.Format ("Invalid day (%d)",nDay); AfxMessageBox (msg); return (FALSE); } pTime+=2; break; case 'H' : // hour (00-23) sscanf (pTime,"%2d",&nHour); if (nHour <0 || nHour> 23) { msg.Format ("Invalid hour (%d)",nHour); AfxMessageBox (msg); return (FALSE); } pTime+=2; break; case 'M' : // minute (00-59) sscanf (pTime,"%2d",&nMin); if (nMin <0 || nMin> 59) { msg.Format ("Invalid minute (%d)",nMin); AfxMessageBox (msg); return (FALSE); } pTime+=2; break; case 'S' : // second (00-59) sscanf (pTime,"%2d",&nSec); if (nSec <1 || nSec> 31) { msg.Format ("Invalid second (%d)",nSec); AfxMessageBox (msg); return (FALSE); } pTime+=2; break; default : msg.Format("Invalid format specifier (%c)",*pFmt); AfxMessageBox(msg); return (FALSE); break; } } else { if (!isdigit((int)(*pTime))) { if (*pTime == *pFmt) { pTime++; } else { msg.Format ("Character mismatch : Expected %c, found %c",*pFmt,*pTime); AfxMessageBox ((LPCTSTR)msg); return (FALSE); } } } pFmt++; } // success time = CTime(nYear,nMonth,nDay,nHour,nMin,nSec); return (TRUE); } 二进制还是文本方式? 问:怎样测定一个文件是用二进制模式还是文本模式打开? 答:所有的文件(数据文件或应用文件)都一系列的字节组成的,通常是通过文件的扩展名 来知道 某一文件的内容。当程序读一个文件时,你需要说明这个文件的格式,这通常 文件格式会有相应的 说明。比如可能是这个样子的,“第 11 到 14 字节是一个长字节,指 向图像数据的开始处”。 如果文件是你自己定义的格式,那么你的读取数据的程序必须与写入数据的程序相 匹配, 如果是一个已确定的文件格式,可以通过以下的站点得到具体内容。 http://www.wotsit.org 发送消息 问:怎样发送一个消息 CBN_SELCHANGE 给组合框? 答:下面的代码会使你满意的。 CWnd *pWnd = GetTopLevelParent(); if ( pWnd ) { lResult = pWnd->SendMessage ( WM_COMMAND, wParam, ( LONG ) hWnd ); if ( lResult == 0 ) //perhaps may parent is a dialog box; { pWnd = GetParent (); lResult = pWnd->SendMessage ( WM_COMMAND, wParam, ( LONG ) hWnd ); } } 怎样知道菜单运行时的状态 问:我想在程序运行时从一个属性表中检查某菜单是否 enable 或 disable,但我不会做, 有谁能告 诉我该怎么办? 答:如果你想通过 MFC 来完成你所想的,而使用 CN_UPDATE_COMMAND_UI 事件,你的代码 不能正常运 行,这是因为 MFC enable/disable 菜单在激活之前就已经完成了。你可以用 MFC 的 CWnd::OnCommand 函数来解决这个问题,就象下面所做的, CTestCmdUI state; state.m_nID =3D ID_MODIFY; // All will work fine without this line AfxGetMainWnd()->OnCmdMsg(ID_MODIFY, CN_UPDATE_COMMAND_UI, &state, NULL); if (state.m_bEnabled) { CMyPage* pMyPage=3D( CMyPage*)GetParent(); pMyPage->Modify(); // this is my function } DLL 编译出错 问:我建立了一个常规 DLL,在 VC 环境下编译联接没有任何错误。但在命令行中编译却发现有 如下 错误: link.exe @C:\TEMP\nme00204. mfcs42d.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in MSVCRTD.lib(dllmain.obj) 答:1)可能你有些 cpp 文件包括了 stadafx.h,而又有些包括了 windows.h?在这种情况下你应该在 文件 中使用 stdafx.h。 2)VC 环境是使用.DSP 来建立一个项目,可能你的编译器或连接器设置中与你的.MAK 文件中的 设置不 匹配 通用控件的显示窗口 MFC 提供了几个 CView 派生的视窗类,封装了通用控件的功能,但仍然使用工 作框文档显示窗口体系结构:CEditView 封装了编辑控件,CTreeView 保持了树列表 控件,CListView 封装了列表显示窗口控件,CRichEditView 可以处理多种编辑控件。 如何禁止和使能控件 控件也是窗口,所以可以调用 CWnd : : EnableWindow 使能和禁止控件。 //Disable button controls . m_wndOK.EnableWindow (FALSE ) ; m_wndApply.EnableWindow (FALSE ) ; 如何在 OLE 控件中使用 OLE_COLOR 数据类型 诸如 COleControl : : GetFortColor 和 COleControl : : GetBackColor 等函数返回 OLE _COLOR 数据类型的颜色,而 GDI 对象诸 如笔和刷子使用的是 COLORREF 数据类型,调用 COleControl : : TranslateColor 可以很容易地将 OLE_COLOR 类型改为 COLORREF 类型。下例创建了一个当前背景颜色的刷子: void CSampleControl : : OnDraw (CDC* pdc const Crect& rcBounds , const Crect& rcInvalid ) { //Create a brush of the cuttent background color . CBrush brushBack (TranslateColor (GetBackColor ( ) ) ); //Paint the background using the current background color . pdc—> FilllRect (rcBounds , &brushBack) ; //other drawign commands … } 在不使用通用文件打开对话的情况下如何显示一个文件列表 调用 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 ; } 为什么旋转按钮控件看起来倒转 需要调用 CSpinCtrl : : SetRange 设置旋转按钮控件的范围,旋转按钮控件的缺省上限为 0,缺省下限为 100,这意味着增加 时旋转按控件的值由 100 变为 0。下例将旋转按钮控件的范围设置为 0 到 100: BOOL CAboutDlg : : OnInitDialog ( ) { CDialog : : OnInitDialog ( ) //set the lower and upper limit of the spin button m_wndSpin . SetRange ( 0 ,100 ) ; return TRUE ; } Visual C++ 4.0 Print 对话中的 Copise 旋转按钮控件也有同样的问题:按下 Up 按钮时拷贝的数目减少,而按下 Down 按钮时 拷贝的数目增加。 为什么旋转按钮控件不能自动地更新它下面的编辑控件 如果使用旋转按钮的 autu buddy 特性, 则必须保证在对话的标记顺序中 buddy 窗口优先于旋转按钮控件。从 Layout 菜单中 选择 Tab Order 菜单项(或者按下 Crtl+D)可以设置对话的标签顺序。 如何动态创建控件 分配一个控件对象的实例并调用其 Create 成员函数。开发者最容易忽略两件事:忘记指定 WS_VISBLE 标签和在栈中分配 控件对象。下例动态地创建一个下压按钮控件: //In class declaration (.H file ). private : CButton* m _pButton ; //In class implementation (.cpp file ) . m_pButton =new CButton ; ASSERT_VALID (m_pButton); m_pButton —>Create (_T ("Button Title ") , WS_CHILD |WS_VISIBLE |BS_PUSHBUTTON. Crect ( 0, 0, 100 , 24) , this , IDC _MYBUTTON ) 如何显示旋转文本 只要用户使用 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 rcClient; GetClientRect (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 object LOGFONT 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_NORMAL; stFont.ifClipPrecision=LCIP_LH_ANGLES; strcpy (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 (); } 如何让 TOOLTIP 的字体变大 前几天有个虫虫问如何让 vc4.0 的 Tooltip 的字体变大,可现在文章没有了.不过现在我 有个方法:在 Windows 95 Desktop 属性中有 desktop scheme 中有 Tooltip 一项,可以该变 TOOLTIP 的字体和大小.不过这样做所有程序的 Tooltip 都变大了.这可能不是你的本意. 但 Tooltip 是 Windows 95 Common Control,由 Windows 95 内部实现,VC4.0 的 CTooltip 类并不实现 Tips 的显示,所以要实现针对某个程序的 Tooltip 的特殊显示,有一定难度.我以前曾经试图实现 Tooltip 的多行显示,做到了当 Toolt. 显示时触发我的函数,消失时触发我的函数,但在显示时却出 GP 错误.现在我认为最简 单的方法是从头自己实现 Tooltip 类.一切随心所欲.* 在 TreeList 中使用 Edit 功能 首先了讲该 TreeList 应该使用 TVS_EDITLABELS 风格,可以在创建资源时指定,或者在使用 Create 时指定,或者在 PreCreateWindos()中改变。 接下来需要处理 TVN_BEGINLABELEDIT 和 TVN_ENDLABELEDIT 消息。 void CXXXX::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) { TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR; // Limit text length GetEditControl()->LimitText(127); *pResult = 0; } 如果不处理 TVN_ENDLABELEDIT 消息,则文本的更改不会生效。 void COutline::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) { GetEditControl()->GetWindowText(s); // Set result to TRUE to accept the changes *pResult = TRUE; } TreeList control 中使用 check box 方法很简单,一句话总结:定义用户定义状态,并对不同的状态(state)使用不同的图片。 在下面的 sample 中,我们使用 CTreeListCtrl 作为父类。由于 TreeList control 支持一些现有 state 所以用户定义的 state 必需 使用 INDEXTOSTATEIMAGEMASK(i)进行变换。 如果对本文所讲的方法有不明的地方,可以先熟悉一下 TreeList Control 的使用,然后再看本文。 Step 1: 创建 state list image 创建的图片有三种状态。 state ImageList 只是用于和 state 改变有关的显示图片,TreeList Control 中还应包含其他 image List,如:焦点选择改变的 imageList,用于在选中和未选中是改变显示图片。 Step 2: 初始化 CImageList m_imageState; 成员变量 m_imageState.Create( IDB_STATE, 13, 1, RGB(255,255,255) );//创建 ImageList m_tree.SetImageList( &(m_tree.m_imageState), TVSIL_STATE );//在 TreeList 中加入表示状态的 ImageList。 Step 3: 增加结点时设置标记 重新定义一个 InsertItem 函数。使用 TV_INSERTSTRUCT 来插入结点。 即使用函数 HTREEITEM InsertItem( LPTV_INSERTSTRUCT lpInsertStruct ); lpInsertStruct->item.mask |= TVIF_STATE ;//保证 state 和 stateMask 是有效的。 你必须在 TV_ITEM 中标明 state 和 stateMask。( INDEXTOSTATEIMAGEMASK 宏可以得到 state image 的下标) state 设置为 INDEXTOSTATEIMAGEMASK(1)表示用户定义的第一种状态 stateMask 设置为 TVIS_STATEIMAGEMASK.表示用户定义的状态。 当然也可以调用 SetItemState 设置 state. SetItemState( hItem, INDEXTOSTATEIMAGEMASK(1), TVIS_STATEIMAGEMASK ); Step 4: 增加 mouse button down 消息映射 通过使用 HitTest 来得知是否按在 State 图片上。并需要得到当前 state。 void CTreeCtrlX::OnLButtonDown(UINT nFlags, CPoint point) { UINT uFlags=0; HTREEITEM hti = HitTest(point,&uFlags); if( uFlags & TVHT_ONITEMSTATEICON ) { int iImage = GetItemState( hti, TVIS_STATEIMAGEMASK )>>12; //GetItemState( hti, TVIS_STATEIMAGEMASK )>>12 对用户定义 state 反变换 SetItemState( hti, INDEXTOSTATEIMAGEMASK(iImage == 1 ? 2 : 1), TVIS_STATEIMAGEMASK ); return; } } Step 5:处理 OnKeyDown void CTreeCtrlX::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if( nChar == VK_SPACE ) { HTREEITEM hti = GetSelectedItem(); int iImage = GetItemState( hti, TVIS_STATEIMAGEMASK )>>12; SetItemState( hti, INDEXTOSTATEIMAGEMASK(iImage == 1 ? 2 : 1), TVIS_STATEIMAGEMASK ); return; } } Step 6: 增加其他的功能函数 BOOL CTreeCtrlX::IsItemChecked(HTREEITEM hItem) { return GetItemState( hItem, TVIS_STATEIMAGEMASK )>>12 == 2; } HTREEITEM CTreeCtrlX::GetFirstCheckedItem() { for ( HTREEITEM hItem = GetRootItem(); hItem!=NULL; hItem = GetNextItem( hItem ) ) if ( IsItemChecked(hItem) ) return hItem; return NULL; } HTREEITEM CTreeCtrlX::GetNextCheckedItem( HTREEITEM hItem ) { for ( hItem = GetNextItem( hItem ); hItem!=NULL; hItem = GetNextItem( hItem ) ) if ( IsItemChecked(hItem) ) return hItem; return NULL; } HTREEITEM CTreeCtrlX::GetPrevCheckedItem( HTREEITEM hItem ) { for ( hItem = GetPrevItem( hItem ); hItem!=NULL; hItem = GetPrevItem( hItem ) ) if ( IsItemChecked(hItem) ) return hItem; return NULL; } 可以使用 Drag&Drop 的 CTreeView CTreeViewExt 是 MFC 使用者可重用的类,该类由 CTreeView 派生,可以用在文档-视结构的应用程序中,并且支持 Drag&Drop。 使用者所需要做的仅仅是将文件加到 AppWizard 产生的工程中,(CTreeView 为基类)并且将 CTreeView 替换为 CTreeViewExt。 并重载三个 Virtual Function。 (WenYY:这很简单吧,下面是源代码,我会在必要的地方加上注释,但由于原作者并未加,所以如果有出入请原谅,作者定 义了三处虚拟函数,其作用是让使用者重载后,加入自己的判断条件和结果处理的功能,很巧妙的思想: CopyItemProperties IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget); BOOL ItemCanBeDragged(HTREEITEM hItem);//检查是否可以对该 ITEM 实施 Drag&Drop ) Header file #if !defined(AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_) #define AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 // TreeViewExt.h : header file // ///////////////////////////////////////// // CTreeViewExt view class CTreeViewExt : public CTreeView { protected: CTreeViewExt(); // protected constructor used by dynamic creation DECLARE_DYNCREATE(CTreeViewExt) // Attributes public: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CTreeViewExt) protected: virtual void OnDraw(CDC* pDC); // overridden to draw this view //}}AFX_VIRTUAL // Implementation protected: HTREEITEM m_hDraggedItem; BOOL m_bDraggingNow; //标记 CImageList *m_pDragImageList; virtual ~CTreeViewExt(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif // Generated message map functions protected: virtual void CopyItemProperties(HTREEITEM hNewItem, HTREEITEM hDraggedItem); virtual BOOL IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget); virtual BOOL ItemCanBeDragged(HTREEITEM hItem);//检查是否可以对该 ITEM 实施 Drag&Drop //{{AFX_MSG(CTreeViewExt) afx_msg void OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult);//必须重载的函数 afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; ///////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line. #endif // !defined(AFX_TREEVIEWEXT_H__99D8F6F8_79F0_11D1_8DC6_0000E8125FE5__INCLUDED_) Implementation file // TreeViewExt.cpp : implementation file // #include "stdafx.h" #include "TreeViewExt.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////// // CTreeViewExt IMPLEMENT_DYNCREATE(CTreeViewExt, CTreeView) CTreeViewExt::CTreeViewExt() { m_bDraggingNow = FALSE; m_hDraggedItem = NULL; m_pDragImageList = NULL; } CTreeViewExt::~CTreeViewExt() { } BEGIN_MESSAGE_MAP(CTreeViewExt, CTreeView) //{{AFX_MSG_MAP(CTreeViewExt) ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag) ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////// // CTreeViewExt drawing void CTreeViewExt::OnDraw(CDC* pDC) { CDocument* pDoc = GetDocument(); // TODO: add draw code here } ///////////////////////////////////////// // CTreeViewExt diagnostics #ifdef _DEBUG void CTreeViewExt::AssertValid() const { CTreeView::AssertValid(); } void CTreeViewExt::Dump(CDumpContext& dc) const { CTreeView::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////// // CTreeViewExt message handlers void CTreeViewExt::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; if (!m_bDraggingNow) {//先检查是否正在过程中 if (ItemCanBeDragged(pNMTreeView->itemNew.hItem)) {//查询条件,是否允许 Drag&Drop CTreeCtrl& tree = GetTreeCtrl(); tree.SetCapture(); m_bDraggingNow = TRUE; m_hDraggedItem = pNMTreeView->itemNew.hItem;//保存变量 tree.Select(m_hDraggedItem, TVGN_CARET); m_pDragImageList = tree.CreateDragImage(m_hDraggedItem); m_pDragImageList->DragEnter(&tree, pNMTreeView->ptDrag); m_pDragImageList->BeginDrag(0, CPoint(0, 0)); } } *pResult = 0; } void CTreeViewExt::OnMouseMove(UINT nFlags, CPoint point) { if (m_bDraggingNow) { CTreeCtrl& tree = GetTreeCtrl(); m_pDragImageList->DragEnter(&tree, point); m_pDragImageList->DragMove(point); } CTreeView::OnMouseMove(nFlags, point); } void CTreeViewExt::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bDraggingNow) { ReleaseCapture(); m_bDraggingNow = FALSE; m_pDragImageList->EndDrag(); delete m_pDragImageList; m_pDragImageList = NULL; CTreeCtrl& tree = GetTreeCtrl(); UINT flags; HTREEITEM hTargetItem = tree.HitTest(point, &flags);//得到目标 if (hTargetItem != NULL && IsItemCanBeDroppedOn(m_hDraggedItem, hTargetItem)) {//查询是否可以成功完成,条件是开始时选中的 Item 和结束使选中的 ITEM 是否满足你的条件 HTREEITEM hNewItem = tree.InsertItem("Untitled", hTargetItem); CopyItemProperties(hNewItem, m_hDraggedItem);//进行处理 if (nFlags != MK_CONTROL) tree.DeleteItem(m_hDraggedItem); } m_hDraggedItem = NULL; } CTreeView::OnLButtonUp(nFlags, point); } BOOL CTreeViewExt::ItemCanBeDragged(HTREEITEM hItem) {//作用为决定现在是否能开始,可以作为一种运行时的选项 return FALSE; } BOOL CTreeViewExt::IsItemCanBeDroppedOn(HTREEITEM hSource, HTREEITEM hTarget) {//决定现在结束条件是否正常,如不正常则放弃这次操作 return FALSE; } void CTreeViewExt::CopyItemProperties(HTREEITEM hNewItem, HTREEITEM hDraggedItem) {//按照你的需要对两个 ITEM 进行处理。 } 有关属性对话框(property sheet )的几个提示 下面的所有例子,都假定你从 CPropertySheet 中派生了新类。 1、隐藏 APPLY 按钮 使用 PSH_NOAPPLYNOW 标志. propsheet.m_psh.dwFlags |= PSH_NOAPPLYNOW; 2、增加新的子窗口 使用成员变量。CEdit m_edit. BOOL CMyPropSheet::OnInitDialog() { BOOL bResult = CPropertySheet::OnInitDialog(); CRect rectWnd; GetWindowRect(rectWnd); SetWindowPos(NULL, 0, 0, rectWnd.Width() + 100, rectWnd.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); m_edit.CreateEx( WS_EX_CLIENTEDGE, _T("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER, rectWnd.Width(), 20, 80, 24, m_hWnd, 0, 0 ); m_edit.SetFont( GetFont() ); CenterWindow(); return bResult; } 3、改变页片上的字体 在 OnInitDialog() 中: // m_fontEdit is a member variable // Create a bold font m_fontEdit.CreateFont( -8, 0, 0, 0, 700, 0, 0, 0, 1, 0, 0, 0, 0, _T("MS Sans Serif") ); GetTabControl()->SetFont( &m_fontEdit ); 4、使用 Image m_imageTab 为成员变量。 BOOL CMyPropSheet::OnInitDialog() { BOOL bResult = CPropertySheet::OnInitDialog(); m_imageTab.Create( IDB_TABIMAGES, 13, 1, RGB(255,255,255) ); CTabCtrl *pTab = GetTabControl(); pTab->SetImageList( &m_imageTab ); TC_ITEM tcItem; tcItem.mask = TCIF_IMAGE; for( int i = 0; i <3; i++ ) { tcItem.iImage = i; pTab->SetItem( i, &tcItem ); } return bResult; } 为 TreeCtrl 中的项增加 ToolTip 要点:通过 OnToolHitTest 来增加 ToolTip,CTreeCtrl::HitTest(...)的使用,TTN_NEEDTEXT 消息的处理。 定义一个新类,有 CTreeCtrl 派生 Step 1:打开 ToolTip 功能 void CTreeCtrlX::PreSubclassWindow() { CTreeCtrl::PreSubclassWindow(); EnableToolTips(TRUE); } Step 2: OnToolHitTest() 的重载 首先通过 HitTest 决定是否增加 ToolTip,如果需要则返回非零。 在本例中 ToolTip 使用了 LPSTR_TEXTCALLBACK,而没有立即设定显示字符串。 在本例只在鼠标指向每项的图片时才显示 ToolTip int CTreeCtrlX::OnToolHitTest(CPoint point, TOOLINFO * pTI) const { RECT rect; UINT nFlags; HTREEITEM hitem = HitTest( point, &nFlags ); if( nFlags & TVHT_ONITEMICON ) { CImageList *pImg = GetImageList( TVSIL_NORMAL ); IMAGEINFO imageinfo; pImg->GetImageInfo( 0, &imageinfo ); GetItemRect( hitem, &rect, TRUE ); rect.right = rect.left - 2; rect.left -= (imageinfo.rcImage.right + 2); pTI->hwnd = m_hWnd; pTI->uId = (UINT)hitem; pTI->lpszText = LPSTR_TEXTCALLBACK; pTI->rect = rect; return pTI->uId; } else if( nFlags & TVHT_ONITEMSTATEICON ) { CImageList *pImg = GetImageList( TVSIL_NORMAL ); IMAGEINFO imageinfo; pImg->GetImageInfo( 0, &imageinfo ); GetItemRect( hitem, &rect, TRUE ); rect.right = rect.left - (imageinfo.rcImage.right + 2); pImg = GetImageList( TVSIL_STATE ); rect.left = rect.right - imageinfo.rcImage.right ; pTI->hwnd = m_hWnd; pTI->uId = (UINT)hitem; pTI->lpszText = LPSTR_TEXTCALLBACK; pTI->rect = rect; // return value should be different from that used for item icon return pTI->uId*2; } return -1; } Step 3: ?? TTN_NEEDTEXT 由于在增加 ToolTip 是使用用了 LPSTR_TEXTCALLBACK,因此 ToolTip 在显示时会发送该消息来得到显示字符串。 BEGIN_MESSAGE_MAP(CTreeCtrlX, CTreeCtrl) //{{AFX_MSG_MAP(CTreeCtrlX) //}}AFX_MSG_MAP ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText) END_MESSAGE_MAP() protected: //{{AFX_MSG(CTreeCtrlX) //}}AFX_MSG afx_msg BOOL OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult ); DECLARE_MESSAGE_MAP() BOOL CTreeCtrlX::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult ) { // need to handle both ANSI and UNICODE versions of the message TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR; TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR; CString strTipText; UINT nID = pNMHDR->idFrom; // Do not process the message from built in tooltip if( nID == (UINT)m_hWnd && (( pNMHDR->code == TTN_NEEDTEXTA && pTTTA->uFlags & TTF_IDISHWND ) || ( pNMHDR->code == TTN_NEEDTEXTW && pTTTW->uFlags & TTF_IDISHWND ) ) ) return FALSE; // Get the mouse position const MSG* pMessage; CPoint pt; pMessage = GetCurrentMessage(); ASSERT ( pMessage ); pt = pMessage->pt; ScreenToClient( &pt ); UINT nFlags; HTREEITEM hitem = HitTest( pt, &nFlags ); if( nFlags & TVHT_ONITEMICON ) { int nImage, nSelImage; GetItemImage( (HTREEITEM ) nID, nImage, nSelImage ); strTipText.Format( "Image : %d", nImage ); } else { strTipText.Format( "State : %d", GetItemState( (HTREEITEM ) nID, TVIS_STATEIMAGEMASK ) ); } #ifndef _UNICODE if (pNMHDR->code == TTN_NEEDTEXTA) lstrcpyn(pTTTA->szText, strTipText, 80); else _mbstowcsz(pTTTW->szText, strTipText, 80); #else if (pNMHDR->code == TTN_NEEDTEXTA) _wcstombsz(pTTTA->szText, strTipText, 80); else lstrcpyn(pTTTW->szText, strTipText, 80); #endif *pResult = 0; return TRUE; // message was handled } 在 MFC 加入"这是什么?"的帮助提示 MFC 在 CPropertySheet 中封装了属性,但不支持标题的"这是什么?"帮助提示.函数 CPropertySheet::OnNcCreate()屏蔽了扩展风 格 WS_EX_CONTEXTHELP, 因此,即使你在构造函数中加入了扩展风格,它也不能出现在窗口中. 解决方法很简单,在继承类中设置好风格位,如下所示: BOOL CWhatsThisPropertySheet::OnNcCreate( LPCREATESTRUCT lpCreateStruct) ( if(!CPropertySheet::OnNcCreate(lpCreateStruct)) return FALSE; //显式地定义此风格 //CPropertySheet 默认是关 ModifyStyleEx(0, WS_EX_CONTEXTHELP); return true; ) 精通工具条 VC++的工具条有很多特性,但有时候也会让你感到困惑. 这里有一些使它们服服贴贴的小技巧. 要移走一个工具条项,只须将它拖到空工具条的右边,然后点击右上角的关闭按钮. 注意显示在浮动工具条菜单条上的工具条的名称,可以通过右击菜单条来关闭 一个工具条,使之挂起. 反过来,激活一个挂起的工具条,右击你菜单条或另一个工具条,然后选中 你想看到的工具条的名字. 如果你想同时开关好几个工具条,不用一个一个地去右击,使用菜单上的工具, 用户化菜单命令,会出现工具条制表顺序对话框, 然后进行选择. 这个对话框也允许挂起干扰你的工具条,或者增大看不见工具条按钮的图标. 你可以在调试时使用和编辑代码时不同的工具条布局,而二者不互相干扰. 当你发现浮动工具条停在不期望的位置时,按住 Ctrl 键,然后用鼠标将它移到旁边去, 当你停下来的时候,它不再回去,即使你 把它放在另一个工具条的上面. 如何改变视窗的背景颜色 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 reClip ; pDC—>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; } 为 MFC 应用程序添加全屏幕显示功能 在 CMainFrame 类中添加下列成员变量和成员函数(使用 ClassWizard),下面是这些变量和函数的功能说明: 成员变量: BOOL m_bFullScreen; //全屏幕显示标志 CRect m_FullScreenWindowRect; //全屏幕显示窗口 Rect WINDOWPLACEMENT m_wpPrev; //用于保存正常视图时的窗口位置信息 CToolBar * m_wndFullScreenBar; //全屏幕显示时的浮动工具条 成员函数: void OnMenuFullscreen(); //全屏幕显示的处理函数 void OnGetMinMaxInfo(); //捕获 WM_GETMINMAXINFO 消息以便允许你增加窗口大小 void OnUpdateViewFullScreen(); //更新“全屏幕显示”菜单的状态 源码 void CMainFrame::OnMenuFullscreen() {//全屏幕显示的处理函数 RECT rectDesktop; WINDOWPLACEMENT wpNew; if (m_bFullScreen) {//全屏幕显示模式 //隐藏工具条和状态条 m_wndStatusBar.ShowWindow(SW_HIDE); m_wndToolBar.ShowWindow(SW_HIDE); //保存正常视图时的窗口位置信息以便恢复原来状态 GetWindowPlacement (&m_wpPrev); m_wpPrev.length = sizeof m_wpPrev; //调整 RECT 为新的窗口尺寸 ::GetWindowRect ( ::GetDesktopWindow(), &rectDesktop ); ::AdjustWindowRectEx(&rectDesktop, GetStyle(), TRUE, GetExStyle()); //保存 RECT 以便 OnGetMinMaxInfo()使用 m_FullScreenWindowRect = rectDesktop; wpNew = m_wpPrev; wpNew.showCmd = SW_SHOWNORMAL; wpNew.rcNormalPosition = rectDesktop; //生成新的工具条 m_wndFullScreenBar=new CToolBar; if(!m_wndFullScreenBar->Create(this, CBRS_SIZE_DYNAMIC|CBRS_FLOATING) || !m_wndFullScreenBar->LoadToolBar(IDR_FULLSCREEN)) { TRACE0("Failed to create toolbar\n"); return; // fail to create } //不允许工具条停泊 m_wndFullScreenBar->EnableDocking(FALSE); m_wndFullScreenBar->SetWindowPos(0,100,100,0,0,SWP_NOSIZE |SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW); m_wndFullScreenBar->SetWindowText(_T("全屏幕显示")); FloatControlBar(m_wndFullScreenBar, CPoint(100,100)); m_bFullScreen=TRUE; } else {//正常显示模式 //删除全屏幕工具条 m_wndFullScreenBar->DestroyWindow(); delete m_wndFullScreenBar; m_bFullScreen=FALSE; //恢复工具条和状态条 m_wndStatusBar.ShowWindow(SW_SHOWNORMAL); m_wndToolBar.ShowWindow(SW_SHOWNORMAL); wpNew = m_wpPrev; } //设置窗口显示状态 SetWindowPlacement ( &wpNew ); } void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) { if (m_bFullScreen) { lpMMI->ptMaxSize.y = m_FullScreenWindowRect.Height(); lpMMI->ptMaxTrackSize.y = lpMMI->ptMaxSize.y; lpMMI->ptMaxSize.x = m_FullScreenWindowRect.Width(); lpMMI->ptMaxTrackSize.x = lpMMI->ptMaxSize.x; } } void CMainFrame::OnUpdateMenuFullscreen(CCmdUI* pCmdUI) {//更新菜单的状态 pCmdUI->Enable(); pCmdUI->SetCheck(m_bFullScreen); } VC 常用数据类型使用转换详解 我们先定义一些常见类型变量借以说明 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 位 后记:本文匆匆写成,错误之处在所难免,欢迎来信指正. Email:appleII@sohu.com 用 Visual C++操作 INI 文件 一.将信息写入.INI 文件中. 1.所用的 WINAPI 函数原型为: BOOL WritePrivateProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTSTR lpFileName ); 其中各参数的意义: LPCTSTR lpAppName 是 INI 文件中的一个字段名. LPCTSTR lpKeyName 是 lpAppName 下的一个键名,通俗讲就是变量名. LPCTSTR lpString 是键值,也就是变量的值,不过必须为 LPCTSTR 型或 CString 型的. LPCTSTR lpFileName 是完整的 INI 文件名. 2.具体使用方法:设现有一名学生,需把他的姓名和年龄写入 c:\stud\student.ini 文件中. CString strName,strTemp; int nAge; strName="张三"; nAge=12; ::WritePrivateProfileString("StudentInfo","Name",strName,"c:\\stud\\student.ini"); 此时 c:\stud\student.ini 文件中的内容如下: [StudentInfo] Name=张三 3.要将学生的年龄保存下来,只需将整型的值变为字符型即可: strTemp.Format("%d",nAge); ::WritePrivateProfileString("StudentInfo","Age",strTemp,"c:\\stud\\student.ini"); 二.将信息从 INI 文件中读入程序中的变量. 1.所用的 WINAPI 函数原型为: DWORD GetPrivateProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName ); 其中各参数的意义: 前二个参数与 WritePrivateProfileString 中的意义一样. lpDefault : 如果 INI 文件中没有前两个参数指定的字段名或键名,则将此值赋给变量. lpReturnedString : 接收 INI 文件中的值的 CString 对象,即目的缓存器. nSize : 目的缓存器的大小. lpFileName : 是完整的 INI 文件名. 2.具体使用方法:现要将上一步中写入的学生的信息读入程序中. CString strStudName; int nStudAge; GetPrivateProfileString("StudentInfo","Name"," 默认姓名 ",strStudName.GetBuffer(MAX_PATH),MAX_PATH,"c:\\stud\\student.ini"); 执行后 strStudName 的值为:"张三",若前两个参数有误,其值为:"默认姓名". 3.读入整型值要用另一个 WINAPI 函数: UINT GetPrivateProfileInt( LPCTSTR lpAppName, LPCTSTR lpKeyName, INT nDefault, LPCTSTR lpFileName ); 这里的参数意义与上相同.使用方法如下: nStudAge=GetPrivateProfileInt("StudentInfo","Age",10,"c:\\stud\\student.ini"); 三.循环写入多个值,设现有一程序,要将最近使用的几个文件名保存下来,具体程序如下: 1.写入: CString strTemp,strTempA; int i; int nCount=6; file://共有 6 个文件名需要保存 for(i=0;iFillRect(rect,&m_brushBackground); ///用背景画刷填充区域 为了避免背景的闪烁,使显示更加完美,我们添加 WM_ERASEBKGND 消息的处理函数,并取消调用父类的处理函数,代 码如下: BOOL CTestView::OnEraseBkgnd(CDC* pDC) { return TRUE; } 更新窗体方法 1、 UpdateWindow(); 2、 Invalidate(true); 3、 UpdateData(false) 更改窗口控件的能动和不能动(以按钮控件为例) CButton *pButton; pButton=(CButton*)GetDlgItem(IDCANCEL); pButton->EnableWindow(FALSE); //不能 (pButton->EnableWindow(TRUE);) //能 窗口响应键盘事件 BOOL CTestcursorDlg::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class if(pMsg -> message == WM_KEYDOWN) { //根据按下的键值来获得事件 if (pMsg->wParam==38) MessageBox("p"); //下面的代码获得每次按下按键的键值 CString strwParam; strwParam.Format("%d ",pMsg->wParam); CDC* pDC = GetDC(); pDC->TextOut(10,10,strwParam); ReleaseDC(pDC); } return CDialog::PreTranslateMessage(pMsg); } 我们首先想到的是响应 WM_KEYDOWN 消息,但实际运行却发现没有任何效果。 原因是对话框里的控件需要首先对按键作出响应,比如多行编辑框必须首先 处理回车,不至于回车使对话框关闭。 我们要想在第一时间对对话框的按键做出响应,需要重载 PreTranslateMessage, 以下的代码实现了在对话框中显示虚拟键值(virtual-key code) BOOL CTestDlg::PreTranslateMessage(MSG* pMsg) { if(pMsg->message == WM_KEYDOWN) { ///或者直接调用 OnKeyDown CString strwParam; strwParam.Format("%d ",pMsg->wParam); CDC* pDC = GetDC(); pDC->TextOut(10,10,strwParam); ReleaseDC(pDC); } return CDialog::PreTranslateMessage(pMsg); } 此方法也适用于 FORMVIEW 或其它控件中对键盘按键的响应,以下的代码来自 MSDN, 实现了当按下上下左右方向键时调用 OnKeyDown,我们可以在 OnKeyDown 中作相应处理。 BOOL CSampleControl::PreTranslateMessage(LPMSG lpmsg) { BOOL bHandleNow = FALSE; switch (lpmsg->message) { case WM_KEYDOWN: switch (lpmsg->wParam) { case VK_UP: case VK_DOWN: case VK_LEFT: case VK_RIGHT: bHandleNow = TRUE; break; } if (bHandleNow) OnKeyDown(lpmsg->wParam, LOWORD(lpmsg ->lParam), HIWORD(lpmsg->lParam)); break; } return bHandleNow; } 密码框输入受保护 创建新 CEdit 类 从 CEdit 继承一个子类 CPasswordEdit, 申明全局变量 g_bAuthorIdentity 表明消息发送者的身份: BOOL g_bAuthorIdentity; 然后响应 CWnd 的虚函数 DefWindowProc,在这个回调函数中进行身份验证: LRESULT CPasswordEdit::DefWindowProc(UINT message,WPARAM wParam, LPARAM lParam) { // 对 Edit 的内容获取必须通过以下两个消息之一 if(( message == WM_GETTEXT) ||( message == EM_GETLINE)) { // 检查是否为合法 if( !g_bAuthorIdentity) { // 非法获取,显示信息 AfxMessageBox(_T("我的密码,可不能让你看哦!")); return 0; } // 合法获取 g_bAuthorIdentity = FALSE; } return CEdit::DefWindowProc(message, wParam, lParam); } 2) 在数据输入对话框中做处理 在对话框中申明一个类成员 m_edtPassword: CPasswordEdit m_edtPassword; 然后在对话框的 OnInitDialog()中加入下列代码: m_edtPassword.SubclassDlgItem(IDC_EDIT_PASSWORD, this); 其目的是将控制与新类做关联。 之后在对话框的数据交换中将身份设为合法: void CDlgInput::DoDataExchange(CDataExchange* pDX) { // 如果获取数据 if( pDX- >m_bSaveAndValidate) { g_bAuthorIdentity = TRUE; } CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDlgInput) DDX_Text(pDX, IDC_EDIT_PASSWORD, m_sPassword); //}}AFX_DATA_MAP } 最高窗口的实现 最高窗口就是总浮动在其他窗口上的,不会被一般窗口遮住的窗口,最高窗口技术在编程中有着很广泛 的应用。VC++中对基于 SDI、MDI 的运用程序,要实现最高窗口,只要在框架窗口类 CMainFrame 中的 PreCreateWindow()函数中加入“cs.dwExStyle =WS_EX_TOPMOST;”即可。关于函数 PreCreateWindow()及结 构 CREATESTRUCT 的详细信息可参见 VC++的联机文档。 而对基于对话框的运用程序,如何实现最高窗口却很少论及,以下便是一种实现方法。 重载要实观最高窗口的对话框的 OnInitDialog()函数,方法是进入 ClassWizard,在 Object ID 列表框中选择 该对话框的 ID,在 Message 列表框中选择 WM_INITDIALOGG,单击 Add Function 按钮后,即对 onlnitDialog 函数进行了重载。再按下 Edit code 按钮,加入以下语句: const CWnd * pWndInsertAfter; pWndInsertAfter = &wndTopMost; SetWindowPos(pWndInsertAfter,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE); 函数 SetWindowPos 原型为 BOOL SetWindowPos(const CWnd * pWndInsertAfter,int x,int y,int cx,int cy,UINT nFlags); pWndInsertAfter 为指向标识窗口类型的 CWnd 对象的指针。 x,y 为窗口左上角的坐标。 cx,cy 为窗口的宽与高。 nFlags 确定窗口的大小及位置。当为 SWP_NOSIZE 时,忽略 cx,cy。当为 SWP_NOMOVE 时,忽略 x,y。 实现窗口动态写入汉字和改变汉字颜色形状 在窗口当中建立变量 HICON m_hIcon; 然后在窗口中添加 ON_PAINT,改为如下代码/ if (IsIconic()) { CPaintDC dc(this); SendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0); int cxIcon=GetSystemMetrics(SM_CXICON); int cyIcon=GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x=(rect.Width()-cxIcon+1)/2; int y=(rect.Height()-cyIcon+1)/2; dc.DrawIcon(x,y,m_hIcon); } else { CPaintDC dc(this); CString string; string=_T("创智数码流媒体计费软件 V1.0"); CFont m_fontLogo; //创建字体 m_fontLogo.CreateFont(20,0,0,0,FW_BOLD|FW_BLACK|FW_HEAVY,TRUE,TRUE,0,1,1,1,1,1,"Arial") dc.SetBkMode(TRANSPARENT); CRect rectText; GetClientRect(&rectText);//字体在窗口的位置 rectText.left = 0; rectText.top = 0; rectText.right =280; rectText.bottom = 20; CFont *OldFont=dc.SelectObject(&m_fontLogo); COLORREF OldColor=dc.SetTextColor(::GetSysColor(COLOR_INFOBK));// (金 色);//COLOR_3DHILIGHT)); //COLORREF OldColor=dc.SetTextColor(::GetSysColor(COLOR_INACTIVECAPTION));//(黑雕刻) //dc.DrawText(string,rectText+CPoint(1,1),DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_CENTER); dc.DrawText(string,rectText+CPoint(1,1),DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_CENTER); dc.SetTextColor(::GetSysColor(COLOR_MENUTEXT));//COLOR_3DSHADOW)); dc.DrawText(string,rectText,DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_CENTER); dc.SetTextColor(OldColor); dc.SelectObject(OldFont); }
还剩122页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享pdf获得金币 ] 2 人已下载

下载pdf

pdf贡献者

ch1990

贡献于2013-06-17

下载需要 8 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf