VC/MFC FAQ整理

Q 如何处理ComboBox中的回车键?避免退出程序? A 在一般的EDIT中采用的方法是处理PretranlateMessage(),执行代码 CWnd *pWnd = GetFocus(); if(pWnd != NULL) { if(pWnd == GetDlgItem(IDC_EDIT1) { …//IDC_EDIT1具有焦点 } }

但在ComboBox中好象不同,是ComboBox的编辑控件得到了焦点,所以判断代码: BOOL CDlg::PreTranslateMessage(MSG pMsg) { if(pMsg->message==WM_KEYDOWN && pMsg->wParam == VK_RETURN) { CWnd pWnd = GetFocus(); if(pWnd != NULL) { if(pWnd->GetParent() == GetDlgItem(IDC_COMBO1)//更改ID { return TRUE; } } } return CDialog::PreTranslateMessage(pMsg); }

//————————————————- Q 动态创建的组合框如何设置下拉列表框的高度? A m_combo.Create(WS_CHILD | WS_VISIBLE | WS_VSCROLL CBC_SORT | CBC_DROPDOWNLIST | WS_TABSTOP, CRect(320,10,580,280),this,114); //CRect的最后一个参数(这里是280)就表示下拉大小

//————————————————- Q 是否能不选择下拉列表样式而禁止用户输入值,有什么方法可以实现? A 将下拉列表的编辑控件设置为只读的,方法如下: CComboBox pcombo; CWnd pWnd = pcombo->GetWindow(GW_CHILD); while(pWnd) { char classname[256]; ::GetClassName(pWnd->m_hWnd,classname,256) if(strcmp(classname,”edit”) == 0) { CEdit *pEdit; pEdit = new CEdit(); pEdit->SubClassWindow(pWnd->m_hWnd); pEdit->SetReadOnly(); pWnd = pWnd->GetNextWindow(); delete pEdit; } if(pWnd) pWnd = pWnd->GetNextWindow(); }

//————————————————- Q ComboBox的自定义弹出菜单,想在右击组合框的编辑部分的时候弹出菜单? A 一种方法就是在CCustomCombo的OnCtlColor函数里进行,生成ComboBox中编辑框的子类,示例: HBRUSH CCustomCombo::OnCtlColor(CDC pDC,CWnd pWnd,UINT nCtlColor) { if(nCtlColor == CTLCOLOR_EDIT) { if(m_edit.GetSafeHwnd()==NULL) m_eidt.SubClassWindow(pWnd->GetSafeHwnd()); } HBRUSH hbr = CComboBox::OnCtlColor(pDC,pWnd,nCtlColor); return hbr; } //其中m_edit是CEdit类的实现,它在WM_RBUTTONUP上显示右键菜单

//————————————————- Q 如何给按钮加位图 A 对动态创建的按钮: CButton button; button.Create(_T(“My Button”),WS_CHILD | WS_VISIBLE | BS_BITMAP,CRect(10,10,60,50),pParentWnd,1); button.SetBitmap(::LoadBitmap(NULL,MAKEINTRESOURCE(IBM_CHECK))); 或者修改风格: UINT Style = Button.GetButtonStyle(); Style = Style | BS_BITMAP; Button.SetBitmap(::LoadBitmap(NULL,MAKEINTRESOURCE(IBM_CHECK)));

//————————————————- Q 如何在CButton派生类中以及父对话框中捕获BN_CLICKED消息? A 于WM_NOTIFY消息相反,通知消息BN_CLICKED作为WM_COMMAND消息发送。因此应用程序应该使用ON_CONTROL_REFLECT_EC而不是ON_NOTIFY_REFLECT

//————————————————- Q 如何判断某个对象是否具有当前焦点? A return (CWnd::GetFocus() == pWnd);

//————————————————- Q 如何设置编辑控件的数字限制属性? A long Style = GetWindowLong(m_EditCtrl.m_hWnd,GWL_STYLE); Style |= ES_NUMBER; SetWindowLong(m_EditCtrl.m_hWnd,GWL_STYLE,Style);

//————————————————- Q 希望在LISTCTRL中显示文件,如何才能得到explorer使用的相同图象? A 可以将系统的ImageList加到LISTCTRL上,然后用具有SHGFI_ICON标志的SHGetFileInfo获取适当的图标索引: //图象列表设置 HIMAGELIST himagelist; SHFILEINFO fi; CImageList m_smalllist; //得到系统小图标列表的句柄 himagelist = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T(“C:\“),0,&fi;,sizeof(SHFILEINFO),SHGFI_SYSICONINDEX | SHGFI_SMALLICON); //添加到小图象列表 m_smalllist.Attach(himagelist); //设置LISTCTRL的图象列表 m_listCtrl.SetImageList(&m;_smalllist,LVSIL_SMALL); //分离图象列表 m_smalllist.Detach();

//————————————————- Q 如何在列表的任何一列显示图标,而不是第一列? A LV_ITEM item; … item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM; item.iItem = …//设置行号 item.lParam = …//如何需要就设置lparam参数 item.iSubItem = …//设置列号,从0开始的 item.stateMask = LVIS_STATEIMAGEMASK; item.state = INDEXTOSTATEIMAGEMASK(…);//参数为图标号 item.iImage = …//设置图标号 item.pszText = …//显示文本 //插入新项 m_listctrl.InsertItem(&item;); //现在设置图标 m_listctrl.SetItemText(0,4,szField);

//————————————————- Q 给LISTBOX添加新项时如何实现自动下滚? A 在调用AddString后,添加如下代码: m_listbox.SetTopIndex(m_listbox.GetCount()-1);

//————————————————- Q listBox的文本超过框的宽度时,如何让水平滚动条正常工作? A 用下面的代码,设置滚动条的宽度为最长的字符串宽度 void SetHorizontalExtent(CListBox &listbox;) { int index = listbox.GetCount(); if(index == LB_ERROR) return; int nExtent = 0; if(index) { CDC pDC = listbox.GetDC(); CFont poldfont = pDC->SelectObject(listbox.GetFont()); CString s; SIZE text; LONG maxtxt = 0; whilw(index–) { listbox.GetText(index,s); text = pDC->GetOutputTextExtent(s); if(text.cx > maxtxt) maxtxt = text.cx; } text.cx = maxtxt; pDC->LPToDP(&text;); nExtent = text.cx+2; pDC->SelectObject(poldfont); listbox.ReleaseDC(pDC); } listbox.SetHorizontalExtent(nExtent); }

//————————————————- Q 在拆分视图的时候,创建了四个视图(2行2列),右下的是CFormView,其他的都是CView,在CMainFrame的OnCreateCilent不管怎么指定CRect的大小,下方的两个视图都占了整个窗口,需要拖动! A 一般只需要在OnCreateClient的末尾添加: m_wndSpitter.SetRowInfo(0,200,0);//添加此行代码

//————————————————- Q 如何指定拆分窗口的最小宽度? A 使用CSpitterWnd::SetColumnInfo() void SetColumnInfo(int col, //指定列 int deal, //理想宽度(像素) int cxmin); //最小宽度(像素) 在使用SetColumnInfo之后还应该调用RecalLayout();重新调整布局。

//————————————————– Q 如何判断工具栏是水平还是垂直的? A if((m_toolbar.GetBarStyle() & CBRS_ALIGN_LEFT) == CBRS_ALIGN_LEFT ||

(m_toolbar.GetBarStyle() & CBRS_ALIGN_RIGHT) == CBRS_ALIGN_RIGHT) AfxMessageBox(“vertical”); else AfxMessageBox(“horizontal”);

//————————————————– Q 编程方式修改工具栏按钮的可见性? A 示例代码: DWORD style = m_toolbar.GetButtonStyle(nIndex); if(m_bHide) m_toolbar.SetButtonStyle(nIndex,style & ~WS_VISIBLE); else m_toolbar.SetButtonStyle(nIndex,style | WS_VISIBLE); m_bHide = !m_bHide;

//————————————————– Q 如何在状态栏添加按钮并响应? A 创建一个从CButton派生的CMyButton类,在主框架类添加CMyButton类的成员变量,然后在OnCreate函数中创建按钮,并把它和状态栏关联起来: m_mybtn.Create(“MyButton”,WS_CHILD | VISIBLE,CRect(0,0,60,20),&m;_WndStatusBar,0); 通过处理BN_CLICKED消息,可以在CMyButton类中处理所有的点击事件

//————————————————– Q 如何隐藏属性CPropertySheet的标题栏,使用ModifyStyle(WINDOW_CAPTION,0)没有效果 A 创建自己的CPropertySheet派生类,并覆盖OnInitDialog,转到默认的情况后,使用ModifyStyle来删除WS_CAPTION标志

//————————————————– Q 如何让属性页有两行标签? A 从CPropertySheet派生类,添加PreCreateWindow的处理,在调用基类之前添加代码: cs.style |= TCS_MULTILINE;

//—————————————————— Q 如何在属性表的两个页之间传递数据? A CPropertyPage有一个成员函数QuerySiblings(WPARAM, LPARAM)。应用程序可以使用这个函数。 QuerySiblings生成一条PSM_QUERYSIBLINGS消息,它传递给所有的兄弟,也就是属性表上的其他属性页。 一般可创建一个所有页可见的枚举,如: enum{QUERY_MY_STRING, QUERY_SOMETHING_ELSE,…….} 然后,在一个属性页需要其他属性页中的信息时,使用代码: CString myString; if(lL == QuerySiblings(QUERY_MY_STRING,(LPARAM)&myString;)) { ….//获取字符串 } 提供字符串的页处理PSM_QUERYSIBLINGS消息: LRESULT CPageThatHasString::OnQuerySiblings(WPARAM wParam, LPARAM lParam) { if(QUERY_MY_STRING == wParam) { ((CString )lParam) = _T(“Test String“); return 1L; } else return 0L; }

//———————————————————- Q 如何让属性页具有两行标签? A 从CPropertySheet派生一个自己的类,添加一个PreCreateWindow的处理,然后在调用基类的处理前加如下代码:cs.style |= TCS_MULTILINE;

//———————————————————– Q 如何隐藏属性页的标题栏? A 从CPropertySheet派生一个自己的类,并覆盖OnInitDialog,在转到默认的情况以后,使用 ModifyStyle来删除标题栏标志WS_CAPTION。 ModifyStyle(WS_CAPTION,0);

//——————————————————————- Q 如何枚举桌面项目? A 1 得到指向IShellFolder接口的指针 2 得到指向IMalloc接口的指针 3 得到指向IEnumIDList接口的指针 4 提取枚举中下一项目的PIDL 5 测定PIDL代表的标志符的类型 6 处理该项目 7 释放PIDL分配的内存 8 重复4到7步,知道所有的项目都枚举完 9 释放IShellFolder IMalloc IEnumIDList接口的指针

LPSHELLFOLDER lpshellfolder; LPMALLOC lpmalloc; LPENUMIDLIST lpidlist; m_namecount = 0; HRESULT hr = SHGetDestopFolder(&lpshellfolder;); if(hr == NOERROR) { hr = ::SHGetMalloc(&lpmalloc;); if(hr == NOERROR) { hr = lpshellfolder->EnumObject(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS,&lpidlist;); if(hr == NOERROR) ProcessFolder(lpshellfolder,lpmalloc,lpidlist);//custom deal function lpmalloc->Release(); lpidlist->Release(); InValidate(); } lpshellfolder->Release(); }

void *::ProcessFolder(LPSHELLFOLDER lpshellfolder,LPMALLOC lpmalloc,LPENUMIDLIST lpidlist) { STRRET strret; ULONG numfetch; LPITEMIDLIST lpitemlist; HRESULT hr = lpidlist->Next(1,&lpitemlist;,&numfetch;); while(hr == NOERROR) { ULONG attributes = SFGAO_FOLDER; lpshellfolder->GetAttributes(1,(const struct _ITEMIDLIST )&lpitemlist;,&attributes;); if(attributes & SFGAO_FOLDER) { hr = lpshellfolder->GetDiaplayNameOf(lpitemlist,SHGDN_NORMAL,&strret;); if(m_nameCount < 20) m_names[m_namecount++] = strret.str; } lpmalloc->Free(lpitemlist); hr = lpidlist->Next(1,&lpitemlist;,&numfetch;); } } //——————————————————————- Q 如何创建桌面快捷方式? A: 1 initialize com 2 create LShellLink Object 3 Use IShellLink interface to get the pointer about IPersistFile 4 Use IShellLink interface to initialize link 5 Use LPersistFile interface to save the link 6 Release all the com pointer 7 Com return to previous status

1 HRESULT hr = CoInitialize(NULL); if(hr == S_OK) { …//Continue }

2 IShellLink *pshelllink; pshelllink = CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(void **)&pshelllink;);

3 IPersistFile *persistfile; persistfile = pshelllink->QueryInterface(IID_IPersistFile,(void **)&persistfile;);

4 pshelllink->SetPath(“C:\config.sys”); pshelllink->SetDescription(“ShortCut to config.sys”);

5 char path[MAX_PATH]; GetWindowsDirectory(path,MAX_PATH); int len = strlen(path); strcpy(&path;[len],”\desktop\config.lik”); //change the char from ANSI to UNICODE OLECHAR widepath[MAX_PATH]; MultiByteToWideChar(CP_ACP,0,path,-1,widepath,MAX_PATH); persistfile->Save(widepath,TRUE);

6 pshelllink->Release(); psersistfile->Release();

7 CoUnInitialize();

支持原创技术分享,据说打赏我的人,都找到了女朋友!