Các điều khiển list-box, combo-box và menu có một kiểu dáng đặc biệt gọi là “kiểu tự vẽ”, có nghĩa là chúng ta tự vẽ các phần tử, văn bản của phần tử bằng mã lệnh thực thi. Đây là phương cách hay dùng để đưa các đồ hoạ vào điều khiển.
Thông thường, để tạo một đối tượng tự vẽ trong C++ Builder, chúng ta phải qua ba bước sau:
- Chỉ định để hệ thống biết là đối tượng tự vẽ.
Cả hai danh sách listbox và combobox đều có một thuộc tính Style. Style cho phép chỉ định phương pháp vẽ các phần tử là mặc định hay tự vẽ. Grid (lưới) sử dụng một thuộc tính DefaultDrawing để cho phép hay khơng cho phép việc hệ thống vẽ các mục chọn một cách mặc định.
Listbox và Combobox có thêm kiểu tự vẽ gồm: fixed và variable được diễn giải trong bảng sau:
Kiểu tự
vẽ Ý nghĩa Giá trị
Fixed Mỗi phần tử có cũng chiều cao, chiều cao này được định bởi thuộc tính ItemHeight.
lbOwnerDrawFixed, csOwnerDrawFixed Variable Mỗi phần tử có thể có chiều cao khác
nhau và phụ thuộc vào dữ liệu tại thời điểm thực thi.
lbOwnerDrawVariable, csOwnerDrawVariable - Thêm các đối tượng hình ảnh vào trong một String List.
Một một string list đều có khả năng lưu giữa một danh sách các đối tượng kèm theo một danh sách chuỗi. Ví dụ, trong một ứng dụng quản lý tập tin, chúng ta có thể thêm hình ảnh để chỉ ổ đĩa với từng tên của ổ đĩa. Để thực hiện điều này, chúng ta cần phải thêm một số hình ảnh vào trong ứng dụng, sau đó sao chép chúng vào một string list. Chúng ta cũng có thể sử dụng các hình ảnh trong các đối tượng hình ảnh ẩn, chẳng hạn như:
+ Thêm một đối tượng hình ảnh vào form chính. + Cài đặt tên cho đối tượng.
+ Cài đặt thuộc tính Visible thành false. + Tải hình ảnh bằng thuộc tính Picture.
Đối tượng hình ảnh này sẽ ẩn khi ứng dụng được thực thi.
Một khi chúng ta sử dụng hình ảnh trong ứng dụng, chúng ta có thể đính kèm nó với danh sách văn bản trong String list. Chúng ta có thể thêm đồng thời cả đối tượng và văn bản đính kèm vào trong string list.
Ví dụ dưới đây sẽ cho phép chúng ta tìm hiểu cách thêm hình ảnh vào một string list. Đây là một phần của chương trình quản lý tập tin, trong đó, mỗi ổ đĩa sẽ chó một hình ảnh và một ký tự đi kèm. Để thêm hình ảnh, chúng ta truy bắt sự kiện OnCreate của Form như đoạn lệnh dưới
void __fastcall TFMForm::FormCreate(TObject *Sender) {
char Drive;
int AddedIndex;
{
switch(GetDriveType(Drive + ':/"))
{ /* positive calues mean valid drives */ DRIVE_REMOVABLE: // add a tab
AddedIndex = DriveTabSet->Tabs->AddObject(Drive, Floppy->Picture- >Graphic);
DRIVE_FIXED: //add a tab *
AddedIndex = DriveTabSet->Tabs->AddObject(Drive, Fixed->Picture->Graphic); DRIVE_REMOTE: // add a tab
AddedIndex = DriveTabSet->Tabs->AddObject(Drive, Network->Picture- >Graphic);
if (Drive == DirectoryOutline.Drive) then //current drive?
DriveTabSet.TabIndex := AddedIndex; //then make that current tab }
} }
- Vẽ các phần tử.
Khi một đối tượng được cài đặt kiểu dáng thành tự vẽ, Windows sẽ khơng vẽ đối tượng đó trên màn hình mà nó sẽ phát sinh sự kiện cho mỗi phần tử trong đối tượng. Chúng ta phải viết mã lệnh để vẽ các phần tử này tương ứng với các sự kiện vẽ phần tử. Chỉ sử dụng một đoạn mã lệnh thống nhất để vẽ cho tất cả các phần tử Trước khi cho phép ứng dụng vẽ đối tượng, Windows sẽ phát sinh một sự kiện đơn vị đo của phần tử. Sự kiện này nói lên rằng phần tử sẽ được hiển thị ở đâu trên đối tượng. Windows sẽ tính tốn kích thước của phần tử (thơng thường, nó đủ lớn để hiển thị văn bản của đối tượng trong font chữ hiện tại). Chúng ta phải nắm giữ các thơng tin này và thay đổi hình chữ nhật mà windows chọn. Ví dụ, nếu chúng ta muốn vẽ một hình ảnh thay cho văn bản của phần tử thì chúng ta đổi hình chữ nhật cho khớp với kích thước của hình ảnh. Để đổi kích thước của phần tử tự vẽ, chúng ta phải viết mã lệnh đáp ứng cho sự kiện đo phần tử. Tuỳ thuộc vào từng đối tượng, tên này có thể khác nhau. Đối với listbox và combobox, tên của sự kiện đo phần tử là OnMeasureItem. Lưới (Grid) khơng có sự kiện đo phần tử. Sự kiện này có hai tham số quan trọng: chỉ số của phần tử và kích thước của phần tử đó.
Kích cỡ có thể thể hiện theo nhiều cách khác nhau, đối với listbox và combobox. Kích thước chứa độ cao của phần tử, cịn độ rộng ln ln bằng độ rộng của đối tượng. ví dụ:
void __fastcall TFMForm::DriveTabSetMeasureTab(TObject *Sender, int Index, int &TabWidth)
{
int BitmapWidth; TBitmap *temp;
temp =(TBitmap *)DriveTabSet->Tabs->Objects[Index]; BitmapWidth = temp->Width;
TabWidth= 2 + BitmapWidth; }
Sau đó tiến hành vẽ đối tượng theo sự kiện OnDrawTab (trong listbox và combo box là OnDrawItem)
void __fastcall TFMForm::DriveTabSetDrawTab( TObject *Sender, TCanvas *TabCanvas,
TRect R, int Index, bool Selected) TBitmap *Bitmap;
{
Bitmap = (TBitmap *)DriveTabSet->Tabs->Objects[Index];
TabCanvas->Draw(R.Left, R.Top + 4, Bitmap); { draw bitmap */ TabCanvas->TextOut(R.Left + 2 + Bitmap.Width, { position text */ R.Top + 2, DriveTabSet.Tabs[Index]); { and draw it to the right of the bitmap */
}
Trong trường hợp một số đối tượng có hỗ trợ thuộc tính Image hay thuộc tính Images, chúng ta có thể đưa hình ảnh trực tiếp khi thiết kế đối tượng bằng cách tải hình ảnh vào hoặc thơng qua ImageList. Riêng nội dung vẽ các phần tử tự vẽ chúng tôi sẽ đề cập sâu hơn trong bài 7.
5.5 Thực hành
Bài tập 1: Thực hiện lại các bài ví dụ trong bài. Bài tập 2: Viết chương trình quản lý file đơn giản.
Bài tập 3: Viết chương trình kéo một phần tử từ listbox sang Edit và ngược lại.
Bài tập 4: Viết chương trình cho phép kéo và thả một hình ảnh từ một điều khiển image sang một điều khiển image khác.