Exportou dados do Access para o Excel e as colunas ficaram truncadas? Veja como apontar para o Workbook correto, aplicar AutoFit em colunas e linhas, ganhar desempenho e evitar armadilhas comuns do VBA ao automatizar o Excel a partir do Microsoft Access.
Contexto: por que as colunas não se autoajustam
Ao exportar dados de uma tabela no Access (por exemplo, tbl_printExcel
) para o Excel via VBA, é comum que o conteúdo apareça cortado. O motivo quase sempre é uma combinação de:
- Referência incorreta ao Excel: usar
ActiveWorkbook.Name
(string) em vez de manter uma variável-objeto para oWorkbook
e aWorksheet
. - Ordem das operações: aplicar
AutoFit
antes de terminar de preencher a planilha dispara recálculos desnecessários e pode não refletir os dados finais. - Faixas fixas: usar
Columns("A:M")
limita o ajuste a 13 colunas, o que falha quando a tabela cresce. - Planilhas com formatação anterior:
UsedRange
pode estar “poluído” por estilos herdados; é preciso limpar ou calcular o intervalo usado de forma robusta.
Princípio-chave
Para um AutoFit confiável a partir do Access: capture objetos Excel explícitos (Application → Workbook → Worksheet
), preencha todos os dados primeiro, e então aplique AutoFit
ao UsedRange
ou a um intervalo calculado dinamicamente.
Solução consolidada (passo a passo)
Passo | Trecho essencial de código | Observações / Boas práticas |
---|---|---|
Pegar o objeto correto | Dim xlApp As Object, wb As Object, ws As Object On Error Resume Next Set xlApp = GetObject(, "Excel.Application") 'anexa se existir If xlApp Is Nothing Then Set xlApp = CreateObject("Excel.Application") On Error GoTo 0 Set wb = xlApp.Workbooks.Open("C:\caminho\arquivo.xlsx") Set ws = wb.Worksheets(1) | Não use ActiveWorkbook.Name como se fosse objeto; mantenha variáveis-objeto para Workbook e Worksheet . |
Exportar os dados | 'Ex.: usando CopyFromRecordset (rápido) Dim rs As DAO.Recordset Set rs = CurrentDb.OpenRecordset("SELECT * FROM tbl_printExcel", dbOpenSnapshot) 'Cabeçalhos: Dim i As Long For i = 0 To rs.Fields.Count - 1 ws.Cells(1, i + 1).Value = rs.Fields(i).Name Next 'Dados a partir da célula A2: ws.Range("A2").CopyFromRecordset rs rs.Close: Set rs = Nothing | Escreva tudo primeiro; evite AutoFit dentro do loop. CopyFromRecordset é bem mais rápido que célula a célula. |
Autoajustar colunas | ws.UsedRange.Columns.AutoFit | UsedRange foca no que foi realmente preenchido. Se houver formatações “fantasma”, veja a seção de diagnóstico. |
(Opcional) Autoajustar linhas | ws.UsedRange.Rows.AutoFit | Útil quando há quebras de linha (WrapText ) ou textos longos no cabeçalho. |
Tornar visível e limpar objetos | xlApp.Visible = True 'Feche/Quit apenas se você criou a instância 'Set ws = Nothing: Set wb = Nothing: Set xlApp = Nothing | Liberar recursos evita instâncias “órfãs” do Excel em segundo plano. |
Código‑modelo enxuto (late binding) com tratamento de erros
Este exemplo cria (ou anexa a) uma instância do Excel, exporta a tabela tbl_printExcel
, ajusta colunas e linhas, e deixa a pasta aberta ao usuário. Não requer referência ao objeto Excel no projeto do Access.
Option Explicit
'Constantes Excel (evita referência Early Binding)
Private Const xlCalculationManual As Long = -4135
Private Const xlCalculationAutomatic As Long = -4105
Sub ExportarParaExcel_AutoFit()
Const ARQUIVO As String = "C:\Caminho\saida.xlsx"
```
Dim xlApp As Object, wb As Object, ws As Object
Dim created As Boolean, calcMode As Long
On Error GoTo TrateErro
'1) Excel
Set xlApp = GetOrCreateExcel(created)
'Desempenho (restaurado no final)
calcMode = xlApp.Calculation
xlApp.ScreenUpdating = False
xlApp.Calculation = xlCalculationManual
xlApp.EnableEvents = False
'2) Abra ou crie um arquivo
If Dir$(ARQUIVO) <> "" Then
Set wb = xlApp.Workbooks.Open(ARQUIVO)
Else
Set wb = xlApp.Workbooks.Add
wb.SaveAs ARQUIVO
End If
Set ws = wb.Worksheets(1)
'3) Limpe destino e escreva cabeçalhos + dados
ws.Cells.Clear
Dim rs As DAO.Recordset, i As Long
Set rs = CurrentDb.OpenRecordset("SELECT * FROM tbl_printExcel", dbOpenSnapshot)
For i = 0 To rs.Fields.Count - 1
ws.Cells(1, i + 1).Value = rs.Fields(i).Name
Next
If Not (rs.BOF And rs.EOF) Then
ws.Range("A2").CopyFromRecordset rs
End If
rs.Close: Set rs = Nothing
'4) AutoFit após preencher TUDO
With ws.UsedRange
.Columns.AutoFit
.Rows.AutoFit
End With
'5) Mostrar ao usuário
xlApp.Visible = True
wb.Activate
```
LimpeTudo:
'Restaure e limpe
On Error Resume Next
xlApp.ScreenUpdating = True
xlApp.Calculation = calcMode
xlApp.EnableEvents = True
```
Set ws = Nothing
Set wb = Nothing
If created Then
'Se criamos o Excel, fechamos ao final (se desejar manter aberto, comente as duas linhas abaixo)
'xlApp.Quit
End If
Set xlApp = Nothing
Exit Sub
```
TrateErro:
MsgBox "Falha ao exportar: " & Err.Number & " - " & Err.Description, vbCritical
Resume LimpeTudo
End Sub
Private Function GetOrCreateExcel(ByRef created As Boolean) As Object
On Error Resume Next
Set GetOrCreateExcel = GetObject(, "Excel.Application")
If GetOrCreateExcel Is Nothing Then
Set GetOrCreateExcel = CreateObject("Excel.Application")
created = True
End If
On Error GoTo 0
End Function
Variante: usando DoCmd.TransferSpreadsheet e depois AutoFit
Se você prefere delegar a exportação ao Access, dá para chamar TransferSpreadsheet
e apenas abrir o Excel para o AutoFit:
Sub ExportarComTransferSpreadsheet()
Const ARQUIVO As String = "C:\Caminho\saida.xlsx"
Const PLANILHA As String = "Dados"
```
'Exporta a tabela para o Excel (cria uma planilha nova chamada "Dados")
DoCmd.TransferSpreadsheet _
TransferType:=acExport, _
SpreadsheetType:=acSpreadsheetTypeExcel12Xml, _
TableName:="tbl_printExcel", _
FileName:=ARQUIVO, _
HasFieldNames:=True, _
Range:=PLANILHA
'Abre para AutoFit
Dim xl As Object, wb As Object, ws As Object
Dim created As Boolean
Set xl = GetOrCreateExcel(created)
Set wb = xl.Workbooks.Open(ARQUIVO)
Set ws = wb.Worksheets(PLANILHA)
ws.UsedRange.Columns.AutoFit
ws.UsedRange.Rows.AutoFit
xl.Visible = True
wb.Activate
```
End Sub
Diagnóstico avançado: quando UsedRange
não ajuda
Se a planilha recebeu formatações antigas, UsedRange
pode ser maior que os dados reais. Nestes casos, calcule o último valor com .Cells.Find
e aplique AutoFit apenas no intervalo real:
Private Sub AutoFitIntervaloReal(ws As Object)
'Constantes Excel (late binding)
Const xlByRows As Long = 1
Const xlByColumns As Long = 2
Const xlPrevious As Long = 2
```
Dim lastCell As Object, lastRow As Long, lastCol As Long
On Error Resume Next
Set lastCell = ws.Cells.Find(What:="*", After:=ws.Cells(1, 1), _
LookIn:=-4163, LookAt:=1, SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, MatchCase:=False)
On Error GoTo 0
If Not lastCell Is Nothing Then
lastRow = lastCell.Row
Set lastCell = ws.Cells.Find(What:="*", After:=ws.Cells(1, 1), _
LookIn:=-4163, LookAt:=1, SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, MatchCase:=False)
lastCol = lastCell.Column
ws.Range(ws.Cells(1, 1), ws.Cells(lastRow, lastCol)).Columns.AutoFit
ws.Range(ws.Cells(1, 1), ws.Cells(lastRow, lastCol)).Rows.AutoFit
End If
```
End Sub
Dica: se houver células mescladas, o AutoFit pode não ampliar corretamente a altura de linhas; evite mesclas em dados tabulares.
Atalho turbo: escreva tudo de uma vez (sem loop) e só então AutoFit
Para grandes volumes, evite preencher célula a célula. Três alternativas mais rápidas:
CopyFromRecordset
(já mostrado): ótimo custo/benefício.- Matriz Variant: carregue os dados no Access (DAO/ADO), monte uma matriz bidimensional e atribua direto ao
Range
de destino. - QueryTable/ListObject: para fontes externas, alimente uma tabela do Excel; depois, AutoFit no intervalo da tabela.
Boas práticas indispensáveis
- Variáveis‑objeto explícitas: mantenha
xlApp
,wb
ews
em escopo; não confie emActiveWorkbook
/ActiveSheet
. - AutoFit no final: somente após preencher todas as células.
- Desempenho: para planilhas grandes, desligue
ScreenUpdating
,EnableEvents
e coloqueCalculation
como manual; restaure ao fim. - Liberação: feche
Recordset
, zere objetos e chameQuit
apenas se você criou o Excel. - Resiliência: envolva pontos críticos em
On Error
e restaure o Excel caso haja falhas intermediárias. - Intervalo dinâmico: prefira
UsedRange
ou a função de “última célula” a faixas fixas como"A:M"
. - Formatação: para cabeçalhos longos, aplique
WrapText = True
antes doAutoFit
de linhas.
Exemplo completo: do Access para um arquivo novo com cabeçalhos, formato e AutoFit
Sub ExportarTbl_ComFormato()
Const ARQUIVO As String = "C:\Caminho\relatorio.xlsx"
```
Dim xlApp As Object, wb As Object, ws As Object
Dim created As Boolean
Dim rs As DAO.Recordset, i As Long
On Error GoTo TrateErro
Set xlApp = GetOrCreateExcel(created)
xlApp.ScreenUpdating = False
Set wb = xlApp.Workbooks.Add
Set ws = wb.Worksheets(1)
ws.Name = "Relatorio"
'Dados
Set rs = CurrentDb.OpenRecordset("SELECT * FROM tbl_printExcel", dbOpenSnapshot)
'Cabeçalhos
For i = 0 To rs.Fields.Count - 1
ws.Cells(1, i + 1).Value = rs.Fields(i).Name
Next
ws.Range("A1").Resize(1, rs.Fields.Count).Font.Bold = True
ws.Range("A1").Resize(1, rs.Fields.Count).WrapText = True
'Linhas
If Not (rs.BOF And rs.EOF) Then ws.Range("A2").CopyFromRecordset rs
rs.Close: Set rs = Nothing
'AutoFit
With ws.UsedRange
.Columns.AutoFit
.Rows.AutoFit
.EntireColumn.HorizontalAlignment = -4131 'xlLeft (late binding)
End With
'Congelar painel na primeira linha
ws.Rows(2).Select
xlApp.ActiveWindow.FreezePanes = True
wb.SaveAs ARQUIVO
xlApp.Visible = True
wb.Activate
```
Limpe:
On Error Resume Next
xlApp.ScreenUpdating = True
Set ws = Nothing: Set wb = Nothing
If created Then
'xlApp.Quit 'se necessário
End If
Set xlApp = Nothing
Exit Sub
TrateErro:
MsgBox "Erro: " & Err.Number & " - " & Err.Description, vbCritical
Resume Limpe
End Sub
Quando usar macro interna ou atalho manual
Se o usuário final puder interagir no Excel, duas alternativas simples resolvem sem mexer no Access:
- Macro no Excel (no próprio arquivo):
Sub AutoFitColumns()
Cells.Select
Cells.EntireColumn.AutoFit
Cells.EntireRow.AutoFit
End Sub
- Barra de Ferramentas de Acesso Rápido: adicione o comando “Autofit Column Width” para um clique ajustar a planilha aberta.
Checklist de solução de problemas
- AutoFit não muda nada? Verifique se há conteúdo de fato nas células (fórmulas vs valores vazios). Confirme que você está chamando
AutoFit
na Worksheet correta (ws
). - Linhas não aumentam de altura? Ative
WrapText
nos cabeçalhos ou células com quebras de linha antes doAutoFit
. Evite mesclar células. - Colunas continuam estreitas? Remova formatação antiga (
ws.Cells.ClearFormats
antes de escrever) ou calcule o intervalo real com.Cells.Find
(veja função acima). - Excel fica lento? Desligue atualização de tela e cálculo automático durante a escrita; religue ao final.
- Excel fica “preso” em segundo plano? Só chame
Quit
se você criou a instância (flagcreated = True
), e sempre libere objetos.
Comparativo rápido: late binding x early binding
Critério | Late Binding (Object) | Early Binding (Excel.Application) |
---|---|---|
Dependência de referência | Não requer referência ao Excel | Requer marcar “Microsoft Excel xx.x Object Library” |
Intellisense | Não | Sim (tipos e constantes) |
Portabilidade | Alta entre versões | Pode quebrar entre versões |
Desempenho | Sem diferença relevante para este caso | Sem diferença relevante para este caso |
Resumo prático
- Guarde objetos do Excel (nada de strings de
Name
). - Preencha a planilha toda e só então chame
AutoFit
. - Use
UsedRange
ou calcule o intervalo real com.Find
. - Para desempenho, escreva em bloco (
CopyFromRecordset
), desligue atualização/ cálculo e restaure ao final. - Feche e limpe com critério, evitando instâncias órfãs do Excel.
Perguntas frequentes
“Definir ColumnWidth = 50
antes do AutoFit ajuda?”
Não é necessário. O AutoFit
calcula a largura ideal com base no conteúdo. Definir uma largura fixa antes só aumenta trabalho e pode atrasar a execução.
“Por que o AutoFit
às vezes reduz pouco a largura?”
Porque há estilos/formatos aplicados (como formatação de número com muitos dígitos) que influenciam o cálculo. Limpar formatos antigos antes de escrever os dados costuma resolver.
“Consigo aplicar AutoFit em todas as planilhas do arquivo?”
Sim. Basta iterar:
Dim sht As Object
For Each sht In wb.Worksheets
sht.UsedRange.Columns.AutoFit
sht.UsedRange.Rows.AutoFit
Next
Conclusão
Ao substituir referências ambíguas por variáveis‑objeto, escrever os dados primeiro e aplicar AutoFit
ao intervalo correto, o ajuste de colunas (e linhas) passa a funcionar de forma consistente após a exportação do Access para o Excel. Os exemplos acima oferecem um caminho confiável, performático e fácil de manter — do script enxuto ao modelo completo com tratamento de erros.