Forzare in ordine numerico delle caselle combinate tramite VBA

di BLUES il
32 risposte

Ciao,

ho strutturato sulla maschera con le caselle combinate in gerarchia con TAG a "X", inserisco i codici nell'evento dopo aggiornamento della  prima casella combinata:

getRequery

e

Private Function getRequery()
Dim ctl As Access.Control

    For Each ctl In Me.Controls
        If ctl.Tag = "X" Then
            If ctl.ControlType = acComboBox Then
                ctl.Requery
                    If ctl.ListCount <= 1 Then ctl = ctl.ItemData(0)
            End If
        End If

    Next
    Set ctl = Nothing
End Function

Fin qui tutto funziona ma ho notato facendo delle prove usando TabIndex che seleziona le caselle combinate prima a 6 poi a 3 poi a 5, ecc...

Da notare che sulla maschera le caselle combinate in gerarchia sono già in ordine di tabulazione ma in VBA non va come dovrebbe...

ciò che vorrei è che possano essere in ordine numerico forzato, se avete i suggerimenti da fare vi ringrazio.

Saluti

32 Risposte

  • Secondo me puoi risolvere in modo più semplice.

    Se adotti un sistema di nomenclatura per i ComboBox che sia numericamente progressivo, tipo:

    cmbCascata1, cmbCascata2, cmbCascata3, cmbCascata4, ....

    Puoi lanciare il requery di ognuno con un ciclo For...Next:

    For i = 1 To 4   '-> Oppure il numero massimo dei tuoi controlli
        With Me.Controls("cmbCascata" & i)
            .Requery
            If .ListCount <= 1 Then .Value= .ItemData(0)
        End With
    Next i

    In questo modo ti rendi completamente indipendente dalla posizione sul form, dalla sequenza di tabulazione e, soprattutto, eviti di analizzare controlli che non fanno parte del tuo sistema a cascata, visto che il tuo codice cicla comunque tutti i controlli del form.

    TheTruster

  • 12/01/2026 - TheTruster ha scritto:

    For i = 1 To 4 '-> Oppure il numero massimo dei tuoi controlli Me.Controls("cmbCascata" & i).Requery Next i

    Ottimo, così va molto meglio, grazie.

  • Grazie a te per il riscontro

    TheTruster

  • Ciao, i codici che mi avevi postato funzionano tutto perfettamente anche se ho dovuto rinominare, anche in VBA, tutti i CombBox per i numeri allora ho pensato che per evitare di rinominare tutte le caselle, comandi, ecc..., inserisco nel TAG i numeri senza complicazioni:

        For Each ctl In Me.Controls
        
        For I = 1 To 8
            If ctl.Tag = I Then
                If ctl.ControlType = acComboBox Then
                    ctl.Requery
                    If ctl.ListCount <= 1 Then ctl = ctl.ItemData(0)
                End If
            End If
        Next I
        
        Next
        Set ctl = Nothing

    ho voluto provare anche con TabIndex al posto di TAG ma mi dà errore e non so qual è la parola giusta sempre se è fattibile.

    If ctl.TabIndex = I Then 'qui mi dà l'errore

    Cmq penso che per i TAG possano andare più che bene.

    Antonio

  • 13/01/2026 - BLUES ha scritto:

    If ctl.TabIndex = I Then 'qui mi dà l'errore

    A me funziona tranquillamente accedendo direttamente alla TabIndex.

    A te che errore da?

    Comunque, magari prova così:

    If ctl.Properties("TabIndex").Value = I Then ...

    C'è da dire che, attualmente col tuo codice, fai un doppio ciclo su tutti i controlli. Magari ti conveniva perdere un po' di tempo a rinominarli con i numeri ;-)

    TheTruster

  • 12/01/2026 - BLUES ha scritto:

    Fin qui tutto funziona ma ho notato facendo delle prove usando TabIndex che seleziona le caselle combinate prima a 6 poi a 3 poi a 5, ecc...

    Da notare che sulla maschera le caselle combinate in gerarchia sono già in ordine di tabulazione ma in VBA non va come dovrebbe...

    ciò che vorrei è che possano essere in ordine numerico forzato, se avete i suggerimenti da fare vi ringrazio.

    anche in funzione di questa osservazione:

    12/01/2026 - TheTruster ha scritto:

    Secondo me puoi risolvere in modo più semplice.

    Se adotti un sistema di nomenclatura per i ComboBox che sia numericamente progressivo, tipo:

    cmbCascata1, cmbCascata2, cmbCascata3, cmbCascata4, ....

    Puoi lanciare il requery di ognuno con un ciclo For...Next:

    se hai elementi eterogenei e vuoi dare un ordine puoi usare una array.

    mytabarray={primovalore, secondovalore, ..., ultimovalore}

    cicli l'array e al mytabarray[x] ottieni il nome del controllo.

    nell'esempio

    cmbCascata1, cmbCascata2, cmbCascata3, cmbCascata4

    se l'ordine è 

     cmbCascata3, cmbCascata1, cmbCascata2, cmbCascata4

    basta popoplare l'array con i valori in ordine e richiamarli dall'array.

  • 13/01/2026 - sihsandrea ha scritto:

    se hai elementi eterogenei e vuoi dare un ordine puoi usare una array.

    Ottima idea.

    Basterebbe poi usarlo così:

    Dim myTabArray as Variant
    myTabArray=Array("Controllo1", "Combo4", "Testo7")
    With Me.Controls(myTabArray(i))
    '...
    End With

    TheTruster

  • 13/01/2026 - TheTruster ha scritto:

    13/01/2026 - BLUES ha scritto:

    If ctl.TabIndex = I Then 'qui mi dà l'errore

    A me funziona tranquillamente accedendo direttamente alla TabIndex.

    A te che errore da?

    Comunque, magari prova così:

    If ctl.Properties("TabIndex").Value = I Then ...

    C'è da dire che, attualmente col tuo codice, fai un doppio ciclo su tutti i controlli. Magari ti conveniva perdere un po' di tempo a rinominarli con i numeri ;-)

    TheTruster

    Mi da l'errore di run-time '438' Proprietà o Metodo non supportati dall'oggetto

    Poi non capisco perché a te funziona e a me no.

    Inoltre per un doppio ciclo su tutti i controlli non succederà se uso a partire dal numero di partenza "n"

    For I = n To 8

    Antonio

  • 13/01/2026 - BLUES ha scritto:

    Mi da l'errore di run-time '438' Proprietà o Metodo non supportati dall'oggetto

    Poi non capisco perché a te funziona e a me no.

    Dato l'errore, è verosimile pensare che alcuni dei controlli che stai ciclando non abbiano questa proprietà. E' il caso delle Label, ad esempio, per le quali infatti, non è possibile impostare il TabIndex. Eventualmente nel ciclo controlla esplicitamente che si tratti di ComboBox.

    In alternativa, se non puoi rinominare i ricontrolli, la soluzione più pulita ed efficiente ritengo sia quella dell'array, suggerita da sihsandrea

    TheTruster

  • 13/01/2026 - BLUES ha scritto:

    If ctl.ListCount <= 1 Then ctl = ctl.ItemData(0)

    ctl.ListCount   controllo/proprietà

    ctl.ItemData(0) controllo/proprietà

    e poi... solo ctl? che proprietà? questo ti porta l'errore che riscontri

    ctl.ListCount<=1 significa zero...

    If ctl.ListCount = 1 Then ctl.value = ctl.ItemData(0)

    prova la modifica

  • 12/01/2026 - TheTruster ha scritto:

    With Me.Controls("cmbCascata" & i) .Requery If .ListCount <= 1 Then .Value= .ItemData(0) End With

    infatti qui si usa .value del controllo

  • 13/01/2026 - BLUES ha scritto:

    For Each ctl In Me.Controls For I = 1 To 8 If ctl.Tag = I Then If ctl.ControlType = acComboBox Then ctl.Requery If ctl.ListCount <= 1 Then ctl = ctl.ItemData(0) End If End If Next I Next Set ctl = Nothing

    Qualquadra non mi cosa...

    Da 1 a 8... For each?

    Controltype=combobox? E se controltype=textbox ripeti il numero del ciclo?

    Ma fallo per le 8 combo per la sequenza che vuoi e basta

  • 13/01/2026 - sihsandrea ha scritto:

    Da 1 a 8... For each?

    Controltype=combobox? E se controltype=textbox ripeti il numero del ciclo?

    Ma fallo per le 8 combo per la sequenza che vuoi e basta

    Difatti era quello che proponevo fin dall'inizio:

    12/01/2026 - TheTruster ha scritto:

    Puoi lanciare il requery di ognuno con un ciclo For...Next:

    For i = 1 To 4   '-> Oppure il numero massimo dei tuoi controlli
        With Me.Controls("cmbCascata" & i)
            .Requery
            If .ListCount = 1 Then .Value= .ItemData(0)
        End With
    Next i

    In questo modo ti rendi completamente indipendente dalla posizione sul form, dalla sequenza di tabulazione e, soprattutto, eviti di analizzare controlli che non fanno parte del tuo sistema a cascata

    E comunque trovo molto sensata la tua proposta di utilizzare un Array per limitare i controlli da ciclare, così nella With Me.Controls si può passare direttamente l'elemento dell'Array usando come indice la variabile di controllo del ciclo For...Next

    TheTruster

  • In questi casi si può usare una Collection, se non si usa la Key in fase di Add(Item), ovviamente poi per puntare all'item specifico va ciclato ma con i controlli direi che è inutile, è discretamente più performante di un Array.

    Option Compare Database
    Option Explicit
    
    Dim mCCombo As Collection
    
    Private Sub Form_Load()
        Set mCCombo = New Collection
        With mCCombo
            .Add Me!Combo1
            .Add Me!Combo2
            .Add Me!Combo3
            .Add Me!Combo4
        End With
    End Sub

    Poi per usarla:

    Private Sub TestCollection()
        Dim mCbo As Access.Combo
        For Each mCbo In mCCombo
            Debug.Print mCbo.Name
        Next
    End Sub
Devi accedere o registrarti per scrivere nel forum
32 risposte