win32 api 实现不规则形状按钮

本文详细介绍了使用Windows SDK进行Win32 API编程的经验,特别是如何创建不规则窗口和按钮。通过调整窗口和按钮的形状,开发者能够实现更加灵活和个性化的UI设计。文章中分享了利用SetWindowRgn API和类样式属性来修改子窗口形状的方法,并提供了实际的代码示例。此外,还讨论了SetClassLong和SetWindowLong的区别以及如何消除CS_PARENTDC属性以使窗口形状生效。

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

最近在看<<Windows环境下32位汇编语言程序设计>>这本书。与其说在看汇编,更像是在看windows sdk.这本书基本上就是<<Windows程序设计>>的汇编版。但是我觉得这本书比<<Windows程序设计>>看起来更舒服,也许是那本书是翻译过来的原因吧,总觉得看起来没有这本书说得透彻。


看了78章,收获非常大,都是win32 api方面的收获。具体的知识点就不罗列了,总的说有几个关键性的技术比一下了解了,感觉很爽。当然,收获大也跟自己太菜的原因有关,要是我特别牛奔,早就啥都知道了,看啥也就都不会觉得有收获了~


比较让我兴奋的,是创建不规则窗口、窗口的随意拖动等东西。这些东西书上都有例子,照着例子按也不觉得如何复杂。创建不规则窗口主要依赖SetWindowRgn这个API.窗口能够不规则了,按钮可不可以呢?


直接给按钮这个子窗口SetWindowRgn是行不通的。

上网上搜索了许多不规则按钮,都是MFC的例子,没有SDK的,于是自己琢磨了琢磨,也上网上提问了,终于解决了问题。


给子窗口设置形状,依然需要SetWindowRgn.

但是区别在于,子窗口都包含CS_PARENTDC,需要把这个东西从Class中去除,才能使得SetWindowRgn生效.


步骤

1.GetClassLong,取出Style,

2.Style=Style and (not CS_PARENTDC)

3.SetClassLong,设置为新的Style

做完了这3步骤,就可以像设置对话框一样形状一样,SetWindowRgn~


汇编代码主要是这几句

 

; Get handle of btn

invoke GetDlgItem,hWnd,IDC_NOTBLOCK

mov @hBtn,eax


; Delete CS_PARENTDC from btn

invoke GetClassLong,@hBtn,GCL_STYLE

mov @BtnStyle,eax

mov eax,0ffffH

xor eax,CS_PARENTDC

and @BtnStyle,eax

invoke SetClassLong,@hBtn,GCL_STYLE,@BtnStyle


; Set btn's region

invoke CreateEllipticRgn,0,0,130,130

push eax

invoke SetWindowRgn,@hBtn,eax,FALSE

pop eax

invoke DeleteObject,eax


 


这里面有个值得注意的地方,

那就是 Set/GetClassLongSet/GetWindowLong的区别。把SetClassLong换成SetWindowLong就不管用了。


网上许多地方都说,这两个的区别,一个是设置整个所有类的属性,另外一个是设置单个窗口的。我到现在也不是很理解,也非常希望路过的高人给我留言指点指点。


说说自己的猜测吧:

SetWindowLong能够修改除了类别以外,所能控制的属性

SetClassLong能够修改类别而决定的属性

而且还可能是因为

只有CS_PARENTDC(Class Style)

而没有 "WS_PARENTDC",

所以只能 SetClassLong来消除掉这个属性

上代码:

ns.rc

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include	<resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define		DLG_MAIN		1000
#define		IDC_NOTBLOCK		1001
#define		IDB_BACK		100
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IDB_BACK	BITMAP			"back.bmp"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN	DIALOG	100,100,200,200
STYLE	DS_MODALFRAME|WS_POPUP|WS_VISIBLE|WS_CAPTION|WS_SYSMENU
CAPTION	"MiaoLearn"
FONT 9,"宋体"
{
PUSHBUTTON	"我不是方块!",IDC_NOTBLOCK,50,50,100,100
}


ns.asm

		.386
		.model flat,stdcall
		option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include		windows.inc
include		kernel32.inc
includelib	kernel32.lib
include		user32.inc
includelib	user32.lib
include		gdi32.inc
includelib	gdi32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>		
DLG_MAIN	equ		1000
IDC_NOTBLOCK	equ		1001
IDB_BACK	equ		100
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.data?
hInstance	dd		?	
hDlgMain	dd		?	
hBmpBack	dd		?
hBrushBack	dd		?

		.const
		
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain	proc	uses ebx edi esi hWnd,wMsg,wParam,lParam
		
		LOCAL	@hDc
		LOCAL	@stPs:PAINTSTRUCT
		
		LOCAL	@hBtn
		LOCAL	@BtnStyle
		
		mov	eax,wMsg
		.if	eax==WM_INITDIALOG
			push	hWnd
			pop	hDlgMain
			
			;	Get handle of btn
			invoke	GetDlgItem,hWnd,IDC_NOTBLOCK
			mov	@hBtn,eax
			
			;	Delete CS_PARENTDC from btn
			invoke	GetClassLong,@hBtn,GCL_STYLE
			mov	@BtnStyle,eax
			mov	eax,0ffffH
			xor	eax,CS_PARENTDC
			and	@BtnStyle,eax
			invoke	SetClassLong,@hBtn,GCL_STYLE,@BtnStyle
			
			;	Set btn's region
			invoke	CreateEllipticRgn,0,0,130,130
			push	eax
			invoke	SetWindowRgn,@hBtn,eax,FALSE
			pop	eax
			invoke	DeleteObject,eax
			
		.elseif eax==WM_PAINT
		
			;	draw a background for seeing result
			invoke	BeginPaint,hWnd,addr @stPs	
			mov	@hDc,eax
			
			invoke	LoadBitmap,hInstance,IDB_BACK
			mov	hBmpBack,eax
			invoke	CreatePatternBrush,hBmpBack
			mov	hBrushBack,eax
			invoke	SelectObject,@hDc,hBrushBack
			invoke	PatBlt,@hDc,0,0,300,300,PATCOPY
			invoke	DeleteObject,eax
			
			invoke	EndPaint,hWnd,addr @stPs
			
			
			
		.elseif	eax==WM_CLOSE
			invoke	DeleteObject,hBmpBack
			invoke	EndDialog,hWnd,NULL
		.else
			mov	eax,FALSE
			ret
		.endif
		mov	eax,TRUE
		ret
_ProcDlgMain	endp
start:
	invoke	GetModuleHandle,NULL
	mov	hInstance,eax
	invoke	DialogBoxParam,hInstance,DLG_MAIN,NULL,_ProcDlgMain,NULL
	invoke	ExitProcess,NULL
end	start		
		



 

截图:

ns.exe


Ps:

为了便于观察,给了DIALOG一个背景.中间那个圆形的是按钮,可以点的……

如果想用位图绘制按钮,就在父窗口里处理WM_DRAWITEM事件即可。

如果想实现一个比较复杂的窗口,可以控制Rgn,具体可以参考Rgn相关的API.

本想把这个实例做复杂点,把最近觉得新鲜的东西全用上,但是时间有限啊~

而且我想做的其它功能书上都有,就择出来这个书上没提的功能,把它说清楚吧

ps:

本来打算和小静静十一期间浪漫浪漫的,但是限制于各种因素,没浪起来…………

但是咱们那天去怀柔,玩的也挺好的。

 


最近的小静静很烦....都在烦些什么呢?

1.十一休息完了,又该上班了,小静静迎来了不爽期。

2.因为一下要上7天班,导致小静静一直愁眉苦脸;

3.再加上胃疼、肚子疼、牙碎等身体因素困扰小静静,小静静的心情更是雪上加霜了;

4.再再加上小静静总觉得自己胖了(其实一点也没有鄙视),所以小静静的心情一下跌落到了谷底。

 

乖乖的小静静呀~

咱们周六就去医院看看你的胃、肚子和牙,

然后咱们跑跑步锻炼锻炼,别不高兴了~

至于上班连续7天……

这个没办法了,还请可爱的小静静再忍忍吧!

 

小静静不爽没有关系,我最大的兴趣爱好同时也是我所有课余时间都投身的事业,就是当小静静的出气筒阿!!

有啥不爽就来A我吧!!



Using CVtxButton Implementing the CVtxButton class is surprisingly easy: Include Vtx.h, Vtx.ccp, VtxButton.h, and VtxButton.cpp in your project. Drop a button on your dialog in Developer Studio. Add #include "VtxButton.h" immediately before #include "MyDlg.h" in MyDlg.cpp and MyApp.cpp. For each button on the dialog that you want to be a CVtxButton, add CVtxButton m_cButton1; immediately after //{{AFX_DATA(CMyDlg) in the public section of your dialog class' specification. Also add DDX_Control(pDX, IDC_BUTTON1, m_cButton1); immediately after //{{AFX_DATA_MAP(CMyDlg) in DoDataExchange() for each button. This is enough to create a default CVtxButton. The button is drawn as a rectangle that takes up the entire client area. The sides will not be shaded the same as CButton because they are colored according to the difference of their angle and the angle of light source. If you use at least one CVtxButton on a dialog, it is suggested that you change all your CButton's to CVtxButton's to maintain a coordinated look. If you want to change the look of the CVtxBuUtton, there are two ways of doing so: Use a predefined shape by adding m_cButton1.SetVtx(VTX_RECT); to OnInitDialog() in MyDlg.cpp. There are four predefined shapes which can be passed as an argument to SetVtx(): VTX_RECT VTX_DIAMOND VTX_CIRCLE VTX_STRETCHEDCIRCLE Create a CVtxPolygons object and pass it as an argument to SetVtx(): CRect rect; m_cButton1.GetClientRect(&rect); // Get the button's original dimensions CVtxPolygons vtxPolygons; int offset[4] = {0, 1, 2, 4}; for (int i = 0; i < 4; i++) // Iterate through each of the polygons { // Add the corners vtxPolygons.Add(i, CVertex(rect.left + offset[i], rect.top + offset[i])); vtxPolygons.Add(i, CVertex(rect.right - offset[i] - 1, rect.top + offset[i])); vtxPolygons.Add(i, CVertex(rect.right - offset[i] - 1, rect.bottom - offset[i] - 1)); vtxPolygons.Add(i, CVertex(rect.left + offset[i], rect.bottom - offset[i]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值