重画控件与系统托盘图标编写(VC_MFC)

目录

控件重绘
系统托盘图标

(本章节中例子都是用 VS2005 编译调试的)


控件重绘

注意:

  • 要自绘的控件必须在 Owner Draw 属性上设置为 true,
  • 或者用 Create 函数创建控件时候,具备自绘属性(例如 CButton 在用 Create 创建时候需具备 BS_OWNERDRAW, CStatic 在用 Create 创建时候需具备 SS_OWNERDRAW 等等)

在重绘某个控件时

重要结构体:

DRAWITEMSTRUCT(MSDN 链接)

作用:  为需要自绘的控件或者菜单项提供了必要的信息

结构体定义:

View Code
typedef struct tagDRAWITEMSTRUCT { 
  UINT CtlType;  // Unsigned integer that specifies the control type. 
  UINT CtlID; // Unsigned integer that specifies the identifier of the combo box, list box, or button. This member is not used for a menu.
  UINT itemID; // Unsigned integer that specifies the menu item identifier for a menu item or the index of the item in a list box or combo box.
  UINT itemAction; // Unsigned integer that specifies the drawing action required.
  UINT itemState; // Unsigned integer that specifies the visual state of the item after the current drawing action takes place.
  HWND hwndItem; // Handle to the control for combo boxes, list boxes, buttons, and static controls. For menus, this member is a handle to the menu containing the item.
  HDC hDC; // Handle to a device context.
  RECT rcItem; // RECT structure that specifies a rectangle that defines the boundaries of the control to be drawn. 
  ULONG_PTR itemData;  
} DRAWITEMSTRUCT; 

注意:  在 CListBox,CListCtrl,CTreeCtrl,CComboBox 控件中可以使用 SetItemData 来设置结构体中的 itemData 值. ( CListBox::SetItemData , CListCtrl::SetItemData , CTreeCtrl::SetItemData , CComboBox::SetItemData )

相关文献链接:

代码样例:

这里以 List Box 控件为例子来说,首先在新建的工程中添加一个 List Box 控件,并设置 Has Strings 属性为 true,Owner Draw 属性上设置为 fixed,List Box控件资源为 IDC_LIST1,对话框资源视图如下:

然后为这个 List Box 添加一个关联的控制变量 m_listBox 这里的变量类型先选默认的 CListBox 然后点击确定.然后派生一个 CMyListBox 基类为 CListBox ,然后为 CMyListBox 去添加一个控件重绘函数(即 DrawItem,这里可以用 VS 帮你自动生成这个函数),然后在控件中添加以下操作,可以使 List Box 选中项以黑色背景,白色字体显示,非选中项以黑色字体,白色背景显示,具体代码如下:

View Code
//添加一个 CDC 对象然后关联 List Box 项的资源 DC
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
//判断是否是选中项,通过判断这个项是否具有焦点
CBrush bs;
if(lpDrawItemStruct->itemState & ODS_SELECTED)
{
    //绘制选中项的背景色为黑色
    bs.CreateSolidBrush(RGB(0,0,0));
    dc.FillRect(&lpDrawItemStruct->rcItem,&bs);
    //文本背景色为黑色,字体为白色
    dc.SetBkColor(RGB(0,0,0));
    dc.SetTextColor(RGB(255,255,255));
}
else
{
    //绘制未选中项的背景色为白色,
    bs.CreateSolidBrush(RGB(255,255,255));
    dc.FillRect(&lpDrawItemStruct->rcItem,&bs);
    //文本背景色为白色,字体为黑色
    dc.SetBkColor(RGB(255,255,255));
    dc.SetTextColor(RGB(0,0,0));
}
CString str;
GetText(lpDrawItemStruct->itemID,str);
//绘制文本
dc.DrawText(str,&lpDrawItemStruct->rcItem,DT_VCENTER|DT_LEFT|DT_SINGLELINE);
//分离资源 DC
dc.Detach();

运行结果:

相关文献:

 


系统托盘图标

重要结构体:

NOTIFYICONDATA(MSDN 链接)

作用:  记录着在托盘中相关项的相关信息

结构体定义:

View Code
typedef struct _NOTIFYICONDATA { 
  DWORD cbSize; // Size of this structure, in bytes.
  HWND hWnd; // Handle to the window that receives notification messages associated with an icon in the taskbar status area.
  UINT uID; // Application-defined identifier of the taskbar icon. Values from 0 to 12 are reserved and should not be used.
  UINT uFlags; // Array of flags that indicate which of the other members contain valid data. 
  UINT uCallbackMessage; // Application-defined message identifier
  HICON hIcon; // Handle to the icon to add, modify, or delete.
  WCHAR szTip[64]; // Null-terminated string that contains ToolTip text to display for the icon.
} NOTIFYICONDATA, *PNOTIFYICONDATA;

操作流程:

代码示例:

这里以对话框为例(单/多文档也类似),在对话框工程中添加一个成员 NOTIFYICONDATA 类型的 m_NotifyIconData 变量,然后在对话框初始化的函数(即 OnInitDialog 函数)中添加具体实现代码,代码如下:( MSDN链接: Shell_NotifyIcon)

View Code
/* 托盘图标的初始化工作 ************************************************************************/
//初始化 m_NotifyIconData 内存空间
memset(&m_NotifyIconData, 0, sizeof(NOTIFYICONDATA));
//使托盘中图标对应于本窗体,这样它便可以把托盘图标的事件发送给窗体程序
m_NotifyIconData.hWnd = GetSafeHwnd();
ASSERT(m_NotifyIconData.hWnd != NULL);
//定托盘图标产生事件时候发出的事件
m_NotifyIconData.uCallbackMessage = WM_NOTI;
//填充结构体的大小
m_NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
//加载托盘图标(这里以默认的资源图标)
m_NotifyIconData.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
//设置鼠标移动到托盘图标时候的提示文字
memcpy (m_NotifyIconData.szTip,L"test",sizeof(L"test"));
//设置托盘图标的属性
m_NotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
//设置托盘图标的图标资源 ID
m_NotifyIconData.uID = IDR_MAINFRAME;


/* 显示托盘图标 *********************************************************************************/
Shell_NotifyIcon(NIM_ADD, &m_NotifyIconData);

然后为托盘图标写事件响应函数,即先在对话框的消息映射中添加消息的消息映射,然后定义相关消息映射函数(参数说明: wParam:任务栏图标的ID, lParam:鼠标事件值)

View Code
/* 对话框头文件 **********************************/
 ...
#pragma once
//消息定义
#define WM_NOTI (WM_USER+1)

// CtestDlg 对话框
class CtestDlg : public CDialog
{
    ...
    //NOTITYICONDAT结构
    NOTIFYICONDATA m_NotifyIconData;
    ...
    //托盘图标响应事件消息的函数
    afx_msg LRESULT OnMyNoTi(WPARAM wParam, LPARAM lParam);
};




/* 对话框实现文件 ********************************/
...

BEGIN_MESSAGE_MAP(CtestDlg, CDialog)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
    //消息映射
    ON_MESSAGE(WM_NOTI,OnMyNoTi)
END_MESSAGE_MAP()

...

LRESULT CtestDlg::OnMyNoTi(WPARAM wParam,LPARAM lParam)
{ 
    // TODO: 处理用户自定义消息
    //当用户单击托盘图标时候弹出一个消息框
    if(lParam == WM_LBUTTONUP)
        MessageBox(L"test");
    return 0; 
}

然后在对话框窗口销毁的时候删除托盘中的图标,即为对话框添加 WM_DESTORY 事件响应函数,然后加入以下代码:

Shell_NotifyIcon(NIM_DELETE, &m_NotifyIconData);

相关文章

原文地址:https://www.cnblogs.com/kzang/p/2790736.html