Dividere un menu in più colonne (Tutorial completo)
Utilizzando le informazioni contenute nelle lezioni precedenti sui menu, creiamo adesso
un piccolo esempio che mostra come suddividere un menu in più colonne.
Il risultato sarà del tutto simile a quello mostrato nella figura sottostante:
Cominciamo subito, visto che avremo tante cose da fare.
Iniziamo aprendo un progetto EXE Standard. Verrà creata per default una form
denominata Form1. Creiamo un menu con l'editor di menu. Tale menu deve avere
come minimo una struttura di questo tipo:
&Files
...&Apri
...&Chiudi
ossia il menu Files deve contenere almeno due voci, visto che divideremo il menu in due
colonne.
Naturalmente l'esempio è applicabile senza restrizioni anche ad un menu
formato da più voci. L'inserimento del numero di voci è a discrezione di ognuno: il
codice si preoccuperà di individuare quante voci ci sono e di dividerle in due colonne.
Il risultato sarà questo:
Fatto questo, passiamo al codice. Non verranno trattate in maniera approfondita le
API e le strutture utilizzate nel progetto in quanto già analizzate in precedenza. Per ogni
dubbio fare riferimento all'indice analitico di guide e tutorials.
Siccome utilizzeremo solamente Form1, è del tutto inutile aprire un nuovo modulo.
Le API, le strutture e le costanti verranno dunque dichiarate come PRIVATE. Anche
in questo caso è possibile consultare la guida relativa.
Ecco la parte generale del modulo dove vengono dichiarate la struttura MENUITEMINFO,
la funzione GETMENU, la funzione GETMENUITEMINFO,
la funzione GETMENUITEMCOUNT, la funzione SETMENUITEMINFO
e per finire la funzione GetSubMenu:
Private Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type
Private Declare Function GetMenu Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As _
Long) As Long
Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, _
ByVal nPos As Long) As Long
Private Declare Function GetMenuItemInfo Lib "user32" Alias _
"GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long,
ByVal b As _
Boolean, lpmii As MENUITEMINFO) As Long
Private Declare Function SetMenuItemInfo Lib "user32" Alias _
"SetMenuItemInfoA" (ByVal hMenu As Long, ByVal uItem As Long, ByVal _
fByPosition As Long, lpmii As MENUITEMINFO) As Long
Private Const MIIM_STATE As Long = &H1
Private Const MIIM_ID As Long = &H2
Private Const MIIM_SUBMENU As Long = &H4
Private Const MIIM_CHECKMARKS As Long = &H8
Private Const MIIM_TYPE As Long = &H10
Private Const MIIM_DATA As Long = &H20
Private Const MFT_RADIOCHECK As Long = &H200
Private Const MFT_STRING As Long = &H0
Private Const RGB_STARTNEWCOLUMNWITHVERTBAR As Long = &H20
Private Const RGB_STARTNEWCOLUMN As Long = &H40
Private Const RGB_EMPTY As Long = &H100
Private Const RGB_VERTICALBARBREAK As Long = &H160
Private Const RGB_SEPARATOR As Long = &H800
|
Notare che anche le costanti dei membri della struttura MENUITEMINFO sono già stati
ampiamente trattati.
A questo punto buttiamoci sul codice che ci permetterà di dividere il menu in più colonne.
E' a tal fine possibile inserire il codice nell'evento Click di un CommandButton. Noi
per semplicità e per evitare di avere controlli sul piano, lo inseriremo semplicemente
nell'evento Load di Form1. Cominciamo col dichiarare le variabili ossia hSubMenu, cioè
il riferimento (o HANDLE) al sottomenu, nOggetti cioè il numero di voci presenti nel menu, mii la struttura
(MENUITEMINFO) ed OggettoExtra, che poi vedremo a cosa servirà:
Private Sub Form_Load()
Dim hSubMenu As Long
Dim nOggetti As Long
Dim mii As MENUITEMINFO
Dim OggettoExtra As Long
|
Adesso troviamo l'intero tramite il quale da ora in poi potremo fare riferimento
al sottomenu:
hSubMenu = GetSubMenu(GetMenu(Me.hwnd), 0)
|
E contiamo il numero di oggetti presenti nel sottomenu (nel nostro esempio, 2)
nOggetti = GetMenuItemCount(hSubMenu)
|
A questo punto introduciamo il concetto di Modulo, un operatore associato
alla divisione tra numeri interi: quando viene effettuata la divisione tra interi, l'operazione
stessa fornisce il quoziente mentre il Modulo ritorna il resto.
Ad esempio 5 Mod 3 dà 2 poichè 5 / 3=1 col resto di 2, 0 Mod 8 dà 8 poichè 0 / 8 = 0
col resto di 8, 4 Mod 2 dà 0 perchè 4 / 2 dà 2 senza resto.
Se quindi la divisione tra il numero di voci presenti nel sottomenu ed il numero di colonne
nel quale si vuole dividere il sottomenu ritorna un resto che è diverso da 0, questo resto
è rappresentato da una voce in più, che dev'essere inserita nella seconda colonna del sottomenu:
If nOggetti Mod 2 <> 0 Then OggettoExtra = 1
|
Ora, dopo aver definito le caratteristiche della struttura,
inseriamo al suo interno le informazioni relative all'ultima voce del sottomenu:
With mii
.cbSize = Len(mii)
.fMask = MIIM_TYPE
.fType = MFT_STRING
.dwTypeData = Space$(256)
.cch = Len(.dwTypeData)
End With
GetMenuItemInfo hSubMenu, (nOggetti \ 2) + OggettoExtra, True, mii
|
Modifichiamo per finire le caratteristiche del sottomenu invocando la funzione
SetMenuItemInfo che ci permette di inserire un separatore verticale tra le
due colonne, e chiudiamo il codice con un End Sub:
mii.fType = RGB_STARTNEWCOLUMNWITHVERTBAR
mii.fMask = MIIM_TYPE
SetMenuItemInfo hSubMenu, (nOggetti \ 2) + OggettoExtra, True, mii
End Sub
|
Per concludere, riassumiamo qui di seguito il codice completo del progetto:
Private Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type
Private Declare Function GetMenu Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As _
Long) As Long
Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, _
ByVal nPos As Long) As Long
Private Declare Function GetMenuItemInfo Lib "user32" Alias _
"GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long,
ByVal b As _
Boolean, lpmii As MENUITEMINFO) As Long
Private Declare Function SetMenuItemInfo Lib "user32" Alias _
"SetMenuItemInfoA" (ByVal hMenu As Long, ByVal uItem As Long, ByVal _
fByPosition As Long, lpmii As MENUITEMINFO) As Long
Private Const MIIM_STATE As Long = &H1
Private Const MIIM_ID As Long = &H2
Private Const MIIM_SUBMENU As Long = &H4
Private Const MIIM_CHECKMARKS As Long = &H8
Private Const MIIM_TYPE As Long = &H10
Private Const MIIM_DATA As Long = &H20
Private Const MFT_RADIOCHECK As Long = &H200
Private Const MFT_STRING As Long = &H0
Private Const RGB_STARTNEWCOLUMNWITHVERTBAR As Long = &H20
Private Const RGB_STARTNEWCOLUMN As Long = &H40
Private Const RGB_EMPTY As Long = &H100
Private Const RGB_VERTICALBARBREAK As Long = &H160
Private Const RGB_SEPARATOR As Long = &H800
Private Sub Form_Load()
Dim hSubMenu As Long
Dim nOggetti As Long
Dim mii As MENUITEMINFO
Dim OggettoExtra As Long
hSubMenu = GetSubMenu(GetMenu(Me.hwnd), 0)
nOggetti = GetMenuItemCount(hSubMenu)
If nOggetti Mod 2 <> 0 Then OggettoExtra = 1
With mii
.cbSize = Len(mii)
.fMask = MIIM_TYPE
.fType = MFT_STRING
.dwTypeData = Space$(256)
.cch = Len(.dwTypeData)
End With
GetMenuItemInfo hSubMenu, (nOggetti \ 2) + OggettoExtra, True, mii
mii.fType = RGB_STARTNEWCOLUMNWITHVERTBAR
mii.fMask = MIIM_TYPE
SetMenuItemInfo hSubMenu, (nOggetti \ 2) + OggettoExtra, True, mii
End Sub
|
|