📄 编写 windows 标准控件㈡ .txt
字号:
WM_KILLFOCUS ;失去焦点
invoke ParentNotify,hList,MLN_KILLFOCUS,wParam
and [ebx].fStyle ,not MLFS_FOCUS
invoke InvalidateRect,hList,0,TRUE
同上。只不过是去掉风格。
WM_STYLECHANGED ;风格更改的
mov esi,lParam
assume esi:ptr STYLESTRUCT
.if ([esi].styleOld & WS_VSCROLL) && !([esi].styleNew & WS_VSCROLL)
;去掉滚动条
invoke ShowScrollBar,hList,SB_VERT,0
.elseif !([esi].styleOld & WS_VSCROLL) && ([esi].styleNew & WS_VSCROLL)
invoke ShowScrollBar,hList,SB_VERT,TRUE
.endif
.if ([esi].styleOld & WS_HSCROLL) && !([esi].styleNew & WS_HSCROLL)
;去掉
invoke ShowScrollBar,hList,SB_HORZ,0
.elseif !([esi].styleOld & WS_HSCROLL) && ([esi].styleNew & WS_HSCROLL)
;添加
invoke ShowScrollBar,hList,SB_HORZ,TRUE
.endif
invoke GetClientRect,hList,addr [ebx].rt
invoke SetWindowPos,hList,0,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_DRAWFRAME
invoke InvalidateRect,hList,0,TRUE ;刷新
当窗口的风格变化时,这个消息将被接收。
通过旧风格包含,新风格未包含判定为去掉。旧风格没有,而新风格有,则为加上。当然如果只是单独判断风格是否存在,这也是可行的。
重新获得客户区域是因为当非客户区变化后(滚动条显示/不显示),是不会有WM_SIZE消息的。我们手动重新获得。
然后刷新非客户区域,这样滚动条才会显示/隐藏
WM_MOUSEWHEEL 鼠标滚轮
mov eax,wParam
shr eax,16
movsx eax,ax
.if SDWORD ptr eax<0 ;向上滚动滚轮
invoke SendMessage,hList,WM_VSCROLL,SB_LINEDOWN,0
.elseif SDWORD ptr eax>0 ;向下滚动滚轮
invoke SendMessage,hList,WM_VSCROLL,SB_LINEUP,0
.endif
直接调用滚动消息。唯一需要注意的是,高16位是表示方向,而它是一个有符号数,所以扩展成32位时,必须使用Movsx.
WM_VSCROLL 垂直滚动条
mov sci.cbSize,sizeof SCROLLINFO
mov sci.fMask,SIF_ALL
invoke GetScrollInfo,hList,SB_VERT,addr sci
mov edi,sci.nPos
mov eax,wParam
and eax,0ffffh
.if eax==SB_THUMBTRACK
mov ecx,sci.nTrackPos
mov sci.nPos,ecx
.elseif eax==SB_TOP
mov eax,sci.nMin
mov sci.nPos,eax
.elseif eax==SB_BOTTOM
mov eax,sci.nMax
mov sci.nPos,eax
.elseif eax==SB_LINEUP
dec sci.nPos
.elseif eax==SB_LINEDOWN
inc sci.nPos
.elseif eax==SB_PAGEUP
mov eax,sci.nPage
dec eax
sub sci.nPos,eax
.elseif eax==SB_PAGEDOWN
mov eax,sci.nPage
dec eax
add sci.nPos,eax
.endif
mov sci.fMask ,SIF_POS or SIF_DISABLENOSCROLL
invoke SetScrollInfo,hList,SB_VERT, addr sci, TRUE
invoke GetScrollInfo,hList, SB_VERT, addr sci
mov esi,sci.nPos
.if esi != edi
mov [ebx].iTop,esi
.if esi>edi
mov eax,esi
sub eax,edi
imul eax,[ebx].iHeight
neg eax
invoke ScrollWindow,hList,0,ecx,0,0
.else
mov eax,edi
sub eax,esi
imul eax,[ebx].iHeight
invoke ScrollWindow,hList,0,eax,0,0
.endif
.endif
滚动条消息的处理,设置之后,再获取是为了判断是否是正确的位置,比如如果手动滚动,使用了-1,而滚动条设置函数SetScrollInfo会自动限定在范围内,这个时候再获得的就是正确的位置。
然后通过滚动的相差位置,用ScrollWindow向相反的方向滚动一样的距离。无闪烁滚动,在重绘内容相当复杂,或者用时长时必须要滚动之后再自己重绘.本控件重绘时费的时间相当少,可以直接 Invalidatrect,相差不大.肉眼是看不出来的.
WM_HSCROLL 水平滚动
mov sci.cbSize,sizeof SCROLLINFO
mov sci.fMask,SIF_ALL
invoke GetScrollInfo,hList,SB_HORZ,addr sci
mov edi,sci.nPos
mov eax,wParam
and eax,0ffffh
.if eax==SB_THUMBTRACK
mov eax,sci.nTrackPos
mov sci.nPos,eax
.elseif eax==SB_LEFT
mov eax,sci.nMin
mov sci.nPos,eax
.elseif eax==SB_RIGHT
mov eax,sci.nMax
mov sci.nPos,eax
.elseif eax==SB_LINEUP
mov eax,[ebx].iWidth
sub sci.nPos,eax
.elseif eax==SB_LINEDOWN
mov eax,[ebx].iWidth
add sci.nPos,eax
.elseif eax==SB_PAGEUP
mov eax,sci.nPage
shr eax,1
sub sci.nPos,eax
.elseif eax==SB_PAGEDOWN
mov eax,sci.nPage
shr eax,1
add sci.nPos,eax
.endif
mov sci.fMask ,SIF_POS or SIF_DISABLENOSCROLL
invoke SetScrollInfo,hList,SB_HORZ, addr sci,TRUE
invoke GetScrollInfo,hList, SB_HORZ, addr sci
mov eax,sci.nPos
.if eax != edi
mov [ebx].iLeft,eax
invoke InvalidateRect,hList,0,0
.endif
同上
WM_GETDLGCODE 对话框处理
.if fStyle & MLS_CLASS
mov eax,DLGC_WANTALLKEYS 需要所有按键处理
.else
mov eax,DLGC_WANTARROWS 只需要方向键
.endif
这个消息只在对话框中有效,并且是被动的。默认需要方向键,别的交给对话框处理。如果有MLS_CLASS风格,则处理所有的键。
控件其实并没有处理除方向之外的键,所以这个风格其实是多余的,但是你可以在WM_KEYDOWN消息中处理像VK_RETURN/VK_TAB/VK_SPACE之类的键,做一个判断,这样当有这个风格时,你的处理就可以用了。
WM_SETFONT 设置字体
mov eax,[ebx].hFont
push eax
mov ecx,wParam
mov [ebx].hFont,ecx
invoke GetDC,hList
mov ps.hdc,eax
invoke SelectObject,ps.hdc,[ebx].hFont
invoke GetTextExtentPoint32,ps.hdc,CTXT("W"),1,addr p
mov eax,p.y
.if eax<MIN_HEIGHT
mov eax,MIN_HEIGHT
.endif
mov [ebx].iHeight,eax
mov eax,p.x
mov [ebx].iWidth,eax
invoke ReleaseDC,hList,ps.hdc
pop eax
设置控件显示的字体,并且根据字体的大小,来自动设置高度与字宽。其中字宽在水平滚动时使用。而高度则是项目使用。
字体的设置一般是在创建时,尤其在对话框中,在创建之后会自动发送,之后除非手动设置是不会再有。所以,单独设置项目高度时注意一下。
WM_GETFONT 获得字体
mov eax,[ebx].hFont
获得当前使用的字体
控件自定义消息
MLM_ADDSTRING
mov MI.imask,MIF_TEXT or MIF_IMAGE
invoke lstrlen,lParam
mov MI.cbText,eax
mov eax,lParam
mov MI.lpszText,eax
mov eax,wParam
mov MI.iImage,eax
invoke SendMessage,hList,MLM_SETITEM,-1,addr MI
添加一个项目,wParam是图形索引,-1表示不显示,lParam指向字符串
设置好参数,真正添加的功能在MLM_SETITEM消息中。
MLM_DELETESTRING
mov edi,[ebx].lpItems
mov esi,wParam
.if sdword ptr esi>=0 && esi<[ebx].iCount
invoke HeapFree,[ebx].hHeap,HEAP_NO_SERIALIZE,[edi+esi*4]
;移动数组内存块
mov eax,[ebx].iCount
sub eax,esi
shl eax,2
invoke RtlMoveMemory,addr [edi+esi*4],addr [edi+esi*4+4],eax
dec [ebx].iCount
invoke SendMessage,hList,WM_SIZE,0,0
.endif
删除一个项目,wParam为索引,lParam==0
直接释放内存,然后移动数组内存
MLM_SETITEM ;添加或设置项目数据
wParam==-1时,表示添加一个新项目,否则是修改对应索引的项目。lParam指向ML_ITEM结构
成功返回索引值,失败返回-1
MIF_TEXT equ 1h
MIF_IMAGE equ 2h
MIF_USERDATA equ 4h
ML_ITEM struct
imask dd ? ;MIF_*
cbText dd ?
lpszText dd ?
iImage dd ?
dwData dd ?
ML_ITEM ends
imask标识哪些成员可用。MIF_TEXT时,cbText,lpszText可用。MIF_IMAGE时,iImage可用。MIF_USERDATA包含时,dwData有用。
mov eax,MLM_ERROR
mov esi,lParam
mov edi,[ebx].lpItems
assume esi:ptr ML_ITEM
mov edx,wParam
.if edx==-1
mov eax,[ebx].iCount
inc eax
.if eax>=[ebx].cbItems ;数组太小,重新分配
add eax,1024
shl eax,2
invoke HeapReAlloc,[ebx].hHeap,HEAP_NO_SERIALIZE or HEAP_ZERO_MEMORY,[ebx].lpItems,eax
.if eax==0
@@:
dec eax
jmp @@Ret
.endif
mov [ebx].lpItems,eax
mov edi,eax
add [ebx].cbItems,1024
.endif
判断如果是添加,则比较数组是否还够用,否则重新分配内存,比原来大1024个项目。
xor eax,eax
.if [esi].imask & MIF_TEXT
cmp [esi].cbText,0ffffh ;字串不能超过FFFFh大小
jae @B
mov eax,[esi].cbText
.endif
add eax,sizeof MYLIST_ITEM
.if eax<0FFh
mov eax,0FFh ;最小为0FFh
.endif
invoke HeapAlloc,[ebx].hHeap,HEAP_NO_SERIALIZE or HEAP_ZERO_MEMORY,eax
test eax,eax
jz @B
然后分配项目内存,它是根据字串的长度来分配的,但是大不能超过0FFFF个字节。
@@SetExistItem:
.if [esi].imask & MIF_IMAGE
mov ecx,[esi].iImage
mov [eax].MYLIST_ITEM.iImage,ecx
.else
mov [eax].MYLIST_ITEM.iImage,-1
.endif
.if [esi].imask & MIF_USERDATA
mov ecx,[esi].dwData
mov [eax].MYLIST_ITEM.dwData,ecx
.endif
.if wParam==-1
mov ecx,[ebx].iCount
push ecx
mov [edi+ecx*4],eax
inc [ebx].iCount
.else
push edx
.endif
.if [esi].imask & MIF_TEXT
mov ecx,[esi].cbText
mov [eax].MYLIST_ITEM.cbText,ecx
invoke lstrcpy,addr [eax].MYLIST_ITEM.lpText,[esi].lpszText
invoke GetDC,hList
mov ps.hdc,eax
invoke SelectObject,ps.hdc,[ebx].hFont
invoke GetTextExtentPoint32,ps.hdc,[esi].lpszText,[esi].cbText,addr p
mov eax,p.x
.if eax>[ebx].iMaxWidth
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -