Lớp Scroll Bar Trong Lập Trình C Trên Windows

LỚP SCROLL BAR TRONG LẬP TRÌNH C TRÊN WINDOWS

Trong các chương trước thanh cuộn cửa sổ được tạo ra bằng cách sử dụng hai thông số WS_VSCROLL hay WS_HSCROLL, thanh cuộn được tạo ra trong trường hợp này nằm ở bên dưới hoặc bên phải vùng client. Bây giờ tạo lập một control thanh cuộn mà kiểu điều khiển thanh cuộn này xuất hiện bất cứ nơi nào trong vùng thao tác. Bằng cách sử dụng lớp "scrollbar" cùng với hai kiểu thanh cuộn định nghĩa sẵn SBS_VERT và SBS_HORZ.
Không giống như các kiểu control điều kiển đã đề cặp ở trên, các control thanh cuộn ở đây không gởi thông điệp WM_COMMAND, mà lại gởi thông điệp WS_VSCROLL và WS_ HSCROLL cho cửa sổ cha. Có thể phân biệt được thanh cuộn cửa sổ và kiểu điều khiển thanh cuộn thông qua tham số lParam. Tham số này sẽ bằng 0 nếu như thanh cuộn này là thanh cuộn cửa sổ, còn tham số này sẽ bằng handle của cửa sổ thanh cuộn nếu như thanh cuộn đó là một kiểu điều khiển. Còn tham số wPram thì giống nhau cho cả hai loại thanh cuộn cửa sổ và kiểu điều khiển thanh cuộn.
Bạn có thể tạo một kiểu điều khiển thanh cuộn với chiều dài và chiều rộng tùy ý. Nếu bạn muốn tạo một kiểu điều khiển thanh cuộn có kích thước bằng kích thước của thanh cuộn cửa sổ. Thì dùng hai hàm sau để lấy chều cao và chiều rộng của thanh cuộn cửa sổ.
GetsystemMetrics (SM_CYHCROLL) ;
GetsystemMetrics (SM_CXVCROLL) ;
Tương tự như thanh cuộn cửa sổ chúng ta có thể đặt vùng và vị trí cho kiểu điều khiển thanh cuộn hàm.
SetScrollRange (hwndScroll, SB_CTL, iMin, iMax, bRedraw) ;
hwnScroll là handle của control thanh cuộn. Tham số SB_CTL là một trong hai kiểu SBS_VERT tương ứng với thanh cuộn ngang vàSBS_HORZ tương ứng với thanh cuộn đứng. Theo mặc định thì thanh cuộn nằm trong vùng có giá trị từ 0 đến 100 đơn vị chiều dài, tuy nhiên có thể đặt lại vùng thanh cuộn thông qua hai tham số iMin tương ứng với chặn dưới của vùng và iMax tương ứng với chặn trên của vùng. Tham số nRedraw mang một trong hai giá trị TRUE hoặc FALSE, nếu muốn Windows vẽ lại thanh cuộn dựa trên vùng mới thì phải đặt giá trị này bằng TRUE, còn ngược lại thì đặt giá trị này bằng FALSE.
Dùng hàm sau để đặt lại vị trí con chạy trên thanh cuộn.
SetScrollPos (hwndScroll, SB_CTL, iPos, bRedraw);
Với iPos là vị trí cần đặt con chạy trên vùng control thanh cuộn.

Giao diện bàn phím đối với thanh cuộn

Có thể dùng bàn phím để di chuyển con chạy trên vùng control thanh cuộn khi thanh cuộn đó nhận được focus nhập. Sau đây là các phím di chuyển cùng với các chức năng của nó trên control thanh cuộn.
Các giá trị wParam của thông điệp thanh cuộn
Các phím di chuyểnGiá trị wParam của thông điệp thanh cuộn
HomeSB_TOP
EndSB_BOTTOM
Page UpSB_PAGEUP
Page DownSB_PAGEDOWN
Left hay UpSB_LINEUP
Right hay DownSB_LINEDOWN
Đặt focus nhập cho các thanh cuộn bằng hàm.
SetFocus (hwndScroll);
Với hwnScroll là handle của control thanh cuộn. Muốn đặt focus cho một thanh cuộn nào đó khi khởi động chương trình thì phải đặt focus này khi xử lý thông điệp WM_SETFOCUS trong thủ tục WndProc. Vì lý do, thanh cuộn chỉ quan tâm đến các phím di chuyển, nó không quan tâm đến phím Tab. Điều này làm cho việc sử dụng phím Tab để di chuyển focus nhập từ thanh cuộn này đến thanh cuộn khác gặp nhiều khó khăn. Tuy nhiên để giải quyết vần đề này ta nguyên cứu các kỹ thuật sau.
Nhận địa chỉ thủ tục window của các control thanh cuộn bằng hàm GetWindowLong với định danh GWL_ID. Bạn có thể đặt thủ tục Windows cho thanh cuộn bằng hàm SetWindowLong với định danh GWL_WNDPROC. Trong ví dụ sau đây, hàmSetWindownLong đặt thủ tục window cho thanh cuộn mới và trả về địa chỉ thủ tục window thanh cuộn củ.
Ở hàm xử lý thanh cuộn ScrollProc trong ví dụ sau nhận tất cả các thông điệp gửi đến thủ tục window thanh cuộn. Hàm này chỉ đơn giản thay đổi focus nhập giữa các thanh cuộn khi bấm phím Tab hay Shift-Tab, bằng cách gọi window thanh cuộn củ thông qua hàm CallWindowProc.

Tô màu các thanh cuộn và các static text

Màu của các thanh cuộn được thực hiện bằng cách xử lý các thông điệp WM_CTLCOLORSCROLLBAR.
Trong ví dụ sau ở hàm WinProc ta định nghĩa một mảng gồm có 3 phần tử mỗi phần tử là một handle chổi tô (brush) cho một thanh cuộn.
static HBRUSH hBrush[3];
Các chổi tô trên được tạo ra bằng hàm CreateSolidBrush trong thủ tục xử lý thông điệp WM_CREATE .
for (i = 0; i < 3; i++)
{
hBrush [i] = CreateSolidBrush (color [i]);
}
Trong đó color chứa các giá trị màu sơ cấp RGB (RedGreenBlue). Một trong 3 chổi tô (brush) được trả về khi xử lý thông điệpWM_CTLCOLORCROLLBAR trong thủ tục WinProc bằng đoạn chương trình sau.
case WM_CTLCOLORCROLLBAR:
i = GetWindowLong (HWND) lParam, GWL_ID) :
return (LRESULT) hBrush [i];
Chú ý : Các chổi tô phải được hủy bỏ trước khi kết thúc chương trình thông qua hàm DeleteOject khi xử lý thông điệpWM_DESTROY trong thủ tục xử lý WinProc.
for (i = 0; i < 3; i++)
DeleteObject (hBrush [i]);
Các static text được tô màu tương tự như các thanh cuộn, bằng cách xử lý thông điệp WM_CTLCOLORSTATIC trong thủ tụcWinProc thông qua hàm SetTextColor. Dùng hàm SetBkColor để đặt màu nền chữ, trong ví dụ sau thì màu nền chữ trùng với màu hệ thống COLOR_BTNHIGHLIGHT. Đối với các Static text tĩnh ta chỉ áp dụng màu nền chữ cho hình chữ nhật nằm sau mỗi ký tự chứ không phải toàn bộ chiều rộng của cửa sổ control. Để thực hiện điều này, trong thủ tục WndProc hàm xử lýWM_CTLCOLORSTATIC phải trả về một handle cho một chổi tô (brush) của màu COLOR_BTNHIGHLIGHT. Các chổi tô này được tạo ra khi xử lý thông điệp WM_CREATE và phải được hủy khi xử lý thông điệp WM_DESTROY.

Tô màu nền cửa sổ

Trong ví dụ dưới đây đã tạo ra cửa sổ và một chổi tô màu đen cho vùng thao tác cho cửa sổ này.
Wndclass.hbrBackground = CreateSolidBrush (0) ;
Khi thay đổi việc chọn trên các thanh cuộn thì chương trình tạo ra một chổi tô (brush) mới và chèn handle của chổi tô mới này vào cửa sổ ở trên. Nhận hay đặt handle của chổi tô (brush) bằng hàm GetClassWord và hàm SetClassWord. Có thể tạo một chổi tô (brush) mới và chèn handle của chổi tô này vào cấu trúc của cửa sổ, sau đó xóa chổi tô (brush) cũ.
DeleteObject ( (HBRUSH)SetClassLong( hwnd, GCL_HBRBACKGROUND, (LONG)CreateSolidBrush(RGB (icolor[0], icolor[1], icolor[2])))) ;
Windows sẽ dùng chổi tô mới này để tô vùng thao tác cho lần tô kế tiếp. Dùng hàm sau để xóa 2/3 bên phải của vùng thao tác trước khi vẽ lại vùng này.
InvalidateRect (hwnd, &icolor, TRUE) ;
Hàm InvalidateRect làm cho window đặt thông điệp WM_PAINT vào trong hằng đợi các thông điệp của thủ tục xử lý window. Mà thông điệp WM_PAINT có độ ưu tiên thấp hơn các thông điệp xử lý bàn phím hay chuột nên nó được xử lý sau. Nếu muốn vùng cửa sổ được cập nhật lại màu ngay sau khi di chuyển con chạy trên thanh cuộn thì dùng hàm.
UpdateWindow (hwnd) ;
Tuy nhiên nếu chúng ta dùng hàm này thì làm cho tốc độ xử lý thông điệp chuột và bàn phím chậm lại.
Hàm WndProc không xử lý thông điệp WM_PAINT mà đưa cho hàm DefWindowProc. Như chúng ta biết windows xử lý mặc định thông điệp WM_PAINT chỉ đơn giản là lời gọi hàm BeginPaint và EndPaint. Nhưng ở trên chúng ta chỉ định InvalidateRect là phần nền cần phải xóa, chính điều này hàm BeginPaint sẽ khiến cho Windows tự động phát sinh thông điệp xóa nềnWM_ERASEBKGND.
Chú ý : phải dọn dẹp các chổi tô trước khi chương trình kết thúc bằng hàm DeleteOject trong khi xử lý thông điệp WM_DESTROY.


Ứng dụng minh họa lớp Scroll Bar

Một ứng dụng của thanh cuộn

Hình 3.4 minh họa một ứng dụng về thanh cuộn (Scroll Bar). Trong ví dụ này, ta sử dụng 3 thanh cuộn và 6 static text. Bằng cách dùng chuột hay bàn phím, ta di chuyển con trượt trên thanh cuộn để thay đổi giá trị màu. Màu thay đổi tương ứng sẽ là màu tô của vùng client ở bên cạnh. Ba stactic text ở dưới mỗi thanh cuộn dùng để ghi nhận giá trị màu thay đổi tương ứng với các thanh cuộn.
SCROLLBAR.CPP (trích dẫn)
int idFocus ;
WNDPROC OldScroll[3] ;
LRESULTCALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static COLORREF crPrim[3] = { RGB (255, 0, 0), RGB (0, 255, 0),
RGB (0, 0, 255) };
static HBRUSH hBrush[3], hBrushStatic;
static HWND hwndScroll[3], hwndLabel[3], hwndValue[3], hwndRect;
static int color[3], cyChar ;
static RECT rcColor ;
static TCHAR *szColorLabel[] = { TEXT("Red"),
TEXT("Green"), TEXT("Blue") } ;
HINSTANCE hInstance ;
int i, cxClient, cyClient ;
TCHAR szBuffer[10] ;
switch (message)
{
case WM_CREATE :
hInstance = (HINSTANCEGetWindowLong (hwnd, GWL_HINSTANCE) ;
hwndRect = CreateWindow (TEXT("static"), NULL, WS_CHILD | WS_VISIBLE | SS_WHITERECT, 0, 0, 0, 0, hwnd, (HMENU) 9, hInstance, NULL) ;
for (i = 0 ; i < 3 ; i++)
{
hwndScroll[i] = CreateWindow (TEXT ("scrollbar"), NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | SBS_VERT, 0, 0, 0, 0, hwnd, (HMENU) i, hInstance, NULL) ;
SetScrollRange(hwndScroll[i], SB_CTL, 0, 255, FALSE);
SetScrollPos (hwndScroll[i], SB_CTL, 0, FALSE) ;
hwndLabel[i] = CreateWindow ( TEXT("static"), szColorLabel[i], WS_CHILD|WS_VISIBLE|SS_CENTER, 0, 0, 0, 0, hwnd, (HMENU) (i + 3), hInstance, NULL) ;
hwndValue [i] = CreateWindow (TEXT ("static"), TEXT ("0"), WS_CHILD | WS_VISIBLE | SS_CENTER, 0, 0, 0, 0, hwnd, (HMENU) (i + 6), hInstance, NULL) ;
OldScroll[i] = (WNDPROCSetWindowLong ( hwndScroll[i], GWL_WNDPROC, (LONGScrollProc) ;
hBrush[i] = CreateSolidBrush (crPrim[i]) ;
}
hBrushStatic = CreateSolidBrush GetSysColor (COLOR_BTNHIGHLIGHT)) ;
cyChar = HIWORD (GetDialogBaseUnits ()) ;
return 0 ;
case WM_SIZE :
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
SetRect (&rcColor, 0, 0, cxClient/1.5, cyClient) ;
MoveWindow (hwndRect, cxClient/1.5, 0, cxClient/2, cyClient, TRUE) ;
for (i = 0 ; i < 3 ; i++)
{
MoveWindow (hwndScroll[i], ((int)(1.2 * i + 1) * cxClient) / 13 + (int)cxClient/1.5, 2*cyChar, cxClient / 17, cyClient - 4 * cyChar, TRUE) ;
MoveWindow (hwndLabel[i], (2.3 * i + 1) * cxClient / 28+ cxClient/1.5, cyChar / 2, cxClient / 8, cyChar, TRUE) ;
MoveWindow (hwndValue[i], (2.3 * i + 1) * cxClient / 28+ cxClient/1.5, cyClient - 3 * cyChar / 2, cxClient / 8, cyChar, TRUE) ;
}
SetFocus (hwnd) ;
return 0 ;
case WM_SETFOCUS :
SetFocus (hwndScroll[idFocus]) ;
return 0 ;
case WM_VSCROLL :
i = GetWindowLong ((HWND) lParam, GWL_ID) ;
switch (LOWORD (wParam))
{
case SB_PAGEDOWN :
color[i] += 15 ;
case SB_LINEDOWN :
color[i] = min (255, color[i] + 1) ;
break;
case SB_PAGEUP :
color[i] -= 15 ;
case SB_LINEUP :
color[i] = max (0, color[i] - 1) ;
break;
case SB_TOP :
color[i] = 0 ;
break ;
case SB_BOTTOM :
color[i] = 255 ;
break ;
case SB_THUMBPOSITION :
case SB_THUMBTRACK :
color[i] = HIWORD (wParam) ;
break ;
default :
break ;
}
SetScrollPos (hwndScroll[i], SB_CTL, color[i], TRUE) ;
wsprintf (szBuffer, TEXT ("%i"), color[i]) ;
SetWindowText (hwndValue[i], szBuffer) ;
DeleteObject ( (HBRUSH)SetClassLong( hwnd, GCL_HBRBACKGROUND, (LONG)CreateSolidBrush RGB( color[0], color[1], color[2] ) ) ) ) ;
InvalidateRect (hwnd, &rcColor, TRUE) ;
return 0 ;
case WM_CTLCOLORSCROLLBAR :
i = GetWindowLong ((HWND) lParam, GWL_ID) ;
return (LRESULT) hBrush[i] ;
case WM_CTLCOLORSTATIC :
i = GetWindowLong ((HWND) lParam, GWL_ID) ;
if (i >= 3 && i <= 8)
{
SetTextColor ((HDC) wParam, crPrim[i % 3]) ;
SetBkColor ( (HDC) wParam, GetSysColor ( COLOR_BTNHIGHLIGHT ) );
return (LRESULT) hBrushStatic ;
}
break ;
case WM_SYSCOLORCHANGE :
DeleteObject (hBrushStatic) ;
hBrushStatic = CreateSolidBrush GetSysColor (COLOR_BTNHIGHLIGHT)) ;
return 0 ;
case WM_DESTROY :
DeleteObject ((HBRUSHSetClassLong (hwnd, GCL_HBRBACKGROUND, (LONGGetStockObject (WHITE_BRUSH))) ;
for (i = 0 ; i < 3 ; i++)
DeleteObject (hBrush[i]) ;
DeleteObject (hBrushStatic) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
LRESULT CALLBACK ScrollProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int id = GetWindowLong (hwnd, GWL_ID) ;
switch (message)
{
case WM_KEYDOWN :
if (wParam == VK_TAB)
SetFocus (GetDlgItem (GetParent (hwnd), (id + (GetKeyState (VK_SHIFT) < 0 ? 2 : 1)) % 3)) ;
break ;
case WM_SETFOCUS :
idFocus = id ;
break ;
}
returnCallWindowProc(OldScroll[id],hwnd,message,wParam,lParam);
}

0 Comment:

Đăng nhận xét

Thank you for your comments!