VBA AutoFit in Excel dopo export da Access: guida completa, codice e best practice

Quando esporti da Access a Excel con VBA, è frequente ritrovare colonne troppo strette e dati illeggibili. In questa guida trovi cause, soluzioni e codice pronto per eseguire AutoFit su colonne (e righe) in modo affidabile, subito dopo il trasferimento dei dati.

Indice

Problema

L’utente importa con VBA i dati di una tabella o query di Access in un foglio Excel. Al termine dell’operazione, le colonne rimangono con larghezze predefinite o arbitrarie, rendendo numeri, testi e date difficili da leggere. L’obiettivo è applicare un ridimensionamento automatico a colonne (e opzionalmente a righe) che tenga conto dell’area realmente popolata, senza rallentare inutilmente l’esecuzione e senza introdurre errori legati a riferimenti di oggetti errati.

Cause principali degli errori iniziali

ErroreDescrizione
ActiveWorkbook.Name usato come oggettoRestituisce solo il nome del file (stringa), non l’oggetto Workbook.
Oggetto Excel.Application non correttamente istanziato o recuperatoSenza un riferimento valido, ogni metodo su Workbooks o Worksheets fallisce.
Columns("A:M").ColumnWidth = 50 usato prima dell’inserimento datiImposta una larghezza fissa che viene poi comunque superata dal contenuto.

Altri intoppi comuni che peggiorano l’esperienza:

  • Applicare .AutoFit prima di scrivere i dati: Excel non può calcolare una larghezza sensata.
  • Usare ActiveWorkbook/ActiveSheet al posto di riferimenti espliciti (wb, ws): in contesti multipli (Access → Excel) l’attivo può non essere quello atteso.
  • Foglio vuoto: UsedRange su un foglio senza dati torna solo A1; l’AutoFit non ha effetto.
  • Celle unite o con wrap text forzato: la misura può risultare falsata se il testo va a capo, o se ci sono celle merge.

Soluzioni funzionanti

Correggere i riferimenti agli oggetti

La prima causa di errori è l’uso di stringhe o riferimenti “attivi” al posto degli oggetti COM reali. Instanzia o intercetta una sessione di Excel e apri in modo esplicito la cartella di lavoro di destinazione:

' Crea (o intercetta) l’istanza di Excel
Dim xlApp As Object            ' Excel.Application
Dim wb    As Object            ' Excel.Workbook
Set xlApp = CreateObject("Excel.Application")  ' oppure GetObject(, "Excel.Application") se è già aperto
Set wb = xlApp.Workbooks.Open(percorsoCompleto)  ' apri o crea il file

' Ora wb è un vero oggetto Workbook

Consigli pratici:

  • Evita ActiveWorkbook/ ActiveSheet nel codice di Access. Lavora sempre con wb e wb.Worksheets(1) (o per nome).
  • Se usi late binding (come nell’esempio), non servono riferimenti a librerie. Se preferisci early binding, imposta il riferimento a “Microsoft Excel xx.x Object Library” e dichiara gli oggetti come Excel.Application, Excel.Workbook, Excel.Worksheet.

Applicare AutoFit dopo aver scritto i dati

La regola d’oro: esegui l’AutoFit dopo l’inserimento dei dati. Usa UsedRange per evitare di lavorare su colonne vuote e velocizzare l’operazione:

With wb.Worksheets(1)
    '… codice che riempie il foglio …
    .UsedRange.Columns.AutoFit     ' tutte le colonne usate
    .UsedRange.Rows.AutoFit        ' opzionale, righe
End With

Nota: UsedRange garantisce che vengano considerate solo le colonne effettivamente popolate, evitando sprechi su colonne vuote. Se il foglio è realmente vuoto, l’AutoFit non eseguirà modifiche (ed è corretto così).

Eseguire AutoFit col ciclo su colonne (alternativa)

Utile con dati molto sparsi o quando serve un controllo più fine (per esempio per applicare limiti min/max a certe colonne):

Dim c As Long
With wb.Worksheets(1)
    For c = 1 To .UsedRange.Columns.Count
        .Columns(c).AutoFit
    Next c
End With

Macro residente in Excel

Vuoi isolare il ridimensionamento dal codice Access? Inserisci nel file Excel una macro semplicissima:

Sub AutoFitAllColumns()
    Cells.EntireColumn.AutoFit
End Sub

e chiamala da Access quando l’import è finito:

wb.Application.Run "AutoFitAllColumns"

Pulsante sulla “Barra di accesso rapido”

Per scenari manuali: aggiungi “Autoadatta larghezza colonne” alla Barra di accesso rapido di Excel. Dopo l’import automatizzato, un click rifinisce la formattazione.

Codice di riferimento (semplificato)

Sub EsportaEAutoFit()
    Const percorsi As String = "C:\Percorso\tbl_excel.xlsx"
```
Dim xlApp As Object, wb As Object
Set xlApp = CreateObject("Excel.Application")
Set wb = xlApp.Workbooks.Open(percorsi)

' Pulizia e riscrittura dati (esempio)
wb.Worksheets(1).Range("A:M").ClearContents
' … loop che copia i recordset di Access …

' Auto‑ridimensionamento
With wb.Worksheets(1)
    .UsedRange.Columns.AutoFit
    .UsedRange.Rows.AutoFit
End With

xlApp.Visible = True
```
End Sub 

Versione robusta pronta per la produzione

La seguente procedura è pensata per ambienti reali: gestisce errori, migliora le prestazioni, esegue l’AutoFit solo dove serve e ripristina le impostazioni di Excel. Usa late binding per essere plug-and-play da Access.

Option Compare Database
Option Explicit

Public Sub ExportToExcel_WithAutoFit()
    ' === Costanti per late binding (Excel non è referenziato) ===
    Const xlCalculationAutomatic As Long = -4105
    Const xlCalculationManual    As Long = -4135

    Dim xlApp As Object      ' Excel.Application
    Dim wb    As Object      ' Excel.Workbook
    Dim ws    As Object      ' Excel.Worksheet

    Dim calcPrev As Variant
    Dim scrPrev  As Variant
    Dim dispPrev As Variant

    On Error GoTo CleanFail

    ' 1) Ottieni/crea Excel e apri il file
    Set xlApp = GetOrCreateExcelApp()
    Set wb = xlApp.Workbooks.Open("C:\Percorso\tbl_excel.xlsx")
    Set ws = wb.Worksheets(1)   ' o per nome: wb.Worksheets("Dati")

    ' 2) Performance: sospendi aggiornamento/calcolo/alert
    calcPrev = xlApp.Calculation
    scrPrev  = xlApp.ScreenUpdating
    dispPrev = xlApp.DisplayAlerts

    xlApp.ScreenUpdating = False
    xlApp.Calculation = xlCalculationManual
    xlApp.DisplayAlerts = False

    ' 3) Scrivi o sostituisci i dati
    '    Esempio: pulizia area target e scrittura da Recordset
    ws.Range("A1").CurrentRegion.ClearContents
    ' ... apertura Recordset e ws.Range("A1").CopyFromRecordset rs ...

    ' 4) AutoFit sicuro solo se il foglio ha dati
    AutoFitSafe ws, True, True, 8, 60  ' colonne+righe, min=8, max=60

    ' 5) Salva e mostra
    wb.Save
    xlApp.Visible = True

CleanExit:
    ' Ripristina impostazioni
    On Error Resume Next
    xlApp.Calculation = calcPrev
    xlApp.ScreenUpdating = scrPrev
    xlApp.DisplayAlerts = dispPrev

    ' Rilascio (NON chiudere se vuoi lasciare il file aperto)
    Set ws = Nothing
    Set wb = Nothing
    Set xlApp = Nothing
    Exit Sub

CleanFail:
    ' Messaggio d’errore e uscita pulita
    MsgBox "Errore durante export/AutoFit: " & Err.Number & " - " & Err.Description, vbExclamation
    Resume CleanExit
End Sub

Private Function GetOrCreateExcelApp() As Object
    ' Tenta di usare una sessione esistente di Excel, altrimenti ne crea una nuova
    On Error Resume Next
    Set GetOrCreateExcelApp = GetObject(, "Excel.Application")
    If GetOrCreateExcelApp Is Nothing Then
        Set GetOrCreateExcelApp = CreateObject("Excel.Application")
    End If
    On Error GoTo 0
End Function

Private Sub AutoFitSafe(ByVal ws As Object, _
                        Optional ByVal doCols As Boolean = True, _
                        Optional ByVal doRows As Boolean = False, _
                        Optional ByVal minColW As Double = 0, _
                        Optional ByVal maxColW As Double = 0)
    ' Esegue AutoFit su UsedRange e applica opzionale clamp min/max
    Dim ur As Object, c As Object

    Set ur = ws.UsedRange
    ' Se il foglio è vuoto, UsedRange= A1: AutoFit non serve
    If ws.Application.WorksheetFunction.CountA(ws.Cells) = 0 Then Exit Sub

    If doCols Then
        ur.Columns.AutoFit
        If minColW > 0 Or maxColW > 0 Then
            For Each c In ur.Columns
                If minColW > 0 And c.ColumnWidth < minColW Then c.ColumnWidth = minColW
                If maxColW > 0 And c.ColumnWidth > maxColW Then c.ColumnWidth = maxColW
            Next c
        End If
    End If

    If doRows Then
        ur.Rows.AutoFit
    End If
End Sub

Perché questo approccio è solido

  • Riferimenti espliciti (wb, ws) riducono al minimo i rischi di operare sul file o foglio sbagliato.
  • Prestazioni: sospendere ScreenUpdating e Calculation accelera la scrittura massiva; si ripristina tutto in uscita.
  • AutoFit mirato su UsedRange limita l’operazione alle aree popolate.
  • Clamp min/max evita colonne smisurate per stringhe eccezionalmente lunghe.
  • Gestione errori centralizzata: l’utente è avvisato e le impostazioni vengono ripristinate.

Alternative di export e dove innestare l’AutoFit

Con DoCmd.TransferSpreadsheet

Se esporti con i comandi nativi di Access, applica l’AutoFit subito dopo l’export:

DoCmd.TransferSpreadsheet _
    TransferType:=acExport, _
    SpreadsheetType:=acSpreadsheetTypeExcel12Xml, _
    TableName:="qryVendite", _
    FileName:="C:\Percorso\report.xlsx", _
    HasFieldNames:=True

Dim xl As Object, wb As Object
Set xl = CreateObject("Excel.Application")
Set wb = xl.Workbooks.Open("C:\Percorso\report.xlsx")

With wb.Worksheets(1)
.UsedRange.Columns.AutoFit
.UsedRange.Rows.AutoFit
End With

wb.Save: xl.Quit
Set wb = Nothing: Set xl = Nothing 

Con Recordset + CopyFromRecordset

Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT * FROM tblDati")
Dim xl As Object, wb As Object, ws As Object
Set xl = CreateObject("Excel.Application")
Set wb = xl.Workbooks.Add
Set ws = wb.Worksheets(1)

ws.Range("A1").CopyFromRecordset rs
ws.UsedRange.Columns.AutoFit

wb.SaveAs "C:\Percorso\export.xlsx"
xl.Quit 

Trucchi pratici per un AutoFit impeccabile

  • Area precisa: se i dati sono in una tabella strutturata (ListObject):
    wb.Worksheets(1).ListObjects(1).Range.Columns.AutoFit
  • Colonne da escludere: puoi bloccare alcune larghezze manuali: With ws .UsedRange.Columns.AutoFit .Columns("A").ColumnWidth = 14 ' forza una larghezza standard .Columns("F").ColumnWidth = 10 End With
  • Wrap e celle unite: l’AutoFit ignora spesso la vera altezza quando ci sono merged cells. Evita merge ove possibile; in alternativa imposta WrapText=False prima di .AutoFit, poi ripristina.
  • Numeri lunghi: formattali per evitare notazione scientifica che altera la misura visiva (.NumberFormat = "@" per testo o "0" per interi).
  • Righe: .UsedRange.Rows.AutoFit è utile quando il testo va a capo (WrapText=True).

Confronto approcci e impatto prestazionale

ApproccioVantaggiQuando usarloNote prestazionali
UsedRange.Columns.AutoFitRapido, semplice, robustoDataset compatti o mediItera solo sulle colonne popolate: ottimo compromesso
Loop per colonnaControllo fine (clamp, esclusioni)Dati sparsi, colonne con logiche diverseLeggermente più lento, ma flessibile
Cells.EntireColumn.AutoFitCopre tutto il foglioFoglio pulito o tabelle singolePuò essere più lento su fogli ampi con aree vuote
ListObject.Range.Columns.AutoFitPrecisione per tabelle strutturateDati tabellari con HeaderMolto efficiente, evita aree fuori tabella

Eventi Excel e automazioni lato file

Per spostare la logica in Excel, puoi usare gli eventi di ThisWorkbook:

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    On Error Resume Next
    Sh.UsedRange.Columns.AutoFit
End Sub

Oppure un pulsante o voce di macro AutoFitAllColumns richiamabile da Access con xlApp.Run. Valuta le impostazioni di sicurezza macro in base al tuo ambiente.

Risoluzione problemi (troubleshooting)

  • “Metodo AutoFit dell’oggetto Range non riuscito”: verifica che ws punti a un foglio esistente e che UsedRange non sia Nothing. Con late binding, errori di battitura diventano errori runtime.
  • AutoFit non cambia nulla: il foglio potrebbe essere vuoto; assicurati di chiamare l’AutoFit dopo la scrittura. Prova a forzare l’aggiornamento di UsedRange accedendo a ws.UsedRange dopo l’inserimento o salvando il file.
  • Colonna “monstre” per una cella lunghissima: usa il clamp min/max come in AutoFitSafe o applica WrapText=True e Rows.AutoFit per far andare a capo il testo.
  • Excel rimane “appeso” in background: rilascia gli oggetti in ordine (Set rs = Nothing, wb.Close se appropriato, xlApp.Quit, Set xlApp = Nothing). Evita variabili oggetto locali non liberate.
  • Filtro/colonne nascoste: AutoFit calcola sulla base delle celle visibili. Se alcune colonne sono nascoste, valuta di mostrarle temporaneamente prima dell’AutoFit o applicare l’AutoFit al CurrentRegion della tabella.

Esempio modulare riutilizzabile

Questo modulo fornisce funzioni pronte da riusare in più progetti Access:

' === Modulo: ExcelExportUtils ===
Option Compare Database
Option Explicit

Public Function ExcelOpenOrCreate(ByVal path As String, Optional ByVal createNew As Boolean = False) As Object
Dim xl As Object, wb As Object
Set xl = GetOrCreateExcelApp()
If createNew Then
Set wb = xl.Workbooks.Add
wb.SaveAs path
Else
Set wb = xl.Workbooks.Open(path)
End If
Set ExcelOpenOrCreate = wb
End Function

Public Sub WriteRecordsetToSheet(ByVal wb As Object, ByVal rs As DAO.Recordset, _
Optional ByVal sheetIndex As Long = 1, Optional ByVal startCell As String = "A1")
Dim ws As Object
Set ws = wb.Worksheets(sheetIndex)
ws.Range(startCell).CopyFromRecordset rs
End Sub

Public Sub AutoFitClamp(ByVal ws As Object, Optional ByVal minW As Double = 0, Optional ByVal maxW As Double = 0, Optional ByVal doRows As Boolean = False)
AutoFitSafe ws, True, doRows, minW, maxW
End Sub 

Best practice essenziali

  1. Chiudi risorse: rilascia Recordset, Workbook e Application oppure salva e chiudi esplicitamente per evitare istanze fantasma di Excel.
  2. Evita magic numbers: sostituisci intervalli fissi come "A:M" con .UsedRange o calcoli dinamici (CurrentRegion, ListObject.Range).
  3. Gestisci gli errori: usa On Error GoTo e messaggi chiari per file bloccati, macro disabilitate o oggetti non disponibili.
  4. Prestazioni: disattiva ScreenUpdating e imposta Calculation su manuale durante la scrittura, riattiva alla fine. Evita .Select e .Activate.
  5. Formattazione coerente: applica formati numerici e date prima dell’AutoFit per ottenere misure realistiche di larghezza.

Checklist finale

  • Instanzia/recupera l’oggetto Excel.Application e apri il Workbook corretto.
  • Scrivi i dati (TransferSpreadsheet o CopyFromRecordset).
  • Esegui .UsedRange.Columns.AutoFit (e .Rows.AutoFit se serve).
  • Eventualmente applica clamp min/max e formati.
  • Salva, ripristina impostazioni, libera risorse.

In sintesi

Il problema era dovuto a riferimenti errati agli oggetti Excel e all’uso di metodi nel momento sbagliato. Corretto l’oggetto Workbook e l’ordine delle operazioni, l’uso di .UsedRange.Columns.AutoFit (o macro dedicate) risolve definitivamente la larghezza non adeguata delle colonne dopo l’esportazione da Access. Con le varianti mostrate (loop per colonna, clamp, macro lato Excel) puoi adattare la soluzione a qualsiasi scenario, mantenendo codice pulito, veloce e facile da mantenere.


Appendice: snippet “chiavi in mano”

AutoFit dell’area dati corrente

With wb.Worksheets(1)
    .Range("A1").CurrentRegion.Columns.AutoFit
End With

AutoFit con esclusione di certe colonne

Dim ur As Object, col As Object
Set ur = wb.Worksheets(1).UsedRange
ur.Columns.AutoFit
For Each col In ur.Columns
    Select Case col.Column
        Case 1, 6 ' A e F
            ' Mantieni larghezze predefinite
            col.ColumnWidth = 12
    End Select
Next col

AutoFit solo su tabelle strutturate (ListObject)

Dim lo As Object
Set lo = wb.Worksheets(1).ListObjects("tblDati")
lo.Range.Columns.AutoFit

Macro Excel richiamabile da Access

' Nel modulo standard di Excel
Public Sub AutoFitAllColumns()
    Cells.EntireColumn.AutoFit
End Sub

' Da Access:
xlApp.Run wb.Name & "!AutoFitAllColumns" 
Indice