Trao đổi với tôi

http://www.buidao.com

12/29/16

[MASM], TUT COMBOBOX

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)