Tặng các bạn Unicode Menu trong Userform - UMU (SourceCode)

Nguyễn Duy Tuân

Nghị Hách
Thành viên danh dự
Tham gia ngày
13 Tháng sáu 2006
Bài viết
4,080
Được thích
9,532
Điểm
860
Nơi ở
Hà Nội
Hiện nay bộ code Unicode menu in userform chỉ chạy trong môi trường Office 32-bit. Tới đây nếu thu xếp được thời gian mình sẽ chỉnh sửa để chạy được cả 2 môi trường 32 và 64-bit.
 

Thaiduc

Thành viên hoạt động
Tham gia ngày
13 Tháng ba 2007
Bài viết
118
Được thích
6
Điểm
0
Tuổi
56
Anh Tuấn ơi!
Anh xem giúp tại sao mình chọn lọc lấy 3 người có số phiếu trên 50% và người có tuổi lo971n hơn trúng cử, nhưng kết quả lại là 4 người có số phiếu trên 50% vậy.
Mong Anh giúp và hướng dẫn thêm nhé.
Cám ơn Anh nhiều. (có gửi File kèm theo)
 

File đính kèm

Nguyễn Duy Tuân

Nghị Hách
Thành viên danh dự
Tham gia ngày
13 Tháng sáu 2006
Bài viết
4,080
Được thích
9,532
Điểm
860
Nơi ở
Hà Nội
Anh Tuấn ơi!
Anh xem giúp tại sao mình chọn lọc lấy 3 người có số phiếu trên 50% và người có tuổi lo971n hơn trúng cử, nhưng kết quả lại là 4 người có số phiếu trên 50% vậy.
Mong Anh giúp và hướng dẫn thêm nhé.
Cám ơn Anh nhiều. (có gửi File kèm theo)
Bạn chỉ ra sheet nào và yêu cầu lọc ra sao?
 

batman1

Thành viên gắn bó
Tham gia ngày
8 Tháng chín 2014
Bài viết
1,820
Được thích
2,826
Điểm
360
Nhân tiện bạn có ý sửa và làm phiên bản 64 bit tôi góp ý chút.
Hồi xa xưa, khi tôi mới tham gia GPE, tôi từng định góp ý nhưng thấy bạn không quan tâm nên thôi. Bây giờ thấy đã có tận phiên bản 1.2.2 nhưng những lỗi tôi phát hiện vẫn còn nên chỉ ra để bạn sửa. Tôi cũng có thể đề xuất phương án sửa nhưng đây là sản phẩm của bạn. Tôi chỉ chỉ ra lỗi và cho biết nguyên nhân.

1. Bạn hãy mở UserForm. Lúc này bạn có menu "tự vẽ", tiếng Việt. Bây giờ bạn mở menu Ngôn ngữ và chọn mục menu English. Lúc này bạn có tiếng Anh. Bạn mở menu Options chỉ để hiển thị, không chọn gì cả (nhiều khi click nhầm, click xong nghĩ lại và thôi) mà click trên Form để đóng menu. Từ lúc này bạn có thể thay đổi ngôn ngữ qua lại bao nhiêu lần tùy thích nhưng cứ chọn ngôn ngữ Việt là bạn có menu Options như hình1 đính kèm.
Nguyên nhân:
The window receives a WM_MEASUREITEM message before the menu is displayed for the first time
Có nghĩa là với mỗi drop-down menu và submenu thì thông điệp WM_MEASUREITEM chỉ được gửi 1 lần duy nhất ở thời điểm trước khi menu đó được hiển thị lần đầu tiên. Trong các lần hiển thị tiếp theo của menu đó thì WM_MEASUREITEM không được gửi. Vậy thì nếu lần mở đầu tiên các text có độ dài nhỏ thì trong OnMeasureItemMenu bạn tính chiều dài dựa trên các text ngắn đó (nếu submenu có vd. 5 mục con thì bạn trả về cho Windows 5 độ rộng và Windows sẽ lấy giá trị lớn nhất làm độ rộng của submenu). Khi đổi xong ngôn ngữ bạn mở lại menu đó thì do WM_MEASUREITEM không được gửi nữa nên chiều rộng của menu vẫn thế nhưng text đã thay đổi do đổi ngôn ngữ. Nếu text ở ngôn ngữ mới này dài hơn thì nó bị cắt cụt. Nói đúng hơn là bạn vẽ nhưng đoạn nằm ngoài chiều rộng menu sẽ không có.

Lưu ý là những cái tôi viết ở trên là cho phiên bản hồi xưa.

Bây giờ thì chả cần làm gì cả cứ Show Form rồi chọn menu bất kỳ thì các submenu đều bị cắt cụt (trong tất cả các menu chính). Vd. trong menu "Tùy chọn" như hinh2 đính kèm.

2. Trong UserForm_Initialize bạn thay

MyUMUMenu.DrawStyle = dsOwnerdraw

thành

MyUMUMenu.DrawStyle = dsSystem

Bạn mở UserForm. Lúc này bạn có menu do system tự vẽ, tiếng Việt. Bạn có thể thay đổi ngôn ngữ (click ckLang) bao nhiêu lần tùy ý thì chỉ có text trên thanh menu là thay đổi, còn text của các mục menu trong drop-down menu và submenu LUÔN LUÔN là tiếng Việt.

Nguyên nhân: nó ở đoạn code này (ở phiên bản xa xưa, ở phiên bản mới tôi lười không xem lại)
Mã:
Sub ChangeLang()
    Dim I As Long, szName$, szDetail$

    For I = 1 To MenuItemCount
        With ArrayPopupMenus(I)
            .lpName = mMenuData(.RowID, nIndexOfMenuName).Value
            .lpDetails = mMenuData(.RowID, nIndexOfMenuDetails).Value
            If .ParentID = 0 Then
                ModifyMenu hMenu, .ID, MF_BYCOMMAND Or MF_STRING, .ID, StrPtr(.lpName)
            End If
        End With
    Next I
 
End Sub
Nhìn code là biết nếu là dsSystem thì Windows chỉ có những text mà bạn cung cấp khi tạo menu, tức tiếng Việt. Bạn chỉ thay đổi (ModifyMenu) cho các mục menu chính. Khi là dsOwnerdraw thì không sao vì lúc đó "bạn" tự vẽ và bạn lấy text ở cấu trúc UMU_MenuItemInfo, đã có text thay đổi trong block With ... End With
-------------
Trong lập trình thì không ai có thể phát hiện ra tất cả các lỗi, kể cả ông lớn phần mềm là Windows. Chuyện phát hiện ra lỗi là khó nhất vì khó lường được mọi tình huống. Nhưng nếu đã biết lỗi ở đâu thì chuyện sửa là chuyện nhỏ. Bạn biết tạo menu, biết thêm mục menu, thay đổi và xóa có nghĩa là bạn đã biết làm tất cả. Bạn có thể tự sửa được.

Tôi cũng cảm thấy là lỗi 1 nếu người dùng không biết lập trình mà chỉ thử hoạt động nhưng thử không kỹ thì khó phát hiện ra lỗi. Nhưng bạn phải thừa nhận với tôi là lỗi 2 nó hiện ra liền nếu ta chọn phương án cho system vẽ. Vì vậy tôi ngạc nhiên là sao không có ai phát hiện ra.
 

File đính kèm

Nguyễn Duy Tuân

Nghị Hách
Thành viên danh dự
Tham gia ngày
13 Tháng sáu 2006
Bài viết
4,080
Được thích
9,532
Điểm
860
Nơi ở
Hà Nội
Nhân tiện bạn có ý sửa và làm phiên bản 64 bit tôi góp ý chút.
Hồi xa xưa, khi tôi mới tham gia GPE, tôi từng định góp ý nhưng thấy bạn không quan tâm nên thôi. Bây giờ thấy đã có tận phiên bản 1.2.2 nhưng những lỗi tôi phát hiện vẫn còn nên chỉ ra để bạn sửa. Tôi cũng có thể đề xuất phương án sửa nhưng đây là sản phẩm của bạn. Tôi chỉ chỉ ra lỗi và cho biết nguyên nhân.

1. Bạn hãy mở UserForm. Lúc này bạn có menu "tự vẽ", tiếng Việt. Bây giờ bạn mở menu Ngôn ngữ và chọn mục menu English. Lúc này bạn có tiếng Anh. Bạn mở menu Options chỉ để hiển thị, không chọn gì cả (nhiều khi click nhầm, click xong nghĩ lại và thôi) mà click trên Form để đóng menu. Từ lúc này bạn có thể thay đổi ngôn ngữ qua lại bao nhiêu lần tùy thích nhưng cứ chọn ngôn ngữ Việt là bạn có menu Options như hình1 đính kèm.
Nguyên nhân:

Có nghĩa là với mỗi drop-down menu và submenu thì thông điệp WM_MEASUREITEM chỉ được gửi 1 lần duy nhất ở thời điểm trước khi menu đó được hiển thị lần đầu tiên. Trong các lần hiển thị tiếp theo của menu đó thì WM_MEASUREITEM không được gửi. Vậy thì nếu lần mở đầu tiên các text có độ dài nhỏ thì trong OnMeasureItemMenu bạn tính chiều dài dựa trên các text ngắn đó (nếu submenu có vd. 5 mục con thì bạn trả về cho Windows 5 độ rộng và Windows sẽ lấy giá trị lớn nhất làm độ rộng của submenu). Khi đổi xong ngôn ngữ bạn mở lại menu đó thì do WM_MEASUREITEM không được gửi nữa nên chiều rộng của menu vẫn thế nhưng text đã thay đổi do đổi ngôn ngữ. Nếu text ở ngôn ngữ mới này dài hơn thì nó bị cắt cụt. Nói đúng hơn là bạn vẽ nhưng đoạn nằm ngoài chiều rộng menu sẽ không có.

Lưu ý là những cái tôi viết ở trên là cho phiên bản hồi xưa.

Bây giờ thì chả cần làm gì cả cứ Show Form rồi chọn menu bất kỳ thì các submenu đều bị cắt cụt (trong tất cả các menu chính). Vd. trong menu "Tùy chọn" như hinh2 đính kèm.

2. Trong UserForm_Initialize bạn thay

MyUMUMenu.DrawStyle = dsOwnerdraw

thành

MyUMUMenu.DrawStyle = dsSystem

Bạn mở UserForm. Lúc này bạn có menu do system tự vẽ, tiếng Việt. Bạn có thể thay đổi ngôn ngữ (click ckLang) bao nhiêu lần tùy ý thì chỉ có text trên thanh menu là thay đổi, còn text của các mục menu trong drop-down menu và submenu LUÔN LUÔN là tiếng Việt.

Nguyên nhân: nó ở đoạn code này (ở phiên bản xa xưa, ở phiên bản mới tôi lười không xem lại)
Mã:
Sub ChangeLang()
    Dim I As Long, szName$, szDetail$

    For I = 1 To MenuItemCount
        With ArrayPopupMenus(I)
            .lpName = mMenuData(.RowID, nIndexOfMenuName).Value
            .lpDetails = mMenuData(.RowID, nIndexOfMenuDetails).Value
            If .ParentID = 0 Then
                ModifyMenu hMenu, .ID, MF_BYCOMMAND Or MF_STRING, .ID, StrPtr(.lpName)
            End If
        End With
    Next I
 
End Sub
Nhìn code là biết nếu là dsSystem thì Windows chỉ có những text mà bạn cung cấp khi tạo menu, tức tiếng Việt. Bạn chỉ thay đổi (ModifyMenu) cho các mục menu chính. Khi là dsOwnerdraw thì không sao vì lúc đó "bạn" tự vẽ và bạn lấy text ở cấu trúc UMU_MenuItemInfo, đã có text thay đổi trong block With ... End With
-------------
Trong lập trình thì không ai có thể phát hiện ra tất cả các lỗi, kể cả ông lớn phần mềm là Windows. Chuyện phát hiện ra lỗi là khó nhất vì khó lường được mọi tình huống. Nhưng nếu đã biết lỗi ở đâu thì chuyện sửa là chuyện nhỏ. Bạn biết tạo menu, biết thêm mục menu, thay đổi và xóa có nghĩa là bạn đã biết làm tất cả. Bạn có thể tự sửa được.

Tôi cũng cảm thấy là lỗi 1 nếu người dùng không biết lập trình mà chỉ thử hoạt động nhưng thử không kỹ thì khó phát hiện ra lỗi. Nhưng bạn phải thừa nhận với tôi là lỗi 2 nó hiện ra liền nếu ta chọn phương án cho system vẽ. Vì vậy tôi ngạc nhiên là sao không có ai phát hiện ra.
Cảm ơn anh đã phân tích cơ chế của WM_MEASUREITEM rất kỹ, đúng là em k chú ý tới cơ chế làm việc của nó là chỉ lần đầu tiên đc gọi, cứ nghĩ mỗi lần vẽ menu là nó chạy lại để tính toán kích thươvs item. Trong bộ code này còn một lỗi nghiêm trọng nữa là tràn bộ nhớ, em đã từng tìm nguyên nhân nhưng chưa ra. Lâu quá bỏ bê code này, thời gian tới chắc e sẽ xem xét và tìm cách fix, sẵn nhờ anh nếu thu xếp đc time thì kiểm tra giúp lỗi tràn bộ nhớ.

Cảm ơn anh!
 

batman1

Thành viên gắn bó
Tham gia ngày
8 Tháng chín 2014
Bài viết
1,820
Được thích
2,826
Điểm
360
sẵn nhờ anh nếu thu xếp đc time thì kiểm tra giúp lỗi tràn bộ nhớ.
Tôi không hiểu lắm. Tràn bộ nhớ? Biểu hiện thế nào, sảy ra trong những tình huống nào? Tôi hỏi vì tôi không sử dụng nên không phát hiện được tràn bộ nhớ.
 

Nguyễn Duy Tuân

Nghị Hách
Thành viên danh dự
Tham gia ngày
13 Tháng sáu 2006
Bài viết
4,080
Được thích
9,532
Điểm
860
Nơi ở
Hà Nội
Tôi không hiểu lắm. Tràn bộ nhớ? Biểu hiện thế nào, sảy ra trong những tình huống nào? Tôi hỏi vì tôi không sử dụng nên không phát hiện được tràn bộ nhớ.
Anh mở form có menu lên, để chuột mở qua mở lại nhiều lần menu (cho nó vẽ đi vẽ lại). Thì Windows chạy chậm đi (cảm giác nhưng đúng), đến một lúc nào đó thì Excel vẽ màu sắc lung tung.
 

batman1

Thành viên gắn bó
Tham gia ngày
8 Tháng chín 2014
Bài viết
1,820
Được thích
2,826
Điểm
360
Anh mở form có menu lên, để chuột mở qua mở lại nhiều lần menu (cho nó vẽ đi vẽ lại). Thì Windows chạy chậm đi (cảm giác nhưng đúng), đến một lúc nào đó thì Excel vẽ màu sắc lung tung.
Khó nhất là những lỗi mà không phải lúc nào cũng sảy ra. Và những lỗi sảy ra sau một thời gian dài.
Tôi không đủ kiên nhẫn để test. Tôi mở đi mở lại menu nhưng không thấy vấn đề gì. Sau một thời gian mỏi tay quá nên tôi thôi. Chỉ còn việc dò xem code trong OnDrawItemMenu

1. Về brush và Font thì có DeleteObject.

2. Về bitmap ...
Có
Mã:
If Not Pic Is Nothing Then
    bmpHDC = CreateCompatibleDC(di.hdc)
    oldPic = SelectObject(bmpHDC, Pic.Handle)
    ... 
    'SelectObject bmpHDC, oldPic
    DeleteDC bmpHDC
    DeleteObject oldPic
End If
Trong help có:
"The SelectObject function selects an object into the specified device context. The new object replaces the previous object of the same type
...
This function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object. "

Như thế thì không biết có thể tự mình DeleteObject oldPic được không. Tôi không dám chắc về điều này. Mà tôi cũng không bao giờ thử DeleteObject oldPic, vì tôi luôn làm theo help mà không thử làm khác đi bao giờ.

Theo tôi nên chọn oldPic vào lại device context bmpDC. Sau đó gọi DeleteDC. Còn system làm gì với oldPic và hủy khi nào thì system tự lo liệu. Làm như thế để khỏi áy náy, băn khoăn ;)

Tức nếu là tôi thì
Mã:
If Not Pic Is Nothing Then
    bmpHDC = CreateCompatibleDC(di.hdc)
    oldPic = SelectObject(bmpHDC, Pic.Handle)
    ... 
    SelectObject bmpHDC, oldPic
    DeleteDC bmpHDC
End If
Các code khác tôi cũng lướt qua nhưng không thấy gì đáng ngờ cả. Về API thì mọi cái đều được làm bài bản. Cái này thì tôi chịu.
 

adult

Thành viên hoạt động
Tham gia ngày
2 Tháng mười hai 2007
Bài viết
186
Được thích
29
Điểm
670
Các bác nào download xong bản 1.2.2 thì có thể share lại giúp em với. Em đã vào link của bài #1 để làm theo hướng dẫn mà hơn 1 tuần rồi vẫn chưa nhận được file.
Cảm ơn các bác trước nha
 

khitamdao

Thành viên mới
Tham gia ngày
30 Tháng ba 2017
Bài viết
17
Được thích
0
Điểm
163
Mình cũng vửa mới đăng ký theo #1, hy vọng sớm nhận được sản phẩm
 
Top