VicoTas
Câu hỏi
Manh Linh manhlinh
26/04/2013 21:03

Một số ứng dụng hiển thị menu dropdown với 1 hình chữ nhật màu xanh kéo dài từ trên xuống dưới. Xin chỉ cách tạo menu như vậy bằng VB6.0?



Danh sách câu trả lời (1)
Chip chip chipchip 26/04/2013 21:03
Mặc dù Windows cho phép ứng dụng tạo và hiển thị các menu theo đặc thù riêng của mình, nhưng các môi trường lập trình trực quan như VB 6.0, VC++ không cho phép người lập trình có thể thiết kế trực quan hệ thống menu có cách hiển thị đặc thù. Do đó nếu bạn muốn hiển thị menu theo cách đặc thù (thí dụ có hình chữ nhật màu xanh kéo dài từ trên xuống dưới ở phía trái của 1 menu dropdown), bạn phải tự viết code gọi các hàm API thực hiện yêu cầu này. Về mặt viết code, Windows cho phép bạn khai báo sự hiển thị menu dropdown theo nhiều mức độ khác nhau:

• Hiển thị từng "menu item" theo chế độ text hay bitmap hay tổng hợp cả 2 chế độ.

• Định nghĩa icon đồ họa để hiển thị kèm theo "menu item" ở chế độ chọn/không chọn item đó.

• Giao phó cho ứng dụng tự hiển thị lấy từng menuItem theo đặc thù riêng của mình.

Trong 3 mức độ hiển thị menuItem trên, mức độ giao phó cho ứng dụng hiển thị là tổng quát nhất, người ta gọi chế độ này là "owner-drawn menu item". Để dùng chế độ hiển thị menu này, ta sẽ thực hiện 3 bước sau:

1. Tạo mới từng menu item với chế độ hiển thị "owner-drawn". Nếu menu item đã được thiết kế trực quan rồi thì ta có thể gọi hàm SetMenuItemInfo() để thiết lập lại chế độ hiển thị "owner-drawn" cho nó.

2. Viết code phục vụ sự kiện WM_MEASUREITEM để thiết lập kích thước cho từng "menu item".

3. Viết code phục vụ sự kiện WM_DRAWITEM để tự hiển thị menu item theo yêu cầu riêng.

Việc viết code quản lý và hiển thị các menu Item sẽ phải gọi nhiều hàm API của Windows và xử lý nhiều cấu trúc dữ liệu phức tạp của Windows nên dùng ngôn ngữ VC++ sẽ thích hợp hơn và đơn giản hơn nhiều so với dùng VB. Để giúp bạn thấy cụ thể việc tạo 1 menu dropdown đặc thù, chúng tôi sẽ lấy thí dụ về 1 ứng dụng VC++ dùng giao diện SDI (Single Document Interface) có 1 thanh menubar, trong đó menu đầu tiên của nó là menu File có sự hiển thị đặc thù như sau :

Qui trình điển hình để tạo ứng dụng VC++ có menu File như trên:

1. Chạy trình VC++ 6.0.

2. Chọn menu File.New để hiển thị cửa sổ New, chọn tab "Project", chọn mục "MFC AppWizard (exe)", chọn vị trí thư mục trên đĩa để chứa các thành phần của Project ở comboBox "Location", nhập tên project ở ComboBox "Project name" (thí dụ tên là MyBitmapMenu), chọn button OK để tiếp tục.

3. Trong cửa sổ "MFC AppWizard Step 1", đánh dấu chọn checkbox "Single Document", chọn button "Finish" để hoàn thành việc tạo Project với các thông số mặc định còn lại.

4. Chọn tab "Resource View" trong cửa sổ Project (thường nằm phía trái màn hình), ấn vào dấu cộng của phần tử gốc "MyBitmapMenu resources" để hiển thị chi tiết các

tài nguyên giao diện của ứng dụng, ấn vào dấu cộng của mục "Menu" để hiển thị chi tiết các menu của ứng dụng, lúc này chỉ có 1 menu mặc định với tên là IDR_MAINFRAME, đây là menu chính do VC++ tạo tự động cho ứng dụng. Ấn kép chuột vào mục IDR_MAINFRAME để hiển thị trực quan menu hầu hiệu chỉnh lại nó. Các thành phần ban đầu của menubar như sau (ta chỉ quan tâm đến menu File):

5. Chọn mục "Save As" rồi ấn vào icon "Cut" trên Toolbar để xóa nó, tiếp tục xóa các option còn lại cho đến option Exit thì dừng lại. Lúc này menu File chỉ còn 4 phần tử như hình bên.

6. Dùng trình "Screen Saver" nào đó, copy vùng đồ họa hình chữ nhật miêu tả các option của menu File, chạy ứng dụng xử lý đồ họa mạnh nào đó (thí dụ CorelDraw), dán hình bitmap vừa copy vào cửa sổ làm việc của nó rồi hiệu chỉnh lại theo đặc thù riêng của bạn, thí dụ thêm thanh hình chữ nhật xanh lợt dần về phía dưới như hình trên. Sau khi đã có hình ảnh tổng thể về menu cần hiển thị, bạn chọn từng vùng một, mỗi vùng bitmap miêu tả 1 menuItem, cắt nó và dán lên 1 cửa sổ khác rồi cất lên file dạng *.bmp. Cuối cùng ta được 4 file b0.bmp, b1.bmp, b2.bmp, b3.bmp, mỗi file chứa ảnh bitmap của 1 menuItem. Lưu ý là nên chỉnh kích thước giống nhau cho 4 file ảnh miêu tả 4 menuItem. Tạo thêm 1 file ảnh khác (thí dụ b4.bmp) chứa ảnh bitmap có cùng kích thước với ảnh bitmap của menuItem nhưng chỉ toàn pixel đen, ảnh bitmap này sẽ được dùng làm "mask" cho hoạt động đảo ngược màu menuItem được chọn. Copy 5 file ảnh vừa tạo được vào thư mục của Project ứng dụng rồi quay lại cửa sổ VC++.

7. Chọn menu View.ClassWizard để hiển thị cửa sổ ClassWizard, chọn tab "Message Map", chọn CMainFrame trong listbox "Class name", chọn mục CMainFrame trong listbox "Object IDs", duyệt và chọn mục "WindowProc" trong listbox "Messages", ấn button "Add function" để tạo hàm xử lý các sự kiện của cửa sổ MainFrame, ấn button "Edit Code" để mở cửa sổ soạn code cho hàm WindowProc() vừa tạo. Viết đoạn code sau cho hàm WindowProc():

// CMainFrame message handlers

LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {

// TODO: Add your specialized code here and/or call the base class

switch (message) {

case WM_CREATE:

if (!MyOnCreate(m_hWnd))

return -1;

break;

case WM_MEASUREITEM:

MyOnMeasureItem(m_hWnd, (LPMEASUREITEMSTRUCT) lParam);

return TRUE;

case WM_DRAWITEM:

MyOnDrawItem(m_hWnd, (LPDRAWITEMSTRUCT) lParam);

return TRUE;

}

return CFrameWnd::WindowProc(message, wParam, lParam);

}

8. Viết tiếp các hàm được gọi từ hàm WindowProc như sau (nên để đoạn code sau nằm trước hàm WindowProc):

// khai báo các hằng và biến cần dùng

#define IDB_ITEMMASK 4

HBITMAP hbmList[5];

HINSTANCE hInst;

// hàm thiết lập lại thuộc tính onwer-drawn cho các menuItem của menu File

BOOL WINAPI MyOnCreate(HWND hwnd) {

int i;

HMENU hMenuBar = GetMenu(hwnd);

HMENU hFileMenu = GetSubMenu(hMenuBar,0);

MENUITEMINFO mii;

hInst = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);

// Load các bitmap cho các menuItem

hbmList[0] = (HBITMAP)LoadImage(hInst,"b0.bmp",IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

hbmList[1] = (HBITMAP)LoadImage(hInst,"b1.bmp",IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

hbmList[2] = (HBITMAP)LoadImage(hInst,"b2.bmp",IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

hbmList[3] = (HBITMAP)LoadImage(hInst,"b3.bmp",IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

hbmList[4] = (HBITMAP)LoadImage(hInst,"b4.bmp",IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

for (i = 0 ; i <4; i++) {

// Chuẩn bị các thông số cho record

mii.cbSize = sizeof(MENUITEMINFO);

mii.fType = MFT_OWNERDRAW;

mii.fMask = MIIM_TYPE | MIIM_DATA;

mii.dwItemData = (DWORD) i;

// thiết lập lại thông số cho menuItem

SetMenuItemInfo(hFileMenu, i, TRUE, &mii);

}

return TRUE;

}

// Hàm vẽ menu item tương ứng với trạng thái selected/noselected

BOOL PASCAL FDrawMaskHBitmap(HDC hDC, LPPOINT lppt, HBITMAP hBitPaint, HBITMAP hBitMask) {

HDC hMemDC1;

HDC hMemDC2;

HBITMAP hBitTemp;

BITMAP bm;

WORD cx, cy; //biến tạm làm code dễ đọc

hMemDC1=CreateCompatibleDC(hDC);

hMemDC2=CreateCompatibleDC(hDC);

SetMapMode(hMemDC1, GetMapMode(hDC));

SetMapMode(hMemDC2, GetMapMode(hDC));

GetObject(hBitPaint, sizeof(BITMAP), (LPSTR)&bm);

cx=bm.bmWidth;

cy=bm.bmHeight;

hBitTemp=CreateCompatibleBitmap(hDC, cx, cy);

// Vẽ mask

SelectObject(hMemDC1, hBitMask);

SelectObject(hMemDC2, hBitTemp);

BitBlt(hMemDC2, 0, 0, cx, cy, hDC, lppt->x, lppt->y, SRCCOPY);

BitBlt(hMemDC2, 0, 0, cx, cy, hMemDC1, 0, 0, SRCAND);

SelectObject(hMemDC1, hBitPaint);

BitBlt(hMemDC2, 0, 0, cx, cy, hMemDC1, 0, 0, SRCPAINT);

BitBlt(hDC, lppt->x, lppt->y, cx, cy, hMemDC2, 0, 0, SRCCOPY);

DeleteDC(hMemDC1);

DeleteDC(hMemDC2);

DeleteObject(hBitTemp);

return TRUE;

}

// hàm phục vụ sự kiện WM_MEASUREITEM

// chức năng : thiết lập kích thước cho menuItem

void WINAPI MyOnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpItem) {

BITMAP bm;

WORD wIDBitmap;

WORD cxCheck;

wIDBitmap=LOWORD(lpItem->itemData);

cxCheck=LOWORD(GetMenuCheckMarkDimensions());

GetObject(hbmList[wIDBitmap], sizeof(BITMAP), (LPVOID)&bm);

lpItem->itemWidth=bm.bmWidth-cxCheck;

lpItem->itemHeight=bm.bmHeight;

}

// hàm phục vụ sự kiện WM_DRAWITEM

// chức năng : vẽ menuItem

void WINAPI MyOnDrawItem(HWND hwnd, LPDRAWITEMSTRUCT lpItem) {

BITMAP bm;

WORD wIDBitmap;

POINT pt;

if (ODA_DRAWENTIRE & lpItem->itemAction){

wIDBitmap=LOWORD(lpItem->itemData);

GetObject(hbmList[wIDBitmap], sizeof(BITMAP), (LPVOID)&bm);

pt.x=0;

pt.y=lpItem->rcItem.top;

// Vẽ bitmap miêu tả menuItem

FDrawMaskHBitmap(lpItem->hDC, &pt, hbmList[wIDBitmap], hbmList[IDB_ITEMMASK]);

//nếu menuItem đang được chọn, đảo bitmap của nó.

if (ODS_SELECTED & lpItem->itemState)

InvertRect(lpItem->hDC, &(lpItem->rcItem));

} else {

// Selection state is being changed, so just invert.

if (ODA_SELECT & lpItem->itemAction)

InvertRect(lpItem->hDC, &(lpItem->rcItem));

}

}

9. Chọn menu Build.Execute MyBitmapMenu.exe để chạy thử ứng dụng, chọn menu File bạn sẽ thấy kết quả như mong muốn (như hình dưới đây):

Bạn có thể liên hệ tòa soạn PCWorld để copy toàn bộ project VC++ của ứng dụng demo này (tên là VCMyBitmapMenu).
Trả lời câu hỏi
Tải lại mã
Câu hỏi lĩnh vực Lập trình
Đức Vân Dùng VB.NET để viết chương trình quản lý hồ sơ theo mô hình client/server, tôi không biết làm cách nào client mở được file *.doc hay file *.pdf ?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

dang duc thang Xin hướng dẫn phương hướng để viết chương trình chơi bóng đá đơn giản. Như kỹ thuật di chuyển camera khi quả bóng di chuyển?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

Manh Linh Làm thế nào để fix lỗi 200 của Turbo Pascal??

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

vietnamconnection Dùng Delphi để lập chương trình thu và phát tiếng nói, dùng các hàm API của Windows (WaveIn_, WaveOut_) nhưng luôn bị báo lỗi tại hàm WaveInOpen?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

nophoto Xin hướng dẫn cách làm từ điển, cách lưu hai loại tiếng Việt và tiếng Anh và tra trực tuyến khi click bất kỳ từ nào trên màn hình?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

vietnamconnection Trong môi trường MSDOS của Win98, tôi có thể dùng lệnh gì để shutdown máy mà không phải quay lại màn hình Windows?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

NgocUk Tôi muốn viết 1 chương trình có chức năng như MS Word, xin hỏi cách định dạng file *.doc và có điều khiển OCX nào có chức năng như MS Word không?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

nophoto Chương trình Visual C++ vẽ các phần tử đồ họa như Rectangle, Circle không hiện được trên màn hình mặc dù chương trình dịch không có lỗi?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

Chip chip Xin hỏi cần phải chuẩn bị những gì để xây dựng 1 chương trình phần mềm? Một chương trình phần mềm bao gồm những gì?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

Lê Thị Hoa Hồng Giúp mình viết chương trình điều khiển thiết bị điện thông qua cổng máy in?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

Chip chip VB 6.0 có thể lập trình điều khiển phần cứng (lập trình hệ thống) được không? Tài liệu có thể tìm ở đâu?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

MrTien Có ActiveX Control nào thực hiện nhận diện chữ viết từ ảnh bitmap rồi phát âm ra loa không?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

Vinh Các chương trình như Winamp... có các ‘skin’ khác nhau, làm sao tạo được chúng? Có phần mềm nào lập trình các giao diện khác?

Đăng lúc: 21:03 - 26/04/2013 trong Lập trình

NgocUk Xin hỏi muốn sử dụng hình ảnh cho checkbox và Option Button thì phải làm sao?

Đăng lúc: 21:02 - 26/04/2013 trong Lập trình

Củ Chuối Em đang học Visual Basic và muốn viết một chương trình xem ảnh?

Đăng lúc: 21:02 - 26/04/2013 trong Lập trình

MrTien Khi biên dịch file EXE hoặc Run chương trình được viết bằng Visual Basic 6.0 thì hiện thông báo lỗi: “Run-time error 7. Out of Memory”?

Đăng lúc: 21:02 - 26/04/2013 trong Lập trình

Hương Tôi muốn có chương trình dịch ngược Visual FoxPro 6.0 với mục đích học tập. ? Bạn nào có giúp mình?

Đăng lúc: 21:02 - 26/04/2013 trong Lập trình

Uk Xin cho biết cách lập trình Visual Basic để gởi e-mail?

Đăng lúc: 21:02 - 26/04/2013 trong Lập trình

lighting Tôi lập trình bằng Access 97 và muốn hiển thị văn bản độ dài từ hai trang trở lên? Phải làm thế nào?

Đăng lúc: 23:33 - 26/06/2013 trong Lập trình

Ngô Minh Tùng Tôi viết 1 chương trình xem ảnh bằng Visual Basic nhưng không biết cách nào để mỗi khi nhấn đúp vào 1 file ảnh trên Windows Explorer?

Đăng lúc: 21:02 - 26/04/2013 trong Lập trình

Rao vặt Siêu Vip