Chamando uma subpasta de uma forma de usuário

4

Estou tentando criar uma macro que leia as datas das células em minha planilha e verifique-as em relação a uma data (mês e ano) inserida em um formulário de usuário. Para fazer isso, eu tenho a chamada Userform um Sub Report encontrado em Sheet1 . Inteiros que representam o mês e o ano introduzidos pelo usuário são passados junto com a chamada.

O erro sempre ocorre na linha: Call Sheet1.Report(intMonth, intYear) , que chama Report . O erro lê: Run-time error '1004': Application-defined or object-defined error .

Este é o meu código abreviado, começando com o Userform:

Private Sub cmdOK_Click()

    'Transform month field into an integer (1-12)
    Dim intMonth As Integer
    Select Case cboMonth.Value
        Case Is = strJan 'January - 01
            intMonth = 1
        Case Is = strFeb 'February - 02
            intMonth = 2
        Case Is = strMar 'March - 03
            intMonth = 3
        'and so on...
    End Select

    'Read year field as an Integer
    Dim intYear As Integer
    intYear = txtYear.Value

    Call Sheet1.Report(intMonth, intYear)

End Sub

Em seguida, aqui está o código de Report . Está incompleto até o momento, já que não consegui passar da ligação. Como mencionei anteriormente, sempre acerto o erro na linha de chamada: Call Sheet1.Report(intMonth, intYear) .

Public Sub Report(myMonth As Integer, myYear As Integer)

    'Some incomplete code...
    'Like I said, the macro never gets past the call.

End Sub

Alguma idéia de como corrigir isso? Qualquer ajuda é muito apreciada. Obrigado!

    
por mykrus 29.06.2018 / 00:21

3 respostas

2

Agora que você comprovou que seu código funciona com minha sugestão:

ThisWorkbook.Worksheets("Sheet1").Report intMonth, intYear

Vamos seguir o conselho fornecido por Mathieu. Clique no objeto da pasta na visualização Projeto da sua janela do VBE:

VBAProject > Microsfot Excel Objects > Sheet1 (Sheet1)

A primeira parte é o nome do objeto de pasta, a segunda parte entre parênteses é o nome da planilha, como visto na guia Excel. Chame a janela Properties View do menu suspenso "View" no VBE ou pressionando F4. A primeira coisa na janela de propriedades da planilha deve ser (nome) e esse é o nome do objeto que você chamaria no seu código. Altere para algo descritivo como "Relatório". Em seguida, use um nome descritivo para sua macro, como "Atualizar".

Agora você pode criar um novo relatório ligando:

Report.Update intMonth, intYear

Eu uso essa convenção de nomenclatura porque suponho que sua macro atualiza a folha de relatório. Você também pode seguir seu conselho sobre o estilo de código "model-view-presenter", mas isso está um pouco fora do escopo da sua pergunta.

    
por 29.06.2018 / 18:04
3

Ter a instância padrão de UserForm executando o programa é talvez a coisa mais fácil de se fazer, mas também é uma causa direta de muitos, muitos problemas - desde bugs de fácil introdução, mas difíceis de encontrar até manutenção e extensibilidade. problemas: a solução "nice & quick, works" é o padrão "Smart UI", que funciona muito bem para um protótipo . Projetos maiores que crescem constantemente ao longo do tempo exigem uma arquitetura mais inteligente.

Os programadores chamam de "model-view-presenter". A vista é o formulário. Os dados são o modelo , e depois há o apresentador que coordena tudo.

Calling a Sheet Sub from a Userform

A verdade é que você não sabe. Um modal UserForm é um diálogo , cuja função nada mais é do que coletar a entrada do usuário. Ao torná-lo responsável apenas pela manipulação de dados e deixar a macro / responsável pela chamada responsável pelo fluxo de controle, você torna o código mais robusto e mais fácil de manter - especialmente se o formulário puder fazer muitas coisas.

Comece com um módulo de classe MonthlyReportParams simples:

Option Explicit
Public Month As Integer ' encapsulate into properties to implement 
Public Year As Integer  ' logic for validation on assignment.

Public Property Get IsValid() As Boolean
    IsValid = Month >= 1 And Month <= 12 And _
              Year >= 1900 And Year <= 2100
End Property

Agora, tudo o que o UserForm precisa fazer é trabalhar com esses dados, esse modelo .

Option Explicit
Private params As MonthlyReportParams
Private cancelled As Boolean

Private Sub Class_Initialize()
    Set params = New MonthlyReportParams
End Sub

Public Property Get Model() As MonthlyReportParams
    Set Model = params
End Property

Public Property Set Model(ByVal value As MonthlyReportParams)
    Set params = value
    MonthBox.value = params.Month
    YearBox.value = params.Year
End Property

Public Property Get IsCancelled() As Boolean
    IsCancelled = cancelled
End Property

Private Sub MonthBox_Change()
    ' make sure the textboxes contain numeric values before assigning to Integer
    If IsNumeric(MonthBox.Value) Then params.Month = CInt(MonthBox.Value)
    OnValidate
End Sub

Private Sub YearBox_Change()
    ' make sure the textboxes contain numeric values before assigning to Integer
    If IsNumeric(YearBox.Value) Then params.Year = CInt(YearBox.Value)
    OnValidate
End Sub

Private Sub OkButton_Click()
    Me.Hide
End Sub

Private Sub CancelButton_Click()
    OnCancel
End Sub

Private Sub OnCancel()
    cancelled = True
    Me.Hide
End Sub

Private Sub OnValidate()
    OkButton.Enabled = Model.IsValid
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
' runs when form is just about to close
    If CloseMode = VbQueryClose.vbFormControlMenu Then
        ' user clicked the [X] button
        Cancel = True ' don't destroy the form
        OnCancel
    End If
End Sub

E agora, a macro que exibe este formulário pode recuperar o controle sobre o que está acontecendo: o formulário não está mais exibindo o programa e podemos ler tudo o que está acontecendo em um só lugar:

Public Sub RunMonthlyReport(Optional ByVal targetSheet As Worksheet = Nothing)

    If targetSheet Is Nothing Then
        ' no sheet was specified; work of the ActiveSheet
        Debug.Assert Not ActiveSheet Is Nothing
        Set targetSheet = ActiveSheet
    End If

    ' create the model
    Dim m As MonthlyReportParams
    Set m = New MonthlyReportParams
    m.Month = Month(Now)
    m.Year = Year(Now)

    ' create the dialog, assign the model
    With New MonthlyReportParamsDialog
        Set .Model = m
        .Show ' next line only runs after dialog has closed

        If Not .IsCancelled Then
            ' run the report with the values in the model
            targetSheet.Report m.Month, m.Year
        End If
    End With

End Sub

Informações adicionais sobre os benefícios dessa "inversão de responsabilidades" podem ser encontradas neste artigo e outra lógica de retorno de chamada neste artigo - disclaimer: Eu escrevi os dois; esse blog é o blog oficial do Rubberduck projeto add-in VBIDE OSS, que eu possuo.

    
por 29.06.2018 / 06:22
0

HackSlash respondeu minha pergunta:

Seu exemplo de código funcionou para mim. Tenha em mente que o uso de "Sheet1" como objeto é o nome do objeto de pasta e não o nome da planilha exibido na guia da planilha do Excel. Se você quiser chamá-lo pelo nome da planilha, tente o seguinte: ThisWorkbook.Worksheets ("Sheet1"). Report intMonth, intYear Observação: você não precisa da instrução de chamada se você remover os parênteses. - HackSlash 7 minutos atrás

    
por 29.06.2018 / 01:23