Excel VBA: mover linha automaticamente para outra planilha pela lista suspensa

Automatize seu fluxo no Excel: ao selecionar um Status em uma lista suspensa, a linha inteira é movida automaticamente para a aba cujo nome coincide com o valor escolhido (ex.: “Zone1”). A mesma lógica traz a linha de volta se o Status for alterado novamente.

Índice

Visão geral e objetivo

Em muitos controles operacionais (cadastros, filas de atendimento, kanbans, checklists), a coluna Status indica para onde cada registro deve “andar” no processo. Este artigo mostra como implementar, em Excel/VBA, uma movimentação automática: sempre que você altera o Status na planilha Register (ou em qualquer aba, na versão global), a linha completa de A:M é transferida para a planilha cujo nome é exatamente o novo Status. A linha deixa de existir na origem, evitando duplicação. Se o Status mudar de novo, a linha volta a ser movida, mantendo um único “dado mestre”.

Quando usar esta abordagem

  • Você precisa mover fisicamente os dados entre abas (não apenas filtrá-los).
  • Os nomes dos Status coincidem com os nomes das planilhas de destino (ex.: Zone1, Zone2, Finalizados).
  • Você quer simplificar o trabalho do usuário: basta trocar o Status na lista suspensa.

Pré-requisitos

  • Arquivo salvo como .xlsm (pasta de trabalho habilitada para macro).
  • Macros habilitadas (Central de Confiabilidade do Excel).
  • Planilhas de destino já criadas e nomeadas exatamente como os valores da lista.
  • Coluna de Status posicionada na coluna I (ajustável, veja personalizações).
  • Dados por linha ocupando colunas A até M (ajustável).

Como preparar a lista suspensa de Status

  1. Liste os nomes de Status (idênticos às abas) em uma área do arquivo, preferencialmente em uma planilha de parâmetros.
  2. Selecione as células da coluna I na planilha Register (onde o usuário irá escolher o Status).
  3. Vá a Dados > Validação de Dados > Permitir: Lista > Fonte: selecione o intervalo com os nomes dos Status.
  4. Confirme. Agora cada célula dessa coluna terá um drop-down.

Solução funcional na planilha Register

Se você deseja que a movimentação aconteça apenas quando o Status for alterado na aba Register, use o evento Worksheet_Change no módulo da própria planilha Register.

Passo a passo

  1. Salve como .xlsm e habilite as macros.
  2. Pressione Alt+F11 para abrir o Editor do VBA.
  3. No Project Explorer, dê duplo‑clique em Planilha (Register).
  4. Na barra superior do módulo, escolha Worksheet (à esquerda) e Change (à direita).
  5. Cole o código abaixo e salve.
Private Sub Worksheet_Change(ByVal Target As Range)
    On Error GoTo Fim
    ' Executa apenas para uma única célula
    If Target.CountLarge > 1 Then Exit Sub
    ' Coluna I (9)
    If Target.Column <> 9 Then Exit Sub
    If Len(Trim$(Target.Value)) = 0 Then Exit Sub

    Dim wsDest As Worksheet, ultLinha As Long
    On Error Resume Next
    Set wsDest = ThisWorkbook.Worksheets(CStr(Target.Value))
    On Error GoTo 0
    If wsDest Is Nothing Then
        MsgBox "A planilha '" & Target.Value & "' não existe.", vbExclamation
        Exit Sub
    End If

    Application.EnableEvents = False

    ' Próxima linha livre na coluna A da planilha destino
    ultLinha = wsDest.Cells(wsDest.Rows.Count, "A").End(xlUp).Row + 1

    ' Copia A:M da linha alterada
    With Me
        .Range(.Cells(Target.Row, "A"), .Cells(Target.Row, "M")).Copy _
            Destination:=wsDest.Cells(ultLinha, "A")
        ' Apaga a linha original (toda a linha para manter alinhamento)
        .Rows(Target.Row).Delete
    End With

Fim:
    Application.EnableEvents = True
End Sub

Como o código funciona

EtapaDescrição
Filtro do eventoExecuta apenas quando uma única célula da coluna I é alterada e o valor não é vazio.
Validação do destinoConfere se existe uma planilha com o nome exatamente igual ao valor selecionado no drop‑down.
MovimentaçãoCopia o intervalo A:M da linha onde houve a mudança, cola no próximo espaço livre da planilha de destino e exclui a linha original.
SegurançaDesliga e religa Application.EnableEvents para evitar que o próprio código dispare em cascata.

Essencial: os nomes do drop‑down devem coincidir 100% com os nomes das abas de destino; qualquer divergência faz o código avisar e não mover a linha.

Versão aprimorada que funciona em qualquer aba

Se você prefere que a movimentação ocorra mesmo quando o usuário altera o Status fora da Register, coloque este código no módulo ThisWorkbook. Ele reage à mudança na coluna de Status em qualquer planilha do arquivo.

Passos

  1. No Editor do VBA, dê duplo‑clique em ThisWorkbook.
  2. Cole o código a seguir e salve.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    On Error GoTo Fim
    Const STATUS_COL As Long = 9   ' 9 = Coluna I
    Const FIRST_COL  As Long = 1   ' 1 = Coluna A
    Const LAST_COL   As Long = 13  ' 13 = Coluna M

    If Target.CountLarge > 1 Then Exit Sub
    If Intersect(Target, Sh.Columns(STATUS_COL)) Is Nothing Then Exit Sub
    If Len(Trim$(Target.Value)) = 0 Then Exit Sub

    Dim nomeDest As String: nomeDest = CStr(Target.Value)
    Dim wsDest As Worksheet
    On Error Resume Next
    Set wsDest = ThisWorkbook.Worksheets(nomeDest)
    On Error GoTo Fim
    If wsDest Is Nothing Then
        MsgBox "Planilha '" & nomeDest & "' não encontrada.", vbExclamation
        Exit Sub
    End If

    ' Se o destino for a própria planilha, não faz nada
    If wsDest.Name = Sh.Name Then Exit Sub

    Application.EnableEvents = False

    Dim lin As Long, proxima As Long
    lin = Target.Row
    proxima = wsDest.Cells(wsDest.Rows.Count, FIRST_COL).End(xlUp).Row + 1

    Sh.Range(Sh.Cells(lin, FIRSTCOL), Sh.Cells(lin, LASTCOL)).Copy _
        Destination:=wsDest.Cells(proxima, FIRST_COL)

    Sh.Rows(lin).Delete

Fim:
    Application.EnableEvents = True
End Sub

Vantagens desta versão

  • Independente da aba: altera o Status onde estiver e a linha será movida.
  • Constantes fáceis de ajustar: mude STATUSCOL, FIRSTCOL e LAST_COL conforme sua estrutura.
  • Prevenção de loop: não movimenta se o destino for a própria aba (If wsDest.Name = Sh.Name Then Exit Sub).

Adaptações rápidas e comuns

Trocar a coluna do Status

  • Versão por planilha: substitua If Target.Column <> 9 Then por If Target.Column <> 7 Then para usar a coluna G.
  • Versão aprimorada: mude Const STATUS_COL As Long = 9 para 7.

Alterar o intervalo copiado

  • Quer levar A:P? Ajuste na versão global: Const LAST_COL As Long = 16 (P = 16).
  • Na versão por planilha, troque "M" por "P" onde aplicável.

Colar apenas valores (sem fórmulas)

Substitua a linha com Copy Destination por:

Sh.Range(Sh.Cells(lin, FIRSTCOL), Sh.Cells(lin, LASTCOL)).Copy
wsDest.Cells(proxima, FIRST_COL).PasteSpecial xlPasteValues
Application.CutCopyMode = False

Preservar formatação do destino

Se as abas de destino têm tabelas formatadas, considere colar apenas valores e aplicar formatação de tabela (“Formatar como Tabela”) para que novas linhas herdem o estilo automaticamente.

Evitar mover o cabeçalho

Caso sua planilha tenha cabeçalho na primeira linha, você pode impedir a movimentação se o usuário alterar o Status do cabeçalho por engano:

' Acrescente logo após as constantes:
Const FIRSTDATAROW As Long = 2
' E antes de processar:
If Target.Row &lt; FIRSTDATAROW Then Exit Sub

Tabela de referência rápida

ElementoValor padrão do artigoFunção
STATUS_COL9 (coluna I)Coluna onde o usuário escolhe o Status.
FIRST_COL1 (coluna A)Primeira coluna do bloco de dados a mover.
LAST_COL13 (coluna M)Última coluna do bloco de dados a mover.
Intervalo padrãoA:MBloco de dados do registro (linha inteira) que será transferido.

Erros comuns e como resolver

  • Nada acontece: confirme se o código foi colado no módulo correto (Planilha (Register) para a versão local, ThisWorkbook para a global). Verifique se o arquivo está como .xlsm e se os eventos estão ativos. No Imediato do VBA, execute: Application.EnableEvents = True.
  • Planilha não encontrada: a validação lista valores que devem existir como abas. Corrija nomes ou crie a planilha correspondente.
  • Mudança por fórmula: o evento Change não dispara quando a célula muda por resultado de fórmula. O Status deve ser selecionado/alterado pelo usuário (ou por macro).
  • Linhas mescladas: mesclagens costumam causar comportamentos inesperados ao copiar e excluir linhas. Evite mesclar no bloco A:M.
  • Planilhas protegidas: se a origem ou o destino estiverem protegidos, o código pode falhar ao excluir/colar. Desproteja ou trate com Unprotect/Protect no código.
  • Desempenho lento em listas longas: veja as Boas práticas de desempenho abaixo.

Boas práticas de desempenho

  • Desabilite atualizações visuais durante a cópia e exclusão: Dim oldScr As Boolean, oldCalc As XlCalculation oldScr = Application.ScreenUpdating oldCalc = Application.Calculation Application.ScreenUpdating = False Application.Calculation = xlCalculationManual ' ... sua lógica de cópia/exclusão ... Application.Calculation = oldCalc Application.ScreenUpdating = oldScr
  • Evite selecionar/ativar objetos (no VBA, “Select” é quase sempre supérfluo).
  • Padronize faixas com tabelas do Excel para herdar formatação e validações.

Fluxo de trabalho recomendado

  1. Crie/valide as abas de destino (Zone1, Zone2, Zone3 etc.).
  2. Monte a lista suspensa de Status na coluna I.
  3. Instale a versão de macro que melhor se encaixa (apenas Register ou global no ThisWorkbook).
  4. Teste com 3–5 linhas de exemplo, variando os Status e validando se as linhas foram removidas da origem.
  5. Proteja o cabeçalho contra edições indevidas e, se necessário, use a regra de FIRSTDATAROW.

Alternativa sem VBA

Se não é necessário mover fisicamente os dados, uma alternativa mais simples e robusta é manter todos os registros na Register e criar abas por zona exibindo apenas os dados filtrados por fórmula dinâmica:

=FILTER(Register!A:M, Register!I:I="Zone1")

Crie uma fórmula dessas em cada aba (ajustando o valor do Status). Você reduz riscos, mantém uma única fonte de verdade e dispensa macros. É perfeito para cenários de leitura/consulta.

Perguntas frequentes

Posso mover para outra pasta de trabalho?

Sim. Desde que a outra pasta esteja aberta e tenha uma planilha com o mesmo nome do Status, você pode apontar o destino. Exemplo ilustrativo na versão global:

Dim wbDest As Workbook
Set wbDest = Workbooks("Destino.xlsx") ' já aberta
Set wsDest = wbDest.Worksheets(nomeDest)

Em vez de copiar e excluir, posso “cortar” a linha?

É possível usar .Cut para mover células e limpar a origem, mas normalmente você ainda desejará excluir a linha vazia para manter o alinhamento. A abordagem “copiar & deletar” é direta e previsível.

Como impedir que o usuário escolha um Status inexistente?

Alimente a validação de dados diretamente a partir do nome das abas (por exemplo, com um intervalo que liste dinamicamente as planilhas válidas) ou mantenha um intervalo de referência único para o drop‑down e para a criação das abas — o importante é que a escrita do Status corresponda ao nome da planilha.

Checklist de implantação

  • Arquivo salvo em .xlsm e macros habilitadas.
  • Abas de destino criadas e nomeadas.
  • Lista suspensa de Status configurada.
  • Código instalado na posição correta (Register ou ThisWorkbook).
  • Teste com casos simples e com mudanças de Status sequenciais (ex.: Register → Zone1 → Zone2 → Register).
  • Eventos reativados (Application.EnableEvents = True) após testes.

Exemplo prático

Suponha as abas Register, Zone1, Zone2 e Concluídos. Um registro novo é criado em Register. O usuário escolhe Zone1 na coluna I; automaticamente, a linha vai para a aba Zone1 e some de Register. Mais tarde, o operador muda o Status para Concluídos na própria aba Zone1; a versão global move a linha para a aba Concluídos. O histórico lógico do processo é mantido através do próprio Status, sem duplicações.

Segurança e manutenção

  • Armazene o arquivo em local confiável (OneDrive/SharePoint) para reduzir prompts de segurança de macro.
  • Crie cópias de segurança antes de publicar mudanças no VBA.
  • Registre convenções de nomenclatura de abas e de Status para a equipe.

Resumo em uma frase

Com um pequeno evento VBA, você transforma a coluna de Status em um “trilho” que leva cada linha exatamente para a aba correspondente, de forma automática, segura e reversível pela própria mudança do Status.


Solução pronta para copiar

Versão por planilha (Register):

Private Sub Worksheet_Change(ByVal Target As Range)
    On Error GoTo Fim
    If Target.CountLarge > 1 Then Exit Sub
    If Target.Column <> 9 Then Exit Sub
    If Len(Trim$(Target.Value)) = 0 Then Exit Sub```
Dim wsDest As Worksheet, ultLinha As Long
On Error Resume Next
Set wsDest = ThisWorkbook.Worksheets(CStr(Target.Value))
On Error GoTo 0
If wsDest Is Nothing Then
    MsgBox "A planilha '" & Target.Value & "' não existe.", vbExclamation
    Exit Sub
End If

Application.EnableEvents = False
ultLinha = wsDest.Cells(wsDest.Rows.Count, "A").End(xlUp).Row + 1

With Me
    .Range(.Cells(Target.Row, "A"), .Cells(Target.Row, "M")).Copy _
        Destination:=wsDest.Cells(ultLinha, "A")
    .Rows(Target.Row).Delete
End With
```
Fim:
Application.EnableEvents = True
End Sub </code></pre>

<p><strong>Versão aprimorada (ThisWorkbook):</strong></p>
<pre><code class="language-vba">Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    On Error GoTo Fim
    Const STATUS_COL As Long = 9
    Const FIRST_COL  As Long = 1
    Const LAST_COL   As Long = 13```
If Target.CountLarge &gt; 1 Then Exit Sub
If Intersect(Target, Sh.Columns(STATUS_COL)) Is Nothing Then Exit Sub
If Len(Trim$(Target.Value)) = 0 Then Exit Sub

Dim nomeDest As String: nomeDest = CStr(Target.Value)
Dim wsDest As Worksheet
On Error Resume Next
Set wsDest = ThisWorkbook.Worksheets(nomeDest)
On Error GoTo Fim
If wsDest Is Nothing Then
    MsgBox "Planilha '" &amp; nomeDest &amp; "' não encontrada.", vbExclamation
    Exit Sub
End If

If wsDest.Name = Sh.Name Then Exit Sub

Application.EnableEvents = False

Dim lin As Long, proxima As Long
lin = Target.Row
proxima = wsDest.Cells(wsDest.Rows.Count, FIRST_COL).End(xlUp).Row + 1

Sh.Range(Sh.Cells(lin, FIRST_COL), Sh.Cells(lin, LAST_COL)).Copy _
    Destination:=wsDest.Cells(proxima, FIRST_COL)

Sh.Rows(lin).Delete
```
Fim:
Application.EnableEvents = True
End Sub 

Alternativa sem VBA para quem só precisa visualizar por Status

Manter uma única base em Register e projetar cada Status em sua aba com fórmulas dinâmicas simplifica manutenção e reduz risco de quebra por macro:

=FILTER(Register!A:M, Register!I:I="Zone1")

Dica final: para ajustes rápidos, lembre-se — mude a coluna do Status (ex.: G = 7), ajuste o intervalo copiado (ex.: P = 16), e troque a cópia por “somente valores” quando necessário. O núcleo da solução permanece o mesmo.

Índice