Pergunta

É melhor mostrar UserForms ProgressBar no VBA como modal ou sem modo?Quais são as melhores práticas para desenvolver indicadores de progresso em VBA?

UserForms sem modelo requerem o uso de Application.Interactive = False, enquanto os UserForms modais, por sua própria natureza, bloqueiam qualquer interação com o aplicativo até que o procedimento principal seja concluído ou cancelado.

Se Application.Interactive = False é usado, no entanto, a tecla Esc interrompe a execução do código, portanto o uso de Application.EnableCancelKey = xlErrorHandler e tratamento de erros (Err.Number = 18) é necessário tanto no UserForm quanto no procedimento de chamada.

Procedimentos de chamada com uso intensivo de recursos também podem resultar em CommandButton_Click e UserForm_Activate eventos falhando em UserForms sem janela restrita.

Em geral, indicadores de progresso que utilizam UserForms modais parecem mais simples, pois o código que está sendo executado está totalmente contido no módulo UserForm, e há menos necessidade de passagem de variáveis.

O problema, entretanto, com o uso de UserForms modais para indicadores de progresso é que um módulo UserForm separado é necessário para cada procedimento que precisa de um indicador de progresso, porque o procedimento de chamada deve estar dentro do procedimento UserForm_Activate.

Portanto, embora seja possível ter um único indicador de progresso reutilizável em um UserForm sem janela restrita, ele será menos confiável do que executar o código em vários UserForms modais.

Qual caminho é melhor?

Obrigado!

Foi útil?

Solução 2

Vou fechar este e dizer que Modal é o vencedor. Eu tentei nos dois lados, mas você acaba tentando fechar muitas brechas com formas de usuário modificadas. O Modal é mais difícil porque é mais rigoroso, mas incentiva você a dividir seu código em pedaços menores, o que é melhor a longo prazo de qualquer maneira.

Outras dicas

Há também uma terceira maneira, usando o Application.StatusBar. Você pode até simular uma verdadeira barra de progresso usando uma sequência de caracteres U+25A0 e U+25A1.

Definitivamente modal. Se você vai considerar o Modyless, deve executá-lo em um encadeamento separado e fora de processo e não no thread principal do Excel.exe.

Acho que vale a pena responder ao tópico inicial, já que a pergunta foi formulada tão bem que o Google a encontra primeiro.

Seção 1 - Teoria

A primeira coisa a dizer é que transferir as variáveis ​​entre os módulos não é nada difícil.

A única coisa que você precisa fazer é criar um módulo separado e colocar lá todas as variáveis ​​globais.Então você poderá lê-los em todos os lugares, em todos os formulários, planilhas, módulos.

A segunda coisa é que a janela deve ser MODELESS.Porquê isso?A resposta é para manter a mobilidade do código, ou seja

  1. a função onde o processo mais rotineiro é executado não deve estar localizada no módulo UserForm
  2. você pode chamar a janela com barra de progresso de qualquer lugar e
  3. a única conexão entre a função/procedimento da rotina são as variáveis ​​globais

Esta é uma grande vantagem para ser versátil aqui.

Seção 2 - Prática

1) Crie um módulo "Declaração" com as variáveis ​​globais:

Public StopForce como inteiro 'Esta variável será usada como um indicador de que o usuário pressionou o botão Cancelar

PCTDone público como único "Este é o % do trabalho que já foi feito

CurrentFile público como cadeia de caracteres ' qualquer outro parâmetro que queremos transferir para o formulário.

2) Crie o formulário com o botão.No evento OnClick do botão deverá existir um código onde nos referimos à variável global StopForce em Declaração módulo

 Private Sub CommandButton1_Click()

 Declaration.StopForce = 1
  End Sub

3) Adicione um procedimento onde você atualiza a barra de progresso

Sub UpdateProgressBar(PCTDone_in As Single)
With UserForm1
    ' Update the Caption property of the Frame control.
    .FrameProgress.Caption = Format(PCTDone_in, "0%")
    ' Widen the Label control.
    .LabelProgress.Width = PCTDone_in * _
        (.FrameProgress.Width)
    ' Display the current file from global variable   
    .Label1.Caption = Declaration.CurrentFile
End With
End Sub

4) em qualquer outro módulo devemos ter as funções ou o procedimento/sub onde é feita a rotina:

 For i=1 to All_Files

 Declaration.CurrentFile = myFiles (i)

 FormFnc.UpdateProgressBar (i / .Range("C11").Value)


 DoEvents

 If Declaration.StopForce = 1 Then
    GoTo 3
 End If

 Next i

Na verdade, você tem propriedades seguintes, resultando em prós/contras, dependendo da sua necessidade:

Type      | Impact on UI | Impact on caller execution
----------|--------------|-----------------------------
Modal     | Blocked      | Blocked until Form is closed
Modeless  | Not blocked  | Continues

Se você deseja bloquear a interface do usuário e deixar o chamador continuar, então você precisa abrir o formulário no modo modal com Application.OnTime.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top