Tài liệu này dành cho sinh viên, giáo viên khối ngành công nghệ thông tin tham khảo và có những bài học bổ ích hơn, bổ trợ cho việc tìm kiếm tài liệu, giáo án, giáo trình, bài giảng các môn học khối ngành công nghệ thông tin
Trang 1Lập trình hệ thống
GV: Trần Nhật Hóa Bm: Công nghệ PM
Trang 2Chương 1 Cơ sở lập trình hệ thống
Giao tiếp người dùng đồ họa
Đa nhiệm.
Chia sẻ thủ tục mà Windows cung cấp.
Sử dụng thư viện liên kết động (DLL).
Có tính tương thích cao.
Xây dựng dựa trên kiến trúc mở.
Trang 32 Hoạt động của ứng dụng
Theo hướng sự kiện.
được chứa trong duy nhất trong một file.
là thành phần giao tiếp của ứng dụng đối với người dùng gồm các thành phần cơ bản:
thanh tiêu đề
đường viền cửa sổ
vùng làm việc (vùng client…)
Trang 43 Các khái niệm cơ bản
Trang 53 Các khái niệm (tt)
Thông điệp (Message):
Một sự kiện xảy ra luôn phát sinh ra một thông điệp
Thông điệp cho biết bản chất của sự kiện đó là gì
Thông điệp đi kèm bởi các thông tin bổ sung được chứa trong các thông số của nó
Hàng đợi thông điệp (Message queue)
Mỗi ứng dụng đều có một hàng đợi để chứa các thông điệp dành cho nó (tuân theo nguyên tắc FIFO).
Hàng đợi thông điệp do Windows cung cấp
Các thông điệp có thể vào hàng đợi hoặc không tùy thuộc vào độ ưu tiên của các thông điệp
Trang 63 Các khái niệm (tt)
Vòng lặp thông điệp (Message loop)
Vòng lặp thông điệp có chức năng lấy các thông điệp từ hàng đợi để gửi cho chương trình xử lý.
Vòng lặp thông điệp phải được cài đặt từ phía ứng
dụng.
Thủ tục xử lý thông điệp
Do chương trình cung cấp để xử lý các sự kiện cần thiết
Các thông điệp đã được xử lý hoặc không được xử lý bởi chương trình sẽ được gửi cho thủ tục xử lý mặc định
Trang 7Chương 2: Kiến trúc chương trình
Có hai cách tiếp cận cho kiến trúc một chương trình C/Windows, đó là:
- Theo hướng thông điệp (sự kiện)
- Theo hướng thành phần
Trang 8 Theo hướng sự kiện
Sơ đồ (hình bên)
Mô tả (…)
Trang 9Window API
WinMain() Khởi động biến định nghĩa cửa sổ Tạo lập cửa
sổ.
WinMain() Khởi động biến định nghĩa cửa sổ Tạo lập cửa
Chương trình ứng dụng
Lời gọi API
Sơ đồ (hình bên)
Mô tả (…)
Theo hướng thành phần
Trang 11Điểm vào chương trình: WinMain
int WINAPI WinMain (HINSTANCE hInstance,
HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
Các tham số:
Tham số đầu tiên là cái xác định chương trình.
Thể hiện (instance) trước đó của nó hPrevInstance.
Tham số thứ ba là dòng lệnh được sử dụng để thực thi chương trình.
Tham số thứ tư xác định cách thức chương trình sẽ khởi động hiển thị
Trang 12Hàm MessageBox
MessageBox (NULL, TEXT ("Hello, Windows"), TEXT ("HelloMsg"), 0) ;
Biểu diễn một thông báo ngắn.
Tham số đầu tiên của MessageBox là một nắm bắt
cửa sổ (handle to window).
Tham số thứ hai là chuỗi ký tự xuất hiện trên phần thân của hộp message.
Tham số thứ ba là chuỗi ký tự xuất hiện trong thanh tiêu đề của hộp thoại.
Tham số thứ tư xác định loại nút nhấn nào mà ta
muốn nó xuất hiện trong hộp thoại (0 là OK)
Trang 133 Mô hình Lập trình C/Windows
WinMain{
Register Class CreateWindow
MessageLoop}
WndProc(){
Switch
}myWinApp.EXE
”Windows”
message
dispa
tch
Trang 14Ví dụ (HelloWin)
// Khai báo và xác lập các thuộc tính của lớp cửa sổ
Trang 15Ví dụ (tt)
// Đăng ký lớp cửa sổ
// Tạo cửa sổ chương trình
Trang 16Ví dụ (tt)
// Hiển thị cửa sổ
// Cài đặt vòng lặp thông điệp
Trang 17Ví dụ (tt)
//xử lý TĐ: WM_CREATE, WM_PAINT, WM_DESTROY)
Trang 18Kết quả
Trang 19Toàn cục về chương trình
Tiền xử lý
# include <windows.h>
Khai báo hàm xử lý thông điệp của cửa sổ:
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
Hai hàm thành phần của chương trình:
WinMain( )
WndProc( )
Trang 20Các lời gọi hàm
LoadIcon Loads an icon for use by a program
LoadCursor Loads a mouse cursor for use by a program
GetStockObject Obtains a graphic object, in this case a brush
used for painting the window's background
RegisterClass Registers a window class for the program's window
MessageBox Displays a message box
CreateWindow Creates a window based on a window class
ShowWindow Shows the window on the screen
UpdateWindow Directs the window to paint itself
Trang 21Các lời gọi hàm (tt)
GetMessage Obtains a message from the message queue
TranslateMessage Translates some keyboard messages
DispatchMessage Sends a message to a window procedure
PlaySound Plays a sound file
BeginPaint Initiates the beginning of window painting
GetClientRect Obtains the dimensions of the window's client
area
DrawText Displays a text string
EndPaint Ends window painting
PostQuitMessage Inserts a "quit" message into the message
queue
DefWindowProc Performs default processing of messages
Trang 22Ký pháp Hungarian
Trang 23Lớp cửa sổ
Là một cấu trúc được định nghĩa như sau:
Trang 24màn hình (normal, minimized, maximized)
UpdateWindow (hwnd) ;
Trang 25Vòng lặp thông điệp
Trang 26Thủ tục xử lý thông điệp
Trang 27Một số thông điệp
Trang 28Chương 3 Vẽ trên cửa sổ
Trang 291 Painting and Repainting
Khái niệm vùng client (vùng làm việc).
Trong môi trường kí tự, chương trình có thể vẽ vào bất cứ phần nào của màn hình.
Trong Windows, ta chỉ có thể hiển thị chữ hay phần đồ họa trên vùng client.
Windows báo cho thủ tục cửa sổ rằng phần
client của cửa sổ cần vẽ lại bằng thông điệp
WM_PAINT.
Trang 301.1 Thông điệp WM_PAINT
Khi khởi động, chương trình gọi hàm UpdateWindow
Windows gửi cho thủ tục cửa sổ thông điệp
Một vùng cửa sổ bị che được hiện
Người dùng thay đổi kích thước cửa sổ
Trang 311.1 Thông điệp WM_PAINT (tiếp)
Thông điệp WM_PAINT được nhận khi: (tt)
Chương trình sử dụng các hàm ScrollWindow hay
ScrollDC để cuộn phần client của nó
Chương trình sử dụng các hàm InvalidateRect hay
InvalidateRgn để tạo ra các thông điệp WM_PAINT
Một số trường hợp khác Windows lưu phần màn hình nó ghi lên và phục hồi lại:
Con trỏ chuột di chuyển qua vùng client
Một icon được kéo qua vùng client
Trang 321.2 Valid & Invalid Rectangles
Khi nhận được một thông điệp WM_PAINT, nó thường chỉ cập nhật một vùng chữ nhật nhỏ, gọi là: “Vùng
Windows không đặt nhiều thông điệp WM_PAINT trong hàng đợi (Việc xử lý sẽ thế nào?)
Trang 332 GDI (Graphics Device Interface)
Để vẽ vùng client của cửa sổ, ta sử dụng các hàm GDI.
Windows cung cấp một số hàm GDI để ghi các chuỗi văn bản ra vùng client của cửa sổ.
Trang 342.1 Device Context (Ngữ cảnh
thiết bị)
HDC (Handle Device Context)
Một handle đơn giản chỉ là một tham trỏ đến đối
Với màn hình, một device context thường kết hợp
với một cửa sổ trên màn hình
Trang 35 Sau khi một chấm dứt việc vẽ, cần giải phóng
handle device context
Trang 362.2 Nhận handle device context
Method One
Được sử dụng khi xử lý thông điệp WM_PAINT.
Hai hàm được yêu cầu: BeginPaint và EndPaint.
Yêu cầu: handle cửa sổ, địa chỉ của biến cấu trúc PAINTSTRUCT (PAINTSTRUCT ps;)
BeginPaint, nhiệm vụ:
Xóa nền của vùng không hợp lệ để chuẩn bị vẽ.
Điền thông tin vào cấu trúc ps.
Trả về giá trị là handle device context.
HDC hdc;
Loại bỏ handle device context này bởi gọi: EndPaint.
Trang 372.2 Nhận handle device context (tt)
Dạng của xử lý thông điệp WM_PAINT
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
[use GDI functions]
EndPaint (hwnd, &ps) ; return 0 ;
Việc gọi liên tiếp BeginPaint và EndPaint sẽ hợp lý hóa vùng không hợp lệ trước đó
Trang 382.2 Nhận handle device context (tt)
Tuy nhiên, không được dùng thế này:
case WM_PAINT:
return 0 ; // WRONG !!!
Vì sao?
Do Windows không cập nhật vùng không hợp lệ.
Nếu không gọi BeginPaint và EndPaint (hay ValidateRect), Windows sẽ lại gửi cho ta thông điệp WM_PAINT khác Điều đó làm treo chương trình vì không thể thoát được.
Trang 402.3 Cấu trúc paint (Tiếp)
Chương trình chúng ta chỉ sử dụng ba trường đầu tiên, các trường còn lại được sử dụng bên trong bởi
Windows
Chi tiết các trường:
hdc: handle device context
fErase: cờ FALSE (0), xóa nền của hình chữ nhật không hợp lệ bằng brush chỉ định trong lớp cửa sổ
Nhắc lại (trong WinMain):
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
Trang 412.3 Cấu trúc paint (Tiếp)
Chi tiết các trường (Tiếp):
Trường rcPaint của PAINTSTRUCT là một cấu trúc RECT.
Cấu trúc này định nghĩa một hình chữ nhật.
Để giới hạn vùng không hợp lệ.
Và giới hạn vẽ trong vùng này.
Để vẽ bên ngoài hình chữ nhật khi xử lý thông điệp WM_PAINT,
ta có thể gọi:
InvalidateRect (hwnd, NULL, TRUE) ; trước khi gọi BeginPaint
Làm bất hợp lệ toàn vùng client khiến cho BeginPaint xóa
nền.
Ta có thể vẽ lại toàn bộ vùng client khi nhận được thông điệp
WM_PAINT.
Còn khi ta sử dụng handle device context trả về từ BeginPaint, ta
sẽ không vẽ bên ngoài hình chữ nhật rcPaint.
Trang 422.4 Nhận hdc (Method Two)
Thực sự hữu dụng nếu như:
Ta chỉ vẽ một phần của vùng client trong quá trình xử lý.
Hoặc cần handle device context (hdc) cho mục đích khác.
Để nhận một hdc của vùng client của cửa sổ:
hdc = GetDC (hwnd) ;
[use GDI functions]
ReleaseDC (hwnd, hdc) ;
GetDC và ReleaseDC nên được gọi theo cặp
Khác với hdc nhận được từ BeginPaint, hdc được nhận
bởi GetDC có vùng chữ nhật bằng toàn bộ vùng client
Hàm GetWindowDC trả về một hdc cho phép ta vẽ lên toàn bộ cửa sổ Tuy nhiên cần phải xử lý thêm thông
điệp WM_NCPAINT cho vùng nonclient
Trang 432.5 Hàm TextOut
TextOut là hàm GDI để hiển thị chữ.
TextOut (hdc, x, y, psText, iLength) ;
GetDC hoặc BeginPaint
logic).
Trang 442.6 Thông tin kích thước kí tự
Để hiển thị nhiều hàng chữ bằng hàmTextOut ta cần biết không tin về kích thước kí tự.
Trang 452.7 Chi tiết về Text Metrics
Trang 46static int cxChar, cyChar ;
Nhận chiều rộng và chiều cao của ký tự:
case WM_CREATE:
hdc = GetDC (hwnd) ; GetTextMetrics (hdc, &tm) ; cxChar = tm.tmAveCharWidth ; cyChar = tm.tmHeight + tm.tmExternalLeading ; ReleaseDC (hwnd, hdc) ;
return 0 ;
Trang 472.9 Ví dụ (SysMets1)
Trang 482.9 Ví dụ (tiếp)
Trang 492.9 Ví dụ (tiếp)
Trang 502.9 Ví dụ (tiếp)
Trang 512.9 Ví dụ (tiếp)
Trang 522.9 Ví dụ (tiếp)
Trang 532.9 Ví dụ (tiếp)
Kết quả:
Trang 542.9 Ví dụ (tiếp)
Xem xét chương trình
Thủ tục cửa sổ xử lý 3 loại thông điệp:
WM_CREATE, WM_PAINT, và WM_DESTROY
Thông điệp WM_CREATE
Được tạo ra khi tạo ra cửa sổ (hàm CreateWindow)
Nhận một device context bằng lời gọi GetDC.
Nhận text metrics của font hệ thống bằng GetTextMetrics.
Lưu chiều rộng trung bình của ký tự trong cxChar.
Lưu tổng chiều cao ký tự trong cyChar.
Lưu chiều rộng trung bình của các chữ hoa trong cxCaps.
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;
Thông điệp WM_PAINT
Xem các lời gọi hàm TextOut()…
Hạn chế của chương trình?
Trang 553 Các thanh cuộn
Để đưa các thanh cuộn vào chương trình, ta cần thêm vào các định danh WS_VSCROLL (cuộn dọc) hay WS_HSCROLL (cuộn ngang) trong hàm CreateWindow:
Trang 563 Các thanh cuộn (tiếp)
Scroll Bar Range and Position
Mỗi thanh cuộn đều kết hợp một range (khoảng, vùng) và position (vị trí).
Trang 573 Các thanh cuộn (tiếp)
Mặc định, vùng của thanh cuộn có giá trị từ 0 – 100
Có thể thay đổi các giá trị này bằng lời gọi:
SetScrollRange (hwnd, iBar, iMin, iMax, bRedraw) ;
iBar sẽ là: SB_VERT hoặc SB_HORZ
iMin, iMax: là các giá trị mới
bRedraw đặt bằng TRUE nếu ta muốn Windows vẽ lại thanh cuộn dựa trên vùng mới
Các giá trị thumb:
Đặt vị trí mới bằng câu lệnh:
SetScrollPos (hwnd, iBar, iPos, bRedraw) ;
Trang 583 Các thanh cuộn (tiếp)
Của Windows:
Của chương trình:
Trang 593 Các thanh cuộn (tiếp)
Các thông điệp thanh cuộn:
WM_VSCROLL (cuộn dọc)
WM_HSCROLL (cuộn ngang)
Các tham số đi kèm: wParam và lParam
Thông số lParam có thể bỏ qua
Thông số wParam được chia thành một word thấp
và một word cao
Word thấp chỉ định tác động của chuột lên thanh cuộn (xem hình dưới)
Trang 603 Các thanh cuộn (tiếp)
Các mã thông báo của tác
động được định nghĩa như
hình bên:
Trong đó: các định danh
LEFT, RIGHT đối với các
thanh cuộn ngang;
UP,DOWN,TOP,BOTTOM
đối với thanh cuộn dọc.
Trang 61Các thanh cuộn (tiếp)
Trang 623 Các thanh cuộn (tiếp)
Trang 633 Ví dụ (SysMets2)
Trang 643 Ví dụ (tt)
Trang 65Ví dụ (tt)
Kết quả
Trang 66 Ngoài ra, ta có thể nhận một hdc áp dụng cho toàn cửa sổ không chỉ vùng client:
Nhận một Device Context (tiếp)
Trang 67 Một hàm khác để nhận hdc:
hdc = CreateDC (pszDriver, pszDevice, pszOutput, pData) ;
[other program lines]
DeleteDC (hdc) ;
Ví dụ, ta có thể nhận một handle device
context của toàn màn hình:
hdc = CreateDC (TEXT ("DISPLAY"), NULL, NULL, NULL) ;
Nhận một Device Context (tiếp)
Trang 68 Khi ta chỉ cần nhận thông tin về device
context, ta có thể sử dụng hàm CreateIC:
hdc = CreateIC (TEXT ("DISPLAY"), NULL, NULL, NULL) ;
Lưu ý rằng: Ta không thể vẽ lên thiết bị bằng cách sử dụng handle thông tin context này.
Nhận một Device Context (tiếp)
Trang 69 Device Context chỉ đến một thiết bị vật lý.
Ta có thể lấy thông tin về thiết bị bằng lời gọi hàm GetDeviceCap (get device capabilities):
iValue = GetDeviceCaps (hdc, iIndex) ;
iIndex là một trong những định danh được định nghĩa trong WINGDI.H.
Ví dụ: giá trị iIndex của HORZES, VERTRES GetDeviceCaps trả về chiều rộng, cao của thiết bị.
Nhận thông tin Device Context
Trang 70 Xem thêm tài liệu.
Lưu ý các điểm sau:
- Khai báo cấu trúc devcaps[].
Ví dụ (DevCaps1)
Trang 71- Xử lý các thông điệp:
Ví dụ (tiếp)
Trang 72Ví dụ (tiếp)
Trang 73Ví dụ (tiếp)
Kết quả
Trang 74Các thuộc tính của DC
Windows sử dụng Device Context để lưu các thuộc tính xác định cách các hàm GDI hoạt động.
Khi chúng ta nhận một handle device context, Windows đặt tất cả các thuộc tính theo giá trị mặc định.
Ta có thể sử dụng các hàm để nhận hoặc
thay đổi các giá trị này.
Trang 75Các thuộc tính của DC (tt)
Trang 76Lưu Device Context
Khi ta gọi hàm GetDC, BeginPaint ta nhận được một handle device context với các giá trị mặc định đối với các thuộc tính.
Các giá trị này sẽ mất khi device context
được giải phóng (Sau lời gọi: ReleaseDC hay EndPaint).
Trang 77Lưu Device Context (tiếp)
Nếu ta cần sử dụng các thông số device
context không mặc định, ta phải khởi tạo
device context mỗi lúc ta nhận handle context mới:
Trang 78Lưu Device Context (tiếp)
Ta có thể lưu lại các giá trị thuộc tính khi trả lại device context.
Cách thực hiện:
Đặt CS_OWNDC trong lớp cửa sổ khi đăng ký.
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC ;
(ghi chú: Mỗi cửa sổ tạo ra dựa trên lớp cửa sổ này
sẽ có Device Context riêng và nó được tồn tại cho
đến khi cửa sổ bị hủy)
Trang 79Lưu Device Context (tiếp)
Ta chỉ phải khởi tạo các thuộc tính Device Context một lần, khi xử lý thông điệp
WM_CREATE.
Trang 80Lưu Device Context (tiếp)
Lưu trạng thái của Device Context bằng lời gọi:
idSaved = SaveDC (hdc) ;
Khi muốn trở lại trạng thái trước của Device Context, ta thực hiện lời gọi:
RestoreDC (hdc, idSaved) ;
Trang 81Lưu Device Context (tiếp)
Ta có thể gọi SaveDC mà không cần giá trị trả về:
Trang 82Vẽ các điểm và đường thẳng
Trên lý thuyết, tất cả các thiết bị phần cứng chỉ cần có
hai hàm SetPixel (vẽ điểm) và GetPixel (lấy điểm) để
thực hiện thao tác vẽ
Ví dụ, việc vẽ một đường thẳng chỉ cần thực hiện lời gọi
hàm GDI SetPixel nhiều lần với sự thay đổi của tọa độ x
và y tương ứng
Trên thực tế, ta có thể thực hiện tất cả các thao tác vẽ
chỉ cần với hai hàm này (SetPixel và GetPixel), vấn đề
chỉ là hiệu năng
Trang 83Vẽ điểm (Pixel)
SetPixel,GetPixel cung cấp điểm khởi đầu cho việc vẽ
các hình
Hàm SetPixel đặt một điểm tại tọa độ xác định x và y
với một màu nào đó, định dạng hàm như sau:
SetPixel (hdc, x, y, crColor) ;
Tham số đầu tiên là một handle cho device context
Tham số thứ 2 và 3 xác định tọa độ của điểm cần vẽ
Tham số cuối cùng thuộc kiểu COLORREF xác định màu
Hàm GetPixel trả về kết quả là màu của một điêmr
tại một ví trí nào đó:
crColor = GetPixel (hdc, x, y) ;