|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
[VBA Excel] Codice corretto che talvolta dà errore
Ciao, io sto lavorando con un macro di Excel. Sintatticamente è corretta e difatti funziona, tuttavia talvolta far girare il codice mi dà errore. Da che cosa può dipendere?
Ad esempio ecco il codice snellito al minimo che però ha il medesimo comportamento del codice completo: Codice:
Sub test() Sheets("foglio").Range("A5").Select End Sub Questo codice a seconda dei casi mi scatena un errore, come mai? Che dipenda dalla selezione attiva al momento del richiamo della macro? Ciao!!! |
![]() |
![]() |
![]() |
#2 |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Codice:
Public Sub SelezionaFoglio(nomeFoglio As String, indirizzoRange As String) Sheets(nomeFoglio).Activate Range(indirizzoRange).Select End Sub ![]() |
![]() |
![]() |
![]() |
#3 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Ciao Marco, grazie per la risposta, ma sai qual è la cosa curiosa? E' che se spezzo il codice
Codice:
Sub test() Sheets("foglio").Select Range("A5").Select end sub come mai? Ciao! |
![]() |
![]() |
![]() |
#4 |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Activate ( su Foglio ) + Select ( su Range ) è il metodo espressamente consigliato dalla Guida VBA di Excel, perciò mi atterrei a quello. Poi, ci sono casi in cui il Select su Range fallisce, casi in cui sembra funzionare, ma alla prima modifica ti pianta in asso.
Ha certamente a che fare con questioni di Focus... Personalmente non mi sono mai preso la briga di studiare a fondo la casistica, dal momento che il 99% dei .Select così come escono dal registratore Macro si possono tranquillamente cestinare, e inoltre tutte le operazioni possibili in VBA con Celle e Range, si possono eseguire ( e anzi, si DEVONO eseguire ) senza previa selezione degli elementi interessati. |
![]() |
![]() |
![]() |
#5 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Cosa intendi per "questioni di Focus"?
Se ho capito bene mi consigli di non usare una selezione ma di effettuare le operazioni direttamente. Ad esempio dovessi usare un filtro sarbbe melgio fare: Codice:
Sheets("foglio").Range("A5").AutoFilter Field:=13, Criteria1:="paperino" Codice:
Sheets("foglio").Activate Range("A5").Select Selection.AutoFilter Field:=13, Criteria1:="paperino" |
![]() |
![]() |
![]() |
#6 | |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
- Esatto. Tra l'altro la prima AutoFilter è più corretta, compatta, e leggibile della seconda, perciò perchè mai usare .Select e poi Selection.AutoFilter ? Quello è tipico del codice generato dal macro recorder, che è grezzo, prolisso, e anche abbastanza "stupido". - Più che sintassi, direi che il vero problema è l'IDE. L'editor VBA di Office non brilla certo per robustezza ed evidenzia solo una parte degli errori in fase di scrittura. Perfino alcuni errori di sintassi vengono fuori solo a runtime, e non è raro vedere l'intellisense che non parte dopo un punto "." . Per me non è mai stato un problema, dato che mi sono avvicinato a VBA conoscendo già VB6, ma per altri posso capire che sia una gran bella scocciatura. |
|
![]() |
![]() |
![]() |
#7 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Ho capito!
Beh che brutto però che sintassi apparentemente equivalenti (e probabilmente logicamente corrette) scatenino errori...ti chiedo ancora una cosa. Se dovessi fare un filtro congiunto (cioè filtrare la colonna A per un criterio e la B per un altro), come posso fare? Io ho provato così Codice:
Sheets("foglio").Range("A1:C1").AutoFilter Field:=1, Criteria1:="paperino" Sheets("foglio").Range("A1:C1").AutoFilter Field:=2, Criteria1:="pippo" Codice:
Selection.AutoFilter Field:=1, Criteria1:="paperino" Selection.AutoFilter Field:=2, Criteria1:="pippo" ![]() Ultima modifica di superciccio14 : 15-12-2009 alle 20:06. |
![]() |
![]() |
![]() |
#8 |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
- VBA non è colpevole in questo. Ripeto, semmai sono i limiti del VBE di Office... Il fatto che ci siano errori logici non individuati dall'editor è cosa comune a tutti i linguaggi del mondo. Se crei un array di 5 elementi e poi vai a leggere il sesto, sintatticamente è ok, ma poi in debug va in errore, e in questo la stragrande maggioranza degli Ide non ti aiuta...
- No, non funziona così. Se hai una tabella dati su foglio Excel che va dalla colonna A alla C per N righe, con l'AutoFilter devi avere una riga di intestazione campi all'inizio, in questo caso la riga "A1:C1". Inoltre è inutile specificare tutto il range, basta solo la prima cella in alto a sinistra della tabella dati, in questo caso "A1" : Codice:
Sheets("Foglio1").Range("A1").AutoFilter Field:=1, Criteria1:="paperino" Sheets("Foglio1").Range("A1").AutoFilter Field:=2, Criteria1:="pippo" |
![]() |
![]() |
![]() |
#9 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Ciao, in primis ti ringrazio nuovamente per l'aiuto.
ho testato il tuo codice e se lo lancio con selezionato foglio 1 funziona bene, se lo lancio con selezionato un altro foglio invece mi restituisce dei valori completamente sballati. Come mai secondo te? L'esempio sull'array è stato esaustivo, tuttavia secondo me lo si potrebbe annoverare tra gli errori "logici". Per fare un parallelo è coome se in Java facessi Codice:
Persona p; p = new("Nome","Cognome"); Codice:
Persona p = new("Nome","Cognome"); ed in un caso andasse bene mentre nell'altro no. PS. Esiste una guida esustiva e bene fatta su Visual Basic for Application (quello che io abbrevio VBA ![]() PPS: Sulla guida di excel ho trovato dei "metodi" Select applicati ad oggetti Sheets. Che macello... |
![]() |
![]() |
![]() |
#10 | ||||
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
Quote:
Quote:
Quindi puoi trovare manuali su Excel + VBA, Access + VBA, ecc., ma alla fine li definirei in molti modi, eccetto "esaustivi". Quote:
In generale la mia tendenza a non usare e a sconsigliare i .Select e i Selection è mia personale. Potrebbero esserci manuali onesti che invece illustrano come usarli regolarmente. Secondo la mia esperienza con Excel e VBA la trovo una pratica errata. |
||||
![]() |
![]() |
![]() |
#11 | ||||
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Quote:
![]() Quote:
Quote:
![]() Quote:
Codice:
Sheets("foglio che voglio in primo piano").Activate Range("A1").Select ![]() ![]() ![]() Grazie Ancora! |
||||
![]() |
![]() |
![]() |
#12 | ||
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
Quote:
In realtà .Select è disponibile su Sheets(), basta che cerchi "Select" nel visualizzatore oggetti del VBE, e ottieni l'elenco di tutte le classi che lo espongono. Se crei un pulsante su Foglio1 e associ questo codice : Codice:
Sheets("Foglio2").Select I problemi veri insorgono quando si fanno selezioni con .Select e Selection di Celle, Range, Grafici, ecc., da un foglio all'altro, mentre bisognerebbe creare, come ti ho suggerito in precedenza, delle routine pubbliche, a livello di Modulo o di UserForm. Se conosci bene VB6, hai già praticamente in tasca il VBA ( sempre con le dovute limitazioni di quest'ultimo, sia chiaro ), ti rimane solo di apprendere il modello ad oggetti specifico dell'applicazione Office che vuoi usare. |
||
![]() |
![]() |
![]() |
#13 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Ok, capito
![]() Ti chiedo un'ultima cosa. Se io dovessi contare le celle filtrate secondo un certo criterio, lo farei con questo codice: Codice:
Range("A2:A1500").SpecialCells(xlCellTypeVisible).Count ma come faccio a gestire l'eccezione in cui ho 0 celle selezionate? VBE mi darebbe un errore... ![]() Ciao! |
![]() |
![]() |
![]() |
#14 |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Codice:
Dim cnt As Integer On Error Resume Next cnt = Range("A2:A1500").SpecialCells(xlCellTypeVisible).Count MsgBox cnt ![]() |
![]() |
![]() |
![]() |
#15 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Ahh ok, fondamentalmente .Count riconosceva lo 0 solo che mi bloccava l'esecuzione perché lo riconosceva come un errore a runtime!
Cosi facendo gli si dice di ignorare l'errore salvare comunque lo 0. Corretto? Allora mi dichiaro Codice:
On Error Resume Next Grazie. Ciao! ![]() Ultima modifica di superciccio14 : 17-12-2009 alle 14:26. |
![]() |
![]() |
![]() |
#16 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Però così facendo mi ignora eventuali altri errori...
![]() La soluzione artigianale sarebbe quella di usare i subtotali... Ultima modifica di superciccio14 : 17-12-2009 alle 14:58. |
![]() |
![]() |
![]() |
#17 | |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
Se vuoi imparare VBA, accetta un consiglio : cerca da subito di parametrizzare le cose che fai creando Function e Sub generiche e riutilizzabili, non fare tutto quanto in un unico flusso di codice... ![]() Altra alternativa, comunque, è di fare un On Error Goto... |
|
![]() |
![]() |
![]() |
#18 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Cioè tu dici ad esempio
Codice:
Function Pippo(s As Sheets, d As Sheet) Dim cnt As Integer On Error Resume Next cnt = Sheets(s).Range("A2:A1500").SpecialCells(xlCellTypeVisible).Count Sheets(d).Range(A1).Value = cnt; end Function (conta che io sto lavorando in un unico modulo ed ho messo la funzione in testa al codice, prima di sub Modulo1()) Codice:
Pippo("foglio1","foglio2") Ultima modifica di superciccio14 : 17-12-2009 alle 15:42. |
![]() |
![]() |
![]() |
#19 | |
Senior Member
Iscritto dal: Dec 2004
Messaggi: 3210
|
Quote:
Codice:
Public Function ContaRigheFiltrate(foglio As String, intervallo As String) Dim cnt As Integer On Error Resume Next cnt = Sheets(foglio).Range(intervallo).SpecialCells(xlCellTypeVisible).Count ContaRigheFiltrate = cnt End Function E viene usata, ad esempio così : Codice:
MsgBox ContaRigheFiltrate("Foglio1", "A2:A1500") |
|
![]() |
![]() |
![]() |
#20 |
Member
Iscritto dal: Oct 2006
Messaggi: 176
|
Fantastico! Ho capito, funziona!
![]() ![]() ![]() Posso fare ancora un'ultima domanda (spero): ma se volessi fare invece una funzione che mi somma i valori delle celle filtrate? C'è il solito problema dello 0 che ho incontrato per count? Ciao io ho trovato quest'esempio http://ennius.altervista.org/vba/vba59.php ma non so...non usa SpecialCells. Io pensavo: Codice:
Sub Modulo2() Dim cl As Range For Each cl In Sheets("foglio").Range("A2:A1500").SpecialCells(xlCellTypeVisible) 'vado a dargli un offset per individuare la colonna col valore tot = tot + cl.Offset(0, 3).Value Next MsgBox (tot) End Sub Ultima modifica di superciccio14 : 18-12-2009 alle 11:13. |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 07:38.