Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

di il
16 risposte

Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

Salve a tutti…

Nella function che stò testando devo leggere o passare come parametro, solo alcune aree selezionate.

Avendo selezionato più aree in un foglio di lavoro, devo passare alla function tutte le area selezionate fatto eccezione delle righe intere 

esempio:

In questo caso la riga 10, 11 e 16 non devono essere passate alla function
Mentre le righe 13,14,18 e 19 devono essere passate alla function

Pertanto in Range Address mi ritrovo questa selezione:

$11:$11,$A$13,$A$14,$16:$16,$A$18,$A$19,$10:$10

Pensavo di ricostruire un nuovo oggetto Range con le sole parti che ho evidenziato sopra ottenendo:

$A$13,$A$14,$A$18,$A$19

In questa ipotesi elaboro la stringa ricostruendola eliminando gli elementi che non interessano

Oppure

quale approccio sarebbe migliore per non leggere le righe intere?

Ho pensato di utilizzare il  For Each  Range In Selection  ma ovviamente restituisce tutte le singole celle selezionate nelle aree e pertanto non posso più riconoscere quali sono le righe intere e quelle no.

Grazie 

16 Risposte

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    Ciao

    Come ottieni questa riga: “Pertanto in Range Address mi ritrovo questa selezione:

    Prova a pubblicare il codice che utilizzi.

    Ciao,

    Mario

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    07/05/2023 - Marius44 ha scritto:


    Ciao

    Come ottieni questa riga: “Pertanto in Range Address mi ritrovo questa selezione:

    Prova a pubblicare il codice che utilizzi.

    Ciao,

    Mario

    Ciao
    semplicemente su evento Change del foglio di lavoro

    Private Sub Worksheet_Change(ByVal Target As Range)
    
        Se premuto il tasto Canc nel Range Target si ha le aree selezionata
        e in questo esempio si ha: $11:$11,$A$13,$A$14,$16:$16,$A$18,$A$19,$10:$1

    da questo range devo solo trattare ciò che non è “Riga Intera” e passare alla mia Function solo le altre aree selezionate

    Potrei Splittare la stringa in un Array e costruire un nuovo oggetto Range da passare alla mia Function, però se c'è un metodo più consono sarebbe molto meglio.

    Per esempio mi sono creato questa function per avere un range senza le aree di righe intere:

    Sub myNewRange(ByRef Target As Range)
    ' create an array by splitting the range
    Dim arySplit() As String
    arySplit = Split(Target.Address, ",")
    ' create string for the new range
    Dim strNewRange As String
    Dim iX As Integer
    For iX = 0 To UBound(arySplit)
       If Range(arySplit(iX)).Columns.Count < ActiveSheet.Columns.Count Then strNewRange = strNewRange & IIf(Trim(strNewRange) = vbNullString, "", ",") & arySplit(iX)
    Next iX
    ' return new range
    If strNewRange <> vbNullString Then Set Target = Range(strNewRange) Else Set Target = Nothing
    End Sub

    quindi passo alla function l'oggetto range = $11:$11,$A$13,$A$14,$16:$16,$A$18,$A$19,$10:$10
    e la function mi ritorna un oggetto Ragne = $A$13,$A$14,$A$18,$A$19

    Non mi piace un granchè questo metodo e preferirei usare un approccio migliore se esiste.

    A questo punto la mia Function riceve l'oggetto Range per eliminare il contenuto di talune celle con il For Each In Selection:

    Private Sub Worksheet_Change(ByVal Target As Range)
    
    ' if column 1 and cell => 1 and <= max number cells... clean up the celles
    If Target.Column = 1 And Target.Rows.Count >= 1 And Target.Columns.Count <= iColumnE Then
        ' set EnableEvents to prevent recursive calls to worksheet event functions
        Application.EnableEvents = False
        ' clean up the cells
        MyClearRowsMultiple Target
        ' set EnableEvents to restore events
        Application.EnableEvents = True
    End If
    
    End Sub
    
    ___________________________________________________________________________________________________________________________
    In un Modulo viene richiama la Function MyClearRowsMultiple :
    
    ' CLEAR ROW ON SINGLE OR MULTIPLE SELECTION
    Sub MyClearRowsMultiple(Target As Range)
    Dim rngCellSelect As Range
    Dim rngCell As Range
    ' if the cell is selected in column 1 then it clears the area in the row
    If Not Intersect(Range("A:A"), Target) Is Nothing Then
       For Each rngCell In Selection
           ' check only column 1
           If rngCell.Column = 1 Then
               ' clear from column start to column end the contents of the row
               rngCell.Range(Cells(rngCell.Count, iColumnS - 1), Cells(rngCell.Count, iColumnE)).ClearContents
               ' save last selected cell
               Set rngCellSelect = rngCell
           End If
       Next rngCell
       ' move to the last selected cell
       rngCellSelect.Select
    End If
    End Sub

    Obbiettivo: Evitare che il loop For Each range In Selection legga inutilmente tutte le celle per le righe intere selezionate. E' solo perdita di tempo perchè basterebbe leggere e scorrere solo le celle che non appartengano a Righe Intere. 
    (per lo scopo prefissato funziona, ma legge una miriade di celle inutilmente)

    Grazie

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    Ciao

    Se ho capito bene devi eliminare le righe che hanno la selezione per l'intera riga.

    Se così è, visto l'immagine che hai postato all'inizio, ti consiglio 2 cose:

    a) evita la colonna intera ( es. “A:A”) ma trova l'ultima riga valorizzata e dai un intervallo congruo (nel caso di cui sopra "A10:A19");

    b) invece della colonna A utilizza la colonna B: se la cella è selezionata allora elimini l'intera riga altrimenti lasci tutto come è.

    Ciao,

    Mario

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    07/05/2023 - Marius44 ha scritto:


    Se ho capito bene devi eliminare le righe che hanno la selezione per l'intera riga.

    no ;((  non devo eliminare le righe, non le voglio leggere se vengono selezionate.
    Voglio leggere solo le altre aree selezionate che non siano righe intere

    Infatti se mi selezionano solo delle righe intere e danno Canc a me va bene … perchè mi cancellano il contenuto di esse e questo è Ok.
    In questo caso la Function che elimina il contenuto di certe celle non viene richiamata e questo va bene (è cosa buona è giusta)

    Il problema si pone quando mi selezionano più aree diverse, alcune “intere righe” e altre no. 
    Ecco perchè devo riconoscere ed eliminare dal range le selezioni di Riga Intera. Quest'ultime non le devo trattare con la mia Function.

    Grazie

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    Ciao

    Allora, ripeto, utilizza la colonna B: se è selezionata la cella salti la riga.

    Ciao,

    Mario

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    07/05/2023 - Marius44 ha scritto:


    Ciao

    Allora, ripeto, utilizza la colonna B: se è selezionata la cella salti la riga.

    Ciao,

    Mario

    però se mi selezionano l'intera riga vengono selezionate comunque le celle di tutte le colonne, dalla A alla .columns.count  :(( e il problema si pone comunque.

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    Per adesso ho perfezionato la Function per splittare il range di Target che viene reperito dall'evento: Worksheet_Change(ByVal Target As Range)

    • Evalutate
      • Se sono state selezionate delle righe intere (EntireRow) , queste aree vengono eliminate dalla strinta dell'oggetto di Target
    • Return 
      • Se sono state selezione una o più aree ed esistono aree di selezione righe intere (EntireRow), imposto l'oggetto Target con la nuova stringa ottenuta
      • Se esistono una o più aree selezionate e sono solo selezioni di righe intere (EntireRow) imposto l'oggetto Target = Nothing

    La Function:

    ' SPLIT RANGE INTO A NEW RANGE WITHOUT FULL ROW SELECTIONS
    ' Parameters:
    '   Target      ->  ByRef: range to scan if there are entire selected rows
    ' Return Value ByRef:
    '   The function returns a new range in Target which will not contain the entire selected rows
    '   if Target contains only entire selected rows, set the value Nothing in Target Range
    '   ------------------------------------
    '   ' run Function
    '   myNewRange Target
    '   ' Check Target Range
    '   If Not Target Is Nothing Then
    '       ...[Range Target Valid]
    '   Else
    '       ...[Range Target Invalid]
    '   End If
    '   ------------------------------------
    Sub myNewRange(ByRef Target As Range)
    ' create an array by splitting the range
    Dim arySplit() As String
    arySplit = Split(Target.Address, ",")
    ' create string for the new range
    Dim strNewRange As String
    Dim iX As Integer
    For iX = 0 To UBound(arySplit)
       If Range(arySplit(iX)).Columns.Count < ActiveSheet.Columns.Count Then strNewRange = strNewRange & IIf(Trim(strNewRange) = vbNullString, "", ",") & arySplit(iX)
    Next iX
    ' return new range
    If strNewRange <> vbNullString Then Set Target = Range(strNewRange) Else Set Target = Nothing
    End Sub
    Esempio:
    Se Target 		= $A$22,$A$23,$A$24,$28:$28		(range misto con singole selezioni e selezioni di righe intere)
    Return Target	= $A$22,$A$23,$A$24				(return range senza le selezioni di righe intere)
    
    Se Target 		= $A$22,$A$23					(range senza selezioni di righe intere)
    Return Target	= $A$22,$A$23					(return range = a quello passato)
    
    Se Target 		= $28:$28,$30:$30				(range solo con selezioni di righe intere)
    Return Target	= Nothing						(return Nothing Value)

    Per adesso inserisco nel progetto tale Function che mi permette di leggere/processare solo le aree che non siano selezioni di Righe Intere
    Ma se esiste un metodo diverso e migliore sicuramente lo preferirei (dai test che ho eseguito questa Function funziona, ma sarebbe meglio, se esistono, utilizzare comandi standard)

    In attesa di riscontro
    Grazie

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    Guarda se questa idea ti può andare bene

    Option Explicit
    
    Private Sub Worksheet_Change(ByVal Target As Range)
    MsgBox SkipEntireRows(Target).Address
    End Sub
    
    Private Function SkipEntireRows(rng As Range) As Range
    Dim ar As Range
    For Each ar In rng.Areas
        If ar.Rows.Count = 1 Then
            If ar.Count < 16384 Then
                If SkipEntireRows Is Nothing Then
                    Set SkipEntireRows = ar
                Else
                    Set SkipEntireRows = Union(SkipEntireRows, ar)
                End If
            End If
        End If
    Next ar
    End Function
  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    08/05/2023 - Sgrubak ha scritto:


    Guarda se questa idea ti può andare bene

    For Each ar In rng.Areas

    Ciao…  il for each sulle aree !!!!   (sapevo che c'era una strada da seguire nell'ordine naturale delle cose) Bene !!!

    Con questa posso discriminare le varie aree selezionate dall'utente e pilotare la mia Function eliminando le possibili letture inutili e pesanti.
    Pensa se l'utente mi seleziona 100 righe intere e mi da Canc. Excel già le cancella in un batter d'occhio,  questo è ok, per il mio progetto va bene.
    Ma se passo queste righe alla mia Function vado a ciclare con Range In Selection inutilmente la lettura di ben 1.638.400 celle. Anche se non eseguo nessuna operazione su esse è una cosa che devo necessariamente evitare. Un milione di lettura non se po fa ;)) e neanche 50.000 se sono letture inutili.

    Perfetto direi. 
    Da verificare nel caso in cui non ci siano aree da ritornare. In tal caso il valore della function SkipEntireRows sarebbe nullo?  risulterebbe un valore non valido da assegnare ad un oggetto Range.  

    La verifico con molto molto molto piacere, mi sembra l'unica strada percorribile e soprattutto standard.
    Ottimo, mi metto all'opera, controllo verifico e faccio i test.
    Grazie milleeeee!!!  

    P.S. Se la revisiono la Posto in modo che tu mi possa validare eventuali modifiche apportate.

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    08/05/2023 - By65Franco ha scritto:


    Da verificare nel caso in cui non ci siano aree da ritornare. In tal caso il valore della function SkipEntireRows sarebbe nullo?

    Ovviamente si. Non avresti nessun Range valido e quindi…

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    08/05/2023 - Sgrubak ha scritto:


    Guarda se questa idea ti può andare bene

    Ciao Sgrubak…. Perfetto!!!

    In effetti se vengono selezionate solo Entire Rows poi ritornava errore assegnazione di valore alla function.
    Ho mantenuto l'approccio che avevo già preso modificando l'oggetto Target con il passaggio del parametro in Byref, ed assegnare ad esso il valore Nothing qualora non esistono righe da processare in quanto risultano essere solo delle Entire Rows.

    Pertanto eseguirò la mia Function solo se target risulterà diverso da Noting. A questo punto riesco a processare solo le celle che effettivamente devono essere trattare e non mi leggo più le Entire Rows.

    Private Sub Worksheet_Change(ByVal Target As Range)
    ' skip range into a new range without full row selections
    myNewRange Target
    ' clean up the celles
    If Not Target Is Nothing Then
        If Target.Column = 1 Then
            ' set EnableEvents to prevent recursive calls to worksheet event functions
            Application.EnableEvents = False
            ' clean up the cells
            Range(Target.Address).Select
            MyClearRowsMultiple Target
            ' set EnableEvents to restore events
            Application.EnableEvents = True
        End If
    End If
    End Sub
    _________________________________________________________________________________________________________________
    
    ' SKIP RANGE INTO A NEW RANGE WITHOUT FULL ROW SELECTIONS
    Sub myNewRange(ByRef Target As Range)
    ' set new working range with default value Northing
    Dim arNew As Range
    Set arNew = Nothing
    ' create new range and skip EntireRows
    Dim ar As Range
    For Each ar In Target.Areas		
       If ar.Columns.Count < ActiveSheet.Columns.Count Then If arNew Is Nothing Then Set arNew = ar Else Set arNew = Union(arNew, ar)
    Next ar
    ' return new range
    Set Target = arNew
    End Sub

    Continuo a fare i test ma mi sembra che ci siamo ….  se vedi qualcosa da correggere è ben accetto

    Grazie mille

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    08/05/2023 - By65Franco ha scritto:


    Ho mantenuto l'approccio che avevo già preso modificando l'oggetto Target

    A me, modificare Target, piace poco. Opterei per creare una nuova variabile. Se poi ti capita di doverla usare Target? Te la ritrovi modificata…

    08/05/2023 - By65Franco ha scritto:


    Pertanto eseguirò la mia Function solo se target risulterà diverso da Noting

    Hai creato una Sub, non una Function. Le Function, per definizione, dovrebbero ritornare qualcosa (anche se il VBA permette di non farlo). Hai già l'allocazione di memoria per il risultato, non serve allocare anche arNew.

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    08/05/2023 - Sgrubak ha scritto:


    A me, modificare Target, piace poco. Opterei per creare una nuova variabile. Se poi ti capita di doverla usare Target? Te la ritrovi modificata…

    Giustissima osservazione…. anch'io all'inizio ho fatto lo stesso pensiero. Ma questa risulta essere l'ultima elaborazione all'interno dell'evento Worksheet_Change(ByVal Target As Range)  e quindi ho pensato di modificarlo anche perchè nell'evento WorkSheet_Change viene passato come ByVal e se qui dentro modifico Target non vado ad impattare sugli altri eventi di Excel.

    08/05/2023 - Sgrubak ha scritto:


    Hai creato una Sub, non una Function. Le Function, per definizione, dovrebbero ritornare qualcosa (anche se il VBA permette di non farlo). Hai già l'allocazione di memoria per il risultato, non serve allocare anche arNew.

    Si esatto, una Sub, una routine che non deve ritornare nessun valore… Giustissimo!!!
    Se uso la Function con As Range, ritorno valore come Oggetto Range, va benissimo se devo solo testare. Ma se oltre a testare il valore restituito, devo anche passarlo ad una sub o function,  puo' diventare un problema. Infatti in caso di valore restituito = Nothing avrei problemi ad impostarla come parametro nella Sub successiva da eseguire 

    Esempio:

    COME E' ADESSO :
    ' skip range into a new range without full row selections
    myNewRange Target								------->  QUI MODIFICO IL RANGE DI "TARGET" (RIPULENDOLO DALLE ENTIRE ROWS)
    ' clean up the celles
    If Not Target Is Nothing Then
       If Target.Column = 1 Then
           ' set EnableEvents to prevent recursive calls to worksheet event functions
           Application.EnableEvents = False
           ' clean up the cells
           Range(Target.Address).Select
    --->   MyClearRowsMultiple Target				------->  QUI LO PASSO COME PARAMETRO (ELABORO SOLO LE CELLE CHE INTERESSSANO)
           ' set EnableEvents to restore events
           Application.EnableEvents = True
       End If
    End If
    ___________________________________________________________________________________________________________________________
    SE INVECE LA TRATTO COME FUNCTION CHE RITORNA UN OGGETO RANGE :
    ___________________________________________________________________________________________________________________________
    ' skip range into a new range without full row selections
    
    ' clean up the celles
    If Not myNewRange(Target) Is Nothing Then		------->  QUI TESTO SE HO CELLE DA ELABORARE (ESCLUDENDO LE ENTIRE ROWS)
        If Target.Column = 1 Then
            ' set EnableEvents to prevent recursive calls to worksheet event functions
            Application.EnableEvents = False
            ' clean up the cells
            Range(Target.Address).Select
    --->    MyClearRowsMultiple myNewRange(Target)	------->  E QUI IN "TARGET" NON HO IL NUOVO RANGE DA ELABORARE COME SOPRA.
            ' set EnableEvents to restore events			  DOVREI RICHIAMARE NUOVAMENTE LA FUNCTION myNewRange(Target)
            Application.EnableEvents = True					  O MEGLIO, ASSEGNARE AD UN NUOVO OGGETTO RANGE IL VALORE RESTITUITO 
        End If												  DALLA FUNCTION Es: SET newRange = myNewRange(Target)
    End If													  E PASSARE newRange ALLA SUB DA RICHIAMARE

    Tutte corrette e ragionevoli le tue osservazioni…. diciamo che mi sono preso una certa libertà di modificare il contenuto di Target e dovrò tenerne conto come da te suggerito e segnalato.

    Grazie mille ancora, per info e spiegazioni.

  • Re: Vba Excel Ridefinire aree selezionate per nuovo range [RISOLTO]

    08/05/2023 - By65Franco ha scritto:


    in caso di valore restituito = Nothing avrei problemi ad impostarla come parametro nella Sub successiva da eseguire 

    Appunto. Lo assegni ad una variabile e lo testi contro Nothing. Credo che la maniera più ortodossa di procedere sia questa, invece che modificare ByRef. Poi per carità… Se ti trovi più comodo a modificare il codice un domani che si presenta una modifica, fai tu. Lo conosci tu il progetto. Io ci vedo possibili bug, difficili da trovare. Soprattutto se si riprende il codice in mano dopo diverso tempo e per tanto mi metterei al sicuro da subito.

    Come ultima cosa, mi domando a cosa serva

    Range(Target.Address).Select

    Oltre al fatto che selezionare celle in una Sub è al 95% una inutile perdita di tempo, sarebbe più corretto scrivere

    Target.Select

    direttamente. 

Devi accedere o registrarti per scrivere nel forum
16 risposte