How to run vba macro after an access form has loaded? - vba

When I call a sub in Form_Load, it gives me an error cause by Screen.ActiveForm. This is due to the form not being loaded yet.
What sub/function can I use to run a macro once the form has loaded.
I tried Form_Timer, it didn't do anything
Form_Activate produces same error
Form_after… they do not really seem to indicating anything after form load.
Here is my code for Form_Timer:
Private Sub Form_Timer()
call Module6.loadRecords
Me.TimerInterval = 500
End Sub
I was hoping that after 0.5 seconds that my form will be loaded and records will be display in the form controls.

Instead of depending on Screen.ActiveForm, you should simply pass the form reference to the function.
Private Sub Form_Load()
Call Module6.loadRecords(Me)
End Sub
and
Public Sub loadRecords(F As Access.Form)
If you really want to use Screen.ActiveForm, it works like this:
Private Sub Form_Load()
' 1 ms is enough to de-couple the events
Me.TimerInterval = 1
End Sub
Private Sub Form_Timer()
' Reset timer, always the first thing to do for single Timer events
Me.TimerInterval = 0
Call Module6.loadRecords
End Sub

Related

VBA - UserForm Button (Macro) to Continue running the sub

I have a sub called as sub1() which activates the userform1 through the command userform1.show()
This userform1 has a button called as continue. On clicking that button continue - A Macro called as Private Sub continuebutton() gets activated.
I want to program in such a way that it redirects to the line after userform1.show() in sub1().
Is it something that can be done?
Theoretically, what you want is possible, if you do it like this:
In the UserForm:
Private Sub btnContinue_Click()
flag = True
Debug.Print "I continue ..."
sub1
End Sub
In a module:
Public flag As Boolean
Public Sub sub1()
If flag Then
Debug.Print "sub 1 continues here..."
Else
flag = False
UserForm1.Show
Exit Sub
End If
End Sub
It will work exactly as intended, BUT it is not a good practice to work this way. (Some people may throw stones at you for using public variables at all in VBA.) Here are two articles, that give better ideas:
https://rubberduckvba.wordpress.com/2017/10/25/userform1-show/
Disclaimer - this one is mine:
http://www.vitoshacademy.com/vba-the-perfect-userform-in-vba/
On the form properties for userform1, set its "Modal" property to true.
When the form opens, it will have exclusive focus, and the code in sub1 will not continue running until after it closes. This may be the solution you need.
In the code below, the msgbox will only appear once userform1 closes:
sub sub1()
userform1.show()
msgbox "Now continuing with sub1"
end sub
No way as long as you show the form.
If you show the form modal, the calling routine continues if (and only if) the form is closed.
If you show the form non-modal, the code continues to run directly after the show - so it's already done.
So either you have to close the form when the user clicks the "continue..." button to let the calling macro continue or you have to split your code into two routines and call the second on button-click.
You can change your Sub1 as follows:
Sub sub1(Optional Continue As Boolean)
If Continue = True Then
DoSomeStuff
Exit Sub
End If
userform1.show
End sub
And then, you can call your sub1 using:
Private Sub continuebutton()
Call sub1(True)
End Sub
Hope it helps
If you don't want to go with the 'Modal Form' solution, you could add a subroutine to your main module, and call it when required. So, in userform1, you have:
sub sub1()
userform1.show()
end sub
public sub sub2()
msgbox "Now continuing..."
end sub
And then in userform1, set some code on its onClose event:
Private Sub continuebutton()
Call sub2()
end sub

MsgBox AFTER QueryTable refresh is done

I have this code where I refresh a QueryTable:
Sub refreshCD()
ActiveWorkbook.Connections("CD").Refresh
End Sub
How can I display a MsgBox AFTER the refresh is complete? I've tried to place it right after the refresh, but obviously it ran before it was done since there's no type of callback or something.
I've read about DoEvents(), but I couldn't understand very well or apply that, and don't know if this is right method.
Any ideas?
you can create a class module and sink the events of the querytable, you have both before and after refresh available, like so
Private WithEvents qtCustom As QueryTable
Public Function Initialise(qtInput As QueryTable)
Set qtCustom = qtInput
End Function
Private Sub qtCustom_AfterRefresh(ByVal Success As Boolean)
' After Refresh
End Sub
Private Sub qtCustom_BeforeRefresh(Cancel As Boolean)
' Before Refresh
End Sub

form loading the last state it was before hide()

I have 2 forms. I want to open the second form in the last state it was left? I mean changes intact, textfields changed, choices made etc etc. I try using .show but it does load the form from its load sub which resets the form from the fresh state.
Can anyone guide me here? Thanks in advance
If you don't want the form to reload, don't destroy it.
In the main form, store a reference to the single instance of the second form.
Private m_Dialog As Form2
Private Sub Command1_Click()
If m_Dialog Is Nothing Then Set m_Dialog = New Form2
m_Dialog.Show
End Sub
Private Sub Form_Unload(Cancel As Integer)
If Not m_Dialog Is Nothing Then Unload m_Dialog
Set m_Dialog = Nothing
End Sub
In the second form, use Hide() to close it.
Private Sub OKButton_Click()
Me.Hide
End Sub

Having an MS Office UserForm detect which subroutine called it

In a VBA project of mine I am/will be using a series of reasonably complex userforms, many of which are visually identical but have different subroutines attached to the buttons. As a result I'm not overly keen on the idea of duplicating them multiple times in order to get different functionality out of the same layout. Is it possible to have a userform detect which subroutine called it and use this in flow control? I would like to be able to do something like this:
Private Sub UserForm_Initialize()
If [the sub that called the userform is called "foo"] then
Call fooSub
else
Call barSub
End If
End Sub
My backup plan is to have the calling subroutine set a global variable flag and have the userform check that, but that seems like a rather crude and clumsy solution.
Thanks everyone,
Louis
You can use the tag property of the form. Load the form, set the property, then show the form:
Sub PassCallerToForm()
Load UserForm1
UserForm1.Tag = "foo"
UserForm1.Show
End Sub
Now that the property is set, you can determine what to do in the form:
Private Sub UserForm_Activate()
If Me.Tag = "foo" Then
Call fooSub
Else
Call barSub
End If
End Sub
You can also use public variables:
' in userform
Public Caller As String
Private Sub UserForm_Click()
MsgBox Caller
Caller = Now()
Me.Hide
End Sub
' in caller
Sub callUF()
Dim frm As New UserForm1
frm.Caller = "Test Caller"
frm.Show
MsgBox frm.Caller ' valid after Me.Hide
Set frm = Nothing
End Sub
Personally, I would not have one userform doing two disparate activities. The code would get hard to read pretty quickly, I think. Copying the layout of a userform is pretty trivial.
To copy a userform: Open a blank workbook. In the Project Explorer, drag the userform to the new workbook. Rename the userform in the new workbook. Now drag it back to the original workbook. Change the code in the userform copy.
If you absolutely don't want separate userforms, I recommend setting up a property of the userform. Userforms are just classes except they have a user interface component. In the userform module
Private mbIsFoo As Boolean
Public Property Let IsFoo(ByVal bIsFoo As Boolean): mbIsFoo = bIsFoo: End Property
Public Property Get IsFoo() As Boolean: IsFoo = mbIsFoo: End Property
Public Sub Initialize()
If Me.IsFoo Then
FooSub
Else
BarSub
End If
End Sub
I always write my own Initialize procedure. In a standard module:
Sub OpenForm()
Dim ufFooBar As UFooBar
Set ufFooBar = New UFooBar
ufFooBar.IsFoo = True
ufFooBar.Initialize
ufFooBar.Show
End Sub

Why does Showing a UserForm as Modal Stop Code Execution?

The following VBA code stops at Me.Show. From my tests, it seems that Me.Show stops all code execution, even if the code is inside the UserForm.
This part is outside the UserForm:
Public Sub TestProgress()
Dim objProgress As New UserForm1
objProgress.ShowProgress
Unload objProgress
End Sub
This part is inside the UserForm:
Private Sub ShowProgress()
Me.Show vbModal
Dim intSecond As Integer
For intSecond = 1 To 5
Application.Wait Now + TimeValue("0:00:01")
Me.ProgressBar1.Value = intSecond / 5 * 100
Next intSecond
Me.Hide
End Sub
The code stops at Me.Show, after the UserForm is displayed. There is no error, it just discontinues executing code. It seems that the only way to execute code inside a modal UserForm in VBA is to include it in the UserForm_Activate procedure like this:
This part is outside the UserForm:
Public Sub TestProgress()
Dim objProgress As New UserForm1
Load objProgress
Unload objProgress
End Sub
This part is inside the UserForm:
Private Sub UserForm_Initialize()
Me.Show vbModal
End Sub
Private Sub UserForm_Activate()
Dim intSecond As Integer
For intSecond = 1 To 5
Application.Wait Now + TimeValue("0:00:01")
Me.ProgressBar1.Value = intSecond / 5 * 100
Next intSecond
Me.Hide
End Sub
Of course, I can't put Me.Show inside UserForm_Activate because that procedure only fires after the UserForm Show event.
The documentation for UserForm.ShowModal says "When a UserForm is modal, the user must supply information or close the UserForm before using any other part of the application. No subsequent code is executed until the UserForm is hidden or unloaded."
I am trying to use a modal UseForm as a progress bar to prevent the user from interacting with the application while a process runs. But this will be difficult to accomplish if all my code has to be within the UserForm_Activate procedure.
Am I missing something here? Why does all code execution stop at Me.Show?
When the form is displayed with vbModal, the code will suspend execution and wait for user interaction with the form. For example clicking a button or using a dropdown.
If you update the form property
ShowModal = False
and remove vbModal from your code. This will allow code execution to continue when the form is displayed.
I was searching for an answer to why I was getting the following error:
Run time error '5': Invalid procedure call or argument
when running this line of code:
UserForm1.Show True
even though this line works:
UserForm1.Show False
Of course. True is not the same as vbModal! So the simple answer is to use the correct enumerations:
UserForm1.Show vbModal
UserForm1.Show vbModeless
I think I figured this out.
After Me.Show the UserForm_Activate event fires. If there is no code in the UserForm_Activate procedure nothing will happen because VBA is waiting for Me.Hide.
So the order of events is: Me.Show > UserForm_Activate > Me.Hide
Any code that I want to run must be in the UserForm_Activate procedure and must be before Me.Hide.
The structure is very strict, but I may be able to use that structure to my advantage.