Windows MFC 类库使用技巧

来源:互联网 发布:淘宝学习网 编辑:程序博客网 时间:2024/06/05 15:44
转走了,如有版权不能转载,请告知,自当删除,谢谢博主
原文地址:MFC 类库使用技巧">Windows MFC 类库使用技巧作者:faithfish

修改记录---------

2015/4/20 List Box 列表框添加水平滚动条

2011/12/26  初版

修改记录---------

------------------------------------
一、基础概念与用法
二、控件使用
三、对话框操作
【五、常用对话框】
【六、消息处理】
六、常用消息处理
七、绘图
八、菜单
九、任务栏
十、快捷键
【使用小技巧】
【参考】
------------------------------------

一、基础概念与用法
1. 宏定义来确定消息映射
BEGIN_MESSAGE_MAP
ON_WM_SYSCOMMAND() //系统命令
……
END_MESSAGE_MAP

例如:
----------------头文件中开头----------------
// CMyDateTimeCtrl dialog

class CMyDateTimeCtrl : public CDateTimeCtrl
{
protected: 
 virtual void OnLButtonDown(UINT nFlags, CPointpoint);
 DECLARE_MESSAGE_MAP()
};
----------------头文件中结束----------------
----------------CPP文件开头----------------

BEGIN_MESSAGE_MAP(CMyDateTimeCtrl,  CDateTimeCtrl)
 ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

void CMyDateTimeCtrl::OnLButtonDown(UINT nFlags, CPointpoint)
{
 CDateTimeCtrl::OnLButtonDown(nFlags,point);
 return ;
}
----------------CPP文件结束----------------
参考
http://www.cppblog.com/momoxiao/archive/2009/10/22/99206.html
什么是MFC的消息映射机制
http://club.topsage.com/thread-2280593-1-1.html
MFC为何使用消息映射表而不用虚函数?

http://blog.csdn.net/zdl1016/article/details/4813193

2. 消息处理函数
CommandHandler 是消息映射中由 COMMAND_HANDLER 宏的第三个参数标识的函数的名称。
COMMAND_HANDLER( id, code, func )
Parameters
id
[in] The identifier of the menu item, control, oraccelerator.
code
[in] The notification code.
func
[in] The name of the message-handler function.


LRESULT CommandHandler(
   WORD wNotifyCode,
   WORD wID,
   HWND hWndCtl,
   BOOL& bHandled
);
参数
wNotifyCode
通知代码。
wID
菜单项、控件或快捷键的标识符。
hWndCtl
窗口控件的句柄。
bHandled
在调用 CommandHandler 之前,消息映射将 bHandled 设置为 TRUE。如果 CommandHandler不完全处理消息,它应将 bHandled 设置为 FALSE 以指示消息需要进一步处理。
返回值
消息处理的结果。如果成功,则为 0。


3. 点击最小化按钮处理
OnSysCommand函数处理
if (nID ==   SC_MINIMIZE)
{
    MessageBox("对话框最小化 ");
   CDialog::OnSysCommand(nID, lParam);
}

4. 弹出消息对话框
对话框类中调用 MessageBox( "对话框最小化 ");
其它类中调用::AfxGetMainWnd()->MessageBox((LPCTSTR)"您还未连接上服务器n");

5. 常用函数
1)CWinApp* AfxGetApp( );
Return Value
A pointer to the single CWinApp object for the application.
2)获取父窗口HWND句柄

 


7. CString和string的转化
stringstr="ksarea";
CStringcstr(str.c_str());//或者CString cstr(str.data());初始化时才行
cstr=str.c_str();或者cstr=str.data();
str=cstr.GetBuffer(0); //CString -> string
cstr.format("%s", str.c_str()); //string->CString
cstr.format("%s", str.data()); //string->CString
str = LPCSTR(cstr); //CString->string


8. Ctime的使用

CTime tm=CTime::GetCurrentTime();
CString str=tm.Format("%Y-%m-%d");

在VC中,我们可以借助CTime时间类,获取系统当前日期,具体使用方法如下:

CTime t = CTime::GetCurrentTime(); //获取系统日期
int d=t.GetDay(); //获得几号
 
int y=t.GetYear(); //获取年份
 
int m=t.GetMonth(); //获取当前月份
 
int h=t.GetHour(); //获取当前为几时
 
int mm=t.GetMinute(); //获取分钟
 
int s=t.GetSecond(); //获取秒
 
int w=t.GetDayOfWeek(); //获取星期几,注意1为星期天,7为星期六
http://blog.csdn.net/kw123/article/details/1815747


9. 重载函数
VC编辑器-》资源管理器双击类实现文件名(例如ListTreeViewDlg.cpp),然后在属性属性对话框中
就能看到重载按钮。

11. CWnd与HWND的区别与转换
HWND是句柄,CWnd是MFC窗体类,CWnd中包含HWND句柄成员对象是m_hWnd.
HWND是Windows系统中对所有窗口的一种标识,即窗口句柄。这是一个SDK概念。  
CWnd是MFC类库中所有窗口类的基类。微软在MFC中将所有窗口的通用操作都封装到了这个类中,
1)如何得到窗口对象指针CWnd * pCWnd
1,在窗体里,直接用 this->,//this就是本窗体的窗口对象指针
2,主窗体的类对象指针:AfxGetApp()->m_pMainWnd->, //AfxGetApp()->m_pMainWnd就是主窗体的窗口对象指针
3,pCWnd=GetDlgItem(ID_EDIT_NAME);//GetDlgItem函数可以得到某个控件的窗口对象指针
但好像无法获取WS_POPUP类型的窗口对象句柄,需要使用FindWindow
CWnd *cwnd = FindWindow(NULL, "Dialog");
2)如何得到窗口句柄 HWND Handle
1,Handle=this->m_hWnd
2,GetDlgItem(ID_EDIT_NAME);
3,Handle=::GetDlgItem(this,IDC_STATIC_MODE); //得到本窗体内某个控件的句柄
3)转换
CWnd * pCWnd;
HWND Handle;
pCWnd=FromHandle(Handle);
Handle=GetSafeHwnd(pCWnd);

 

 

 


二、控件使用

[X] 控件与变量的交互
UpdateData(TRUE)   ——刷新控件的值到对应的变量。(外部输入值交给内部变量)
即:控件的值—>变量。
UpdateData(FALSE)   —— 拷贝变量值到控件显示。(变量的最终运算结果值交给
外部输出显示)   即:变量值—>控件显示。

DDX_Control
DDX_Text

[X] 控件公共处理
1. 控件使能状态设置
::EnableWindow(::GetDlgItem(m_hWnd, IDC_COMBO_DATASVR_ADDR),TRUE);
IDC_COMBO_DATASVR_ADDR为控件ID

[X] 各个控件的使用
1. Edit Control / RichEdit Control

1)通过向导控件绑定变量。
GetWindowText方法获取控件中的内容。
例如:
CEdit m_ceUserName;
m_ceUserName.GetWindowText(clsCommData.csUserName);
RichEdit初始化: AfxInitRichEditEx();

2)判断控件是否为空
那就调用CString  strName;  
m_xingming.GetWindowText(strName);  
再判断strName.IsEmpty()为真还是为假。

3)设置一次最多能输入的文本字符数
void SetLimitText(UINT nMax);nMax是限制的个数。
richedit需要使用LimitText函数
LimitText(long nChars = 0)

4)设置可以多行显示
属性->Style->Multiline->True

5)设置控件属性
void SetOptions(WORD wOp, DWORD dwFlags );
MSDN查找关键词:CRichEditCtrl class
例如:richedit.SetOptions(ECOOP_XOR, ECO_AUTOVSCROLL); 设置垂直滚动

6)设置响应某个事件
DWORD SetEventMask( DWORD dwEventMask );
例如:RichEdit设置启用与响应超链接:
m_richEdit.SendMessage(EM_AUTOURLDETECT, TRUE, 0);
m_richEdit.SetEventMask(m_richEdit.GetEventMask() | ENM_LINK) ;

7)设置行间距
PARAFORMAT2 pf2
pf2.cbSize = sizeof(PARAFORMAT2);
pf2.dwMask = PFM_LINESPACING | PFM_SPACEAFTER;
pf2.dyLineSpacing = 200;
pf2.bLineSpacingRule = 4;
m_richedit.SetParaFormat(pf2);

8)是否一直显示滚动条
控件属性中 Diable No Scroll 设置为true的时候一直显示

2. Combo Box 组合窗口
int AddString( LPCTSTR lpszItem )添加行,
int DeleteString( UINT nIndex )删除指定行,
SetCurSel 设置当前选中行
GetCurSel() 获取当前选中行
编辑框是否只读,由控件的Type属性决定
DropDown可以更改,DorpList只读

3. List Box 列表框

1)添加数据:int AddString( LPCTSTRlpszItem ) ,
2)数据插入到指定位置:
int InsertString( int nIndex, LPCTSTRlpszItem )。
nIndex为-1时,插入到最后位置。
3)删除指定行:int DeleteString( UINT nIndex ) ,
4)获取数据: void GetText(int nIndex, CString& rString) const
得到/设置当前被选中的行:
5)获取、设置选中行
int GetCurSel( )/int SetCurSel(int iIndex)。没选中返回LB_ERR
6) void ResetContent( )可以删除列表框中所有行。

7) 获取行数
GetCount

8)设置行关联的数据
int SetItemData( int nIndex, DWORD_PTR dwItemData );

9)获取行关联的数据
DWORD GetItemData(int nItem ) const;

10)设置水平滚动条

首先设置设置Horizontial Scoll属性。然后添加并调用如下处理函数

注意:CretrieveDlg是空间所在对话框类名,替换为实际类名。

void CretrieveDlg::displayScroll(CListBox &listbox)

{

  

  CString str;

  CSize sz;

  int dx = 0;

  TEXTMETRIC tm;

  CDC* pDC = listbox.GetDC();

  CFont* pFont =listbox.GetFont();


  // Select the listbox font, save the oldfont

  CFont* pOldFont =pDC->SelectObject(pFont);

  //Get the text metrics for avg char width

  pDC->GetTextMetrics(&tm);


  for (int i=0;i

  {

   listbox.GetText(i,str);

    sz =pDC->GetTextExtent(str);


    //Add the avg width toprevent clipping

   sz.cx+=tm.tmAveCharWidth;


    if (sz.cx>dx)

    dx=sz.cx;

  }


  //Select the old font back into the DC

  pDC->SelectObject(pOldFont);

  listbox.ReleaseDC(pDC);

  // Set the horizontal extent so everycharacter of all strings 

  // can be scrolled to.

 listbox.SetHorizontalExtent(dx); 

}


4. Check List Box 控件
1)创建方法,继承于ListBox,可以用其所有方法,CCheckListBox的使用,和CListBox差不多
 (1)添加ListBox控件
 (2)CCheckListBox的rc设置:
 (3)Style->Owner draw->选中Fixed,选中HasStrings
 (4)添加成员变量, 通过类向导(ClassWizard)给添加成员变量CListBoxm_listbox;
   然后手动改为CCheckListBox m_listbox;
2) 添加一行数据 
 m_list5.AddString("Hello:World!");
3) 勾选checkbox复选框
m_clbUser.SetCheck(uItem, BST_CHECKED);
参考:
http://blog.163.com/zgkingdom@126/blog/static/22734732007912101520444/


5. Radio Box
1)设置选中状态:
CheckRadioButton(IDC_RADIO_SINGLE, IDC_RADIO_MULTIPLE,IDC_RADIO_MULTIPLE);

2)检查选中状态:
if ( BST_CHECKED == IsDlgButtonChecked( IDC_CHECK2 ))这就是判断某个单选框是否
被选上的 IDC_CHECK2是单选框的id

3)获取被选中的单选按钮:GetCheckedRadioButton
函数原型:int GetCheckedRadioButton( int nIDFirstButton, intnIDLastButton );
函数功能:在给定的一组单选框ID中获得当前被选中的单选按钮的ID   
返回值: 当有被选中的单选框时返回被选中的单选框的ID ,如果所给的组中都没被选中则返回0。
参数:   
nIDFirstButton 单选框组中第一个整形值的ID
nIDLastButton 单选框组中最后一个整形值ID


6. TreeCtrl Tree Control
树形控件可以用于树形的结构,其中有一个根接点(Root)然后下面有许多子结点,而每个子
结点上有允许有一个或多个或没有子结点。MFC中使用CTreeCtrl类来封装树形控件的各种操作。
在树形控件中每一个结点都有一个句柄(HTREEITEM)。

1)插入一个节点
HTREEITEM InsertItem( LPCTSTR lpszItem, HTREEITEM hParent =TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST );
参数:lpszItem为插入项的名称,hParent为插入项的父类节点句柄,
hInsertAfter为插入项的前一个项目的句柄。
返回值:InsertItem()返回一个插入项目的句柄。

2)结点关联图标

//创建图标
m_list.Create(16 ,16 , ILC_COLOR32 | TRUE, 0, 4);
CBitmap bm;
bm.LoadBitmap(IDB_BITMAP_TREELIST);
m_list.Add(&bm, RGB(255, 255, 255));//黑色底不透明显示
//关联图标
m_tree.SetImageList(&m_list,TVSIL_NORMAL);
//添加,选中时显示图标1,未选中时显示图标0
m_tree.InsertItem("Parent1",0,1);

3)删除一个节点
m_tree.DeleteItem(HTREEITEM hItem);
4)判断一个被点击(选中)的节点是否是父节点
 HTREEITEM hItem =m_tcShopList.GetSelectedItem();
 HTREEITEM hParent =m_tcShopList.GetParentItem(hItem);
 if(hParent == NULL) {

5)检测鼠标点击的位置是否是节点
 CPoint point;
 GetCursorPos(&point);
 CPoint pointInTree = point;
 m_tcShopList.ScreenToClient(&pointInTree);
 HTREEITEM hItem;
 UINT flag;// = TVHT_ONITEM;
 hItem =m_tcShopList.HitTest(pointInTree,&flag);
 if(hItem != NULL)


6)展开一个节点
m_tcShopList.Expand(iShopInfo->second.hShopItem,TVE_EXPAND);


<常用事件>
1)切换了选项TVN_SELCHANGED
ON_NOTIFY(TVN_SELCHANGED, ID_SHOPLIST_TREE , OnLDownShopList)
处理函数:
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
pNMTreeView->itemOld.hItem 旧项目句柄
pNMTreeView->itemNew.hItem 旧项目句柄

<参考资料>
http://baike.baidu.com/view/4504574.htm
http://wjlsunshine.blog.163.com/blog/static/40715830200731995353209/
7. List Ctrl CListCtrl
1) 关联类:CListCtrl
例:CListCtrl m_list;
2)设置风格
通过调用函数:
设置LVS_XXX开头的基本属性
SetWindowLong(m_lcGoods.m_hWnd, GWL_STYLE,dwStyle|LVS_REPORT);
设置扩展属性:
设置为Report样式时设置整行可以被选中:LVS_EX_FULLROWSELECT
设置每行显示check复选框:        LVS_EX_CHECKBOXES
设置Report样式时每个单元格显示边框:  LVS_EX_GRIDLINES
例:
m_list.SetExtendedStyle(LVS_EX_CHECKBOXES|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
通过修改rc资源属性修改部分属性:
外观 -> Single Selection -> Icon; Small Icon; List; Report报表样式可以插入列
3)设置是否可以选择多项:
rc资源属性: 外观 -> Single Selection -> false为可以选中多项目
4)获取行数
GetItemCount()
5)检查某行是否被选中
GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED
6)检查某行checkbox复选框是否被勾选,需要设置LVS_EX_CHECKBOXES样式
BOOL GetCheck(int nItem)
例如:
CString str;
  for(int i=0; i
  {
  if( m_listCtrl.GetItemState(i, LVIS_SELECTED) ==LVIS_SELECTED || m_listCtrl.GetCheck(i))
  {
  str.Format(_T("第%d行的checkbox为选中状态"), i);
  AfxMessageBox(str);
  }
  }

7)获取/遍历所有被选中项目
 POSITIONpos=m_lcGoods.GetFirstSelectedItemPosition();
 if (pos==NULL)
  AfxMessageBox("No items wereselected!n");
 else
 {
  while (pos)
  {
   intnItem=m_lcGoods.GetNextSelectedItem(pos);
   AfxMessageBox("Item%d was Selected!n",nItem);
   //you coulddo your own processing on nItem here
  }
 }
8)获取符合指定属性的项目
int GetNextItem(int nItem, int nFlags ) const;
例如,从第一个开始查找,被选中的项目
int nItem = m_list.GetNextItem (-1, LVNI_SELECTED);
9)修改列表框的某个属性值
BOOL SetItemState(int nItem, UINT nState, UINT nMask );
例如:m_list.SetItemState( nItem, LVIS_SELECTED, LVIS_SELECTED);
10)删除所有项目
DeleteAllItems()
11)插入标题列
 m_lcGoods.InsertColumn(0,"选中",LVCFMT_CENTER,40); 
 m_lcGoods.InsertColumn(1,"名称",LVCFMT_CENTER,300); 
 m_lcGoods.InsertColumn(2,"品牌",LVCFMT_CENTER,100);  
 m_lcGoods.InsertColumn(3,"店铺",LVCFMT_CENTER,100);

12)插入行数据(行和列从0开始算起)
  m_lcGoods.InsertItem(0,""); //插入行
  m_lcGoods.SetItemText(0,1,"商品1_1");//设置该行的第1列的显示字符
  m_lcGoods.SetItemText(0,2,"品牌1_3");//设置该行的第2列的显示字符
  m_lcGoods.SetItemText(0,3,"店铺1_3");//设置该行的第3列的显示字符
13)获取控件的属性
GetWindowLong

常用事件:
1)NM_CLICK 鼠标单击事件
OnNMClickXXX(NMHDR *pNMHDR, LRESULT *pResult)
NM_LISTVIEW*  pNMListView    (NM_LISTVIEW*)pNMHDR;
鼠标点击位置所在行:pNMListView-> iItem
鼠标点击位置所在列:pNMListView-> iSubItem


9. DateTime Ctrl CDateTimeCtrl
1)时间的初值为空
控件-》属性-》style-》Show None设置为true
CDateTimeCtrl *pWndTemp =(CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER1);
CMonthCalCtrl* pMoCalCtrl = pWndTemp->GetMonthCalCtrl();
COleDateTime oledate;
oledate.m_status = COleDateTime::null;
pWndTemp->SetTime(oledate);
2)检测是否选中时CDateTimeCtrl控件复选框
CDateTimeCtrl *pWndTemp =(CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER1);
CTime timeTime;
DWORD dwResult = pWndTemp->GetTime(timeTime);
if (dwResult == GDT_VALID) {
    //选中
} else {
    //未选中
}

 

10. tab control
1)设置默认的选项卡
 m_tab.SetCurSel(0);
2)获取当前选项卡
int CurSel = m_tab.GetCurSel();

<常用事件>
1) TCN_SELCHANGE消息
发生选项卡切换时触发。
触发CTabctrl 的TCN_SELCHANGE消息:
m_tabChatIndex.SetCurSel(itChatInfo->second.uChatDlg);
  NMHDR nmhdr;
  nmhdr.code =TCN_SELCHANGE; 
  nmhdr.hwndFrom =m_tabChatIndex.GetSafeHwnd(); 
  nmhdr.idFrom=m_tabChatIndex.GetDlgCtrlID(); 
  ::SendMessage(m_tabChatIndex.GetSafeHwnd(),WM_NOTIFY,MAKELONG(TCN_SELCHANGE,itChatInfo->second.uChatDlg),(LPARAM)(&nmhdr));


MSDN文档
http://msdn.microsoft.com/zh-cn/library/cc468272(v=VS.71).aspx
拓展控件
http://www.codeproject.com/KB/miscctrl/bcgdatetime.aspx
http://www.codeproject.com/KB/miscctrl/datetimeeditctrl.aspx

 

 

【三、对话框操作】
1. 创建对话框
1)模式对话框:
CCSvrToolDlg dlgChat;
dlgChat.DoModal();
模式对话框使用dlg.DoModal()函数,程序会在你按下OK或者Cancle按钮之前处于等待状态,
然后点击OK或者Cancle按钮,就可以调用EndDialog函数消除模式对话框。
2)非模式对话框:
非模式对话框可能要显得复杂,你要使用Create函数创建非模式对话框,并且在退出时,
必须调用CWnd::DestroyWindow函数销毁窗口,并且重载窗口的PostNcDestroy函数,里面
添加 delete this; 这句话。
而且要注意的是,你若想点击OK按钮使非模式对话框销毁,要重写OnOK和OnCancel函数,
使其调用CWnd::DestroyWindow,否则对话框只是隐藏了而已。
相关函数:
(1)移动到屏幕中间 CenterWindow()
(2)显示窗口ShowWindow(SW_SHOW) 隐藏窗口ShowWindow(SW_HIDE)
(3) 设置窗口总是在最上面显示
::SetWindowPos(this->m_hWnd, HWND_TOPMOST, 0, 0, 0, 0,SWP_NOSIZE|SWP_NOMOVE);


2. 子对话框
设置属性:Border为None,Style为Child
创建代码:
Tips:重载OnOK()消息函数,这样可以不让对话框退出
获取父对话框Cwnd句柄:GetParent()
获取父对话框HWND:GetParent()->GetSafeHwnd()

3. 多个对话框显示问题
要使用Create创建popup对话框,然后使父窗口无效,达到DoModle的效果
例如:
 CConfigSystemAddEdit *pDlg;
 pDlg = newCConfigSystemAddEdit(DLG_TYPE_AUTO_ADD,this->GetParent());
 pDlg->Create(IDD_DIALOG_CONFIG_SYSTEM_ADDEDIT);
 ::EnableWindow(this->GetParent()->GetSafeHwnd(), FALSE);
       pDlg->ShowWindow(SW_SHOW);

4. 获取窗口大小
GetWindowRect与GetClientRect
GetWindowRect:获取窗口(包括客户区与非客户区)相对于父窗口的坐标。(left,top,right,bottom)
GetClientRect:获取窗口(只是客户区域)的大小。(0,0,宽,高)
http://www.cppblog.com/aurain/archive/2009/03/10/76126.html

5.调整窗口大小
AdjustRect用法
void CDialogDlg::OnSize(UINT nType, int cx, int cy)
{
  CDialog::OnSize(nType, cx, cy);
 
  if(m_tabCtrl.m_hWnd == NULL)
   return;    //Return if window is not created yet.
 
  RECT lpRect;

  // Get size of dialog window.
  GetClientRect(&lpRect);

 
  // Adjust the rectangle to fit the tab controlinto the
  // dialog's client rectangle.
  m_tabCtrl.AdjustRect(FALSE, &lpRect);

  // Move the tab control to the new positionand size.
  m_tabCtrl.MoveWindow(&lpRect,TRUE); 
}

控件自动调整 随窗口大小改变控件
http://10305101ivy.blog.163.com/blog/static/58476589200910273657898/
http://wenku.baidu.com/view/05f1dc0d844769eae009ed21.html
http://www.cppblog.com/mzjs-long/archive/2011/09/21/156478.aspx


6. 添加的对话框如何增加OnInitDialog函数
http://apps.hi.baidu.com/share/detail/23066501
打开需要添加OnInitDialog()的对话框的头文件,在该文件的属性菜单上
有一个“重写”图标,单击该图标出现函数列表,列表里有OnInitDialog()函数。

7. 设置/改变父窗口
函数功能:该函数改变某个子窗口的父窗口。   
函数原型:HWND SetParent(HWND hWndChild,HWND hWndNewParent);   
参数:   hWndChild:子窗口句柄。   hWndNewParent:新的父窗口句柄。
如果该参数是NULL,则桌面窗口就成为新的父窗口。
返回值:如果函数成功,返回值为子窗口的原父窗口句柄;如果函数失败,
返回值为NULL。若想获得多错误信息,请调用GetLastError函数。

8. 检测窗口状态
是否显示还是隐藏 IsWindowVisiable
是否最小化      IsIconic()
是否处于活动状态  GetActiveWindow() !=AfxGetApp()->m_pMainWnd

9. 获取窗口的各种属性
LONGGetWindowLong(         HWND hWnd,int nIndex);
例如,获取controllist控件设置的扩展属性
DWORD dwStyle = GetWindowLong(m_list.m_hWnd, GWL_EXSTYLE);

【五、常用对话框】
1. 系统对话框-字体对话框 FontDialog
richedit与fontdialog结合
http://www.4ucode.com/Study/Topic/982017
FontDialog扩展
http://www.codeproject.com/KB/dialog/XMonoFontDialog.aspx
1)成员函数说明:
http://bk.chinaar.com/index.php?doc-view-77
http://blog.csdn.net/natepan/article/details/6668958
2)CHARFORMAT2结构说明
http://msdn.microsoft.com/en-us/library/windows/desktop/bb787883(v=vs.85).aspx
3)LogFont与CharFormat互相转换2
http://blog.csdn.net/carl2380/article/details/4356014
4)像素和磅转换
http://wenku.baidu.com/view/32632bd728ea81c758f578ef.html
5)有关pixel(像素)和twips(缇)的换算
http://hi.baidu.com/xtruggle/blog/item/3ceab557f9bcf34dd00906b0.html

2. 系统对话框-文件对话框
使用CFileDialog类
函数原型:
CFileDialog(BOOL  bOpenFileDialog,
LPCTSTR   lpszDefExt=NULL,
LPCTSTR  lpszFileName=NULL,
DWORD  dwFlags   OFN_HIDEREADONLY   OFN_OVERWRITEPR   OMPT,
LPCTSTR   lpszFilter=NULL,
CWnd    pParentWnd=NULL);

参数说明:
bOpenFileDialog:为TRUE或FALSE。TRUE为打开文件;FALSE为保存文件。
lpszDefExt          :为缺省的扩展名。
lpszFileName        :为显示在文件名组合框的编辑框的文件名,一般可选NULL
dwFlags             :为对话框风格,一般为OFN_HIDEREADONLY   OFN_OVERWRITEPROMPT,即隐藏只读选项和覆盖已有文件前提示。
LpszFilter          :为下拉列表枢中显示文件类型。
“|”前为显示的文字,“|”后为对应的扩展名,如果对应多个,用“;”分隔
pParentWnd          :一般可选NULL。
 
CFileDialog myDlg(TRUE, "bmp", NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"支持的图片文件|*.bmp;*.png",NULL);
INT_PTR nResponse = myDlg.DoModal();
if(nResponse == IDOK) {
   m_RECtlSendText.InsertBitmap(myDlg.GetFileName());
}

【六、消息处理】
1. 自定义消息添加
下面为发送用户自定义消息的方式:
1)
   //可以在头文件stdafx.h中定义用户消息
   //定义用户消息,不可与系统消息冲突,所以就这样定义
    #defineWM_MYMESSAGE WM_USER+100 //WM+USER表示用户消息,加100还是加其他值并没多大区别的

2)
   //在MainFrm.h中定义如下:
  //其中wParam接收SendMessage的第二个参数true,lParam接收第三个参数2
    LRESULTOnTestMessage(WPARAM wParam, LPARAM lParam);
3)

//在主程序框架MainFrm.cpp接收自定义的消息WM_MYMESSAGE

   BEGIN_MESSAGE_MAP()

   ON_MESSAGE(WM_MYMESSAGE, OnTestMessage)

   END_MESSAGE_MAP()

//在MainFrm.cpp中实现消息处理函数:

    LRESULTCMainFrame::OnTestMessage(WPARAM wParam, LPARAM lParam)

    {

       // 添加你想要的代码 //

       return 0L;

    }

2. 系统消息添加
   //下面为处理系统消息的方式

   //在MyDialog.h中定义消息

   afx_msg LRESULTOnMouseLeave(WPARAM, LPARAM);//响应鼠标离开事件

 

   //在MyDialog.cpp中接收消息

  BEGIN_MESSAGE_MAP(CMyDialog, CDialog)

   ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)

   END_MESSAGE_MAP()

 

   //响应鼠标离开事件
   LRESULTCMyDialog::OnMouseLeave( WPARAM, LPARAM )

   {
    CPoint   pt;

    //WINAPI函数:获得鼠标当前位置 
    GetCursorPos(&pt);

 

    CRect rect;

    //WINAPI函数:获得当前对话框(窗口)的大小
    GetWindowRect(&rect);

 

    //判断鼠标是否当前窗口上,FALSE为不在
    if(FALSE == PtInRect(&rect, pt))
    {
      AfxGetMainWnd()->SendMessage(WM_MYMESSAGE,true,2);
    }
    return 0;
    }

 


3. 触发消息
   //向主程序框架MainFrm发送消息
  //SendMessage第二第三参数可以为其他更多的类型,不局限于此
   AfxGetMainWnd()->SendMessage(WM_MYMESSAGE,true,2); 或者
   AfxGetMainWnd()->PostMessage(WM_MYMESSAGE,true,2);
PS:向其他类发送消息的实现方式是类似的,只是调用方式为:

      CMyDialog dlg;

      dlg.SendMessage();

      或者用类的指针也行,大同小异。

PostMessage 是异步的,SendMessage 是同步的。
PostMessage 只把消息放到队列,不管消息是不是被处理就返回,消息可能不被处理;
SendMessage等待消息被处理完了才返回,如果消息不被处理,发送消息的线程将一直处于

阻塞状态,等待消息的返回。

六、常用消息处理

1. OnTimer消息
cpp文件添加映射宏 ON_WM_TIMER()
cpp文件添加实现函数:OnTimer(UINT nIDEvent)
h文件添加声明:afx_msg void OnTimer(UINT nIDEvent);
触发timer函数:

2. ON_UPDATE_COMMAND_UI_RANGE

ON_UPDATE_COMMAND_UI_RANGE( id1, id2, memberFxn )

参数: id1 一个连续的命令ID范围的起始ID。
id2 一个连续的命令ID范围的结束ID。
memberFxn 命令被映射到的更新消息处理函数的名字。

头文件中手工添加afx_msg void OnUpdateMenu(CCmdUI *pCmdUI);
在cpp文件messgae map处添加ON_UPDATE_COMMAND_UI_RANGE( id1, id2,OnUpdateMenu),id1和id2是你的菜单项的起始和最终ID,在OnUpdateMenu(CCmdUI*pCmdUI)中通过判断pCmdUI的m_nID或m_nIndex来实现你自己的逻辑。

例:

void CDynMenuView::OnUpdateOptions(CCmdUI* pCmdUI)
{
 CMenu *pAddinMenu, *pTopMenu;
 pTopMenu = AfxGetMainWnd()->GetMenu();
 pAddinMenu = pTopMenu->GetSubMenu(1);

 switch (pCmdUI->m_nID)
 {
  case ID_EXPAND:
  pCmdUI->Enable(pAddinMenu->GetMenuItemCount() == 2);
   break;
  case ID_STANDARD:
  pCmdUI->Enable(pAddinMenu->GetMenuItemCount() != 2);
 }
}

参考资料
http://blog.sina.com.cn/s/blog_738537840100squ7.html
http://msdn.microsoft.com/zh-cn/library/fahezczh(v=VS.90).aspx

 


七、绘图
1. 从R(red),G(green),B(blue)三色得到COLORREF类型的颜色值
COLORREF  RGB(  BYTE  byRed,BYTE  byGreen,BYTE  byBlue   );
例如COLORREF  bkcolor    RGB(0x22,0x98,0x34);

从COLORREF类型的颜色值得到RGB三个颜色值
BYTE  Red   GetRValue(bkcolor);  ///得到红颜色
BYTE  Green   GetGValue(bkcolor);  ///得到绿颜色
BYTE  Blue   GetBValue(bkcolor);  ///得到兰颜色

2. 窗口重绘,刷新
InvalidateRect()或者调用Invalidate()
他会引起发送WM_DRAWITEM消息,引起对CWnd::OnDrawItem();的调用。

3. JPG,PNG格式图片加载与显示
使用CImage类,使用这个类首先要在stdafx.h中添加 #include 。

将bmp另存为jpg:
    CImageimage;
   image.Load(TEXT("e:\images\1.bmp")); //加载图片
   image.Save(TEXT("e:\images\1.jpg")); //另存为图片
显示jpg:
           CImage image;
           CRect zcRect;
           GetClientRect(&zcRect);
           image.Load(TEXT("e:\images\1.jpg"));
           SetStretchBltMode(GetDC()->m_hDC, COLORONCOLOR);//防止图片失真
           image.Draw(GetDC()->m_hDC,zcRect.left,zcRect.top,zcRect.Width(),zcRect.Height());//显示图片

<参考资料 CImage用法>
http://blog.sina.com.cn/s/blog_5a82024e0100c84g.html

八、菜单
1. 添加主菜单
 m_pMainMenu =new CMenu;

 m_pMainMenu->LoadMenu(MAKEINTRESOURCE(IDR_MENU_MAINDLG));

 this->SetMenu(m_pMainMenu);

2. 添加右键菜单
CPoint point;
GetCursorPos(&point);
CMenu menu;
menu.LoadMenu(IDR_MENU);
menu.GetSubMenu(1)->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x, point.y, this, NULL);
TPM_RIGHTBUTTON表示右键点击菜单项有效,TPM_LEFTALIGN表示弹出菜单出现在鼠标左面(左对齐)

3. 主菜单中动态添加菜单
CMenu menu2;
menu2.CreatePopupMenu();
menu2.AppendMenu(MF_STRING,IDM_APPEND_MENU_START_INDEX+1,"在线");
menu2.AppendMenu(MF_STRING,IDM_APPEND_MENU_START_INDEX+2,"离开");
menu2.AppendMenu(MF_STRING,IDM_APPEND_MENU_START_INDEX+3,"隐身");
m_pMainMenu->GetSubMenu(0)->AppendMenu(MF_POPUP,(UINT_PTR)menu2.m_hMenu, "店铺1");

4. 响应菜单命令时获取顶级菜单项句柄(HMENU)
响应处理WM_MENUSELECT消息,可将最后点击菜单的顶级菜单HMENU保存下来。
if((nFlags & MF_MOUSESELECT) &&  nFlags  !=   65535) {
 //TRACE("popup:%d,%d,%xn",nItemID,nFlags,hSysMenu);
 m_lCurSelHMenu = hSysMenu;
}

5. 菜单消息处理
ON_UPDATE_COMMAND   响应菜单命令
ON_UPDATE_COMMAND_UI 响应菜单界面的刷新
例如:
ON_UPDATE_COMMAND_UI_RANGE(ID_32778, ID_32780,OnUpdateShopStateMenu)
ON_COMMAND_RANGE(ID_32796, ID_32797, OnRecomdUserGoods)
afx_msg void OnUpdateShopStateMenu(CCmdUI* pCmdUI);
afx_msg void OnRecomdUserGoods(UINT nId);

6 右键弹出菜单无效
EnableMenuItem
九、任务栏
1. 任务栏上程序图标闪烁
this->FlashWindow(TRUE);

十、快捷键
方法一:

http://support.microsoft.com/?kbid=222829

 插入一个新的Accelerator到资源里,把加速键和对应的响应控件(如一个按钮)关联
  在对话框头文件中声明:
   HACCEL   m_hAccel;
  在对话框的构造函数里初始化m_hAccel
   m_hAccel   ::LoadAccelerators(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_ACCELERATOR1));
 然后重载对话框的PreTranslateMessage函数,在
BOOL  CAboutDlg::PreTranslateMessage(MSG*  pMsg)  
{
     if  (m_hAccelTable)  
     {
           if  (::TranslateAccelerator(m_hWnd,  m_hAccelTable,  pMsg))  
           {
                 return(TRUE);
           }
     }
     return  CDialog::PreTranslateMessage(pMsg);
}

方法二:
     声明热键消息处理函数原型        
  在.h中消息映射声明处(AFX_mSG字样之后)加入如下语句:        
  LRESULT    OnHotKey(WPARAM    wParam,LPARAM    lParam);        
2.    消息与相应处理函数相关联        
  在.Cpp中加入消息映射宏,使消息与相应处理函数发生关系,    
             ON_MESSAGE(WM_HOTKEY,OnHotKey);        
3.    为方便以后的操作  
       预先在类中创建一个响应WM_CREATE和WM_DESTROY消息的函数    
             OnCreate()与OnDestroy()的框架
4.向系统登记热键        
  在OnCreate()函数中加入如下代码以向系统登记热键,本例子的热键设为    
             Ctrl+Shift+A.        
  RegisterHotKey(m_hWnd,1001,MOD_CONTROL|MOD_SHIFT, 'A');        
  RegisterHotKey(m_hWnd,1002,MOD_CONTROL|MOD_SHIFT, 'a');        
  5.处理热键        
  在消息处理函数OnHotKey()中对热键进行处理,并可加入用户希望运行的程序代码    
  LRESULT  C****::OnHotKey(WPARAM    wParam,LPARAM    lParam)        
  if(wParam==1001||wParam==1002)        
  CWnd::SetForegroundWindow();//使得被激活窗口出现在前景        
  MessageBox( "Hello!");        
                //用户可在此添加代码        
  return    0;        
  6.程序运行完毕后解除热键        
  在OnDestroy()中通过UnRegisterHotKey()解除热键登记,释放系统资源.        
  UnRegisterHotKey(m_hWnd,1001);        
  UnRegisterHotKey(m_hWnd,1002);        
  7.编译并运行程序

【使用小技巧】
1. MFC对话框按回车后关闭
重载OnOK()函数
2. 系统API和MFC提供的API区别
获取HWND  要用系统API ::GetDlgItem
获取CWnd* 要用MFC提供的成员函数GetDlgItem
获取控件类实例句柄要用GetDlgItem,例如:
CEdit *petGoodsName =  (CEdit*)GetDlgItem(IDC_EDIT_GOODSNAME);
3. 不要在其它线程操作MFC的窗口类,会引起崩溃。
  MFC不支持其它线程访问。
4. 窗口类之间的转换
正确:CEdit *pEdit = (CEdit*)GetDlgItem(IDC_EDIT_VALID_MSG);
错误:CEdit *pEdit = (CEdit*)::GetDlgItem(m_hWnd,m_HWIDC_EDIT_VALID_MSG);

5. char*和CString之间互转

(1) char*转换成CString

  若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:

        char chArray[] = "Char  test";
        TCHAR * p = _T("Char test");( 或LPTSTR p = _T("Char test");)
        CString theString = chArray;
        theString.Format(_T("%s"), chArray);
        theString = p;

(2) CString转换成char*

若将CString类转换成char*(LPSTR)类型:
使用强制转换。例如:
   CString theString( (_T("Chartest "));
   LPTSTR lpsz=(LPTSTR)(LPCTSTR)theString;


【参考】
1. 不同进程间消息通信
http://blog.csdn.net/ybdesire/article/details/6248610
2. 按钮样式更改
http://www.codeproject.com/KB/buttons/cbuttonst.aspx
http://www.codeproject.com/KB/buttons/betterbmpbutton.aspx
3. RGB颜色表
http://www.114la.com/other/rgb.htm

4. MFC在线教程
http://tech.china.com/zh_cn/netschool/programme/c/656/20001207/vc01.html
P19 文档  P29 控件  P51 对话框

5. MFC常用方法
http://blog.sina.com.cn/s/blog_4b2208510100d81m.html
http://blog.sina.com.cn/s/blog_4b2208510100d81n.html
http://blog.sina.com.cn/s/blog_4b2208510100d81o.html

DDX_Control和DDX_Text
资源编辑框 控件选中
CFaceEdit 的使用
RichEdit有没有apend操作

0 0