LỚP LIST BOX TRONG LẬP TRÌNH C TRÊN WINDOWS
List box là tập hợp các chuỗi kí tự được gói gọn trong một hình chữ nhật. Một chương trình có thể thêm hoặc xóa các chuỗi trong list box bằng cách gởi các thông điệp đến thủ tục window của list box. List box control gởi thông điệp WM_COMMAND đến cửa sổ cha khi có một mục trong list box bị đánh dấu. Cửa sổ cha xác nhận các mục trong list box đã bị đánh dấu.
Một list box có thể chọn được một mục hay nhiều mục cùng một lúc (tùy theo loại list box đơn hay kép).
Các kiểu List Box
Chúng ta tạo một cửa sổ con list box bằng hàm CreateWindow với lớp cửa sổ là "listbox" cùng với loại cửa sổ WS_CHILD. Tuy nhiên kiểu cửa sổ con mặt định này không gởi thông điệp WM_COMMAND đến cửa sổ cha, có nghĩa chương trình tự kiểm tra việc đánh dấu các danh mục trong list box. Vì thế, các kiểu điều khiển list box thường định nghĩa kiểu list box LBS_NOTYFY, điều này cho phép cửa sổ cha nhận thông điệp WM_COMMAND từ list box. Nếu muốn sắp xếp các mục trong list box thì sử dụng kiểuLBS_SORT.
Theo mặc định, những list box tạo ra là những list box đơn. Vì thế, nếu muốn tạo ra một list box kép (tức list box cho phép người dùng chọn nhiều dòng cùng lúc) thì phải sử dụng loại list box LBS_MULTIPLESEL.Thông thường, List box sẽ tự cập nhật khi một mục được thêm vào. Tuy nhiên có thể ngăn cản việc cập nhật này bằng kiểu LBS_NOREDRAW. Việc làm này đôi khi không thích lắm, thay vào đó chúng ta có thể sử dụng thông điệp WM_SETREDRAW để ngăn chặn tạm thời việc vẽ lại của list box.
Theo mặc định, các mục trong list box không có đường viền bao quanh khi hiển thị trên màn hình. Tuy nhiên, có thể thêm đường viền cho các mục bằng định danh cửa sổ WS_BORDER. Thêm thanh cuộn đứng vào list box bằng cách thêm định danh cửa sổWS_VSCROLL.
Thông thường windows định nghĩa một list box gồm các thông số sau : LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER.
Ngoài ra còn có các thông số WS_SIZEBOX và WS_CAPTION dùng để thay đổi kích thước và thêm tiêu đề cho list box. Nên tạo ra một list box có chiều rộng bằng chiều dài của chuổi dài nhất trong list box cộng với chiều dài của thanh cuộn dọc. Chiều dài của thanh cuộn dọc được xác định bằng hàm.
GetSystemMetrics(SM_CXVCROLL);
Đặt các chuỗi vào List Box
Để thêm một chuỗi vào list box ta gởi các thông điệp đến thủ tục Windows list box bằng hàm SendMessage. Khi truyền chuỗi cho hàm SendMessage thì thông số wParam là một con trỏ, trỏ đến chuỗi được kết thúc bởi ký tự NULL. Hàm SendMessage trả về mãLB_ERRSPACE (giá trị -2) khi Windows chạy quá không gian bộ nhớ dành cho list box. Hàm SendMessage trả về mã LB_ERR ( -1) khi xảy ra lỗi khác và trả về mã LB_OKAY ( 0 ) nếu thao tác thêm thành công.
Nếu sử dụng kiểu LBS_SORT thì khi thêm một chuỗi vào list box chỉ cần dùng chỉ thị LB_ADDSTRING theo cấu trúc.
SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM) szString);
Với szString là chuỗi cần thêm vào list box.
Nếu trong list box không dùng kiểu LBS_SORT thì có thể chèn một chuỗi với chỉ thị LB_INSERTSTRING cùng vị trí muốn chèn bằng hàm.
SendMessage(hwndList, LB_INSERTSTRING, iIndex, (LPARAM) szString);
iIndex là vị trí muốn chèn chuỗi vào. Nếu giá trị này bằng -1 thì chuỗi được chèn vào đáy của list box.
Xóa một chuỗi trong list box bằng chỉ thị LB_DELETESTRING.
SendMessage(hwndList, LB_DELETESTRING, iIndex, 0);
Xóa hết các phần tử nằm trong list box thì dùng chỉ thị LB_RESETCONTENT với cấu trúc.
SendMessage(hwndList, LB_LB_RESETCONTENT, 0, 0 );
Khi thêm vào hay xóa thì Windows tự cập nhật lại list box. Tuy nhiên ta cũng có thể tạm thời cản sự cập nhật này bằng cách tắt cờ vẽ lại list box.
SendMessage(hwndList, WMSETREDRAW, FALSE, 0);
Sau khi thực hiện xong ta bật cờ vẽ lại list box bằng hàm.
SendMessage(hwndList, WMSETREDRAW, TRUE, 0);
Chọn và lấy các mục trên List Box
Tương tự như đặt chuỗi vào List box , chọn và lấy mục trong List box cũng phải gởi các thông điệp đến thủ tục Window List box bằng hàm SendMessage.
Dùng chỉ thị LB_GETCOUNT để đếm số mục trong List box.
iCount = SendMessage (hwndList, LB_GETCOUNT, 0, 0 );
Làm sáng mục chọn mặc định thì dùng LB_SETCURSEL.
SendMessage (hwndList, LB_SETCURSEL, iIndex, 0 );
Nếu đặt giá trị iIndex bằng -1 thì window sẽ bỏ tất cả các mục chọn. Để chọn các mục dựa trên chữ bắt đầu của mục, ta dùng hàm.
iIndex = SendMessage (hwndlist, LB_SELECTSTRING, iIndex, (LPARAM) szSearchString);
iIndex là vị trí bắt đầu của việc tìm với kí tự đầu giống szSearchString. Nếu giá trị iIndex bằng -1 thì việc tìm bắt đầu từ vị trí đầu tiên. Hàm sẽ trả về giá trị tìm đượci. Nếu chuỗi không tồn tại thì hàm trả về mã lỗi LB_ERR.
Xác định mục đã chọn khi nhận được thông điệp WM_COMMAND từ list box bằng hàm.
iIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
Hàm trả về vị trí của mục được chọn, còn ngược lại nếu không có mục nào được chọn thì hàm trả về mã lỗi LB_ERR.
Muốn xác định chiều dài của một chuỗi bất kỳ có trong list box dùng hàm.
iLength = SendMessage(hwndList, LB_GETTEXTLEN, iIndex, 0);
Với iIndex là ví trí của chuỗi cần xác định chiều dài. Để chép chuỗi trên vào vùng đệp Buffer, ta dùng hàm.
iLength = SendMessage(hwndList, LB_GETTEXT, iInde, (LPARAM) Buffer);
Giá trị trả về của hai hàm trên là chiều dài của chuỗi ký tự. Nên định kích thước vùng buffer sao cho đủ chứa chiều dài của chuỗi cộng thêm ký tự kết thúc chuỗi cần ghi vào.
Tuy nhiên, đối với list box chọn kép thì chúng ta không thể dùng các chỉ thị LB_SETCURSEL, LB_GETCURSEL, hoặcLB_SELECTSTRING. Thay vào đó phải dùng chỉ thị LB_SETSEL để chọn một mục mà không làm ảnh hưởng đến các mục đã chọn khác.
SendMessage(hwndList, LB_SETSEL, wParam, iIndex);
Tham số wParam khác 0 để chọn và làm sáng mục, bằng 0 để hủy việc chọn.
Xác định trạng thái của một mục nào đó trong list box (loại list box chọn kép) dùng hàm.
iSelect = SendMessage(hwndList, LB_GETSEL, iIndex, 0);
Hàm trả về giá trị khác 0 nếu mục có vị trí iIndex được chọn, và bằng 0 nếu mục ở vị trí đó không được chọn.
Nhận các thông điệp từ List Box
Khi dùng chuột nhấn vào list box, khi đó list box nhận focus nhập. Cửa sổ cha có thể đặt focus nhập đến list box bằng hàm.
SetFocus (hwndList);
Khi list box nhận focus nhập, chúng ta dùng con chuột, các phím chữ, phím Spacebar để chọn các mục trong list box. List box gởi thông điệp WM_COMMAND với các thông số wParam, lParam đến cửa sổ cha với ý nghĩa :
LOWORD (wParam) ID cửa sổ con.
HIWORD (wParam) Mã thông báo.
lParam Handle cửa sổ con.
Mã thông báo | Giá trị | Ý nghĩa |
LBN_ERRSPACE | -2 | Con trol list box chạy quá không gian |
LBN_SELCHANGE | 1 | Cho biết mục chọn hiện hành đã thay đổi |
LBN_DBLCLK | 2 | Cho biết một mục đã bị double click với chuột |
LBN_SELCANCEL | 3 | Cho biết người dùng thay đổi mục chọn trong list box |
LBN_SETFOCUS | 4 | Cho biết list box đang nhận được focus nhập |
LBN_KILLFOCUS | 5 | Cho biết list box đã mất focus nhập |
Mã thông báo LBN_ERRSPACE, LBN_SELCHANGE được gởi đến cửa sổ cha khi kiểu cửa sổ list box bao gồm LBS_NOTIFY.
Một ứng dụng List Box
Sau đây là một ví dụ về list box, kết quả chương trình sau khi chạy thể hiện trong hình 3.2.
Trong ví dụ này, ta tạo ra một list box gồm các phần tử cam, chanh, nho… . Khi dùng chuột hay dùng phím Spacebar cộng với phím mũi tên để chọn các mục trong list box, mục được chọn sẽ có màu tô thể hiện được chọn lựa (mặc định trong Windows là màu xanh) và nội dung mục chọn này được hiển thị lên kiểu điều khiển tĩnh nằm bên trên vùng thao tác của cửa sổ chính. Chương trình minh họa như sau (ví dụ 3.2).
* LISTBOX.CPP (trích dẫn)
#include <windows.h>
#define ID_LIST 1
#define ID_TEXT 2
LRESULTCALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
void FillListBox (HWND hwndList)
{
int i;
static TCHAR *tc[]={TEXT("cam"), TEXT("quyt"), TEXT("buoi"), TEXT("tao"), TEXT("chanh"), TEXT("xoai"), TEXT("nho")};
for(i=0; i<7; i++)
SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)tc[i]);
}
LRESULTCALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndList, hwndText ;
int iIndex, iLength, cxChar, cyChar ;
TCHAR *pVarName;
switch (message)
{
case WM_CREATE :
cxChar = LOWORD (GetDialogBaseUnits ()) ;
cyChar = HIWORD (GetDialogBaseUnits ()) ;
// Tạo một listbox
hwndList = CreateWindow ( TEXT("listbox"), NULL, WS_CHILD | WS_VISIBLE | LBS_NOTIFY | LBS_STANDARD, cxChar, cyChar * 3, cxChar * 16 + GetSystemMetrics (SM_CXVSCROLL), cyChar * 5, hwnd, (HMENU) ID_LIST, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL ) ;
// tạo một control "static"
hwndText = CreateWindow ( TEXT("static"), NULL, WS_CHILD | WS_VISIBLE | SS_LEFT, cxChar, cyChar, GetSystemMetrics(SM_CXSCREEN), cyChar, hwnd, (HMENU) ID_TEXT, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL) ;
FillListBox (hwndList) ;
return 0 ;
case WM_SETFOCUS : //đặt focus nhập cho list box
SetFocus (hwndList) ;
return 0 ;
//xử lý các thông điệp khi chọn mục trong list box
case WM_COMMAND :
if (LOWORD (wParam) == ID_LIST && HIWORD (wParam) == LBN_SELCHANGE)
{
// lấy chỉ ví trí của mục được chọn
iIndex=SendMessage(hwndList,LB_GETCURSEL, 0, 0);
iLength = SendMessage (hwndList, LB_GETTEXTLEN, iIndex, 0) + 1 ;
pVarName =(char*) calloc (iLength, sizeof (TCHAR)) ;
SendMessage ( hwndList, LB_GETTEXT, iIndex, (LPARAM)pVarName) ;
SetWindowText (hwndText, pVarName) ;
free (pVarName) ;
}
return 0 ;
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
Khi dùng chuột hay bàn phím chọn mục trong list box, thì list box gởi thông điệp WM_COMMAND cho thủ tục WndProc của cửa sổ cha xử lý. Khi thủ tục WndProc nhận được thông điệp WM_COMMAND, nó kiểm tra word thấp của tham số wParam có bằng định danh của list box (ở ví dụ trên là ID_LIST) không và word cao của tham số wParam(mã thông báo) có bằng LBN_SELCHANGEkhông. Nếu bằng, nó lấy chỉ số của mục được chọn thông qua hàm:
SendMessage (hwndList, LB_GETCURSEL, 0, 0) ;
Và tiếp tục lấy nội dung của mục được chọn thông qua hàm.
SendMessage ( hwndList, LB_GETTEXT, iIndex, (LPARAM) pVarName);
Sau cùng, hiển thị mục được chọn lên control tĩnh thông qua hàm.
SetWindowText (hwndText, pVarName);
0 Comment:
Đăng nhận xét
Thank you for your comments!