Windows程序设计学习笔记(四)自绘控件与贴图的实现

Windows系统提供大量的控件供我们使用,但是系统提供的控件样式都是统一的,不管什么东西看久了自然会厌烦,为了使界面更加美观,添加一些新的东西我们需要自己绘制控件。

控件在默认情况下并不进行自绘,如果是在窗口中利用CreateWindow创建的话要在风格中加入一个对应的自绘风格,这个一般在MSDN中都可以查到比如按钮的自绘风格是BS_OWNERDRAW、列表框是 LBS_OWNERDRAWFIXED (列表项的高度一致)、LBS_OWNERDRAWVARIABLE(列表项的高度可以不一致),如果我们是在对话框下通过资源的方式创建的可以在其属性上将自绘风格选上。控件被改为自绘时,每当需要自画时控件都会向其父窗口发送一条WM_DRAWITEM消息,该消息中两个参数的如下:

WM_DRAWITEM 
idCtl = (UINT) wParam;             // 控件ID
lpdis = (LPDRAWITEMSTRUCT) lParam; // 一个指向DRAWITEMSTRUCT的结构体

结构体DRAWITEMSTRUCT的定义如下:

typedef struct tagDRAWITEMSTRUCT {
    UINT  CtlType; //控件类型
    UINT  CtlID; //控件ID
    UINT  itemID; //控件子项的ID只用于菜单项、组合框、列表框
    UINT  itemAction; //控件行为,一般在一个动态的行为发生时产生
    UINT  itemState; //控件状态,在处于某个静态时产生
    HWND  hwndItem; //控件句柄
    HDC   hDC; //绘制控件的设备上下文句柄
    RECT  rcItem; //控件项的矩形范围
    DWORD itemData; //程序为菜单项、列表项、组合框中的列表项指定的32值
} DRAWITEMSTRUCT; 

对于列表框和组合框,在重绘时会发送一条消息:WM_MEASUREITEM,该消息用于设置列表项的大小信息。

可以在该消息中利用下面的代码设置行高:

LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;
lpmis->itemHeight = 32;

下面来说说贴图。贴图的一般步骤为:

1)使用LoadBitmap加载一幅图片,该函数的原型为:

HBITMAP LoadBitmap(//函数返回一个对应位图的对象句柄
  HINSTANCE hInstance,  //实例句柄,系统通过这个值找到对应的位图
  LPCTSTR lpBitmapName  //位图名称,这个值可以通过MAKEINTRESOURCE宏获得
);

2)用CreateCompatiableDC函数创建一个与指定DC兼容的内存设备描述符。

3)利用SelectObject函数将对应位图选入到对应的HDC中,该函数返回一个原来未被替代的对象句柄,一般我们需要保存这个变量以便以后用于恢复。

4)使用BitBlt贴图

函数BitBlt,该函数的原型如下:

BOOL BitBlt(
  HDC hdcDest, // 目的控件的设备上下文句柄
  int nXDest,  // 
  int nYDest,  // 这两个参数表示需要贴在目的设备对应矩形中的哪个位置,分别是客户坐标的横坐标和纵坐标

  int nWidth,  
  int nHeight, //图片的大小和宽度
  HDC hdcSrc,  // 源图片所在的DC的句柄
  int nXSrc,   
  int nYSrc,   //表示从原图片的哪个像素点开始,这两个值表示开始位置的横纵坐标
  DWORD dwRop  // 贴图的方式,它规定了原图片颜色如何与目标控件颜色组合已形成最终的颜色
);

对于第二步的操作并不是必要的,在贴图时我们可以使用同一个句柄作为原和目的句柄,但是当我们需要贴的图片过多,使用同一个句柄会造成客户区的闪烁,所以可以另外定义一个句柄,保存我们所需要的所有图片,然后一次性通过源DC贴到目的DC,这样可以一次完成,避免了客户区的闪烁。

下面的例子采用的是ListBox控件:

	HWND hList = CreateWindow("LISTBOX", "", WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS  |WS_VISIBLE | LBS_HASSTRINGS | LBS_NOTIFY  | LBS_OWNERDRAWFIXED
				, 0,0,200,800,hWnd, (HMENU)123, g_hInst, NULL);//在创建ListBox时定义为自画风格,同时WS_CLIPSIBLINGS风格指明在重绘子窗口时不重绘整个客户区

在WM_DRAWITEM消息中编写重绘的代码:

LPDRAWITEMSTRUCT lpDis = (LPDRAWITEMSTRUCT)lParam;
RECT rtListItem = lpDis->rcItem;
if (ODT_LISTBOX == lpDis->CtlType)
{
	if (ODS_SELECTED & lpDis->itemState)//当某项被选中时设置虚线框并使背景为蓝色
	{
		rtListItem.right -= 2;
		rtListItem.bottom -= 2;
		HBRUSH hBlue = CreateSolidBrush(RGB(0,0,255));
		HGDIOBJ hOld = SelectObject(lpDis->hDC, hBlue);
		FillRect(lpDis->hDC, &rtListItem, hBlue);
		DrawFocusRect(lpDis->hDC, &rtListItem);
	}
	//贴图,并将图片背景色设置为所在矩形框的背景色
<span style="white-space:pre">	</span>HBITMAP  hBitMap = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1));
	HDC hMerDc= CreateCompatibleDC(lpDis->hDC);
	SelectObject(hMerDc, hBitMap);
	BitBlt(lpDis->hDC, lpDis->rcItem.left, lpDis->rcItem.top, lpDis->rcItem.right - lpDis->rcItem.left, lpDis->rcItem.bottom - lpDis->rcItem.top, 
		hMerDc, 0, 0, SRCAND);
	SelectObject(lpDis->hDC,hBitMap);
	DeleteObject(hMerDc);
<span style="white-space:pre">	</span>//将文字设置为透明、并显示文字
	SetBkMode(lpDis->hDC, TRANSPARENT);
					
	DrawText(lpDis->hDC, g_Person[lpDis->itemID].pszName,strlen(g_Person[lpDis->itemID].pszName), 
		&(lpDis->rcItem),DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏LIN_ZONE

markdown 基本语法(转载)

最近感觉一直使用富文本编辑器写东西,感觉有点烦,所以就试着学习了一下简单的markdown编辑器的使用

942
来自专栏熊二哥

Markdown快速入门

现在博文写作次数渐渐变多,经常看到很多园友的博文样式都非常的美观,个人虽然是个土鳖,但对美也是有很强需求的,同时由于最近将要上线一个博客项目,因此也很关心如何可...

2406
来自专栏葡萄城控件技术团队

Spread for Windows Forms快速入门(3)---行列操作

开发人员可以定义用户与行和列的交互,如是否可以更改行或列的大小、是否可以移动行或列、冻结指定的行或列、在行或列中查找数据等。 更改行或列的大小 你可以允许用户重...

2826
来自专栏Windows Community

Windows Community Toolkit 3.0 - InfiniteCanvas

InfiniteCanvas 是一个 Canvas 控件,它支持无限画布的滚动,支持 Ink,文本,格式文本,画布缩放操作,撤销重做操作,导入和导出数据。

773
来自专栏HT

基于HT for Web矢量实现HTML5文件上传进度条

在HTML中,在文件上传的过程中,很多情况都是没有任何的提示,这在体验上很不好,用户都不知道到时有没有在上传、上传成功了没有,所以今天给大家介绍的内容是通过HT...

2139
来自专栏谈补锅

工作中碰到的js问题(disabled表单元素不能提交到服务器)

今天碰到一个奇葩的问题,asp页面表单提交后,有一个文本框<input type="text" name="phone" id="phone" />在后台获取不...

1582
来自专栏非著名程序员

基础篇章:关于 React Native 之 ViewPagerAndroid 组件的讲解

今天我们来讲解一下关于 ViewPager 的使用,它是一个允许子视图左右滚动翻页的容器。而且每一个 ViewPagerAndroid 的子容器会被视作一个单独...

2295
来自专栏林德熙的博客

win10 uwp 简单MasterDetail UWP 导航List点击后退按钮页面更改大小修改显示修改我代码源码左右的列表和内容的相互操作

本文主要讲实现一个简单的界面,可以在窗口比较大显示列表和内容,窗口比较小时候显示列表或内容。也就是在窗口比较小的时候,点击列表会显示内容,点击返回会显示列表。

950
来自专栏Windows Community

New UWP Community Toolkit - ImageEx

概述 UWP Community Toolkit  中有一个图片的扩展控件 - ImageEx,本篇我们结合代码详细讲解  ImageEx 的实现。 Image...

3247
来自专栏林德熙的博客

WPF 使用 SharpDX 在 D3DImage 显示 介绍创建控件D3D 设备设置指针画出来

本文告诉大家如何使用 SharpDX 在 D3DImage 显示。在上一篇WPF 使用 SharpDX只是使用窗口,也就是无法使用其它的 WPF 控件。所以这一...

3131

扫码关注云+社区

领取腾讯云代金券