2

I am trying to Close a User Form from a module, but it's not working.

Here is what I have tried

Sub UpdateSheetButton()
    Dim subStr1 As String
    Dim subSrrt2() As String
    Dim tmp As Integer
    Dim pos As Integer

    Dim Form As WaitMessage
    Set Form = New WaitMessage

    With Form
        .Message_wait = Module2.Label_PleaseWait  
        .Show
    End With

    For Each Cell In ActiveSheet.UsedRange.Cells
        subStr1 = RemoveTextBetween(Cell.formula, "'C:\", "\AddIns\XL-EZ Addin.xla'!")
        tmp = Len(subStr1) < 1
        If tmp >= 0 Then
            Cell.formula = subStr1
            status = True
        End If
    Next

    Unload Form

    MsgBox Module2.Label_ProcessComplete

End Sub

Form Name is WaitMessage.

I have also tried WaitMessage.Hide but it's also not working.

Community
  • 1
  • 1
AddyProg
  • 2,960
  • 13
  • 59
  • 110
  • [Progress bar in VBA Excel](http://stackoverflow.com/q/5181164/11683) might help. – GSerg Nov 12 '14 at 13:24
  • Is it possible to declare a userform like that? I have never seen that before. you could try `unload WaitMessage`. also I highly recommend you to stop using `usedrange`. – Goos van den Bekerom Nov 12 '14 at 13:27
  • Siddharth Rout has a very nice answer on the latter here: http://stackoverflow.com/questions/11169445/error-finding-last-used-cell-in-vba/11169920#11169920 – Goos van den Bekerom Nov 12 '14 at 13:28
  • Why not just `Set Form = Nothing`? – RubberDuck Nov 12 '14 at 13:30
  • *"it's not working."* - what is not working? how is it not working? what is the expected result and what actually is happening? What is the outcome of your step-through code analysis? –  Nov 12 '14 at 14:32
  • 1
    It may be as simple as `.Show False` but it's hard to be sure with such a vague description. ;) – Rory Nov 12 '14 at 14:44

4 Answers4

2

Considering a modeless form, create a subroutine within the userform:

Sub UnloadThisForm ()
    unload me
End Sub

and call the sub from outside the userform;

call Userform1.UnloadThisForm
Adriano P
  • 2,045
  • 1
  • 22
  • 32
1

Another possibility could be to put your code to ClassModule and to use Events to callback to WaitMessage user form. Here short example. HTH

Standard module creates the form and the updater object and displays the form which starts processing:

Public Sub Main()
    Dim myUpdater As Updater
    Dim myRange As Range
    Dim myWaitMessage As WaitMessage

    Set myRange = ActiveSheet.UsedRange.Cells
    Set myUpdater = New Updater
    Set myUpdater.SourceRange = myRange

    ' create and initialize the form
    Set myWaitMessage = New WaitMessage

    With myWaitMessage
        .Caption = "Wait message"
        Set .UpdaterObject = myUpdater
        ' ... etc.
        .Show
    End With

    MsgBox "Module2.Label_ProcessComplete"
End Sub

Class module containes the monitored method and has events which are raised if progress updated or finished. In the event some information is send to the form, here it is the number of processed cells but it can be anything else:

Public Event Updated(updatedCellsCount As Long)
Public Event Finished()
Public CancelProcess As Boolean
Public SourceRange As Range

Public Sub UpdateSheetButton()
    Dim subStr1 As String
    Dim subSrrt2() As String
    Dim tmp As Integer
    Dim pos As Integer
    Dim changesCount As Long
    Dim myCell As Range
    Dim Status

    ' process task and call back to form via event and update it
    For Each myCell In SourceRange.Cells

        ' check CancelProcess variable which is set by the form cancel-process button
        If CancelProcess Then _
            Exit For

        subStr1 = "" ' RemoveTextBetween(Cell.Formula, "'C:\", "\AddIns\XL-EZ Addin.xla'!")
        tmp = Len(subStr1) < 1
        If tmp >= 0 Then
            myCell.Formula = subStr1
            Status = True
        End If

        changesCount = changesCount + 1
        RaiseEvent Updated(changesCount)

        DoEvents
    Next

    RaiseEvent Finished
End Sub

User form has instance of updater class declared with 'WithEvent' keyword and handles events of it. Here form updates a label on 'Updated' event and unloads itself on 'Finished' event:

Public WithEvents UpdaterObject As Updater

Private Sub UpdaterObject_Finished()
    Unload Me
End Sub

Private Sub UpdaterObject_Updated(updatedCellsCount As Long)
    progressLabel.Caption = updatedCellsCount
End Sub

Private Sub UserForm_Activate()
    UpdaterObject.UpdateSheetButton
End Sub

Private Sub cancelButton_Click()
    UpdaterObject.CancelProcess = True
End Sub

enter image description here

Daniel Dušek
  • 13,683
  • 5
  • 36
  • 51
0

A userform is an object in it's own right, you do not need to declare or set as a variable. Also, when you use the .Show Method it will set the Modal property to True by default, which will pause code execution until the user interacts in some way (i.e. closes the form).

You can get around this by using a boolean declaration after the .Show method to specify if the userform is to be shown modal.

Try this instead:

Sub UpdateSheetButton()
Dim subStr1 As String
Dim subSrrt2() As String
Dim tmp As Integer
Dim pos As Integer

With WaitMessage
    .Message_wait = Module2.Label_PleaseWait
    .Show False
End With

For Each Cell In ActiveSheet.UsedRange.Cells
    subStr1 = RemoveTextBetween(Cell.Formula, "'C:\", "\AddIns\XL-EZ Addin.xla'!")
    tmp = Len(subStr1) < 1
    If tmp >= 0 Then
        Cell.Formula = subStr1
        Status = True
    End If
Next

Unload WaitMessage

MsgBox Module2.Label_ProcessComplete

End Sub
SierraOscar
  • 17,507
  • 6
  • 40
  • 68
  • 1
    `A userform is an object in it's own right, you do not need to declare or set as a variable` - the ability to use an instance of a form as if it was a pre-created singleton object is one of the frowned upon features originally intended to simplify programming for those who have little clue about it. Declaring a variable and setting an instance to it is the correct and preferred way. – GSerg Nov 12 '14 at 14:08
0

i guess you can do yourself the screenupdating and enableevents, so here is :

(next time add more description to what you are trying to do, and no just post code...)

Option Explicit 'might help to avoid future miss declaring of variables...

Sub UpdateSheetButton()
Dim subStr1 As String
'Dim subSrrt2() As String 'not used in shown code !
'Dim tmp As Integer
Dim pos As Long
Dim Cell as Range 'you forgot to declare this

Dim Form As object
Set Form = New WaitMessage

load Form
With Form
    .Message_wait = Module2.Label_PleaseWait  
    .Show false 'if you ommit false, the code won't continue from this point unless the Form is closed !
End With

For Each Cell In ActiveSheet.UsedRange.Cells
    subStr1 = RemoveTextBetween(Cell.formula, "'C:\", "\AddIns\XL-EZ Addin.xla'!")
    'tmp = Len(subStr1) < 1 'might replace with a boolean (true/false, instead 0/-1)
    'If tmp >= 0 Then 'you don't use tmp later, so i guess its just using variables without need
     if substr1<>"" then 'why use a cannon to put a nail in a wall?, go to the point
        Cell.formula = subStr1
        pos = pos+1 'you declared pos but didn't use it !?
        Form.SomeTextbox.caption = pos 'or other counter
        'can also use the .width property of a button or picture... to make a progression bar.
        status = True 'Status is not declared , and not used elsewhere , so what ?!
    End If
Next

Unload Form
set Form = Nothing

MsgBox Module2.Label_ProcessComplete

End Sub
Patrick Lepelletier
  • 1,596
  • 2
  • 17
  • 24