C++学习 2019-1-18

本文详细介绍了如何使用MFC创建带有托盘图标和热键的截屏工具,包括添加托盘图标、响应双击事件、注册热键等功能。此外,还讲解了基于对话框的MFC应用程序创建过程,演示了模态与非模态对话框的使用,以及如何在对话框中添加和显示图片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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)) 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值