首页 > 编程语言 > 详细

MFC实践小例子

时间:2021-06-16 22:19:49      阅读:60      评论:0      收藏:0      [点我收藏+]

  项目都是依托于VC驿站的SYC的小项目例子进行,有兴趣的可以:https://www.cctry.com/

一. 枚举窗口 EnumDialog

  1.枚举窗口: 

    • 方式1:  GetWindow
技术分享图片
 1     HWND hChildWnd = ::GetWindow(GetDesktopWindow()->GetSafeHwnd(), GW_CHILD);
 2     while (hChildWnd)
 3     {
 4         TCHAR acDlgTitle[MAX_PATH] = { 0 };
 5         if (0 < ::GetWindowText(hChildWnd, acDlgTitle, MAX_PATH))//获取窗口标题或文本
 6         {
 7             CString strRow, strPID;
 8             strRow.Format(_T("%d"), m_uiRow);
 9             strPID.Format(_T("%d"), ::GetWindowThreadProcessId(hChildWnd, NULL));//获取进程ID
10 
11             m_ListDlg.InsertItem(m_uiRow, strRow);//插入行
12             m_ListDlg.SetItemText(m_uiRow, 1, acDlgTitle);
13             m_ListDlg.SetItemText(m_uiRow++, 2, strPID);
14         }
15 
16         hChildWnd = ::GetWindow(hChildWnd, GW_HWNDNEXT);
17     }
View Code
    • 方式2:  EnumWindows, EnumChildWindows
技术分享图片
 1 EnumWindows(EnumWindowsPro, (LPARAM)this);//枚举当前所有窗口
 2 
 3 ... ...
 4 
 5     TCHAR acDlgTitle[MAX_PATH] = { 0 };
 6     CEnumDialogDlg* pEnumDialogDlg = (CEnumDialogDlg*)lParam;
 7 
 8     if (0 < ::GetWindowText(hWnd, acDlgTitle, MAX_PATH))//获取窗口标题或文本
 9     {
10         CString strRow, strPID;
11         strRow.Format(_T("%d"), pEnumDialogDlg->m_uiRow);
12         strPID.Format(_T("%d"), ::GetWindowThreadProcessId(hWnd, NULL));//获取进程ID
13 
14         pEnumDialogDlg->m_ListDlg.InsertItem(pEnumDialogDlg->m_uiRow, strRow);//插入行
15         pEnumDialogDlg->m_ListDlg.SetItemText(pEnumDialogDlg->m_uiRow, 1, acDlgTitle);
16         pEnumDialogDlg->m_ListDlg.SetItemText(pEnumDialogDlg->m_uiRow++, 2, strPID);
17     }
View Code

  2. 查找窗口: FindWindow  +   spy++

    • 原理:  使用spy++ 获取需要查找的窗口的类名及标题, 再通过FindWindow获取窗口句柄, 再进行操作. 本想以电脑自带的"计算器"举例说明,结果win10系统的计算器使用UWP开发,有兴趣的可以查看源码:https://github.com/Microsoft/calculator, 本文不在此展开. 所以此方式对MFC开发的窗口效果最好, 像QQ, 迅雷都是用的自己的DirectUI库开发, YY使用的QT库开发, 此法无用.
技术分享图片
 1     //win10计算器C++源码:https://github.com/Microsoft/calculator
 2     //win10特有的UWP应用:ApplicationFrameWindow的主窗口,
 3     //两个名为ApplicationFrameTitleBarWindow的childwindow,
 4     //一个Windows.UI.Core.CoreWindow子窗口和ApplicationFrameInputSinkWindow子窗口
 5 
 6     HWND hWnd = ::FindWindow(NULL, _T("计算器"));//ApplicationFrameWindow
 7     if (NULL != hWnd)
 8     {
 9         HWND hCoreWnd = ::FindWindowEx(hWnd, NULL, NULL, _T("计算器"));//Windows.UI.Core.CoreWindow
10         HWND hInputWnd = ::FindWindowEx(hWnd, NULL, _T("ApplicationFrameInputSinkWindow"), NULL);//ApplicationFrameInputSinkWindow
11         if (NULL != hInputWnd)
12         {
13             //尝试获取RichEditBox的窗口句柄
14             HWND hRichEditBox = ::FindWindowEx(hInputWnd, NULL, _T("Microsoft.UI.Xaml.Controls.RichEditBox"), NULL);
15             //实际 hRichEditBox = NULL,猜测窗口里的控件使用的是DuirectUI的形式,所以捕获不到
16         }
17 
18         //获取窗口类名
19         TCHAR acClassName[MAX_PATH] = { 0 };
20         ::GetClassName(hWnd, acClassName, MAX_PATH);
21 
22         CString strClassName = _T("win10计算器类名:");
23         strClassName += acClassName;
24 
25         MessageBox(strClassName);
26     }
View Code

二.  按钮激活测试 ButtonActive

  1. 原理: 学习MFC或win32原生控件可以知道所有的控件本质都是窗口, 所以我们只需要获取当前活动的窗口, 再通过EnumChildWindows枚举出所有的子窗口,再将没有激活的窗口激活.

  2. 说明: 在网上找了类似的软件, 基本都是对MFC开发的窗口才有效, eg.像DuirectUI开发的界面,只有一个主窗口,其余的控件都是自绘出来的,并不是真正意义上的窗口,所以此方法对此无效.

技术分享图片
 1 BOOL CALLBACK EnumWindowsPro(HWND hWnd, LPARAM lParam)
 2 {
 3     if (FALSE == IsWindowEnabled(hWnd))
 4     {
 5         EnableWindow(hWnd, TRUE);
 6     }
 7 
 8     return TRUE;
 9 }
10 
11 void CButtonActiveDlg::OnTimer(UINT_PTR nIDEvent)
12 {
13     // TODO:  在此添加消息处理程序代码和/或调用默认值
14     HWND hWnd = ::GetForegroundWindow();//获取当前正在使用的窗口
15     if (NULL != hWnd)
16     {
17         TCHAR acDlgTitle[MAX_PATH] = { 0 };
18         ::GetWindowText(hWnd, acDlgTitle, MAX_PATH);
19         SetDlgItemText(IDC_STC_TITLE, acDlgTitle);
20 
21         EnumChildWindows(hWnd, EnumWindowsPro, NULL);
22     }
23 
24     CDialogEx::OnTimer(nIDEvent);
25 }
View Code

三.  星号密码获取 AsterPassword

  1. 原理: 先再过WindowFromPoint获取我们需要操作的窗口, 然后再GetWindow获取所有子窗口并判断鼠标位置具体在哪个子窗口内(当然鼠标位置肯定在Edit控件上), 获取到Edit窗口后,通过WM_GETTEXT 获取到文本的具体内容.

技术分享图片
 1 void CDragStatic::OnTimer(UINT_PTR nIDEvent)
 2 {
 3     //前面我们使用过::GetForegroundWindow: 获取当前正在使用的窗口句柄
 4     HWND hWnd = ::GetDesktopWindow();//获取桌面窗口的句柄
 5     HDC hDeskDc = ::GetWindowDC(hWnd);//获取屏幕DC
 6     int iOldRop2 = SetROP2(hDeskDc, R2_NOTXORPEN);//前景色为背景色的反色
 7 
 8     CPoint pt = { 0 };
 9     GetCursorPos(&pt);//获取当前鼠标位置
10 
11     //HWND hWndParent = ::WindowFromPoint(pt);//获取当前点所在的窗口句柄
12     //CRect stRect = { 0 };
13     //HWND hWndCurrent = ::GetWindow(hWndParent, GW_CHILD);//获取父窗口的子窗口
14     //while (NULL != hWndCurrent)
15     //{
16     //    ::GetWindowRect(hWndCurrent, &stRect);//获取当前窗口的大小
17     //    if (::PtInRect(stRect, pt))//检测鼠标位置是否在当前窗口内
18     //        break;
19     //    else
20     //        hWndCurrent = ::GetWindow(hWndCurrent, GW_HWNDNEXT);//获取当前窗口的下一个兄弟窗口
21     //}
22 
23     //if (NULL == hWndCurrent)
24     //{
25     //    hWndCurrent = hWndParent;//当前窗口没有子窗口
26     //    ::GetWindowRect(hWndCurrent, &stRect);
27     //}
28 
29     //替换:发现像group这样的类,继续在里面遍历
30     CRect stRect = { 0 };
31     HWND hWndCurrent = SmallestWindowFromPoint(pt);//查找最小窗口
32     ::GetWindowRect(hWndCurrent, &stRect);
33 
34     //对程序窗口不作显示处理
35     if (GetWindowThreadProcessId(GetSafeHwnd(), NULL) == GetWindowThreadProcessId(hWndCurrent, NULL))
36     {
37         GetParent()->SetDlgItemText(IDC_STC_DLG, _T(""));
38         return;
39     }
40 
41     //显示窗口信息
42     ShowDlgInfo(hWndCurrent);
43 
44     //开始画闪烁边框
45     if (stRect.top < 0) stRect.top = 0;
46     if (stRect.left < 0) stRect.left = 0;
47     
48     HPEN hPenNew = ::CreatePen(0, 3, RGB(125, 0, 125));//创建画笔
49     HGDIOBJ hPenOld = ::SelectObject(hDeskDc, hPenNew);//将画笔选入设备
50     ::Rectangle(hDeskDc, stRect.left, stRect.top, stRect.right, stRect.bottom);//画矩形
51     Sleep(200);
52     ::Rectangle(hDeskDc, stRect.left, stRect.top, stRect.right, stRect.bottom);//取反色,与SetROP2对应
53 
54     //原因:前面画刷被选入设备,如果不恢复缺省或系统画刷,::DeleteObject(hPenNew)就会失效,造成内存泄露,但不会报错
55     ::SetROP2(hDeskDc, iOldRop2);
56     ::SelectObject(hDeskDc, hPenOld);
57 
58     ::DeleteObject(hPenNew);//删除画笔
59     ::ReleaseDC(hWnd, hDeskDc);//释放DC
60       
61     CStatic::OnTimer(nIDEvent);
62 }
View Code

  2. 对根据鼠标位置获取到的窗口进行闪烁画框, 这里涉及到GDI编程, 先不展开.

四. 控件提示功能 ToolTips

  1. 原理: MFC提供了专门CToolTipCtrl类, 掌握其用法即可.

       2. 静态添加: 适合固定文本的控件

技术分享图片
 1     CString strDirPath = _T("C:\\Program Files (x86)\\Tencent\\WeMeet\\2.8.8.403\\resource\\Default\\html");
 2 
 3     //静态添加
 4     if (!m_objToolTip.Create(this, TTS_ALWAYSTIP)) return FALSE;
 5     ::SetWindowTheme(m_objToolTip.m_hWnd, _T(""), _T(""));//兼容不同的视觉样式信息集,解决SetTipTextColor失效
 6     SetDlgItemText(IDC_EDIT_STATIC, strDirPath);
 7 
 8     m_objToolTip.SetTipTextColor(RGB(99, 184, 255));
 9     m_objToolTip.AddTool(GetDlgItem(IDC_EDIT_STATIC), strDirPath);
10     m_objToolTip.Activate(TRUE);
View Code

  3. 动态添加: 适合变动文本的控件, eg, edit控件的文件选择等

技术分享图片
 1 EnableToolTips(TRUE);
 2 
 3 ... ...
 4 
 5 
 6 ON_NOTIFY_EX(TTN_NEEDTEXT, 0, &CToolTipsDlg::OnTtnNeedText)
 7 
 8 ... ...
 9 
10 BOOL CToolTipsDlg::OnTtnNeedText(UINT id, NMHDR *pNMHDR, LRESULT *pResult)//msdn给的例子
11 {
12     UNREFERENCED_PARAMETER(id);//不作处理
13 
14     TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
15     UINT_PTR nID = pNMHDR->idFrom; //获得目标窗口ID,有可能是HWND
16     BOOL bRet = FALSE;
17 
18     if (pTTT->uFlags & TTF_IDISHWND) { //表明nID是否为HWND
19 
20         bRet = TRUE;
21         // idFrom is actually the HWND of the tool
22         nID = ::GetDlgCtrlID((HWND)nID); //从HWND得到ID值,当然你也可以通过HWND值来判断
23         switch (nID)
24         {
25         case IDC_EDIT_AUTO:
26             m_strText.Empty();
27             GetDlgItemText(nID, m_strText);
28             pTTT->lpszText = (LPTSTR)(LPCTSTR)m_strText;
29             pTTT->hinst = AfxGetResourceHandle();
30         default:break;
31         }
32     }
33 
34     *pResult = 0;
35 
36     return bRet;
37 }
View Code

五. 模拟键鼠操作  MouseKeyboardClick

  1. 原理: 在window NT系统之后,MSDN建议不要再使用keybd_eventmouse_event的方式来模拟键鼠操作, 那我们就使用SendInput函数通过设定INPUT指定键鼠消息来实现键鼠操作.

  2. 模拟网易云音乐的系统热键"Ctrl + Alt + P"来实现"播放/暂停"

技术分享图片
 1 //如果电脑上有360请先将程序添加到360的信任区
 2 void CMouseKeyboardClickDlg::OnBnClickedBtnHotkey()
 3 {
 4     HWND hWnd = ::FindWindow(_T("OrpheusBrowserHost"), NULL);//用spy++查找网易云音乐的窗口类
 5     if (!hWnd)
 6     {
 7         AfxMessageBox(_T("没有发现网易云音乐程序"));
 8         return;
 9     }
10         
11     INPUT astKey[6] = { 0 };
12 
13     astKey[0].type = astKey[1].type = astKey[2].type = astKey[3].type = astKey[4].type = astKey[5].type = INPUT_KEYBOARD;
14 
15     //Control + Alt + P 热键:播放/暂停
16     astKey[0].ki.wVk = astKey[5].ki.wVk = VK_CONTROL;
17     astKey[1].ki.wVk = astKey[4].ki.wVk = VK_MENU;
18     astKey[2].ki.wVk = astKey[3].ki.wVk = P;
19 
20     astKey[3].ki.dwFlags = astKey[4].ki.dwFlags = astKey[5].ki.dwFlags = KEYEVENTF_KEYUP;
21 
22     //用系统的时间戳
23     astKey[0].ki.time = astKey[1].ki.time = astKey[2].ki.time = GetTickCount();
24     Sleep(100);
25     astKey[3].ki.time = astKey[4].ki.time = astKey[5].ki.time = GetTickCount();
26 
27     SendInput(ARRAYSIZE(astKey), astKey, sizeof(INPUT));
28 }
View Code

  3. 模拟鼠标点击按钮并使用按钮响应click消息

技术分享图片
 1 void CMouseKeyboardClickDlg::OnBnClickedBtnMouse()
 2 {
 3     //简单测试:如果使用的的是外部的.exe。可使用spy++和::FindWindow获取窗口句柄
 4     INPUT astKey[2] = { 0 };
 5     astKey[0].type = astKey[1].type = INPUT_MOUSE;
 6 
 7     astKey[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
 8     astKey[1].mi.dwFlags = MOUSEEVENTF_LEFTUP;
 9 
10     //重新设置鼠标位置
11     CRect stRect = { 0 };
12     ::GetWindowRect(GetDlgItem(IDC_BTN_TESTOBJ)->m_hWnd, &stRect);
13     ::SetCursorPos(stRect.left + (stRect.right - stRect.left) / 2, stRect.top + (stRect.bottom - stRect.top) / 2);
14 
15     SendInput(ARRAYSIZE(astKey), astKey, sizeof(INPUT));
16 }
View Code

  4. 调试时发现一个问题: SendInput返回值为0, GetLastError返回值也为0, 本以为是权限不够, 添加了提权代码, 结果还是一样. 后来发现是360软件HOOK了SendInput消息, 认为是非法操作,所以需要将程序添加到360的信任区, 程序才能正常运行.

  5. 注意INPUT结构是个联合体, 键盘:ki  鼠标:mi 输入硬件:hi  别使用了错的变量赋值.

六.  自定义截图  ScreenShot

  1.  屏幕截图:  获取屏幕DC, 再将屏幕DC上的位图拷贝到内存DC, 再通过CImage类保存内存DC的位图为可识别的图片格式(jpg, bmp, png).

技术分享图片
 1 void CScreenShotDlg::OnBnClickedBtnScreen()
 2 {
 3     int iWidth = GetSystemMetrics(SM_CXSCREEN);
 4     int iHeight = GetSystemMetrics(SM_CYSCREEN);
 5 
 6     CDC MemDC;
 7     CBitmap MemBit;//微软定义的图片格式
 8     CDC *pDC = CDC::FromHandle(::GetDC(NULL));//获取屏幕DC
 9 
10     MemDC.CreateCompatibleDC(pDC);//指定内存DC
11     MemBit.CreateCompatibleBitmap(pDC, iWidth, iHeight);//指定位图大小,类似CreatePen
12     CBitmap * pOldBit = MemDC.SelectObject(&MemBit);//将位图填充到内存DC
13 
14     //开始绘图
15     MemDC.BitBlt(0, 0, iWidth, iHeight, pDC, 0, 0, SRCCOPY);//将屏幕DC上的数据拷贝到内存DC
16 
17     CImage objImage;//方便处理各种格式的图片:本质是gdi+ + DIB(无位图无关)
18     objImage.Attach(MemBit);//关联位图
19     objImage.Save(_T("E:\\screen.jpg"));
20 
21     MemDC.SelectObject(pOldBit);//
22     MemBit.DeleteObject();//当位图或pen,brush,font,palette,rgn还在设备上下文时,delete会失败
23 
24     MemDC.DeleteDC();
25     ::ReleaseDC(NULL, pDC->m_hDC);//释放屏幕DC
26 }
View Code

  2. 窗口截图:  获取指定窗口,再获取窗口的位图, 保存图片. 由于前面使用过WindowFromPoint方法实现,这里就简单地使用本程序窗口进行说明.

技术分享图片
 1 void CScreenShotDlg::OnBnClickedBtnDlg()
 2 {
 3     //以本程序的窗口举例
 4     CRect stRect = { 0 };
 5     GetWindowRect(&stRect);
 6 
 7     CDC memDC;
 8     CBitmap memBit;
 9     CWindowDC srcDC(this);
10     
11     memDC.CreateCompatibleDC(&srcDC);
12     memBit.CreateCompatibleBitmap(&srcDC, stRect.Width(), stRect.Height());
13     CBitmap* pOldBit = memDC.SelectObject(&memBit);
14 
15     memDC.BitBlt(0, 0, stRect.Width(), stRect.Height(), &srcDC, 0, 0, SRCCOPY);
16 
17     CImage objImage;
18     objImage.Attach(memBit);
19     objImage.Save(_T("E:\\Dialog.jpg"));
20 
21     memDC.SelectObject(pOldBit);
22     memBit.DeleteObject();
23 
24     memDC.DeleteDC();
25     ::ReleaseDC(NULL, srcDC);//释放屏幕DC
26 }
View Code

  3. 自定义截图: 先创建一个模态窗口, 并将屏幕DC的位图拷贝到模态窗口上, 然后使用橡皮筋类CRectTracker获取要自定义截图的区域, 再给不在截图区域的地方使用gdi+上颜色遮罩, 实现开始截图屏幕变灰, 鼠标选中的区域变白的效果.

技术分享图片
 1 void CCaptureDlg::DrawFrame()
 2 {
 3     CDC* pDC = GetDC(); //CDC::FromHandle(::GetDC(NULL));
 4 
 5     //双缓冲避免闪烁
 6     CDC BufferDC;
 7     CBitmap bitBuffer;
 8     BufferDC.CreateCompatibleDC(pDC);
 9     bitBuffer.CreateCompatibleBitmap(pDC, m_iScreenX, m_iScreenY);
10     CBitmap* pOldBitBuffer = BufferDC.SelectObject(&bitBuffer);
11 
12     CDC memDC;
13     memDC.CreateCompatibleDC(&BufferDC);
14     CBitmap* pOldBitMem = memDC.SelectObject(&m_ScreenBit);
15 
16     BufferDC.BitBlt(0, 0, m_iScreenX, m_iScreenY, &memDC, 0, 0, SRCCOPY);//将内存DC上的位图拷贝到窗口DC上
17 
18     if ((0 == m_rect.Width()) && (0 == m_rect.Height()))
19     {
20         m_objGdiplusDraw.DrawImage(&BufferDC, 0, 0, m_iScreenX, m_iScreenY,  0, 0, 8, 8 );//给图片上遮罩
21     }
22     else//鼠标拖动时重新画
23     {
24         AdjustRect(m_rect);//防止拖动矩形框出界,坐标为负时,重新调整坐标
25 
26         CRect stRect = m_rect;
27         stRect.NormalizeRect();//调整矩形坐标;eg,按住鼠标往下拖动,坐标正常;如果按住鼠标往上拖动呢?此函数用来反转坐标
28     
29         CRectTracker::Draw(&BufferDC);//画矩形框    
30         m_objGdiplusDraw.DrawImage(&BufferDC, 0, 0, m_iScreenX, stRect.top, 0, 0, 8, 8);//上区域
31         m_objGdiplusDraw.DrawImage(&BufferDC, 0, stRect.top, stRect.left, stRect.Height(), 0, 0, 8, 8);//左区域
32         m_objGdiplusDraw.DrawImage(&BufferDC, stRect.right, stRect.top, m_iScreenX - stRect.right, stRect.Height(), 0, 0, 8, 8);//右区域
33         m_objGdiplusDraw.DrawImage(&BufferDC, 0, stRect.bottom, m_iScreenX, m_iScreenY - stRect.bottom, 0, 0, 8, 8);//下区域
34     }
35 
36     pDC->BitBlt(0, 0, m_iScreenX, m_iScreenY, &BufferDC, 0, 0, SRCCOPY);//将内存DC的内容一次性贴在屏幕DC上
37 
38     memDC.SelectObject(pOldBitMem);
39     BufferDC.SelectObject(pOldBitBuffer);
40     ReleaseDC(pDC);
41 }
View Code

七. 屏幕放大镜 ScreenMagnify

  1.  原理:  获取鼠标点所在位置的区域位图, 再通过StretchBlt缩放到到指定的控件上.

  2.  说明: 有时候StretchBlt出来的图片会失真, 所以在StretchBlt之前, 我们要设置SetStretchBltMode设备上下文为拉伸模式.

技术分享图片
 1 void CScreenMagnifyDlg::StretchScreenToBitmap(CRect stShowRect, UINT uiZoom, CBitmap& bitmapShow)
 2 {
 3     if (nullptr != bitmapShow.m_hObject) bitmapShow.DeleteObject();//如果位图存在,则删除了资源,后面会再创建,避免泄露
 4 
 5     CDC* pDC = CDC::FromHandle(::GetDC(NULL));
 6 
 7     int iScreenX = GetSystemMetrics(SM_CXSCREEN);
 8     int iScreenY = GetSystemMetrics(SM_CYSCREEN);
 9 
10     //=============获取整个屏幕的位图
11     CDC screenDC;
12     CBitmap bitmapScreen;
13     screenDC.CreateCompatibleDC(pDC);
14     bitmapScreen.CreateCompatibleBitmap(pDC, iScreenX, iScreenY);
15     CBitmap* pOldScreen = screenDC.SelectObject(&bitmapScreen);
16     screenDC.BitBlt(0, 0, iScreenX, iScreenY, pDC, 0, 0, SRCCOPY);
17 
18     //=============获取放大后的屏幕区域的位图
19     CDC memDC;
20     CRect stRect = { 0 };
21 
22     //
23     int iWidth = stShowRect.Width() / uiZoom;
24     int iHeight = stShowRect.Height() / uiZoom;
25 
26     //获取放大后的屏幕坐标
27     AdjustRect(iScreenX, iScreenY, iWidth, iHeight, stRect);
28 
29     //获取位图
30     memDC.CreateCompatibleDC(pDC);
31     bitmapShow.CreateCompatibleBitmap(pDC, stShowRect.Width(), stShowRect.Height());
32     CBitmap* pOldMem = memDC.SelectObject(&bitmapShow);
33     SetStretchBltMode(memDC.m_hDC, COLORONCOLOR);//设置设备上下文为拉伸模式
34     memDC.StretchBlt(0, 0, stShowRect.Width(), stShowRect.Height(), &screenDC, stRect.left, stRect.top, iWidth, iHeight, SRCCOPY);
35 
36     //释放资源
37     screenDC.SelectObject(pOldScreen);
38     memDC.SelectObject(pOldMem);
39 
40     bitmapScreen.DeleteObject();
41 
42     ::ReleaseDC(NULL, pDC->m_hDC);
43 }
View Code

八. 图片浏览器 ImageExplore

  1. 原理: 选择要浏览的文件夹, 然后遍历里面的所有文件,再将图片文件添加到listctrl, 最后选中的item图片将显示在picCtrl控件上.

  2. MFC的文件夹的选择

技术分享图片
 1 void CImageExploreDlg::OnBnClickedBtnChoose()
 2 {
 3     CString strDirPath;
 4     BROWSEINFO stDirInfo = { 0 };
 5     
 6     stDirInfo.hwndOwner = m_hWnd;
 7     stDirInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_DONTGOBELOWDOMAIN | BIF_USENEWUI;
 8     
 9     LPITEMIDLIST lpidlBrowse = ::SHBrowseForFolder(&stDirInfo);
10     if (nullptr != lpidlBrowse)
11     {
12         if (::SHGetPathFromIDList(lpidlBrowse, strDirPath.GetBuffer(MAX_PATH)))
13         {
14             SetDlgItemText(IDC_EDIT_DIR, strDirPath);
15         }
16         ::CoTaskMemFree(lpidlBrowse);
17     }
18 }
View Code

  3.  MFC文件夹的遍历

技术分享图片
 1 void CImageExploreDlg::OnBnClickedBtnGetimage()
 2 {
 3     CString strDirPath;
 4     GetDlgItemText(IDC_EDIT_DIR, strDirPath);
 5     if (strDirPath.IsEmpty()) return;
 6 
 7     //遍历文件夹
 8     CFileFind objFileFind;
 9     CString strFilePath = strDirPath + _T("\\*.*");
10     BOOL bFind = objFileFind.FindFile(strFilePath);
11 
12     while (bFind)
13     {
14         bFind = objFileFind.FindNextFile();
15 
16         if (objFileFind.IsDots() || objFileFind.IsDirectory()) continue;//".",".."或是文件夹
17         //遍历到文件处理
18         TCHAR acExt[_MAX_EXT] = { 0 };
19         CString strFileName = objFileFind.GetFileName();
20         _tsplitpath_s(strFileName, NULL, 0, NULL, 0, NULL, 0, acExt, _MAX_EXT);
21 
22         if (TRUE == m_mpExtMap.Lookup(acExt, bFind))//符合后缀名的进入处理
23         {
24             CImage objImage;
25             CString strRowNum, strImageSize;
26             int iItemCount = m_objListCtrl.GetItemCount();//获取行数
27             //插入行
28             strRowNum.Format(_T("%d"), iItemCount + 1);
29             m_objListCtrl.InsertItem(iItemCount, strRowNum);//0
30 
31             m_objListCtrl.SetItemText(iItemCount, 1, objFileFind.GetFileName());//1
32 
33             objImage.Load(objFileFind.GetFilePath());
34             strImageSize.Format(_T("%d * %d"), objImage.GetWidth(), objImage.GetHeight());
35             m_objListCtrl.SetItemText(iItemCount, 2, strImageSize);//2
36 
37             //保存每一行的额外数据,用于后面显示图片时使用
38             TCHAR* pcFilePath = new TCHAR[MAX_PATH];
39             ZeroMemory(pcFilePath, MAX_PATH);
40             _tcscpy_s(pcFilePath, MAX_PATH, objFileFind.GetFilePath());
41             m_objListCtrl.SetItemData(iItemCount, (DWORD_PTR)pcFilePath);
42         }
43         
44     }
45     objFileFind.Close();
46 }
View Code

  4. GDI+ 绘制.gif图片

技术分享图片
 1 SetTimer(1, 200, NULL);
 2 
 3 ... ...
 4 
 5 void CImageExploreDlg::OnTimer(UINT_PTR nIDEvent)
 6 {
 7     PlayGif();
 8 
 9     CDialogEx::OnTimer(nIDEvent);
10 }
11 
12 ... ...
13 
14 void CImageExploreDlg::PlayGif()
15 {
16     //获取PIC CONTROL大小
17     CRect stPicRect = { 0 };
18     GetDlgItem(IDC_STC_SHOW)->GetClientRect(stPicRect);
19 
20     //获取gif信息
21     GUID acGuidBuf[MAX_PATH] = { 0 };
22     UINT uiCount = m_pGifImage->GetFrameDimensionsCount();//GIF文件的帧的维数
23     m_pGifImage->GetFrameDimensionsList(acGuidBuf, uiCount);// 获得图像帧的GUID
24     UINT uiFrameSize = m_pGifImage->GetFrameCount(&acGuidBuf[0]);//动图的总画面数
25 
26     //绘制
27     CDC* pDC = CDC::FromHandle(::GetDC(GetDlgItem(IDC_STC_SHOW)->m_hWnd));
28 
29     Gdiplus::Graphics graphics(pDC->GetSafeHdc());
30     if (0 == m_uiCurFrame) pDC->FillRect(stPicRect, CBrush::FromHandle(::CreateSolidBrush(GetSysColor(COLOR_3DFACE))));//背景填充
31     graphics.DrawImage(m_pGifImage, m_stGifPos, 0, 0, (Gdiplus::REAL)m_pGifImage->GetWidth(), (Gdiplus::REAL)m_pGifImage->GetHeight(), Gdiplus::UnitPixel);
32     //设置gif下一帧
33     GUID pageGuid = Gdiplus::FrameDimensionTime;
34     m_uiCurFrame = (++m_uiCurFrame) % uiFrameSize;
35     m_pGifImage->SelectActiveFrame(&pageGuid, m_uiCurFrame);//获取下一帧
36 
37     ::ReleaseDC(GetDlgItem(IDC_STC_SHOW)->m_hWnd, pDC->m_hDC);
38 }
View Code

  5. OnCtlColor: 不是对所有控件都有效

技术分享图片
 1 HBRUSH CImageExploreDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
 2 {
 3     HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
 4 
 5     //静态文本
 6     if ((CTLCOLOR_STATIC == nCtlColor) && (GetDlgItem(IDC_STC_CHOOSE)->m_hWnd == pWnd->m_hWnd))
 7     {
 8         //pDC->SetBkMode(TRANSPARENT);
 9         pDC->SetBkColor(RGB(255, 255, 0));
10         pDC->SetTextColor(RGB(255, 0, 0));
11         
12         return   (HBRUSH)::GetStockObject(NULL_BRUSH);
13     }
14     //换成Button就不行了,查阅了MSDN,要求重绘Button类DrawItem重画;VS2008以后出现了MFC colorbutton直接使用就行了,不会画了
15 
16     return hbr;
17 }
View Code

九.  半透明不规则窗口  TransparentCtrl

  1. 原理: 所有的窗口都是在指定的区域Rgn内绘制,不在该区域内的窗体会被裁剪掉,所以要绘制不规则窗体的本质是创建不规则的区域, MFC还专门对区域进行了封装CRgn,那这样处理起来就更简单了。

  2. 文字窗口

    • 先看下效果图

技术分享图片    

    • 核心代码: CRgnSetWindowRgn
技术分享图片
 1 void CFontDlg::DrawFont()
 2 {
 3     CRect stRect;
 4     GetWindowRect(&stRect);
 5 
 6     CDC* pDC = CDC::FromHandle(::GetDC(GetSafeHwnd()));
 7     //创建字体
 8     CFont ojbFont;
 9     ojbFont.CreateFont(
10         100, 40, 0, 0, FW_HEAVY, TRUE, FALSE,
11         0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
12         CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
13         DEFAULT_PITCH | FF_SWISS, _T("宋体"));
14 
15     //透明
16     pDC->SetBkMode(TRANSPARENT);
17     CFont *pOldFont = pDC->SelectObject(&ojbFont);
18     //路径绘制
19     pDC->BeginPath();
20     pDC->TextOut(0, 0, _T("喜欢看日出"));
21     pDC->EndPath();
22     pDC->SelectObject(pOldFont);
23 
24     //将路径转化成区域
25     HRGN wndRgn = ::PathToRegion(pDC->m_hDC);
26     SetWindowRgn(wndRgn, TRUE);
27 
28     ::ReleaseDC(GetSafeHwnd(), pDC->m_hDC);
29 }
View Code

  3. 半透明异形窗口

    • 先看下效果图  

技术分享图片

    • 核心代码:  gdi+  +   UpdateLayeredWindow   
技术分享图片
 1 void CTransDlg::DrawTransDlg()
 2 {
 3     ModifyStyleEx(0, WS_EX_LAYERED);//设置分层窗口
 4 
 5     //获取窗口大小
 6     CRect stWindRect = { 0 };
 7     GetWindowRect(&stWindRect);
 8 
 9     //获取图片资源
10     //Image* pImage = Image::FromFile(_T(".\\res\\background.png"));
11     Image * pImage = CUtility::LoadImage(IDB_PNG2, _T("PNG"), AfxGetResourceHandle());
12     if (nullptr == pImage) return;
13 
14     //获取图片大小
15     int iWidth = pImage->GetWidth();
16     int iHeight = pImage->GetHeight();
17 
18     //修改窗口大小
19     MoveWindow(stWindRect.left, stWindRect.top, iWidth, iHeight);
20 
21     //绘图
22     CDC* pDC = CDC::FromHandle(::GetDC(GetSafeHwnd()));
23 
24     //内存DC选取位图
25     CDC memDC;
26     CBitmap bmpMem;
27     memDC.CreateCompatibleDC(pDC);
28     bmpMem.CreateCompatibleBitmap(pDC, iWidth, iHeight);
29     CBitmap* pOldMem = memDC.SelectObject(&bmpMem);
30 
31     //gdi+绘制图片
32     Graphics graphics(memDC);//在内存DC上绘制
33     graphics.DrawImage(pImage, 0, 0, iWidth, iHeight);
34 
35     //更新窗口参数设置
36     POINT ptWinPos = { stWindRect.left, stWindRect.top };
37     POINT ptSrc = { 0, 0 };
38     SIZE sizeWindow = { iWidth, iHeight };
39     BLENDFUNCTION bf;
40     bf.BlendOp = AC_SRC_OVER;
41     bf.BlendFlags = 0;
42     bf.AlphaFormat = AC_SRC_ALPHA;
43     bf.SourceConstantAlpha = 254;
44 
45     //更新窗口
46     UpdateLayeredWindow(pDC, &ptWinPos, &sizeWindow, &memDC, &ptSrc, 0, &bf, ULW_ALPHA);
47 
48     //释放资源 
49     memDC.SelectObject(pOldMem);
50     DeleteObject(bmpMem);
51 
52     ::ReleaseDC(GetSafeHwnd(), pDC->m_hDC);
53 }
View Code
    • 出现一个问题: 明明在窗口上放一个按钮,但是看不到.为什么? UpdateLayeredWindow是把DC上的位图更新到窗口上, 所以在UpdateLayeredWindow之前, 我们要将所有控件都绘制在DC上,再一起更新上去.由此我们引入下面的实现方式.

  4. 带控件显示的半透明不规则窗口

    • 先看效果图

技术分享图片

    • 原理: 做两个窗口,一个主窗口设置成全透明,用来响应控件消息; 一个是显示窗口,用来铺在主窗口上, 显示半透明不规则的效果. 像前面说的, 在UpdateLayeredWindow之前我们要将所有控件绘制在DC上,作者的实现方式是这样的: 在DrawCtrl里通过WM_PRINT获取主窗口上的控件快照, 再贴到显示窗口的DC上, 所以我们看到的控件都是假控件, 但我们点击的时候是真控件的位置, 之所以我们能看到控件发生变化, 是因为所有假控件设置了窗口过程CtrlWndProc用来刷新原控件快照.
    • 核心代码: DrawCtrl
技术分享图片
 1 void CImgDialogBase::Refresh(void)
 2 {
 3     if( m_bIsRefreshing )
 4         return;
 5 
 6     if( !IsWindow(m_hFakeWnd) )
 7         return;
 8 
 9     m_bIsRefreshing = TRUE;
10 
11     RECT rc;
12     ::GetWindowRect( m_hFakeWnd, &rc);
13     POINT ptSrc = { 0, 0};
14     POINT ptWinPos = { rc.left, rc.top};
15     SIZE szWin = { m_nWidth, m_nHeigh };
16     BLENDFUNCTION stBlend = { AC_SRC_OVER, 0, m_nAlpha, AC_SRC_ALPHA };
17 
18 
19     HDC hDC = ::GetDC(m_hFakeWnd);
20     HDC hdcMemory = ::CreateCompatibleDC(hDC);
21 
22     BITMAPINFOHEADER stBmpInfoHeader = { 0 };   
23     int nBytesPerLine = ((m_nWidth * 32 + 31) & (~31)) >> 3;
24     stBmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);   
25     stBmpInfoHeader.biWidth = m_nWidth;   
26     stBmpInfoHeader.biHeight = m_nHeigh;   
27     stBmpInfoHeader.biPlanes = 1;   
28     stBmpInfoHeader.biBitCount = 32;   
29     stBmpInfoHeader.biCompression = BI_RGB;   
30     stBmpInfoHeader.biClrUsed = 0;   
31     stBmpInfoHeader.biSizeImage = nBytesPerLine * m_nHeigh;   
32 
33     PVOID pvBits = NULL;   
34     HBITMAP hbmpMem = ::CreateDIBSection(NULL, (PBITMAPINFO)&stBmpInfoHeader, DIB_RGB_COLORS, &pvBits, NULL, 0);
35     ASSERT(hbmpMem != NULL);
36     memset( pvBits, 0, m_nWidth * 4 * m_nHeigh);
37     if(hbmpMem)   
38     {   
39         HGDIOBJ hbmpOld = ::SelectObject( hdcMemory, hbmpMem); 
40         Graphics graph(hdcMemory);
41         
42         graph.SetSmoothingMode(SmoothingModeNone);
43         
44         // Draw the background
45         graph.DrawImage( m_pImage, 0, 0, m_nWidth, m_nHeigh);
46 
47         // On draw 
48         OnDraw(graph);
49         
50         // Draw all the controls
51         HWND hwndChild = ::GetWindow( GetSafeHwnd(), GW_CHILD);  
52         while(hwndChild)   
53         {
54             DrawCtrl( graph, hDC, hwndChild);
55             hwndChild = ::GetWindow( hwndChild, GW_HWNDNEXT);   
56         }
57 
58         // draw the caret
59         DrawCaret(graph);            
60         
61         ::UpdateLayeredWindow( m_hFakeWnd
62             , hDC
63             , &ptWinPos
64             , &szWin
65             , hdcMemory
66             , &ptSrc
67             , 0
68             , &stBlend
69             , ULW_ALPHA
70             );
71 
72         graph.ReleaseHDC(hdcMemory);
73         ::SelectObject( hdcMemory, hbmpOld);   
74         ::DeleteObject(hbmpMem); 
75     }
76 
77     
78     ::DeleteDC(hdcMemory);
79     ::DeleteDC(hDC);
80 
81     m_bIsRefreshing = FALSE;
82 }
View Code
    • 关于这一块的实现原理是参考了:https://www.codeproject.com/Articles/34158/Cool-Semi-transparent-and-Shaped-Dialogs-with-Stan. 但是问题又来了?看效果图并没有达到我们的预期,特别是CSlider类, 它是由前景图滑块和背景图显示条构成, 快照出来的效果前景图被覆盖掉了, 而像Edit这样的控件,我们还需要手动的给它添加光标, 原因是假控件上看不到光标, 显然 问题很多, 那有什么办法能解决这个问题呢?由此又引出了下面的实现方式

  5. 修正带控件显示的半透明不规则窗口

    • 先看效果图

技术分享图片    

    • 原理: 还是按照前面的思路,弄两个窗口,一个主窗口,一个显示窗口, 前面我们讲到了区域CRgn的概念, 刚好这里就能很好的用到.首先,我们获取主窗口上的所有控件区域,并求取所有控件区域的RGN_OR并集得到只有控件区域的新区域, 这样我们的主窗口上只有控件区域有显示, 其它地方都被剪裁掉了. 然后, 我们获取显示窗口的区域, 再与新区域求RGN_DIFF, 这样显示窗口上原来显示控件的区域全被扣出来了, 然后UpdateLayeredWindow出来的窗口, 主窗口负责显示控件, 显示窗口负责显示不包含控件区域的半透明不规则图片.
    • 核心代码: CRgn +   UpdateLayeredWindow
技术分享图片
 1 void CMyDrawBase::OnDraw()
 2 {
 3     if (!IsWindow(m_hFakeWnd)) return;
 4 
 5     //获取窗口大小
 6     CRect stWindRect = { 0 };
 7     ::GetWindowRect(m_hFakeWnd, &stWindRect);
 8 
 9     //绘图
10     CDC* pDC = CDC::FromHandle(::GetDC(m_hFakeWnd));
11 
12     //内存DC选取位图
13     CDC memDC;
14     CBitmap bmpMem;
15     memDC.CreateCompatibleDC(pDC);
16     bmpMem.CreateCompatibleBitmap(pDC, m_nWidth, m_nHeight);
17     CBitmap* pOldMem = memDC.SelectObject(&bmpMem);
18 
19     //gdi+绘制图片
20     Graphics graphics(memDC);//在内存DC上绘制
21     graphics.DrawImage(m_pImage, 0, 0, m_nWidth, m_nHeight);
22 
23     //裁剪区域
24     CRgn objRgnCtrl, objRgnTemp, objRgnFakeWnd;
25     GetCtrlRgn(objRgnCtrl, objRgnTemp);//获取所有控件的区域并集
26     objRgnFakeWnd.CreateRectRgn(0, 0, m_nWidth, m_nHeight);//获取fakewnd的区域
27     objRgnFakeWnd.CombineRgn(&objRgnFakeWnd, &objRgnCtrl, RGN_DIFF);//去掉控件的区域
28     pDC->SelectObject(&objRgnFakeWnd);
29 
30     //更新窗口参数设置
31     POINT ptWinPos = { stWindRect.left, stWindRect.top };
32     POINT ptSrc = { 0, 0 };
33     SIZE sizeWindow = { m_nWidth, m_nHeight };
34     BLENDFUNCTION bf;
35     bf.BlendOp = AC_SRC_OVER;
36     bf.BlendFlags = 0;
37     bf.AlphaFormat = AC_SRC_ALPHA;
38     bf.SourceConstantAlpha = m_iAlpha;
39 
40     //更新窗口
41     ::UpdateLayeredWindow(m_hFakeWnd, pDC->m_hDC, &ptWinPos, &sizeWindow, memDC.m_hDC, &ptSrc, 0, &bf, ULW_ALPHA);
42 
43     //将窗口放入裁剪区域
44     ::SetWindowRgn(m_hWnd, objRgnCtrl, TRUE);
45     ::SetWindowRgn(m_hFakeWnd, objRgnFakeWnd, TRUE);
46     
47     //释放资源 
48     memDC.SelectObject(pOldMem);
49     DeleteObject(bmpMem);
50 
51     objRgnCtrl.DeleteObject();
52     objRgnTemp.DeleteObject();
53     objRgnFakeWnd.DeleteObject();
54 
55     ::ReleaseDC(m_hFakeWnd, pDC->m_hDC);
56 }
57 
58 void CMyDrawBase::GetCtrlRgn(CRgn& rgnDst, CRgn& rgnSrc)
59 {
60     CRect stRect;
61     HWND hwndChild = ::GetWindow(m_hWnd, GW_CHILD);//遍历主窗口下的所有控件
62 
63     //获取第一个控件的区域
64     ::GetWindowRect(hwndChild, &stRect);
65     ScreenToClient(&stRect);
66     rgnDst.CreateRectRgnIndirect(stRect);
67 
68     while (hwndChild)
69     {
70         hwndChild = ::GetWindow(hwndChild, GW_HWNDNEXT);
71         if (!IsWindow(hwndChild)) break;
72         //获取第N个控件区域
73         ::GetWindowRect(hwndChild, &stRect);
74         ScreenToClient(&stRect);
75         rgnSrc.CreateRectRgnIndirect(stRect);
76 
77         rgnDst.CombineRgn(&rgnDst, &rgnSrc, RGN_OR);//求两个区域的并集
78         rgnSrc.DeleteObject();//一定要删除,否则会有内存泄露
79     }
80 }
View Code

十.  自适应窗体控件 + 程序托盘图标  TrayTip

  1. 自适应窗体控件

技术分享图片
 1 void CTrayTilDlg::OnSize(UINT nType, int cx, int cy)
 2 {
 3     CDialogEx::OnSize(nType, cx, cy);
 4 
 5     ReSize(nType, cx, cy);
 6     // TODO:  在此处添加消息处理程序代码
 7 }
 8 
 9 int CTrayTilDlg::CalSize(float fSize)//修正控件坐标值
10 {
11     int iTemp = (int)fSize;
12     float fTemp = fSize - (float)iTemp;
13 
14     if (0 >= fSize)
15         return iTemp + (int)((fTemp > -m_fReferSize) ? 0 : -1.0);//
16     else
17         return iTemp + (int)((fTemp < m_fReferSize) ? 0 : 1.0);//
18 }
19 
20 void CTrayTilDlg::ReSize(UINT uiType, int iX, int iY)
21 {
22     if ((0 == m_stOldRect.Width()) || (0 == m_stOldRect.Height())) return;
23 
24     float fZoomX = (float)(iX - m_stOldRect.Width()) / (float)m_stOldRect.Width();
25     float fZoomY = (float)(iY - m_stOldRect.Height()) / (float)m_stOldRect.Height();
26 
27     HWND hChildWnd = ::GetWindow(GetSafeHwnd(), GW_CHILD);
28     while (hChildWnd)
29     {
30         CRect stRect = m_mapCtrl.at(::GetDlgCtrlID(hChildWnd));//使用.at会检测序号值报错, []则不会
31         int iLeft = stRect.left + CalSize(stRect.left * fZoomX);
32         int iTop = stRect.top + CalSize(stRect.top * fZoomY);
33         int iWidth = stRect.Width() + CalSize(stRect.Width() * fZoomX);
34         int iHeight = stRect.Height() + CalSize(stRect.Height() * fZoomY);
35         
36         ::MoveWindow(hChildWnd, iLeft, iTop, iWidth, iHeight, FALSE);//重新设置控件位置
37 
38         hChildWnd = ::GetWindow(hChildWnd, GW_HWNDNEXT);
39     }
40     Invalidate(TRUE);//重绘整个窗口
41 }
42 
43 void CTrayTilDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)//设置最小窗口
44 {
45     // TODO:  在此添加消息处理程序代码和/或调用默认值
46     lpMMI->ptMinTrackSize = {400, 400};
47 
48     CDialogEx::OnGetMinMaxInfo(lpMMI);
49 }
View Code

  2. 程序托盘图标的创建

    • 托盘图标的创建:  Shell_NotifyIcon
技术分享图片
 1 void CTrayTilDlg::MyTrayIcon(DWORD dwMessage, DWORD dwIconIDd, LPCTSTR lpTipTitle)
 2 {
 3     NOTIFYICONDATA stNotifyIcon = { 0 };
 4 
 5     stNotifyIcon.cbSize = sizeof (NOTIFYICONDATA);
 6     stNotifyIcon.hWnd = GetSafeHwnd();
 7     stNotifyIcon.uID = IDR_MAINFRAME;//注意ADD之后,此值作为唯一标识符,不管是Delete还是Modify
 8 
 9 
10     stNotifyIcon.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;//NIF_INFO 气泡提示
11     stNotifyIcon.uCallbackMessage = WM_TRAY_MSG;//设置回调函数的响应消息
12     stNotifyIcon.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(dwIconIDd));//获取位图
13 
14     if (nullptr != lpTipTitle)
15     {
16         _tcscpy_s(stNotifyIcon.szTip, ARRAYSIZE(stNotifyIcon.szTip), lpTipTitle);
17     }
18 
19     _tcscpy_s(stNotifyIcon.szInfo, ARRAYSIZE(stNotifyIcon.szInfo), _T("这是一个气泡提示"));
20     _tcscpy_s(stNotifyIcon.szInfoTitle, ARRAYSIZE(stNotifyIcon.szInfoTitle), _T("气泡提示标题"));
21 
22     Shell_NotifyIcon(dwMessage, &stNotifyIcon);
23 }
View Code
    • QQ闪烁效果的实现: 找一张全透明的png图片, 使用定时器不间断地修改NIM_MODIFY图标样式即可.  
技术分享图片
 1 void CTrayTilDlg::OnTimer(UINT_PTR nIDEvent)
 2 {
 3     // TODO:  在此添加消息处理程序代码和/或调用默认值
 4     static BOOL bTrayIcon = TRUE;
 5     bTrayIcon = !bTrayIcon;
 6     DWORD dwIconID = (TRUE == bTrayIcon) ? IDI_ICON1 : IDR_MAINFRAME;
 7 
 8     MyTrayIcon(NIM_MODIFY, dwIconID, NULL);
 9 
10     CDialogEx::OnTimer(nIDEvent);
11 }
View Code

十一. 总结

  1. 建议学习这些例子准备好"百度" + "带谷歌浏览器的在线MSDN"(可以翻译成中文), 同时在编写例子时多阅读MFC源码(看MFC是如何封装window API的).

  2. MFC很多地方涉及到gdi 和 gdi+ 的编程, 写多了就感觉就好多了, 网上很多关于它的小结, 这里随便贴一个:https://www.cnblogs.com/mengfanrong/p/4492346.html

  3. 学习MFC不要简单地只是用它来实现界面的编程(特别是现在有各种各样的界面库), 把这些例子弄完基本就可以看<<深入浅出MFC>>, 或者看看MFC的六大关键技术, 这里有个通俗版的说明:

    https://blog.csdn.net/netanimals/article/details/6595467

  4. 项目源码地址: https://files-cdn.cnblogs.com/files/blogs/666666/EnumDialog.rar

 

MFC实践小例子

原文:https://www.cnblogs.com/zhoushen4576/p/14890506.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!