Selezionare un area compresa da due dati da cercare in una tabella.   (24/03/03)

con evidenziazione, nell'area trovata, dei caratteri in rosso e in grassetto.

Questa volta l'esercizio proposto rientra in una casistica spesso richiestami: come evidenziare una zona di dati compresa da due valori presenti in una tabella, ma di cui non conosciamo la posizione, sia dei valori nella tabella, sia della tabella stessa. Supponiamo di avere quindi una tabella come quella sotto (in cui per mia comodità ho inserito dei numeri con valore univoco. Attenzione: i valori devono essere univoci, altrimenti le istruzioni qui usate non funzionano; con valori doppi o ripetuti dovremo usare altre istruzioni, ma facciamo una cosa per volta, la routine per i valori doppi la trovate alla fine di questa pagina).

Vediamo i singoli passaggi per capirli meglio, poi alla fine ricostruiamo l'intera sequenza.

  • identificare la posizione della tabella sul foglio di lavoro; per fare questo ci affideremo all' UsedRange, (di cui esistono spiegazioni in questa sezione, paragrafo "Copia/Incolla 4") e assegneremo con l'istruzione Set, un nome alla tabella (zona) dell'UsedRange nel foglio attivo:

Set zona = ActiveSheet.UsedRange

  • faccio presente che la proprietà UsedRange rintraccia una tabella anche se non sono presenti valori, ma purchè le celle destinate a formare la tabella siano state "bordate".

  • Inserimento dell'istruzione che ripristina il colore del font a nero e toglie il grassetto ai font che eventualmente fossero stati evidenziati; per fare questo useremo il costrutto With oggetto....End With, in modo da poter con un'unica istruzione, modificare tutte le "proprietà" volute, all'interno delle celle comprese nell'UsedRange:

With zona
.Font.ColorIndex = 0
.Font.Bold = False
End With

  • inseriamo l'istruzione per chiamare una InputBox (finestra di dialogo) nella quale scriveremo il primo valore da cercare tra i dati presenti nella tabella ( chiamata "zona" ). Il valore che scriveremo dovrà essere  memorizzato e quindi dimensioniamo una variabile, la X, atta a contenere il dato immesso nella InputBox. Nell'istruzione dovremo dichiarare, tra parentesi, il messaggio che la finestra di dialogo ci mostrerà ("dato uno" o qualunque altra frase che noi vorremo) e il titolo (che apparirà nella barra della InputBox: "inserisci il primo dato" ):

X = InputBox("dato uno", "inserisci il primo dato")

  • per evitare che il debugger, in caso di mancanza di inserimento del dato nella inputbox, o per aver premuto il pulsante "annulla", si "arrabbi" e ci segnali un errore, inseriremo una semplice istruzione : se il valore rappresentato dalla X sarà vuoto, usciremo dalla routine:

If X = "" Then Exit Sub

  • inizializiamo ora il ciclo di ricerca assegnando un nome ( CL, ma l'avremmo potuta chiamare "pippo", sarebbe lo stesso ) ad una variabile, ed il "tipo" di variabile come "Object" (oggetto ) (Dim stà per : dimensioniamo).

Dim CL As Object

  • l'istruzione seguente dice : per ogni CL (l'oggetto cella) presente in "zona", se il valore presente nella cella è uguale al valore memorizzato nella X, allora assegnamo alla variabile "uno" l'indirizzo (Address) della cella trovata col valore uguale (indirizzo = riferimento). I cicli For Each....Next consento di eseguire le istruzioni di ricerca, cella per cella, fino alla fine dell'area assegnata. Poi, visto che stiamo lavorando con dei numeri (se si facesse cercare del testo non sarebbe necessario), E' NECESSARIO dichiarare il "tipo" di dati restituito dalla InputBox, altrimenti il codice non riconoscerebbe come numero il dato inserito. Per fare questo usiamo la funzione Val() che restituisce i numeri inclusi in una stringa sotto forma di valore numerico di tipo appropriato. Dobbiamo inoltre ricordare che la funzione Val riconosce solo il punto (.) come separatore decimale valido, se quindi lavoreremo con numeri decimali, nella InputBox dovremo scrivere il valore da cercare usando il punto ( . ) come separatore e NON la virgola, mentre ovviamente sul foglio di lavoro i decimali dovranno essere regolarmente inseriti con la virgola ( , ). Oppure definire come "tipo" di dati non più Val ma CDbl (es. CDbl(X) ) in questo modo potremo usare la virgola ( , ) come separatore, nell'inserimento del valore nella InputBox.

For Each CL In zona
If CL.Value = Val(X) Then uno = CL.Address
Next

  • Dal momento che potremmo cercare un dato che potrebbe essere non presente nell'area, avremo bisogno di essere avvisati con un messaggio, e sopratutto di impedire che la routine prosegua generando poi un errore perchè l'indirizzo assegnato alla variabile "uno" non è stato trovato. Useremo quindi la seguente istruzione: se "uno" è vuoto, avvisa con il messaggio ed esci dalla routine:

If uno = "" Then
MsgBox "Valore non presente"
Exit Sub
End If

  • se invece il valore è presente, proseguiamo con la ricerca, sempre tramite InputBox, del secondo valore da cercare. Le istruzioni sono le stesse usate per il primo ciclo di ricerca, cambiano solo i nomi assegnati alle variabili:

Y = InputBox("dato due", "inserisci il secondo dato")
If Y = "" Then Exit Sub
For Each CL In zona
If CL.Value = Val(Y) Then due = CL.Address
Next

If due = "" Then
MsgBox "Valore non presente"
Exit Sub
End If

  • dato per scontato, di avere trovato tutte e due i valori cercati, e di essere quindi in possesso dei riferimenti delle celle, selezioneremo tutta l'area rappresentata dai riferimenti, con la seguente istruzione :

Range(uno & ":" & due).Select

  • ora che abbiamo selezionato l'area, assegneremo le proprietà ai font presenti: il colore dei font, e il grassetto. Per il colore useremo il codice colore voluto (io ho usato il rosso = 3) e usciremo dalla routine (End Sub)

With Selection
.Font.ColorIndex = 3
.Font.Bold = True
End With

End Sub

E questo sarà il risultato della nostra macro, ipotizzando di avere scelto come primo valore 13 e come secondo 53 :

E questa la routine completa:

Sub selezona()

Set zona = ActiveSheet.UsedRange

With zona
.Font.ColorIndex = 0
.Font.Bold = False
End With

X = InputBox("dato uno", "inserisci il primo dato")
If X = "" Then Exit Sub


Dim CL As Object
For Each CL In zona
If CL.Value = Val(X) Then uno = CL.Address
Next

If uno = "" Then
MsgBox "Valore non presente"
Exit Sub
End If
'secondo ciclo
Y = InputBox("dato due", "inserisci il secondo dato")
If Y = "" Then Exit Sub
For Each CL In zona
If CL.Value = Val(Y) Then due = CL.Address
Next

If due = "" Then
MsgBox "Valore non presente"
Exit Sub
End If

Range(uno & ":" & due).Select


With Selection
.Font.ColorIndex = 3
.Font.Bold = True
End With


End Sub

 

Stessa procedura con variante per selezionare un area cercando due valori uguali presenti nella tabella (zona).

vediamo i passaggi che differiscono dalla precedente:

  • ovviamente inseriremo lo stesso valore sia nella prima che nella seconda InputBox.

  • premessa: il ciclo For Each.....Next "gira" cercando nella zona assegnata tutte le occorrenze uguali al valore da cercare, e nel caso di più valori uguali, li rintraccerebbe tutti ma si fermerebbe sempre all'ultimo valore trovato.

  • dovremo quindi "interrompere" l'azione di ricerca del primo valore dopo che sarà stato trovato e sarà stato memorizzato il suo Address (indirizzo o riferimento cella), in modo da passare alla seconda InputBox che ci chiederà il secondo valore da cercare e inizializzerà il secondo ciclo di ricerca. Per fare questo ci affidiamo all'istruzione GoTo che ci farà uscire dal primo ciclo se il primo valore sarà stato trovato e ci manderà direttamente al secondo ciclo. Questo secondo ciclo, leggerà anche il primo valore, ma si fermerà solo all'ultimo valore trovato e memorizzerà SOLO questo Address.

If CL.Value = Val(X) Then
CL.Select
uno = ActiveCell.Address
GoTo 10

  • GoTo 10 vuol dire semplicemente : "vai al numero di riga 10" e il compilatore si sposterà alla riga indicata senza eseguire le istruzioni che si trovano tra il GoTo e la riga indicata. In questo modo saltiamo l'istruzione Next posta alla fine del primo ciclo interrompendolo in quanto il primo valore è stato trovato, e dovremo cercare il secondo o ultimo. Inseriremo quindi il numero 10 seguito dal segno dei due punti ( : ) immediatamente prima dell'istruzione che dovrà essere eseguita:

10:
Y = InputBox("dato due", "inserisci il secondo dato")
If Y = "" Then Exit Sub
For Each CL In zona
If CL.Value = Val(Y) Then due = CL.Address
Next

In questo modo otteniamo che:

  • se il secondo valore o ultimo non esiste in quanto il valore nella tabella è univoco, verrà evidenziato solo il primo.

  • nel caso di errore di digitazione si cercasse un numero che non è presente, si verrà avvisati che il numero non esiste.

  • se il secondo numero è diverso dal primo ed è presente in tabella, verranno evidenziati tutti i valori compresi tra i due ( e si verifica quello che otteniamo con la prima routine sopra indicata ).

e questa la seconda routine completa:

Sub selezonadue()

Set zona = ActiveSheet.UsedRange

With zona
.Font.ColorIndex = 0
.Font.Bold = False
End With

X = InputBox("dato uno", "inserisci il primo dato")
If X = "" Then Exit Sub
Dim CL As Object
For Each CL In zona
If CL.Value = Val(X) Then
CL.Select
uno = ActiveCell.Address
GoTo 10
If uno = "" Then
MsgBox "Valore non presente"
Exit Sub
End If
End If

Next

10:
Y = InputBox("dato due", "inserisci il secondo dato")
If Y = "" Then Exit Sub
For Each CL In zona
If CL.Value = Val(Y) Then due = CL.Address
Next

If due = "" Then
MsgBox "Valore non presente"
Exit Sub
End If

Range(uno & ":" & due).Select
With Selection
.Font.ColorIndex = 3
.Font.Bold = True
End With
End Sub

 

Buon lavoro.

prelevato sul sito http://ennius.interfree.it