paulsteigel
Nhi bất hoặc!
- Tham gia
- 25/8/08
- Bài viết
- 306
- Được thích
- 683
- Giới tính
- Nam
- Nghề nghiệp
- Governance & Public policy consultant
Có thể chủ đề này hơi cũ rồi nhưng mình xin mạn phép chia sẻ với các bạn một cách nho nhỏ để tạo Menu nhiều lớp bằng VBA trong Excel nhé.
Mình định viết chi tiết một chút nhưng do thời gian hạn hẹp nên chỉ xin phép đăng đoạn Code và file ví dụ để mọi người tiện tham khảo.
Giờ có thêm chút thời gian ngẫm nghĩ, mình xin viết cụ thể một chút.
Thực ra ý tưởng này bắt nguồn từ việc xem các menu quản lý Web của Joomla (một phần mềm nguồn mở quản trị nội dung Web khá nổi tiếng)
Cách tiếp cận của Joomla khá đơn giản, chỉ là mối quan hệ cha-con và thứ tự sắp xếp của các chỉ mục của Menu.
Giải thuật của mình đơn giản thế này thôi
1. Tạo một bảng hoặc một vùng để quản lý thực đơn trong đó có một số điểm quan trọng như sau:
+ Chỉ mục thực đơn (thường quản lý bằng cơ chế Autonumber tức là tự động tăng khi thêm dòng).
+ Số chỉ mục của Menu Cha (ở đây sẽ lưu giữ số thẻ chỉ mục của thực đơn cha). Nếu chỉ mục này rỗng thì đó là thực đơn cấp cao nhất.
+ Tên thực đơn (thực ra dịch thế không đúng, nó phải là tiêu đề thực đơn - Caption mà). Tất nhiên để tùy biến về ngôn ngữ người ta cũng có thể thêm trường quản lý ngôn ngữ chẳng hạn Caption_E cho tiếng Anh, Caption_V cho tiếng Việt.
+ Hành động: đây là dữ liệu quy định mục thực đơn đó sẽ kích hoạt thủ tục/ hàm nào khi được chọn.
+ Tag, đây là một trường phụ ghi chép lại các thông tin bổ sung cho mục thực đơn nếu bạn cần, các nội dung của trường này sẽ được ghi vào thuộc tính Tag khi menu được tạo ra.
+ Ngoài ra còn một số trường khác quy định đặc tính, kiểu hiện thị của thực đơn nữa. Nhưng những nội dung trên đã là quan trọng nhất để tạo ra một thực đơn có thể làm việc được rồi đấy.
+ Đôi khi người ta còn bổ sung kiểu thực đơn - dạng nút/ thực đơn con hoặc là Hộp chọn ... nhưng thường thì phần bổ sung này dễ làm nảy sinh lỗi vì người dùng có thể quên lại cho thuộc tính của một thực đơn phụ là msoControlButton chẳng hạn trong khi nó phải là msoControlPopup. Vì thế dân có kinh nghiệm thì hay xử lý phần này trong Code hoặc kiểm soát các đặc tính này rất kỹ.
2. Sau khi đã có bảng, giờ là lúc tạo thực đơn.
Tất nhiên bạn cần phải quyết định là muốn tạo thực đơn hay thanh công cụ, cú pháp và giải thích cụ thể, xin xem trong bài số 3 của mục này.
Cách tạo thực đơn cũng khá đơn giản, với cách này bạn có thể làm rất nhiều thực đơn đa lớp mà không cần biết nó thuộc lớp 1 hay 2 hay 3.
Cách thực thi cụ thể như tôi giải thích trong phần code dưới đây.
3. Một vài gợi ý:
Nếu bạn phải viết một ứng dụng lớn có phân cấp người dùng và phân cấp ứng dụng (chẳng hạn có nút Open/New) bạn muốn dùng chung trong nhiều ứng dụng trong khi nút Print chỉ hiển thị trong một số ứng dụng khác trong khi đó bạn ngại không muốn tạo nhiều thực đơn. Một trong các gợi ý là sử dụng thẻ Tag trên đây nhưng lưu ý dữ liệu lưu vào thuộc tính tag của thực đơn phải được chuẩn hóa.
Sau này bạn chỉ cần đặc tả tham số tìm kiếm cho cú pháp FindControl là có thể tùy biến việc hiển thị hay tắt hiển thị các mục thực đơn một cách dễ dàng.
Chẳng hạn trong thẻ tag tôi ghi như sau 10_NA thì nó sẽ được dịch ra là đây là thực đơn con của thực đơn có thẻ index là 10 và nó chỉ hiển thị khi Người dùng là bình thường/Normal và người dùng là A/Advanced. Đấy chỉ là các cách tùy biến của dân lập trình thôi.
Đây là Code trong Module
Bạn tải file đính kèm và nhớ điều chỉnh chế độ Macro và xem thử.
Nếu có thời gian mình sẽ viết chi tiết.
Mình định viết chi tiết một chút nhưng do thời gian hạn hẹp nên chỉ xin phép đăng đoạn Code và file ví dụ để mọi người tiện tham khảo.
Giờ có thêm chút thời gian ngẫm nghĩ, mình xin viết cụ thể một chút.
Thực ra ý tưởng này bắt nguồn từ việc xem các menu quản lý Web của Joomla (một phần mềm nguồn mở quản trị nội dung Web khá nổi tiếng)
Cách tiếp cận của Joomla khá đơn giản, chỉ là mối quan hệ cha-con và thứ tự sắp xếp của các chỉ mục của Menu.
Giải thuật của mình đơn giản thế này thôi
1. Tạo một bảng hoặc một vùng để quản lý thực đơn trong đó có một số điểm quan trọng như sau:
+ Chỉ mục thực đơn (thường quản lý bằng cơ chế Autonumber tức là tự động tăng khi thêm dòng).
+ Số chỉ mục của Menu Cha (ở đây sẽ lưu giữ số thẻ chỉ mục của thực đơn cha). Nếu chỉ mục này rỗng thì đó là thực đơn cấp cao nhất.
+ Tên thực đơn (thực ra dịch thế không đúng, nó phải là tiêu đề thực đơn - Caption mà). Tất nhiên để tùy biến về ngôn ngữ người ta cũng có thể thêm trường quản lý ngôn ngữ chẳng hạn Caption_E cho tiếng Anh, Caption_V cho tiếng Việt.
+ Hành động: đây là dữ liệu quy định mục thực đơn đó sẽ kích hoạt thủ tục/ hàm nào khi được chọn.
+ Tag, đây là một trường phụ ghi chép lại các thông tin bổ sung cho mục thực đơn nếu bạn cần, các nội dung của trường này sẽ được ghi vào thuộc tính Tag khi menu được tạo ra.
+ Ngoài ra còn một số trường khác quy định đặc tính, kiểu hiện thị của thực đơn nữa. Nhưng những nội dung trên đã là quan trọng nhất để tạo ra một thực đơn có thể làm việc được rồi đấy.
+ Đôi khi người ta còn bổ sung kiểu thực đơn - dạng nút/ thực đơn con hoặc là Hộp chọn ... nhưng thường thì phần bổ sung này dễ làm nảy sinh lỗi vì người dùng có thể quên lại cho thuộc tính của một thực đơn phụ là msoControlButton chẳng hạn trong khi nó phải là msoControlPopup. Vì thế dân có kinh nghiệm thì hay xử lý phần này trong Code hoặc kiểm soát các đặc tính này rất kỹ.
2. Sau khi đã có bảng, giờ là lúc tạo thực đơn.
Tất nhiên bạn cần phải quyết định là muốn tạo thực đơn hay thanh công cụ, cú pháp và giải thích cụ thể, xin xem trong bài số 3 của mục này.
Cách tạo thực đơn cũng khá đơn giản, với cách này bạn có thể làm rất nhiều thực đơn đa lớp mà không cần biết nó thuộc lớp 1 hay 2 hay 3.
Cách thực thi cụ thể như tôi giải thích trong phần code dưới đây.
3. Một vài gợi ý:
Nếu bạn phải viết một ứng dụng lớn có phân cấp người dùng và phân cấp ứng dụng (chẳng hạn có nút Open/New) bạn muốn dùng chung trong nhiều ứng dụng trong khi nút Print chỉ hiển thị trong một số ứng dụng khác trong khi đó bạn ngại không muốn tạo nhiều thực đơn. Một trong các gợi ý là sử dụng thẻ Tag trên đây nhưng lưu ý dữ liệu lưu vào thuộc tính tag của thực đơn phải được chuẩn hóa.
Sau này bạn chỉ cần đặc tả tham số tìm kiếm cho cú pháp FindControl là có thể tùy biến việc hiển thị hay tắt hiển thị các mục thực đơn một cách dễ dàng.
Chẳng hạn trong thẻ tag tôi ghi như sau 10_NA thì nó sẽ được dịch ra là đây là thực đơn con của thực đơn có thẻ index là 10 và nó chỉ hiển thị khi Người dùng là bình thường/Normal và người dùng là A/Advanced. Đấy chỉ là các cách tùy biến của dân lập trình thôi.
Đây là Code trong Module
PHP:
Option Explicit
Sub CreateMenu()
' Khai bao cac bien chua Command bar truoc
Dim myMnuBar As CommandBar
Dim MuMnuButton As CommandBarControl
Dim mnuTemp As CommandBarControl
Dim tblMenu As Range
Dim MnuType As MsoControlType
' Khai bao cac bien dem
Dim i As Long
' Bay gio doc du lieu tu vung dang chon voi cac header nhu sau cho de nho
' Menu ID Parrent ID Caption Action Tag
Set tblMenu = Selection
' 1. Khoi tao Thanh menu tam thoi, khi thoat excel thi het
If MenuBarExist("mnuBarTest") Then
'neu menubar nay da ton tai - xoa ngay
Application.CommandBars("mnuBarTest").Delete
End If
' Gio thi tao menu bar
Set myMnuBar = Application.CommandBars.Add("mnuBarTest", , , True)
' Hien thi no nao
myMnuBar.Visible = True
' Tao cac menu con
With myMnuBar
' Phai bat dau tu 2 vi ta co dong 1 la header
For i = 2 To tblMenu.Rows.Count
' Kiem tra truong ParentID
If tblMenu.Cells(i, 2) <> "" Then
' Day la menu con
' Tuy nhien phai kiem tra xem no se co the con co menu con nao nua khong nhe
' Sau do thi xac dinh kieu menu do
MnuType = GetMenuType(tblMenu, 2, tblMenu.Cells(i, 1).Value)
' vi mnu co cac mnu con nen phai gan cho no mot gia tri phu nhe
' Nhớ tham số cuối là True nhé - điều này quan trọng nếu không thì sẽ không tìm được đúng mục thực đơn ta cần
Set mnuTemp = myMnuBar.FindControl(, , tblMenu.Cells(i, 2).Value, , True)
If mnuTemp Is Nothing Then
' Khong tim thay menu do, chan qua - bo qua va bao loi
GoTo ExitSub
Else
Set MuMnuButton = mnuTemp.Controls.Add(MnuType, , , , True)
End If
Else
' Day la lop menu tren cung, khoi tao
Set MuMnuButton = .Controls.Add(msoControlPopup, , , , True)
End If
' Thiet lap Caption cho Menu
MuMnuButton.Caption = tblMenu.Cells(i, 3).Value
' Gio nho lai cai tag cua control nay nhe
MuMnuButton.Tag = tblMenu.Cells(i, 1).Value
Next
End With
ExitSub:
Set mnuTemp = Nothing
Set MuMnuButton = Nothing
Set myMnuBar = Nothing
End Sub
Private Function MenuBarExist(MenuBarName As String) As Boolean
' Hàm này xác định xem menubar này có tồn tại không thế.
Dim myMnuBar As CommandBar
Dim mnuCount As Long
On Error GoTo ErrHandler
Set myMnuBar = Application.CommandBars(MenuBarName)
mnuCount = myMnuBar.Controls.Count
MenuBarExist = True
ErrHandler:
End Function
Private Function GetMenuType(DataRange As Range, SearchColumn As Long, MenuTag As String) As MsoControlType
' Thu tuc nay xac dinh kieu menu bang cach tim xem co thay menu nao goi no bang cha khong
Dim SearchRange As Range
Set SearchRange = DataRange.Range(DataRange.Cells(2, SearchColumn), DataRange.Cells(DataRange.Rows.Count, SearchColumn))
If GetRangeValue(SearchRange.Find(MenuTag)) <> "" Then
' Kieu co the co menu con
GetMenuType = msoControlPopup
Else
' Kieu khong co menu con
GetMenuType = msoControlButton
End If
Set SearchRange = Nothing
End Function
Private Function GetRangeValue(MyRange As Variant) As String
' Ham nay de doi gia tri cua rang thanh dang text de ham thuc hien dung
On Error Resume Next
GetRangeValue = MyRange.Value
End Function
Nếu có thời gian mình sẽ viết chi tiết.
File đính kèm
Lần chỉnh sửa cuối: