1.继续截屏工具
1.1 给截屏工具添加一个托盘图标
1.在 Frame 类的 OnCreate 函数中进行托盘图标的添加;
2.添加托盘图标的函数 Shell_NotifyIcon 需要两个参数: DWORD dwMessage 和 PNOTIFYICONDATA lpdata ;第一个参数表示是要添加托盘图标还是删除托盘图标等,第二个是托盘图标的样式设计;
3.完成结构体 lpdata 的设计;
4.使用函数创建图标: ::Shell_NotifyIcon(NIM_ADD, &nid) ;
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
... ...
// 删除菜单栏
this->SetMenu(0);
// 1-18
// 1. ======================================添加托盘图标========================================
PNOTIFYICONDATA nid;
nid.cbSize = sizeof(NOTIFYICONDATA); // 结构体大小
nid.hWnd = this->m_hWnd; // CMainFrame窗口处理托盘图标消息(哪个窗口接收消息)
nid.uID = ID_NOTIFYICON; // ID(自己在 stdafx.h 中自定义的ID)
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; // 发消息、有图标、有提示
nid.uCallbackMessage = UM_MSG_NOTIFYICON; // 发送自定义消息
nid.hIcon = AfxGetApp()->LoadIcon(IDI_ICON1); // 加载图标(先自己添加 ICon 图标资源,在进行加载)
wcscpy_s(nid.szTip, L"截屏"); // 提示信息,wcscopy UNICODE字符串拷贝
::Shell_NotifyIcon(NIM_ADD, &nid);
// =========================================添加托盘图标========================================
// TODO: 如果不需要可停靠工具栏,则删除这三行
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
1.2 当我们双击托盘图标时,我们希望可以打开截屏工具
1.双击托盘图标打开截屏工具的意思就是给 UM_MSG_NOTIFYICON 添加一个消息映射表;由于 nid 是由 Frame 类处理的,因此我们将 UM_MSG_NOTIFYICON 的消息映射表添加到 Frame 类中;
2.给消息映射表中添加一个自定义消息: ON_MESSAGE(UM_MSG_NOTIFYICON, &CMainFrame::OnNotifyICON) ;
3.添加一个自定义消息处理函数: afx_msg LRESULT OnNotifyICON(WPARAM wParam, LPARAM lParam) ;
4.在该函数中,首先判断是否点击了截屏工具的托盘图标,同时若鼠标消息是 WM_LBUTTONDBLCLK ,则弹出截屏工具;
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
... ...
ON_MESSAGE(UM_MSG_NOTIFYICON, &CMainFrame::OnNotifyICON) // 与添加其他命令不同,此处添加的是自定义消息 ON_MESSAGE
END_MESSAGE_MAP()
LRESULT CMainFrame::OnNotifyICON(WPARAM wParam, LPARAM lParam)
{
if(wParam == ID_NOTIFYICON && lParam == WM_LBUTTONDBLCLK)
{
this->GetDesktopBmp(); // 就是构造函数中的显示栈顶元素,本次将这些代码封装为 GetDesktopBmp 函数
this->ShowWindow(SW_MAXIMIZE);
}
return 0;
}
void CMainFrame::GetDesktopBmp()
{
// 1.2 获取一张空位图,并将桌面的图放到空位图里
CWindowDC windc(GetDesktopWindow());
CDC cmptdc;
cmptdc.CreateCompatibleDC(&windc);
CBitmap *p_bitmap = new CBitmap;
p_bitmap->CreateCompatibleBitmap(&windc, m_screen_cx, m_screen_cy);
cmptdc.SelectObject(p_bitmap);
cmptdc.BitBlt(0, 0, m_screen_cx, m_screen_cy, &windc, 0, 0, SRCCOPY);
// 2. 将桌面位图拷贝到栈中
btmp_box.push(p_bitmap);
}
1.3 我们想当我们点击“X”按钮或按“ESC”键时托盘图标也删除
1.我们需要在“X”按钮的消息处理函数和“ESC”按键处理函数中都将托盘图标删除;
2.将结构体 nid 定义为类成员;
// 点击“X”按钮退出
void CMainFrame::OnClickExit()
{
this->PostMessage(WM_CLOSE);
::Shell_NotifyIcon(NIM_DELETE, &nid);
}
// 按“ESC”键退出
void CShutScreenView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// 添加一个功能:按下esc键退出程序
CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd();
if (nChar == VK_ESCAPE)
{
pFrame->PostMessage(WM_CLOSE);
}
::Shell_NotifyIcon(NIM_DELETE, &(pFrame->nid));
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
1.4 考虑一开始运行程序时不截屏,只有当我们双击托盘图标时进行截屏
1.我们一开始运行程序时不进行截屏,那么我们需要将窗口隐藏,在 App 类中的 InitInstance : m_pMainWnd->ShowWindow(SW_HIDE) ;
1.5 注册热键(当程序在后天运行时按某个键来弹出该程序),该热键的功能是唤醒截屏工具
1.在添加完托盘图标之后进行注册热键: ::RegisterHotKey(this->m_hWnd,ID_HOST_CTRL_Q, MOD_CONTROL, ‘Q’) ;
2.其中的 ID_HOST_CTRL_Q 是我们自定义的 ID , MOD_CONTROL 为 ctrl 键, ‘Q’ 为字母 Q 键;
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
... ...
// =======================================注册热键=============================================
::RegisterHotKey(this->m_hWnd,ID_HOST_CTRL_Q, MOD_CONTROL, 'Q');
// =======================================注册热键=============================================
return 0;
}
3.添加一个热键消息处理函数: ON_WM_HOTKEY() ;
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
... ...
ON_WM_HOTKEY()
END_MESSAGE_MAP()
void CMainFrame::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
// 注册热键
if(nHotKeyId == ID_HOST_CTRL_Q)
{
this->GetDesktopBmp();
this->ShowWindow(SW_MAXIMIZE);
}
CFrameWnd::OnHotKey(nHotKeyId, nKey1, nKey2);
}
到此,我们的截屏工具基本完成,希望各位在学习的过程当中可以将遇到的问题告知本人,我们一起将该简单截图工具进行完善。
下面我们将开始学习基于对话框的MFC。
2.基于对话框的MFC
2.1 首先创建一个基于对话框的MFC应用程序;
2.2 给主对话框上添加一个 Button1 按钮,点击这个按钮之后弹出一个对话框;
1.首先在资源文件新建一个对话框,命名为 IDD_DIALOG1 ;
2.在 IDD_DIALOG1 对话框上添加一些控件,并给该对话框添加一个类: COneDlg 类;
3.给主对话框上的 Button1 按钮添加消息处理函数,消息类型为 BN_CLICKED ,类列表为主对话框的类: ON_BN_CLICKED(IDC_BUTTON1, &C对话框Dlg::OnBnClickedButton1) ;
4.在 OnBnClickedButton1 函数中,定义一个 COneDlg 对象,并使用该对象弹出一个模态对话框;
void C对话框Dlg::OnBnClickedButton1()
{
// 创建自定义的dialog对象
COneDlg one_dlg;
one_dlg.DoModal();
int a = 100;
}
2.3 再在主对话框上添加一个按钮 Button2 来弹出一个非模态对话框
1.首先在资源文件新建一个对话框,命名为 IDD_DIALOG2 ;
2.在 IDD_DIALOG2 对话框上添加一些控件,并给该对话框添加一个类: CTwoDlg 类;
3.给主对话框上的 Button2 按钮添加消息处理函数,消息类型为 BN_CLICKED ,类列表为主对话框的类: ON_BN_CLICKED(IDC_BUTTON2, &C对话框Dlg::OnBnClickedButton2) ;
4.在 OnBnClickedButton2 函数中定义一个 CTwoDlg 对象并弹出一个非模态对话框;
5.建立的非模态对话框我们有下面三种方式:第一种建立的对话框会一闪而过,效果不好;第二种建立的对话框只能是第一次点击 Button2 时可以弹出,关闭后在点击 Button2 按钮则不会再次探出并引起程序崩溃;第三种将dlg定义为一个成员,在 OnInitDialog 函数中创建,在点击 Button2 时显示,不会出现只能点击一次的问题;
void C对话框Dlg::OnBnClickedButton2()
{
// 2. 创建非模态对话框
// 2.1 用以下的三行代码进行创建非模态对话框会闪屏,即对话框不会一直显示,而是一闪而过
//CTwoDlg dlg;
//dlg.Create(IDD_DIALOG2, this);
//dlg.ShowWindow(SW_SHOW);
// 2.2 改进:将dlg定义为类成员,此时创建dlg可以,但是当关闭一个后,
// 再创建时就会出错,不允许创建两个对话框
//dlg.Create(IDD_DIALOG2, this);
//dlg.ShowWindow(SW_SHOW);
// 2.3 改进:将创建非模态对话框放到 OnInitDialog 函数里
// 不放在构造函数里的原因是在构造函数里,没有this,没有父窗口,因此创建时会失败
dlg.ShowWindow(SW_SHOW);
}
BOOL C对话框Dlg::OnInitDialog()
{
... ...
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// ======================2.3添加的代码位置===========================
dlg.Create(IDD_DIALOG2, this);
// =================================================================
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
接下来我们来完成一个基于对话框的MFC应用程序,作用是选择本地文件并进行删除,类似于360的文件删除功能。
3.clean
3.1 首先我们在一个基于对话框的MFC应用程序的主对话框上贴一张图片
1.给主对话框上添加一个 Picture Control 控件;更改控件的 Type 属性为 Bitmap , Notify 属性更改为 True (若不更改这个消息则点击消息无法进行发送),ID 更改为 IDC_PICTURE ;
2.将要往对话框上放的图片拷贝到当前工程下的 res 文件夹下;将这两张图片 添加资源 为 Bitmap 资源文件;
3.在 Picture Control 控件的 Image 属性中选择一张位图导入到对话框中;
4.经过上述步骤之后,图片即可贴到对话框上;
5.我们在主对话框上定义两个位图句柄,用来加载我们希望的位图: HBITMAP m_hbtmp7 ; HBITMAP m_hbtmp8 ;并在 CCleanDlg::OnInitDialog 函数中进行加载位图: m_hbtmp7 = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP1)) ; m_hbtmp8 = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP2)) 。