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 |