programing

VBA - 모델이 없는 UserForm 인스턴스를 제대로 제거합니다.

i4 2023. 8. 24. 21:49
반응형

VBA - 모델이 없는 UserForm 인스턴스를 제대로 제거합니다.

소개:

사용자 양식을 보여주는 것이 가장 좋은 방법이라는 것을 알고 있습니다.

  • QueryClose 코드사용자 양식 코드) 에서.If CloseMode = vbFormControlMenu ...)
  • 아무것도 Unload Me기서거겁, 단지이많은많.Me.Hide지시 ([x]착각 및 궁극적인 자멸을 방지한 후)Cancel = True)
  • [class] 수변설정에] 드예() 변수를 설정하는 :.IsCancelled=True)
  • 호출 코드에 의해 UF가 언로드되도록 하기 위해.

유용한 링크

탁월한 개요 "사용자 양식 1".?"는 수많은 SO 답변(Mathieu Guindonaka Mat's Mug and Rubber Duck)뿐만 아니라 https://rubberduckvba.wordpress.com/2017/10/25/userform1-show/ 에서도 확인할 수 있습니다.

추가선택(2019년 5월 1일 기준)


모달 사용자 양식 작업 예제

제가 이해한 바로는 - 그리고 저는 배우려고 노력하고 있습니다 - 모달 UF에 대해 다음 코드가 괜찮을 것입니다.

사례 1a)UF 인스턴스에 대한 로컬 변수와 함께 사용됩니다(자주 볼 수 있음)

Public Sub ShowFormA
  Dim ufA As UserForm1
  Set ufA = New UserForm1
' show userform 
  ufA.Show          ' equivalent to: ufA.Show vbModal

' handle data after user okay
  If Not ufA.IsCancelled Then
      '  do something ...
  End If

' >> object reference destroyed expressly (as seen in some examples)
  unload ufA
End Sub

사례 1b)로컬 변수 없이, 그러나 사용With New코드 블록:

' ----------------------------------------------------------
' >> no need to destruct object reference expressly,
'    as it will be destroyed whenever exiting the with block
' ----------------------------------------------------------
  With New UserForm1
      .Show         ' equivalent to: ufA.Show vbModal

    ' handle data after user okay
      If Not .IsCancelled Then
      '  do something ...
      End If
  End With

문제

MODELESS UserForm 인스턴스를 사용하면 문제가 발생합니다.

좋아요, 위드 블록 방법(cf. 1b)은 객체 참조를 xit한 후 삭제하기에 충분해야 합니다.

  With New UserForm1
      .Show vbModeless  ' << show modeless uf
  End With

하지만 내가 노력한다면,

  • 사용자 취소 가능성에 대한 정보 및
  • Unload(ufA) 뒤에 ")를 사용하여 세례를 받은 경우 Show 수업, 수업,

양식이 MODELESS라는 정확한 이유로 모든 코드 라인이 한 번에 실행됩니다.

  • 코드는 다음 순간에 양식을 표시합니다.
  • 코드에서 사용자를 찾을 수 없습니다. 사용자 작업을 수행할 시간이 없었기 때문입니다. 다음 순간...
  • [사용자 양식에 로컬 변수를 사용하는 경우 코드가 양식을 언로드합니다.]

질문

로컬 변수를 사용하는 경우 a) 올바르게 보고된 사용자 양식이 MODELESS 양식의 호출 코드로 취소되고 b) a(필요합니까?) 언로드를 처리하려면 어떻게 해야 합니까?

사실, 저는 모달 형태에 꽤 많이 초점을 맞추고 있습니다. 왜냐하면 그것이 가장 일반적으로 사용되는 것이기 때문입니다.그 기사에 대한 피드백 감사합니다!

비모달 형식의 경우 원칙은 동일합니다. 링크된 기사와 여기에 대략적으로 설명된 모델-뷰-프레젠터 패턴을 확장하면 됩니다.

차이점은 비모달 형식은 패러다임 전환이 필요하다는 것입니다. 즉, 미리 설정된 일련의 이벤트에 더 이상 응답하지 않고 특정 시간에 발생하거나 발생하지 않는 비동기 이벤트에 응답해야 합니다.

  • 모달 양식을 처리할 때 "보여주기 전"과 "숨기기 후"가 있으며, 양식이 숨겨진 직후에 실행됩니다.이벤트를 사용하여 "표시하는 동안" 발생하는 모든 작업을 처리할 수 있습니다.
  • 비모달 양식을 처리할 때는 "보여주기 전"이 있고, "보여주는 동안"과 "보여준 후"는 모두 이벤트를 통해 처리해야 합니다.

이 여러분의 수업을 담당하도록 하세요.UserForm 및 턴instance스인("), 모수에서준"WithEvents:

Option Explicit
Private WithEvents myModelessForm As UserForm1

연설문Show는 방은법입니다.Set합니다.

Public Sub Show()
    'If Not myModelessForm Is Nothing Then
    '    myModelessForm.Visible = True 'just to ensure visibility & honor the .Show call
    '    Exit Sub
    'End If
    Set myModelessForm = New UserForm1
    '...
    myModelessForm.Show vbModeless
End Sub

양식 인스턴스를 여기서 절차에 로컬로 지정하지 않으려면 로컬 변수 또는With블록이 작동할 수 없습니다. 사용자가 의도하기 전에 개체가 범위를 벗어납니다.그렇기 때문에 모듈 수준의 개인 필드에 인스턴스를 저장합니다. 이제 폼은 발표자 인스턴스만큼 오래 유지됩니다.

에게 ". 은 "대화"에 있는 하는 것입니다. 가장 쉬운 방법은 이벤트를 노출하는 것입니다.UserForm1 뒤 - " - 예들어백", " 사가취확를면원기다", "한인다다를것추", "입니우을할가음리는하소"를합니다.ByRef이벤트에 대한 매개 변수. 발표자의 핸들러가 이벤트 소스(즉, 양식 코드로 다시 전달)로 정보를 전달할 수 있습니다.

Option Explicit
'...private fields, model, etc...
Public Event FormConfirmed()
Public Event FormCancelled(ByRef Cancel as Boolean)

'returns True if cancellation was cancelled by handler
Private Function OnCancel() As Boolean
    Dim cancelCancellation As Boolean
    RaiseEvent FormCancelled(cancelCancellation)
    If Not cancelCancellation Then Me.Hide
    OnCancel = cancelCancellation
End Function

Private Sub CancelButton_Click()
    OnCancel
End Sub

Private Sub OkButton_Click()
    Me.Hide
    RaiseEvent FormConfirmed
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = VbQueryClose.vbFormControlMenu Then
        Cancel = Not OnCancel
    End If
End Sub

이제 발표자는 그것을 처리할 수 있습니다.FormCancelled 이벤트:

Private Sub myModelessForm_FormCancelled(ByRef Cancel As Boolean)
    'setting Cancel to True will leave the form open
    Cancel = MsgBox("Cancel this operation?", vbYesNo + vbExclamation) = vbNo
    If Not Cancel Then
        ' modeless form was cancelled and is now hidden.
        ' ...
        Set myModelessForm = Nothing
    End If
End Sub

Private Sub myModelessForm_FormConfirmed()
    'form was okayed and is now hidden.
    '...
    Set myModelessForm = Nothing
End Sub

그러나 비모달 양식에는 일반적으로 "확인" 및 "취소" 단추가 없습니다.대신, 몇 가지 기능이 노출될 것입니다. 예를 들어 모달 대화상자가 나타납니다.UserForm2그것은 다른 일을 합니다 - 다시 말하지만, 당신은 그것에 대한 이벤트를 노출하고 발표자에서 그것을 처리합니다.

Public Event ShowGizmo()

Private Sub ShowGizmoButton_Click()
    RaiseEvent ShowGizmo
End Sub

발표자는 다음과 같이 말합니다.

Private Sub myModelessForm_ShowGizmo()
    With New GizmoPresenter
        .Show
    End With
End Sub

참고로 모달은UserForm2는 별도의 발표자 클래스와 관련된 문제입니다.

저는 일반적으로 모델리스 사용자 양식 인스턴스의 수명을 워크북의 수명과 연결합니다. 이 워크북 뒤에 있는 다음 행을 따라 코드를 입력합니다.

Option Explicit

Private m_MyForm As UserForm1

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If Not m_MyForm Is Nothing Then
        Unload m_MyForm
        Set m_MyForm = Nothing
    End If
End Sub

Friend Property Get MyForm() As UserForm1
    If m_MyForm Is Nothing Then
        Set m_MyForm = New UserForm1
    End If

    Set MyForm = m_MyForm
End Property

그런 다음 예를 사용하여 코드 전체에서 모델리스 코드를 참조할 수 있습니다.

ThisWorkbook.MyForm.Show vbModeless

기타.

모델이 없는 양식의 경우 사용자 정의 사용자 양식 속성과 결합된 DoEvents를 사용합니다.


Sub test()

    Dim frm As New UserForm1

    frm.Show vbModeless

    Do
        DoEvents
        If frm.Cancelled Then
            Unload frm
        Exit Do
    End If
    Loop Until False

    MsgBox "You closed the modeless form."

    '/ Using With
    With New UserForm1
        .Show vbModeless
        Do
            DoEvents
            If .Cancelled Then Exit Do
        Loop Until False
    End With

    MsgBox "You closed the modeless form (with)"

End Sub

사용자 양식

Private m_bCancelled As Boolean

Public Property Get Cancelled() As Boolean
    Cancelled = m_bCancelled
End Property

Public Property Let Cancelled(ByVal bNewValue As Boolean)
    m_bCancelled = bNewValue
End Property
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    Me.Cancelled = True
    Cancel = 1
    Me.Hide
End Sub

언급URL : https://stackoverflow.com/questions/47357708/vba-destroy-a-modeless-userform-instance-properly

반응형