目标:
- 窗体的形状要是任意的,取自于位图形状。
- 在任务栏不显示图标,且在托盘处有显示,并能有消息处理,比如右键单击有菜单可以控制。
- 程序退出时,托盘处不能遗留图标。
- 窗体可以控制在最顶层。
- 窗体可任意拖动
- 。。。
1.让窗体为图片中形状的窗体图片修改如下:
背景色 → (0,0,255) 其他颜色当然可,最好是(255,0,0)(0,255,0)(0,0,255)这三种色。
步骤:
1.建一个MFC应用程序基于对话框,比如MyPet. (生成三个类CAboutDlg,CMyPetApp,CMyPetDlg)
2.为CMyPetDlg添加变量:
HBITMAP hBitmap; CBitmap m_bitmap; CString m_strBkBmp; //为他初始设定一个值比如"res\\1.bmp"
函数void SetupRegion(CDC *pDC, CBitmap &cBitmap, COLORREF TransColor );根据位图设定窗体区域。(函数代码在下面的附录里)
在BOOL CMyPetDlg::OnInitDialog()中加入:
hBitmap = (HBITMAP)::LoadImage(::AfxGetInstanceHandle(),m_strBkBmp, IMAGE_BITMAP,0,0, LR_CREATEDIBSECTION|LR_LOADFROMFILE); m_bitmap.Attach(hBitmap); BITMAP bm; m_bitmap.GetBitmap(&bm); CRect rect; GetWindowRect(&rect); rect.right = rect.left + bm.bmWidth; rect.bottom = rect.top + bm.bmHeight; MoveWindow(&rect); CClientDC dc(this); SetupRegion(&dc,m_bitmap,RGB(0,0,255)); //设置区域,将背景透明色不显示
此时完成窗体形状的设计。不过对话框的风格是要改变一下才行的。在属性中将Border设置为None.
现在生成的只有位图形状的窗体,却没有位图的显示。在OnPaint()中要加如以下代码:
void CMyPetDlg::OnPaint() { if (IsIconic()) { ...; } else {
CPaintDC dc(this); CDC picDC; picDC.CreateCompatibleDC(&picDC);
CBitmap * pOldBmp; pOldBmp = picDC.SelectObject(&m_bitmap);
BITMAP bm; m_bitmap.GetBitmap(&bm); dc.BitBlt (0,0,bm.bmWidth ,bm.bmHeight,&picDC,0,0,SRCCOPY); dc.SelectObject(pOldBmp);
} }
图片显示出来了!
2.程序在任务栏无图标,在托盘有图标:
步骤:
1.为类CMyPetDlg添加变量
NOTIFYICONDATA nid;
2.去掉在任务栏显示的图标
//使任务栏中不显示图标 DWORD dwExStyle=GetExStyle(); dwExStyle =(~WS_EX_APPWINDOW & dwExStyle) | WS_EX_TOOLWINDOW;
SetWindowLong(GetSafeHwnd(),GWL_EXSTYLE,dwExStyle);
3.托盘图标显示
在CMyPetDlg::OnInitDialog()调用Tray();
// // 托盘图标显示 // void CMyPetDlg::Tray(void) { nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA); nid.hWnd=this->m_hWnd; nid.uID=IDR_MAINFRAME; nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP ; nid.uCallbackMessage=WM_SHOWTRAY; //自定义的消息名称 nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME)); lstrcpy(nid.szTip, "我的小秘书~" ); //信息提示条为"我的小秘书~" Shell_NotifyIcon(NIM_ADD,&nid); //在托盘区添加图标 ShowWindow(SW_HIDE); //隐藏主窗口 }
自定义的消息WM_SHOWTRAY:
①在StdAfx.h里加入#define WM_SHOWTRAY (WM_USER+100)
②为类CMyPetDlg添加WM_SHOWTRAY处理函数
afx_msg LRESULT OnShowTray(WPARAM wParam, LPARAM lParam);
③在类CMyPetDlg实现文件里消息映射里加
ON_MESSAGE(WM_SHOWTRAY, OnShowTray)
④实现OnShowTray函数(代码在下面附录里)
4.程序退出自动将图标删除,将OnCancel()重写
// // 程序退出处理 // void CMyPetDlg::OnCancel() { // TODO: 在此添加命令处理程序代码 Shell_NotifyIcon(NIM_DELETE, &nid); //此时删除的nid与之前的是同一个NOTIFYICONDATA结构,否则删不掉,要鼠标再移上去一次才消失 EndDialog(IDCANCEL); }
3.为窗体添加右击菜单处理
注意:首先要重载对话框中的OnInitMenuPopup()函数,在对话框中使用CFrameWnd::OnInitMenuPopup()的函数,否则,菜单命令无法实现。将函数重写后代码在下面的附录里。
步骤:
1.重写函数OnInitMenuPopup()
2.处理WM_NCRBUTTONDOWN消息
// // 右键消息处理 // void CMyPetDlg::OnNcRButtonDown(UINT nHitTest, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CMenu MenuPop; CMenu *pMenu; CPoint pt; pt = point; MenuPop.LoadMenu(IDR_MENU2); //自己定义的一个菜单 pMenu = MenuPop.GetSubMenu(0); pMenu->SetDefaultItem(ID_POP_TOP); //将ID_POP_TOP设置为默认的选择(加粗) pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
pt.x, pt.y, this);
CDialog::OnNcRButtonDown(nHitTest, point); }
4.使窗体被任意拖动
1.处理WM_NCHITTEST消息
// // 非客户区拖动 // UINT CMyPetDlg::OnNcHitTest(CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 UINT nResult = CDialog::OnNcHitTest(point);
return nResult == HTCLIENT ? HTCAPTION : nResult; }
5.设置动画光标
1.为类CMyPetDlg添加变量
HCURSOR m_hCursor; //光标句柄 CString m_strCursor; //光标的路径,初始化为"res\\1.ani"
2.处理WM_SETCURSOR消息
// 设置光标
BOOL CMyPetDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if(!m_hCursor) { m_hCursor = LoadCursorFromFile(m_strCursor); } SetCursor(m_hCursor); //return CDialog::OnSetCursor(pWnd, nHitTest, message); return TRUE; }
6.使窗体置于顶层
1.添加变量
BOOL m_bTopMost; //初始为FALSE
// // 是否置于顶层 // void CMyPetDlg::OnPopTop() { // TODO: 在此添加命令处理程序代码 CRect rect; GetWindowRect(&rect); if(!m_bTopMost) { ::SetWindowPos(m_hWnd,HWND_TOPMOST,rect.left,rect.top,rect.Width(),rect.Height(), SWP_SHOWWINDOW); } else { ::SetWindowPos(m_hWnd,HWND_NOTOPMOST,rect.left,rect.top,rect.Width(),rect.Height(), SWP_SHOWWINDOW); } m_bTopMost = ! m_bTopMost; }
void CMyPetDlg::OnUpdatePopTop(CCmdUI *pCmdUI) { // TODO: 在此添加命令更新用户界面处理程序代码 pCmdUI->SetCheck(m_bTopMost); }
7.最小化处理
1.添加变量
BOOL m_bIsMin; //是否已最小化初始为FALSE
2.菜单项消息处理
// // 最小最大处理 // void CMyPetDlg::OnPopMin() { // TODO: 在此添加命令处理程序代码 if(!m_bIsMin) { ShowWindow(SW_HIDE); } else ShowWindow(SW_SHOW); m_bIsMin = ! m_bIsMin; }
void CMyPetDlg::OnUpdatePopMin(CCmdUI *pCmdUI) { // TODO: 在此添加命令更新用户界面处理程序代码 if(m_bIsMin) //如果之前强调的那个消息没被重写,这些内容也都是无法实现的 pCmdUI->SetText(_T( "最大化" )); else pCmdUI->SetText(_T( "最小化" )); }