TUT COMBOBOX
Author: Benina 2006
Trước khi đọc tut này, các bạn nên đọc
qua tut số 9,10 trong lọat tuts Iczelion để nắm các kiến thức cơ bản.Tut
này tôi viết rất đơn giản, nó là tut lưu trữ cho tôi.
Dowload source :
http://masm32vn.com/files/combobox.rar
Hay http://h1.ripway.com/benina/files/combobox.rar
A. Lý
thuyết:
1. Một Combo Box là
gì:
A combo box is a unique type of control,
defined by the COMBOBOX class, that combines much of the functionality of a list
box and an edit control.
This overview describes the types and styles of
combo box, the parts of a combo box, the use of an owner-drawn combo box, and
how to subclass a combo box. Additional features of combo boxes are also
discussed.
|
2.Các đặc tính cơ bản cần quan tâm
của một combobox:
-String : của item
được chọn hiển thị trong hộp chọn combobox.
Các thông điệp sử dụng để truyền thông:
CB_ADDSTRING; CB_DELETESTRING; CB_INSERTSTRING; CB_SELECTSTRING; CB_LIMITTEXT
Lấy các thuộc tính string như chiều dài
và chuổi string: CB_GETLBTEXT; CB_GETLBTEXTLEN
-Index: chỉ mục
thành phần của item của combobox
Các thông điệp dùng để truyền thông:
CB_GETCURSEL; CB_SETCURSEL; CB_SELECTSTRING; CB_FINDSTRING; CB_GETTOPINDEX;
CB_RESETCONTENT;
Chú ý: item đầu tiên có index là
0
-Data: là một
giá trị 32-bits liên quan đến item
Các thông điệp dùng để truyền
thông:
CB_SETITEMDATA; CB_GETITEMDATA
3. Cách truyền thông tin và lấy thông
tin từ combobox.
Ta dùng hàm SendMessage để truyền thông cho
combobox
Hàm
SendMessage gởi message được
chỉ định đến một window hay
windows. Hàm này gọi thủ tục
window được chỉ định và ko return cho đến khi window procedure thực hiện xong
thông điệp message. Hàm PostMessage, trái lại, post một message đến một chuổi thông điệp của thread (thread's message
queue) và
return ngay lập tức.
LRESULT SendMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to send
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
Parameters
hWnd
Chỉ định window mà
window procedure của nó sẽ nhận message. Nếu tham số này là HWND_BROADCAST, message được gởi đến tất cả các top-level windows trong system, bao gồm các unowned windows
disabled (mất hiệu lực)
hay invisible (ko trông thấy),
overlapped windows (các windows bị đè), và pop-up windows; nhưng message ko được gởi đến child windows.
Msg
Chỉ định thông điệp được gởi
wParam
Chỉ định các thông tin chỉ định thông
điệp add thêm
lParam
Chỉ định các thông tin chỉ định thông
điệp add thêm
Return Values
Giá trị trả về chỉ định kết quả
of message xử lý và dựa trên message sent.
Remarks
Các ứng dụng cần để truyền thông sử
dụng HWND_BROADCAST sẽ dùng hàm
RegisterWindowMessage để đạt được chỉ một thông điệp cho sự truyền
thông inter-application.
Nếu window chỉ định đã được cài đặt bởi
calling thread, thủ tục window procedure được gọi ngay lập tức như một subroutine. Nếu
window chỉ định đã được cài đặt bởi một
thread khác, Windows bật
thread đó và calls window procedure
thích hợp. Messages gởi giữa các threads được xử lý chỉ khi thread nhận thực thi code
thu lại thông điệp (message retrieval code). Thread gởi đi bị blocked cho
đến khi thread nhận được xử lý message.
|
Ví dụ :
invoke
SendMessage,hCombo,CB_GETCOUNT,0,0
4. Một số thông điệp làm việc trên
combobox dùng cho hàm SendMessage.
a/Thao tác trên String của
combobox
CB_ADDSTRING : Thêm string vào list box của
combobox
CB_DELETESTRING: Xóa string trong list box
của combobox
CB_INSERTSTRING: Chèn string vào list box
của combobox
CB_SELECTSTRING: Tìm trong list của combobox
cho một item bắt đầu với các ký tự như string được chỉ định. Nếu một
item phù hợp như vậy, nó sẽ được chọn và được copy đến edit
control
CB_LIMITTEXT: Giới hàn chiều dài một
string mà người dùng có thể đánh vào trong hộp Edit box của
combobox
Lấy các thuộc tính string như chiều dài
và chuổi string:
CB_GETLBTEXT: : Nhận một string từ trong
list của combobox
CB_GETLBTEXTLEN
b/Thao tác trên Index của item
combobox:
CB_GETCURSEL: Nhận index của item được chọn
hiện hành
CB_SETCURSEL: Chọn một string trong list của
combobox là string hiện hành
CB_FINDSTRING: Tìm trong list của combobox
cho một item có string giống string chỉ định, giá trị trả về là index
của item tìm được.
CB_GETTOPINDEX: to
retrieve the zero-based index of the first visible item in
the list box portion of a combo box. Initially the item with index 0 is at the top of the list box, but if
the list box contents have been scrolled, another item may be at the top.(lấy
index của item đầu tiên trong list box)
CB_RESETCONTENT:
to remove all items from the list box and edit control of a
combo box. (Xóa tất cả các items)
CB_GETCOUNT : Nhận tổng số các
items
C/Thao tác trên data cuả item
combobox:
CB_SETITEMDATA: Set một số 32-bits liên quan
đến item chỉ định
CB_GETITEMDATA: Set một số 32-bits liên quan
đến item chỉ định
Tham khảo thêm trong Win32
Reference.
B. Thực hành
:
Ví dụ này làm rõ cách truyền thông với
combobox như : add thêm 1 item với string mà user đánh vào trong hộp “Edit
a New Item” (tôi ko code phần check string user đánh vào là null, đây là
một bài tập cho bạn đọc). Select 1 item trong combobox lúc đó trong phần
“Combobox Item Properties” sẽ tự động hiện thị các đặc tính của item
hiện hành. Delete item hiện hành khỏi list combobox. Xóa tất cả các
items của combobox. Get và Set data cho item.
1. Trong RadASM ta cài đặt 1 project mới
dùng template là DialogAsMain
2.Ta sọan thảo giao diện ví dụ như sau:
ComboCount là tộng số items của
combobox
Current Index, String, String length là các
đặc tính của item hiện hành
Hộp “Edit a New Item” để người dùng đánh 1
string vào dùng để Add 1 item cho combobox.
Các Button hành động giống tên của
nó.
3.Khai báo các ID và biến trong file
.inc
;-----Khai bao cac ID
cua dialog---------------------------
IDC_CBO1 equ
1001
IDC_EDTCount equ
1009
IDC_EDTIndex equ
1022
IDC_EDTString
equ 1010
IDC_EDTLen
equ 1011
IDC_EDTText
equ 1012
IDC_BTNDelete equ
1013
IDC_BTNAdd
equ 1014
IDC_BTNClearAll equ
1015
IDC_BTNGet
equ 1017
IDC_BTNSet equ
1018
IDC_BTNExit
equ 1019
;-----------------------------------------------------------
4.Khai báo các biến sau đây để dùng
trong ví dụ chúng ta sau này:
Trong .const chúng ta edit lại biến
sau
.const
................
AppName db 'Example
Combobox',0 ; Edit lai
...............
Chúng ta tạo thêm các biến sau:
;------------khai bao
cac bien ---------------
.data
String1 db 'Item 1',0
String2 db 'Item 2',0
ItemSet db 'Item is set!',0
NoSelection db 'This
item doesnt contain data yet, or is 0.',10,13,'Please add Item data first.'
,0
;---------------------------------------------
Vá cuối cùng trong .data? ta thêm biến
sau
.data?
..........................
hCombo dd ?
5.Trong phần xử lý thông điệp
WM_INITDIALOG
Ta cần lấy handle của Combobox
;/* Combobox setup
*/
invoke
GetDlgItem,hWin, IDC_CBO1
mov hCombo,eax
Sau đó ta thêm các lệnh sau đế setup
combobox
;--------------------------------------
;/* Setup combobox startup*/
invoke SendMessage,hCombo,CB_ADDSTRING,0,offset String1
invoke SendMessage,hCombo,CB_ADDSTRING,0,offset String2
;/*Set last item to current item of combobox*/
invoke SendMessage,hCombo,CB_GETCOUNT,0,0
mov edx,eax
dec edx
invoke SendMessage,hCombo,CB_SETCURSEL,edx,0
call FillItem
;--------------------------------------
6. Hàm FillItem để lắp các giá trị cho các thành
phần giao diện edit box, combobox trong giao diện ví dụ của chúng
ta.
FillItem proc
LOCAL
buffer[256]:BYTE
;/* loading infos about the selected item into
"Combobox Item Properties" */
;/*Set Count box*/
invoke
SendMessage,hCombo,CB_GETCOUNT,0,0
mov edx,eax
invoke dwtoa,edx,addr buffer
invoke
SendDlgItemMessage,hWnd,IDC_EDTCount,WM_SETTEXT,0,addr buffer
;/* Set Index box*/
invoke SendMessage, hCombo, CB_GETCURSEL, 0,
0
mov ebx, eax
invoke dwtoa,ebx,addr buffer
invoke
SendDlgItemMessage,hWnd,IDC_EDTIndex,WM_SETTEXT,0,addr buffer
;/* Set String box*/
invoke SendMessage, hCombo, CB_GETLBTEXT, ebx, addr
buffer
invoke
SendDlgItemMessage,hWnd,IDC_EDTString,WM_SETTEXT,0,addr buffer
;/*Set String Lenght*/
invoke
SendMessage,hCombo,CB_GETLBTEXTLEN,ebx,0
mov edx,eax
invoke dwtoa,edx,addr buffer
invoke
SendDlgItemMessage,hWnd,IDC_EDTLen,WM_SETTEXT,0,addr buffer
;/*--------------------------------------------------------------------------*/
;Set null for Edit Text
invoke
SendDlgItemMessage,hWnd,IDC_EDTText,WM_SETTEXT,0,0
ret
FillItem endp
7. Tham khảo trước hàm dwtoa để dùng
sau này:
Là một hàm trong thư viện masm32.lib của
masm32
Vì vậy trước khi dùng nó chúng ta phải
khai báo:
include
masm32.inc
includelib
masm32.lib
Hàm này chuyển đổi 1 DWORD thành một
string ascii. Tham khảo phần Help của masm32
dwtoa
dwtoa proc public
uses esi edi dwValue:DWORD, lpBuffer:PTR BYTE
Note that the parameter lpBuffer is an address
of DWORD size.
Description
dwtoa convert a DWORD value to an ascii
string.
Parameters
1. dwValue The DWORD value to
convert.
2. lpBuffer The address of the
buffer to put the converted DWORD into.
Return Value
There is no return value.
Comments
The buffer for the converted value should be
large enough to hold the string including the terminating zero
|
Đây là source của hàm này:
;
#########################################################################
;
-----------------------------------------
; This procedure was written by Tim
Roberts
;
-----------------------------------------
.386
.model flat, stdcall ; 32 bit memory
model
option casemap :none ; case
sensitive
.code
;
#########################################################################
dwtoa proc public uses esi edi dwValue:DWORD,
lpBuffer:PTR BYTE
;
-------------------------------------------------------------
; convert DWORD to ascii string
; dwValue is value to be
converted
; lpBuffer is the address of the receiving
buffer
; EXAMPLE:
; invoke dwtoa,edx,ADDR buffer
;
; Uses: eax, ecx, edx.
;
-------------------------------------------------------------
moveax, dwValue
mov edi, [lpBuffer]
; Special case zero.
.if (eax == 0)
mov byte ptr [edi], '0'
mov byte ptr [edi][1], 0
ret
.endif
; Is the value negative?
.if(sdword ptr eax < 0)
mov byte ptr [edi], '-'; store a minus
sign
inc edi
neg eax; and invert the value
.endif
mov esi, edi; save pointer to first
digit
mov ecx, 10
.while (eax > 0); while there is more to
convert...
xor edx, edx
div ecx; put next digit in edx
add dl, '0'; convert to ASCII
mov [edi], dl; store it
inc edi
.endw
mov byte ptr [edi], 0; terminate the
string
; We now have all the digits, but in
reverse order.
.while (esi < edi)
dec edi
mov al, [esi]
mov ah, [edi]
mov [edi], al
mov [esi], ah
inc esi
.endw
ret
dwtoa endp
;
#########################################################################
end
|
8. Sọan thảo phần xử lý thông điệp
WM_COMMAND như sau:
.elseif
eax==WM_COMMAND
mov
eax,wParam
mov
edx,eax
shr
edx,16
and
eax,0FFFFh
.if edx==BN_CLICKED
.if
eax==IDM_FILE_EXIT
invoke
SendMessage,hWin,WM_CLOSE,0,0
.elseif
eax==IDM_HELP_ABOUT
invoke
ShellAbout,hWin,addr AppName,addr AboutMsg,NULL
.elseif eax==IDC_BTNExit
;Exit program
invoke
SendMessage,hWin,WM_CLOSE,0,0
.elseif
eax==IDC_BTNAdd ;Add a new item
;-----------------------------------------------------------------
;/* Add
a item for combobox */
invoke
GetDlgItemText,hWnd,IDC_EDTText, addr buffer, sizeof buffer
invoke
SendMessage,hCombo,CB_ADDSTRING,0,addr
buffer
;/*Set
last item to current item of combobox*/
invoke
SendMessage,hCombo,CB_GETCOUNT,0,0
mov
edx,eax
dec
edx
invoke
SendMessage,hCombo,CB_SETCURSEL,edx,0
;/*Fill
Properties*/
call
FillItem
;-----------------------------------------------------------------
.elseif
eax==IDC_BTNDelete ;Delete a current item
;-----------------------------------------------------------------
;/*
Delete a current item */
invoke
SendMessage,hCombo,CB_GETCURSEL,0,0
invoke
SendMessage,hCombo,CB_DELETESTRING,eax,0
;/*Set
last item to current item of combobox*/
invoke
SendMessage,hCombo,CB_GETCOUNT,0,0
mov
edx,eax
dec
edx ;because the first item index is 0
invoke
SendMessage,hCombo,CB_SETCURSEL,edx,0
;/*Fill
Properties*/
call
FillItem
;-----------------------------------------------------------------
.elseif
eax==IDC_BTNClearAll ;Delete all items
;-----------------------------------------------------------------
;/*
Delete all items */
invoke
SendMessage,hCombo,CB_RESETCONTENT,0,0
;/*Fill
Null for Properties and Edit Text*/
invoke
SendDlgItemMessage,hWin,IDC_EDTCount,WM_SETTEXT,0,0
invoke
SendDlgItemMessage,hWin,IDC_EDTIndex,WM_SETTEXT,0,0
invoke
SendDlgItemMessage,hWin,IDC_EDTString,WM_SETTEXT,0,0
invoke
SendDlgItemMessage,hWin,IDC_EDTLen,WM_SETTEXT,0,0
invoke
SendDlgItemMessage,hWin,IDC_EDTText,WM_SETTEXT,0,0
;------------------------------------------------------------------
.elseif eax==IDC_BTNSet
;Set item
data
;--------------------------------------------------------------------
;Set
Item Data
invoke
SendMessage, hCombo, CB_GETCURSEL, 0, 0
mov
edx,eax
;we move
the DWORD value 100 into a selected item and store it there
mov
mValue,100
invoke
SendMessage,hCombo,CB_SETITEMDATA,edx, [mValue]
invoke
MessageBox,hWin,offset ItemSet,offset AppName,MB_OK
;--------------------------------------------------------------------
.elseif eax==IDC_BTNGet
;Get item
data
;--------------------------------------------------------------------
;Get
Item Data
invoke
SendMessage, hCombo, CB_GETCURSEL, 0, 0
mov
edx,eax
;we
retrieve the stored data, if empty then you get a 0
invoke
SendMessage,hCombo,CB_GETITEMDATA,edx,0
mov
mValue,eax
.if
eax==0
invoke
MessageBox,hWin,offset NoSelection,offset
AppName,MB_ICONEXCLAMATION
jmp Exit
.endif
invoke dwtoa,
mValue,addr buffer
invoke
MessageBox,hWin,addr buffer,offset AppName,MB_ICONINFORMATION
Exit:
;--------------------------------------------------------------------
.endif
.elseif edx==CBN_SELCHANGE
;Change selected item
.if
eax==IDC_CBO1
;Get selected item with
error handler
invoke
SendMessage, hCombo, CB_GETCURSEL, 0, 0
.if eax ==
CB_ERR
jmp
NoSel
.endif
mov ebx, eax
call
FillItem
.endif
NoSel:
;USer didnt made any
choice
.endif
Phân tích tóm tắt:
*Xứ lý thông điệp click vào các button
(BN_CLICKED)
-Button Exit :
Ta gởi thông điệp
WM_CLOSE cho Windows để exit chương trình
-Button Add
Item:
;-----------------------------------------------------------------
;/* Add
a item for combobox */
invoke
GetDlgItemText,hWnd,IDC_EDTText, addr buffer, sizeof buffer
invoke
SendMessage,hCombo,CB_ADDSTRING,0,addr
buffer
;/*Set
last item to current item of combobox*/
invoke
SendMessage,hCombo,CB_GETCOUNT,0,0
mov
edx,eax
dec
edx
invoke
SendMessage,hCombo,CB_SETCURSEL,edx,0
;/*Fill
Properties*/
call
FillItem
;-----------------------------------------------------------------
Đầu tiên lấy string trong hộp edit user
đánh vào, sau đó Add string vào list combox bằng cách gởi thông điệp
CB_ADDSTRING. Tiếp theo set item hiện hành là item sau cùng mới add vào.
Và cuối cùng là fill các thông tin của item hiện hành vào các editbox
properties
-Button Delete
Item:
;-----------------------------------------------------------------
;/*
Delete a current item */
invoke
SendMessage,hCombo,CB_GETCURSEL,0,0
invoke
SendMessage,hCombo,CB_DELETESTRING,eax,0
;/*Set
last item to current item of combobox*/
invoke
SendMessage,hCombo,CB_GETCOUNT,0,0
mov
edx,eax
dec
edx ;because the first item index is 0
invoke
SendMessage,hCombo,CB_SETCURSEL,edx,0
;/*Fill
Properties*/
call
FillItem
;-----------------------------------------------------------------
Dùng CB_GETCURSEL
để lấy index của item hiện hành, tiếp theo dùng CB_DELETESTRING đế xóa
string. Set item hiện hành là item cuối cùng trong list combobox. Và cuối
cùng là fill thông tin vào các editbox properties bằng hàm
FillItem.
-Button Clear All
Items:
;-----------------------------------------------------------------
;/*
Delete all items */
invoke
SendMessage,hCombo,CB_RESETCONTENT,0,0
;/*Fill
Null for Properties and Edit Text*/
invoke
SendDlgItemMessage,hWin,IDC_EDTCount,WM_SETTEXT,0,0
invoke
SendDlgItemMessage,hWin,IDC_EDTIndex,WM_SETTEXT,0,0
invoke
SendDlgItemMessage,hWin,IDC_EDTString,WM_SETTEXT,0,0
invoke
SendDlgItemMessage,hWin,IDC_EDTLen,WM_SETTEXT,0,0
invoke
SendDlgItemMessage,hWin,IDC_EDTText,WM_SETTEXT,0,0
;------------------------------------------------------------------
Dùng
CB_RESETCONTENT để xóa tất cả các items của combobox. Và sau đó là set
giá trị Null cho tất cả các editbox giao diện.
-Button Set
Item:
;--------------------------------------------------------------------
;Set
Item Data
invoke
SendMessage, hCombo, CB_GETCURSEL, 0, 0
mov
edx,eax
;we move
the DWORD value 100 into a selected item and store it there
mov
mValue,100
invoke
SendMessage,hCombo,CB_SETITEMDATA,edx, [mValue]
invoke
MessageBox,hWin,offset ItemSet,offset AppName,MB_OK
;--------------------------------------------------------------------
Lấy item hiện
hành trên combobox, dùng CB_SETITEMDATA để set giá trị 100h cho data item
hiện hành. Xuất ra một hộp thọai MessageBox thông báo cho người dùng
biết.
-Button Get
Item:
;--------------------------------------------------------------------
;Get
Item Data
invoke
SendMessage, hCombo, CB_GETCURSEL, 0, 0
mov
edx,eax
;we
retrieve the stored data, if empty then you get a 0
invoke
SendMessage,hCombo,CB_GETITEMDATA,edx,0
mov
mValue,eax
.if
eax==0
invoke
MessageBox,hWin,offset NoSelection,offset
AppName,MB_ICONEXCLAMATION
jmp Exit
.endif
invoke dwtoa,
mValue,addr buffer
invoke
MessageBox,hWin,addr buffer,offset AppName,MB_ICONINFORMATION
Exit:
;--------------------------------------------------------------------
Dùng
CB_GETITEMDATA để lấy item data của item hiện hành. Xuất ra hộp thông
báo cho người dùng biết giá trị item data, hoặc thông báo cho người
dùng item data chưa được set.
*Xử lý thông
điệp thay đổi thành phần item được chọn trong combobox (CBN_SELCHANGE):
.elseif edx==CBN_SELCHANGE
;Change selected item
.if
eax==IDC_CBO1
;Get selected item with
error handler
invoke
SendMessage, hCombo, CB_GETCURSEL, 0, 0
.if eax ==
CB_ERR
jmp
NoSel
.endif
mov ebx, eax
call
FillItem
.endif
NoSel:
;USer didnt made any
choice
.endif
Phần code này đơn
giản ko cần giải thích.
Đến đây là hết. Tut này tui chỉ để lưu trữ
nên ko viết chi tiết mong các bạn thông cảm. Và nói thêm 1 chút , phần
code trên tôi có tham khảo 1 source trên NET tôi wên mất link rồi, sorry
tác giả.
http://masm32vn.com (thanz NTA)
http://h1.ripway.com/benina/
http://benina.250free.com
Benina
04/06/2006
Update
04/06/2006
Mail:
benina@walla.com
(Không
đồng ý bất kỳ ai sử dụng tài liệu này cho mục đích thương mại nếu
ko được phép của người dịch)