Excel con elenchi a discesa condizionati

Anonimo
2018-07-19T11:16:02+00:00

Buongiorno a tutti,

ho cercato varie soluzioni con funzioni tipo Indiretto, CercaVert, etc, ma non riesco a venirne a capo. 

Chiedo gentilmente un aiuto.

Ho un foglio Excel con queste 3 colonne:

A       B        C

Q1 1/4/18 Rossi   

Q1 2/4/18 Bianchi

Q2 1/4/18 Verdi

Q3 2/4/18 Gialli

Q4 1/4/18 Blu

Q4 2/4/18 Blu

In un secondo foglio avrei bisogno di un elenco a discesa in una colonna, supponiamo la A, che mi elenchi univocamente gli elementi della prima colonna suddetta, cioè Q1,Q2,Q3,Q4. Sulla base di questa selezione la colonna B sempre di questo secondo foglio dovrebbe contenere in un elenco a discesa solo le date corrispondenti , cioè 1/4/18 e 2/4/18 se avessi scelto Q1 nella colonna A, oppure solo 2/4/18 se avessi scelto Q3. Quindi una terza colonna, C, con un elenco a discesa in base alle prime due selezioni, cioè elenchi solo Bianchi se nella colonna B avessi selezionato come data 2/4/18 e Q1 nella A.

Spero sia tutto chiaro.

Grazie a tutti, Max.

Microsoft 365 e Office | Excel | Per la casa | Windows

Domanda bloccata. Questa domanda è stata eseguita dalla community del supporto tecnico Microsoft. È possibile votare se è utile, ma non è possibile aggiungere commenti o risposte o seguire la domanda.

0 commenti Nessun commento
Risposta accettata dall'autore della domanda
Anonimo
2018-07-25T19:59:45+00:00

Buonasera a tutti possibile soluzione solo con formule

In foglio1 ho ricostruito la tabella esempio da A2 a C7

In foglio2 da A2 a C2 le celle da usare per le convalide uso tre colonne di sevizio la H la I e la J (eventualmente da nascondere)

in H2 da trascinare in basso

=SE.ERRORE(INDICE(Foglio1!$A$2:$A$100;CONFRONTA(0;INDICE(CONTA.SE($H$1:H1;Foglio1!$A$2:$A$100&""););0));"")

in I2 da trascinare in basso

=SE.ERRORE(INDICE(Foglio1!B$2:B$100;AGGREGA(15;6;RIF.RIGA($A$2:$A$100)/(Foglio1!$A$2:$A$100=$A$2)-1;RIF.RIGA($A1)));"")

in J2 da trascinare in basso

=SE.ERRORE(INDICE(Foglio1!C$2:C$100;AGGREGA(15;6;RIF.RIGA($A$2:$A$100)/(Foglio1!$A$2:$A$100&Foglio1!$B$2:$B$100=$A$2&$B$2)-1;RIF.RIGA($A1)));"")

seleziona la cella A2 del foglio2 DATI->CONVALIDA DATI->ELENCO

nella barra della formula incolla

=SCARTO($H$2;;;MATR.SOMMA.PRODOTTO(--($H$2:$H$100<>"")))

ripeti la procedura per le celle B2 e C2 incollando per B2

=SCARTO($I$2;;;MATR.SOMMA.PRODOTTO(--($I$2:$I$100<>"")))

per C2

=SCARTO($J$2;;;MATR.SOMMA.PRODOTTO(--($J$2:$J$100<>"")))

allego link per scaricare file di lavoro

https://www.dropbox.com/s/9mj9bymrr1tagh6/convalida.xlsx?dl=0

La risposta è stata utile?

0 commenti Nessun commento
Risposta accettata dall'autore della domanda
Anonimo
2018-07-25T18:37:04+00:00

Ho avuto un po' di tempo per testare con un po' più di calma il codice e ho visto che c'era bisogno di qualche modifica soprattutto per gestire il caso in cui l'intervallo dei dati sia vuoto, sia composto da una sola riga o nel caso in cui, in presenza di una voce nella prima colonna ma non vi siano valori in seconda colonna, o se presente in seconda colonna non vi sia valore in terza colonna.

Ho anche apportato una ulteriore modifica alla funzione di Norman perché in automatico ordini matrici ad  una dimensione o a due dimensioni.

Ho anche fatto in modo che se il primo foglio attivo quando si apre il file è quello delle celle con le convalide vengano valorizzati i "riferimenti" lanciando la Sub ImpostaRiferimenti.

Ancora quando viene attivato il figlio con le celle con le convalide ora anche la prima cella viene cancellata (e viene eliminata la convalida) prima di reimpostare la convalida per la prima cella.

Questo il nuovo file di esempio: File esempio #2

Ripropongo il codice per intero.

Nel Modulo1

'----

Option Explicit

Public Const sNomeFoglioIntervallo As String = "Foglio1" '<= da personalizzare

Public Const sPrimaCellaIntervallo As String = "A3" '<= da personalizzare

Const sNomeFoglioConvalide As String = "Foglio2" '<= da personalizzare

Const sCellaConvalida1 As String = "A2" '<= da personalizzare

Const sCellaConvalida2 As String = "B2" '<= da personalizzare

Const sCellaConvalida3 As String = "C2" '<= da personalizzare

Public Wb As Workbook

Dim FoglioIntervallo As Worksheet

Dim FoglioConvalide As Worksheet

Dim rPrimaCellaIntervallo As Range

Dim rIntervalloDati As Range

Public rCellaConvalida1 As Range

Public rCellaConvalida2 As Range

Public rCellaConvalida3 As Range

Dim arrColonna1 As Variant

Dim arrColonna2 As Variant

Dim arrColonna3 As Variant

Sub ImpostaRiferimenti()

   Set Wb = ThisWorkbook

   With Wb

      Set FoglioIntervallo = .Worksheets(sNomeFoglioIntervallo)

      Set FoglioConvalide = .Worksheets(sNomeFoglioConvalide)

   End With

   Set rPrimaCellaIntervallo = FoglioIntervallo.Range(sPrimaCellaIntervallo)

   Set rIntervalloDati = IntervalloDati_LrLc(rPrimaCellaIntervallo, False, False)

   arrColonna1 = rIntervalloDati.Columns(1).Value

   arrColonna2 = rIntervalloDati.Columns(2).Value

   arrColonna3 = rIntervalloDati.Columns(3).Value

   With FoglioConvalide

      Set rCellaConvalida1 = .Range(sCellaConvalida1)

      Set rCellaConvalida2 = .Range(sCellaConvalida2)

      Set rCellaConvalida3 = .Range(sCellaConvalida3)

   End With

End Sub

Sub ImpostaConvalida1()

   Dim ArrConvalida As Variant

   Dim sConvalida As String

   If Wb Is Nothing Then Call ImpostaRiferimenti

   If IsArray(arrColonna1) Then

      ArrConvalida = SortedUniqueList(arrColonna1)

      sConvalida = Join(ArrConvalida, ",")

   Else

      sConvalida = arrColonna1

   End If

   Call ImpostaConvalida(rCellaConvalida1, sConvalida)

End Sub

Sub ImpostaConvalida2()

   Dim strConvalida1 As String

   Dim iStr As String, iStr2 As String

   Dim i As Long, cont As Long

   Dim ArrConvalida() As Variant

   Dim arrConvalidaUnique As Variant

   Dim sConvalida As String

   If Wb Is Nothing Then Call ImpostaRiferimenti

   strConvalida1 = rCellaConvalida1.Value

   If strConvalida1 <> vbNullString Then

      If IsArray(arrColonna1) Then

         For i = 1 To UBound(arrColonna1)

            iStr = arrColonna1(i, 1)

            If Not iStr = vbNullString Then

               If iStr = strConvalida1 Then

                  iStr2 = arrColonna2(i, 1)

                  If Not iStr2 = vbNullString Then

                     cont = cont + 1

                     ReDim Preserve ArrConvalida(1 To cont)

                     ArrConvalida(cont) = iStr2

                  End If

               End If

            End If

         Next i

         If cont > 0 Then

            arrConvalidaUnique = SortedUniqueList(ArrConvalida)

            sConvalida = Join(arrConvalidaUnique, ",")

            Call ImpostaConvalida(rCellaConvalida2, sConvalida)

         End If

      Else

         sConvalida = arrColonna2

         Call ImpostaConvalida(rCellaConvalida2, sConvalida)

      End If

   End If

End Sub

Sub ImpostaConvalida3()

   Dim strConvalida1 As String, strConvalida2 As String

   Dim iStr As String, iStr2 As String, iStr3 As String

   Dim i As Long, j As Long, cont As Long

   Dim ArrConvalida() As Variant

   Dim arrConvalidaUnique As Variant

   Dim sConvalida As String

   If Wb Is Nothing Then Call ImpostaRiferimenti

   strConvalida1 = rCellaConvalida1.Value

   strConvalida2 = rCellaConvalida2.Value

   If strConvalida2 <> vbNullString Then

      If IsArray(arrColonna1) Then

         For i = 1 To UBound(arrColonna1)

            iStr = arrColonna1(i, 1)

            If Not iStr = vbNullString Then

               If iStr = strConvalida1 Then

                  iStr2 = arrColonna2(i, 1)

                  If Not iStr2 = vbNullString Then

                     If iStr2 = strConvalida2 Then

                        iStr3 = arrColonna3(i, 1)

                        If Not iStr3 = vbNullString Then

                           cont = cont + 1

                           ReDim Preserve ArrConvalida(1 To cont)

                           ArrConvalida(cont) = iStr3

                        End If

                     End If

                  End If

               End If

            End If

         Next i

         If cont > 0 Then

            arrConvalidaUnique = SortedUniqueList(ArrConvalida)

            sConvalida = Join(arrConvalidaUnique, ",")

            Call ImpostaConvalida(rCellaConvalida3, sConvalida)

         End If

      Else

         sConvalida = arrColonna3

         Call ImpostaConvalida(rCellaConvalida3, sConvalida)

      End If

   End If

End Sub

Sub ImpostaConvalida(rngConvalida As Range, sConvalida As String)

       With rngConvalida.Validation

        .Delete

        If sConvalida = vbNullString Then Exit Sub

        .Add Type:=xlValidateList, _

             AlertStyle:=xlValidAlertStop, _

             Operator:=xlBetween, _

             Formula1:=sConvalida

        .IgnoreBlank = True

        .InCellDropdown = True

        .InputTitle = ""

        .ErrorTitle = "Errore"

        .InputMessage = ""

        .ErrorMessage = "Selezionare una voce dell'elenco a discesa!"

        .ShowInput = True

        .ShowError = True

    End With

End Sub

'<--- funzione per impostare l'intervallo di celle da elaborare --->

Function IntervalloDati_LrLc(PrimaCellaDati As Range, _

                             Optional bRigaIntestazioni As Boolean = True, _

                             Optional bColonnaIntestazioni As Boolean = False, _

                             Optional sPassword As String = "", _

                             Optional bUserInterfaceOnly As Boolean = False) As Range

  Dim Ws As Worksheet

  Dim rng As Range

  Dim bProtected As Boolean

  Dim UltimaCellaDati As Range

  Dim iUltimaRigaDati As Long, iUltimaColonnaDati As Long

  Set Ws = PrimaCellaDati.Parent

  If bRigaIntestazioni Then Set PrimaCellaDati = PrimaCellaDati.Offset(1, 0)

  If bColonnaIntestazioni Then Set PrimaCellaDati = PrimaCellaDati.Offset(0, 1)

  With Ws

    bProtected = .ProtectContents

    If bProtected Then .Unprotect Password:=sPassword

    Set rng = .Cells

    On Error Resume Next

    iUltimaRigaDati = rng.Find(What:="*", _

                      After:=rng.Cells(1), _

                      LookAt:=xlPart, _

                      LookIn:=xlFormulas, _

                      SearchOrder:=xlByRows, _

                      SearchDirection:=xlPrevious, _

                      MatchCase:=False).Row

    iUltimaColonnaDati = rng.Find(What:="*", _

                         After:=rng.Cells(1), _

                         LookAt:=xlPart, _

                         LookIn:=xlFormulas, _

                         SearchOrder:=xlByColumns, _

                         SearchDirection:=xlPrevious, _

                         MatchCase:=False).Column

    On Error GoTo 0

    With PrimaCellaDati

     If iUltimaRigaDati < .Row Then iUltimaRigaDati = .Row

     If iUltimaColonnaDati < .Column Then iUltimaColonnaDati = .Column

    End With

    Set UltimaCellaDati = .Cells(iUltimaRigaDati, iUltimaColonnaDati)

    Set IntervalloDati_LrLc = .Range(PrimaCellaDati, UltimaCellaDati)

    If bProtected Then .Protect Password:=sPassword, UserInterfaceOnly:=bUserInterfaceOnly

  End With

End Function

Public Function SortedUniqueList(v As Variant) As Variant

   'by Norman David Jones

   Dim oSortedUniqueList As Object

   Dim arrOut() As Variant

   Dim sStr As String

   Dim i As Long

   Dim bool As Boolean

   On Error Resume Next

   bool = UBound(v, 2) > 0

   On Error GoTo 0

   Set oSortedUniqueList = CreateObject("System.Collections.SortedList")

   With oSortedUniqueList

      For i = LBound(v) To UBound(v)

         If bool Then

            sStr = v(i, 1)

         Else

            sStr = v(i)

         End If

       If Not sStr = vbNullString Then

         If Not .ContainsKey(sStr) Then

           .Add Key:=sStr, Value:=i

         End If

      End If

      Next i

      ReDim arrOut(1 To .Count)

      For i = 0 To .Count - 1

         arrOut(i + 1) = .GetKey(i)

      Next i

   End With

   SortedUniqueList = arrOut

End Function

'----

Nel modulo di classe Foglio2

'----

Option Explicit

Private Sub Worksheet_Activate()

   If Wb Is Nothing Then Call ImpostaRiferimenti

   With rCellaConvalida1

      .Validation.Delete

      .ClearContents

   End With

   Call ImpostaRiferimenti

   Call ImpostaConvalida1

End Sub

Private Sub Worksheet_Change(ByVal Target As Range)

   Application.EnableEvents = False

   On Error GoTo Errore

   If Not Intersect(Target(1, 1), rCellaConvalida1) Is Nothing Then

         With rCellaConvalida2

            .Validation.Delete

            .ClearContents

         End With

         With rCellaConvalida3

            .Validation.Delete

            .ClearContents

         End With

         Call ImpostaConvalida2

   End If

   If Not Intersect(Target(1, 1), rCellaConvalida2) Is Nothing Then

      With rCellaConvalida3

         .Validation.Delete

         .ClearContents

      End With

      Call ImpostaConvalida3

   End If

RiprendiErrore:

   Application.EnableEvents = True

   Exit Sub

Errore:

   MsgBox "Si è verificato un errore!" & vbNewLine & _

          "Errore numero: " & Err.Number & vbNewLine & _

          Err.Description, vbCritical, "Errore VBA!"

   Resume RiprendiErrore

End Sub

'----

La risposta è stata utile?

0 commenti Nessun commento

5 risposte aggiuntive

Ordina per: Più utili
  1. Anonimo
    2018-07-25T14:16:06+00:00

    Ciao Max,

    ti propongo una possibile soluzione.

    In un modulo strandard ho inserito il seguente codice:

    ....

    Edit: codice VBA cancellato in quanto sostituito nel successivo messaggio

    ....

    In pratica quando viene attivato il Foglio2 viene lanciata la Sub ImpostaRiferimenti che imposta tutti i riferimenti utili per impostare le tre convalide e inoltre imposta già la prima convalida.

    Poi, a scalare, quando si modifica il valore della cella della prima convalida viene impostata la convalida della seconda cella e quando si modifica il valore presente nella seconda cella viene impostata la convalida della terza cella.

    Quando si cambia una delle celle per le successive viene cancellato il contenuto e cancellato la convalida perché in base al valore della cella precedente potrebbero cambiare i riferimenti e quindi i valori ammessi.

    Una cosa che non sono riuscito è mantenere, all'interno dell'elenco a convalida le date in formato gg/mm/aaaa.

    Nella convalida, nel passaggio VBA, le date vengono visualizzate in formato g/m/aaaa.

    ....

    Edit: link al primo file eliminato in quanto sostituito con quello presente nel successivo messaggio

    ....

    Ho fatto un po' di prove e mi pare riporti i dati correttamente.

    Magari fai tu qualche test più approfondito con i tuoi dati reali.

    Edit: tra le varie routine e function ho preso a prestito una funzione per ordinare le matrici del buon Norman David Jones :)

    La risposta è stata utile?

    0 commenti Nessun commento
  2. Anonimo
    2018-07-25T08:35:03+00:00

    Ciao Andrea, grazie, nel frattempo sto provando con Microsoft Query.

    La risposta è stata utile?

    0 commenti Nessun commento
  3. Anonimo
    2018-07-25T08:14:10+00:00

    Ciao Max

    mentre attendi che uno dei nostri moderatori ti risponda, potresti dare un'occhiata anche al nostro forum specializzato sulla macro di Excel MSDN. Ovviamente, se dovessi aver bisogno di ulteriore supporto, sono a tua disposizione

    Buona gionata

    Andrea

    La risposta è stata utile?

    0 commenti Nessun commento