Search code examples
excelvbauserform

Which display mode should one use for a VBA UserForm in order to display data, controll it and confirm it is ok?


I have the following procedure planed:

1. User selects data using userforms

2. User reviews data using usual Excel

3. User confirms the data is ok (for example with a userform)

4. data gets saved

All in the same VBA program.

Here my prototype:

The Module:

Sub ControlDataUI()
Dim Ui As New UserForm1
Dim Confirmend as Boolean
Debug.Print "dostuff"

With Ui
    .Show (False) 'or .Show(True)
    While Not .IsHiden
    Wend
    Confirmed=.Confirmed
End With

Debug.Print "Do some more stuff!"

If Confirmed then Call SaveStuff 

Debug.Print "I will die!!"
End Sub

The Userform1:

Private Type TView
    IsCancelled As Boolean
    Confirmed As Boolean
    IsHiden As Boolean
End Type

Private this As TView

Public Property Get Confirmed() As Boolean
    Confirmed = this.Confirmed
End Property
Public Property Get IsHiden() As Boolean
    IsHiden = this.IsHiden
End Property

Private Sub CommandButton1_Click()
Debug.Print "YES!!!!"
this.Confirmed = True
this.IsHiden = True
Me.Hide
End Sub

Private Sub CommandButton2_Click()
Debug.Print "NO?!?!"
this.Confirmed = False
this.IsHiden = True
Me.Hide
End Sub

Private Sub UserForm_Terminate()
Debug.Print "Murder! I was killed!"
End Sub

Now the issue:

Modeless

When using modeless the userform is displayed but the code keeps running until done. I tried to stop the code from running through with a While Not .IsHiden construction. The code freezes Excel because it's an infinite loop. So that is ruled out. Is there a way to realize this with modeless display?

Modal

If I use a modal display, the use of excel is blocked and only the userform is shown.

In conclusion: Both Modal and Modeless display do not enable the user to control data in a sheet. Is there a solution to this problem?


Solution

  • I got it!

    The solution to the problem is the following: DoEvents

    The Module

    Sub ControlDataUI()
    Dim Ui As New UserForm1
    Dim IsConfirmed As Boolean
    
    Debug.Print "dostuff"
    
    Application.ScreenUpdating=True
    With Ui
        .Show (0)
        While Not .IsHiden
            DoEvents
        Wend
        If .IsCancelled Then Exit Sub
        IsConfirmed = .Confirmed
    End With
    
    Debug.Print "Do some more stuff!"
    
    If IsConfirmed Then
        Debug.Print "SaveStuff"
    End If
    
    Debug.Print "I will die!!"
    End Sub
    

    The UserForm

    Private Type TView
        IsCancelled As Boolean
        Confirmed As Boolean
        IsHiden As Boolean
    End Type
    
    Private this As TView
    Public Property Get IsCancelled() As Boolean
        IsCancelled = this.IsCancelled
    End Property
    Public Property Get Confirmed() As Boolean
        Confirmed = this.Confirmed
    End Property
    Public Property Get IsHiden() As Boolean
        IsHiden = this.IsHiden
    End Property
    
    Private Sub CommandButton1_Click()
    Debug.Print "YES!!!!"
    this.Confirmed = True
    this.IsHiden = True
    Me.Hide
    End Sub
    
    Private Sub CommandButton2_Click()
    Debug.Print "NO?!?!"
    this.Confirmed = False
    this.IsHiden = True
    Me.Hide
    End Sub
    
    Private Sub UserForm_Click()
    
    End Sub
    
    Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    this.IsCancelled = True
    Me.Hide
    End Sub
    
    Private Sub UserForm_Terminate()
    Debug.Print "Murder! I was killed!"
    End Sub
    

    So the idea was in the right direction but the while loop had to contain a DoEvents in order to process the events comming from the user.

    Summary:

    1. Modeless Userform

    2. While loop with DoEvents until user confirmes

    This allows for the user controll of the sheet and a confirmation at any time. The code will run after the user confirms the data is ok.

    Thanks to @Tom and @Zac