重画控件与系统托盘图标编写(VC_MFC)_diaogui7903的博客-程序员宅基地

技术标签: c/c++  

目录

控件重绘
系统托盘图标

(本章节中例子都是用 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/archive/2012/11/27/2790736.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/diaogui7903/article/details/101250354

智能推荐

关于字符数组以及字符串数组_一尾鱼汤的博客-程序员宅基地

例题13://13.编写一程序,将两个字符串连接起来,结果取代第一个字符串(mark下来加深印象),加油加油加油!(1)自己编写一个strcat函数int main(){ int strcat(char a[100],char b[100]); char a[100]={0}, b[100]={0}; //初始化字符数组; int i=0,j=0; cout<<"请输入两个字符串:"; cin>>a>>b;

Python配置Qt Designer与PyUIC_热心市民付先生的博客-程序员宅基地_python pyuic

Python配置Qt Designer与PyUIC安装pyqt相关包pip install pyqtpip install pyqt5-toolsPyCharm中选择相应的python解释器3. 添加外部工具名称填写自己方便易记得即可,我的名称添加为QTDesigner程序选择designer.exe,位置为当前解释器路径下的Lib\site-packages\pyqt5-tools\designer.exe工作目录为当前项目文件的目录添加选择完毕界面为:确定即可,再次

关于WebSocket_彪彪_的博客-程序员宅基地

原文链接:https://www.liaoxuefeng.com/wiki/1022910821149312/1103303693824096WebSocket是HTML5新增的协议,它的目的是在浏览器和服务器之间建立一个不受限的双向通信的通道,比如说,服务器可以在任意时刻发送消息给浏览器。为什么传统的HTTP协议不能做到WebSocket实现的功能?这是因为HTTP协议是一个请求-响应协议,...

FineUI初学手册_star_2008_的博客-程序员宅基地

女朋友鄙视我原创少...1.下载 进入官方论坛:http://www.fineui.com/bbs/要用到下载源代码和空项目下载http://fineui.codeplex.com/http://fineui.com/bbs/forum.php?mod=viewthread&tid=2123源代码直接下载,注意FineUI版本空项目里下载 对应版本的空项

NSStringDrawingOptions_yinachong的博客-程序员宅基地

NSStringDrawingTruncatesLastVisibleLine:如果文本内容超出指定的矩形限制,文本将被截去并在最后一个字符后加上省略号。如果没有指定NSStringDrawingUsesLineFragmentOrigin选项,则该选项被忽略。NSStringDrawingUsesLineFragmentOrigin:绘制文本时使用 line fragement or

随便推点

HTML5 APP----2014年H5没火,why?2016年H5能火,why?_谷震平的博客-程序员宅基地

0 前言        HTML5做跨平台的APP,在大多数人的脑子里没有什么好感,我身边的朋友也这么说。Anyway,我用完以后得出这样的结论:HTML5跨平台APP开发,在2015年以后会越来越火。    在2014年以前,HTML5的性能和能力都不够充足。特别是性能,因为Android4.4以下版本不能支持webGL技术,所以大部分低端Android手机无法流畅运行手机APP。D

Chromium多进程架构初探-兼谈Android平台版本_coloriy的博客-程序员宅基地

Chromium以多进程架构著称,它主要包含四类进程,分别是Browser进程、Render进程、GPU进程和Plugin进程。之所以要将Render进程、GPU进程和Plugin进程独立出来,是为了解决它们的不稳定性问题。也就是说,Render进程、GPU进程和Plugin进程由于不稳定而引发的Crash不会导致整个浏览器崩溃。本文就对Chromium的多进程架构进行简要介绍,以及制定学习计划。

Mybatis源码分析_风铃峰顶的博客-程序员宅基地

实例import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.*;import org.junit.Before;import org.junit.Test;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.List; private SqlSessionF

Composer常见问题汇总_cicibi6696的博客-程序员宅基地

问题一: [Composer\Downloader\TransportException] ...

什么时候不能使用箭头函数_一水茶缘YY的博客-程序员宅基地

共 2670 字,读完需 5 分钟。编译自 Dmitri Pavlutin 的文章,对原文内容做了精简和代码风格优化。ES6 中引入的箭头函数可以让我们写出更简洁的代码,但是部分场景下使用箭头函数会带来严重的问题,有哪些场景?会导致什么问题?该怎么解决,容我慢慢道来。能见证每天在用的编程语言不断演化是一件让人非常兴奋的事情,从错误中学习、探索更好的语言实现、创造新的语言特性是推动编程语言版本迭代的动