Open VBA code of active form - ms-access

I have an Access database with a huge amount of forms (300+) and VBA code. The backend of this Access db is in MS SQL.
When I am on a control in a form (in formview), I want to "jump" directly to the VBA code of this form without closing or putting the form in design mode. I can do this with a shortcut key which I assign to a function.
This works well when the control is not in a subform. But when this is the case, the code runs into an error telling me that the module of form cannot be found.
This is the code i use:
Dim sFrmName As String
sFrmName = Screen.ActiveControl.Parent.Name
If Nz(sFrmName, "") = "" Then Exit Function
'Open forms module
DoCmd.OpenModule "Form_" & sFrmName
How can i change this code so that i dont have to put the form in design mode to go to the VBA code of this form, which will also work for subforms? I know I can do this manually in VBE, but I'd like to do it in VBA.

Found one way to do it, this also works for subforms:
Dim sFrmName As String
sFrmName = Screen.ActiveControl.Parent.Name
If Nz(sFrmName, "") = "" Then Exit Function
'Open forms module
'DoCmd.OpenModule "Form_" & sFrmName
Application.VBE.ActiveVBProject.VBComponents("Form_" & sFrmName).CodeModule.CodePane.Show

Related

Open multiple forms issue in Access

I got query to make some modification that enable user to open multiple instances of the form when they do search data. I got manage to create a new module following Allen Browne guide and now I can open multiple instances of the spreadsheet which is good step forward but I cannot find solution how I can open that specific form.
In module I have got following code:
Public clnClient As New Collection 'Instances of frmClient.
Function OpenAClient()
'Purpose: Open an independent instance of form frmClient.
Dim frm As Form
'Open a new instance, show it, and set a caption.
Set frm = New Form_SurgeriesForm
frm.Visible = True
frm.Caption = frm.Hwnd & ", opened " & Now()
'Append it to our collection.
clnClient.Add Item:=frm, Key:=CStr(frm.Hwnd)
Set frm = Nothing
End Function
And under my button I replaced bit:
DoCmd.OpenForm "SurgeriesForm", acNormal
Forms!SurgeriesForm.Requery
.. and usef following code:
ModuleInstances.OpenAClient
I recon I need to add / change somehow the code below to be able to open multiple instances but do not have idea how to do it.
DoCmd.OpenForm "SurgeriesForm", acNormal
Forms!SurgeriesForm.Requery
I appreciate for any help with this as i got stuck and do not know how I can achieve this.
I think this is what you want?...
With the button on your SurgeriesForm add this code to the On Click event to open a new instance of the form:
Private Sub Command8_Click()
OpenAClient
End Sub
This will create a new instance of the form each time you click the button.
Next, add a blank combo-box to the form and change it's Row Source Type to Value List.
Add this code to the form:
Private Sub Combo9_GotFocus()
Dim frm As Variant
Combo9.RowSource = ""
For Each frm In clnClient
Combo9.AddItem frm.Caption
Next frm
End Sub
Now, when you click the drop-down it will list each form that you have created an instance of.
Finally, add this code to the form:
Private Sub Combo9_AfterUpdate()
clnClient(Combo9.Value).SetFocus
End Sub
Now, selecting a form name from the combo-box will move the focus to that form.
NB: You'll need to update the name of the controls to match yours.
NB2: Remember to open the first form using OpenAClient or it won't get listed in the combobox (as it's not in the collection).

Loop through every control in a form, with the form name defined as a variable

I am trying to create a basic search which looks for a partial keyword match of any control in a specified form. The form name is selected via combo box and is stored as a variable.
How do I use this to loop through the controls of the selected form?
I can easily loop through the controls of the current form with the following:
For Each ctrl In Me.Controls
Debug.Print ctrl.Name
Next ctrl
But I can't figure out how to reference an external form, with the variable essentially replacing Me.
I've tried using:
Dim ctrl as Control
Dim variableName as String
variableName = Me.cmboFormName
For each ctrl in Forms(variableName).Controls
Debug.Print ctrl.Name
Next ctrl
But this just returns error 438 (Object doesn't support this property or method).
You need to Dim ctrl as well, and you may have spaces in the form name:
Dim ctrl As Control
Dim variableName as String
variableName = "[" & Me.cmboFormName & "]"
For Each ctrl In Forms(variableName).Controls
Debug.Print ctrl.Name
Next
Try this:
For Each ctrl In UserForm1.Controls 'or use your form name.
Debug.Print ctrl.Name
Next ctrl
Since the error is occurring on Forms(variableName).Controls, the instruction is doing too many things to be easily debuggable. Split it up.
Declare a variable to contain a Form object - note, I'm no Access dev, I usually work with Excel and MSForms, so for me that would be a UserForm, but I very strongly suspect that your Access forms aren't from the MSForms type library (you'd have to work pretty hard to get a UserForm in Access), so I'm guessing the type to use is called Form, but I could be wrong - will be happy to edit if corrected in a comment.
Dim theForm As Form
Now Set the form object:
Set theForm = Forms(variableName)
If your code didn't blow up yet, then you've successfully retrieved a form instance. That wouldn't surprise me, because if that step failed you'd probably be facing a subscript out of range error instead.
If your library has a Controls collection class, declare a variable of that type:
Dim theControls As Controls
And assign it:
Set theControls = theForm.Controls
That could possibly blow up with run-time error 438, if Form doesn't have a Controls member... which wouldn't really add up, given Me.Controls seems to work.
So go back and declare theForm As Object, and let VBA's late-binding magic query the object's interface, instead of working with the specific Form interface - again I don't know much Access, but it's fairly possible that Me being a specific form type exposes a Controls collection, but not the general-purpose Form type - VBA UI framework internals are that kind of a mess.
So, to speak COM-gibberish, by declaring it as Object you allow the run-time to query IDispatch and locate the Controls member.
If you can get that instruction (the Controls collection assignment) to run without throwing, then you should be able to iterate its content without problems.
Also keep in mind that it seems the Forms collection only includes open forms.
Forms contains collection of opened forms. Unfortunately you cannot access a closed form using a variable name.
Just check whether the form is available. if not open the form either in nomal or design view and continue your code like this.
Dim ctrl as Control
Dim variableName as String
variableName = Me.cmboFormName
If Not (FN_FORM_ISLOADED(variableNAme)) Then
'Open your form in desired view.
DoCmd.OpenForm variableNAme, acNormal
End If
For each ctrl in Forms(variableName).Controls
Debug.Print ctrl.Name
Next ctrl
Place this function in your public module
Public Function FN_FORM_ISLOADED(iFormName As String) As Boolean
Dim I As Integer
FN_FORM_ISLOADED = False
For I = 0 To Forms.count - 1
If Forms(I).name = iFormName Then
FN_FORM_ISLOADED = True
Exit Function
End If
Next I
End Function

How to close a spawned VBA Access user form via a close button w/o using DoCmd

I have a main form named Calling. It has a button named Travel. That Travel button does:
Private Sub btnTravel_Click()
On Error GoTo btnTravel_Click_Err
DoCmd.OpenForm "Travel", acNormal, "", "", acFormEdit
'If you can find a cleaner way to open a form I will be thankful.
btnTravel_Click_Exit:
Exit Sub
btnTravel_Click_Err:
MsgBox Error$
Resume btnTravel_Click_Exit
End Sub
The Travel info form performs correctly. That Travel form has a Close button with the code:
Private Sub bntClose_Click()
Unload Me
End Sub
When pressed, the Close code generates "Run-time error '361': Can't load or unload this object.
Your help is much appreciated.
You do not need the commas with the empty strings, nor do you need the acFormEdit as when you open the form you will be able to edit and add new records anyway.
If you leave this argument blank the form will open in the data mode set by the forms AllowEdits, AllowDeletions, AllowAdditions, and DataEntry permissions (in the form properties).
DoCmd.OpenForm "Travel", acNormal
As for the next sub routine, I would use docmd.close instead of unload.
Private Sub bntClose_Click()
Me.Undo
DoCmd.Close acForm, "Travel", acSaveNo
End Sub
The me.undo is optional, if you don't want to save, and if you want to save the form change the acSaveNo to acSaveYes.
EDIT:
I have just re-read your question and noticed in the title you want to do this without docmd.
I have had a think about this and docmd is the standard way of closing forms in access using VBA. I am not sure if you have inherited the unload from using VB, but I would stick to docmd.close when using access.
"Unolad me" just doesn't work in Access Form objects.
Access wants you to use DoCmd.Open/DoCmd.Close but you are clever than that and can use Access Form Object as an object. Access names the Form Classes prefixed the name you give them with "Form_". You create a Form named "YourForm", Access create the Class "Form_YourForm". Use this class as a real object:
'Declare a typed variable
Dim f As Form_YourForm
'Create the object
Set f = New Form_YourForm 'This triggers the Open event
'Use the object
f.SetFocus
f.Resize
'... And eventually, dispose the object
Set f = Nothing
'Remember <<Unload f>> won't work, neither you can use DoCmd.Close
Also, you can use Form_YourForm directly as an object variable because VBA Access just create "implicitly" this object out of the class Form_YourForm when you first use it or when you use DoCmd.Open. (Yes, it's a little bit confusing, but Access was create for users that didn't have necessarily programmer skills).
However, you'll get a different instance of the Form_YourForm Class each time you use a variable object typed as any of the Form Class that exist in your project. This means you can open as many instances of a form as you want ...or while it fits your computer's memory. You can't acomplish it using DoCmd.Open.
The main "disadvantages" are that you have to handle the form object from another module. You can still use the "Forms" collection but since you don't know the given key you can't reach your form instance easily. Also, you can't close the form from its own code, but only disposing the typed variable (Set f=nothing).

MS Access 2007 Converting forms into sub form - "form not found" issue

So I recently have been trying to incorporate more sub forms to make the UI more friendly. So I have a pre developed form that runs some VB, so for examples sake lets just say that it runs SQL statement, returns the recordset, and fills text boxes with the data (because this is sort of an interactive dashboard concept:
dim db as database
dim rs as recordset
dim sql as string
set db = current db
sql = "SELECT * FROM tblMain;"
set rs = db.OpenRecordSet(sql)
rs.movefirst
[forms]![DashboardSubName].txtValue1 = rs!Value1
rs.close
set rs = nothing
set db = nothing
with error handling that returns a error "DashboardSubName" not found. So orginally this form was its own form, and opening it by itself it works fine, but once I use it within the parent form i get this error.
im sure it is simply something i am not aware of, but what gives?
thanks guys
justin
When a Form is loaded as a sub-form, it is referenced as if it were just another control on the Main Form - it is no longer part of the global Forms collection.
So the correct reference should be:
Me!DashboardSubName.Form.txtValue1
where DashboardSubName is the name of your sub-form control.
Assuming the code you showed us is part of the subform, rather than the parent form, replace
[forms]![DashboardSubName].txtValue1 = rs!Value1
with
Me.txtValue1 = rs!Value1
The reason for the syntax here is that the subform control is distinct from the subform embedded inside it. The subform control has properties of its own (limited in comparison to the subform itself), and to get to the properties/methods of the subform embedded in it you have to specify that you want the form that the subform embeds.
Me!MySubformControl
...is the subform control.
Me!MySubformControl.Form
...is the form embedded in the subform control.
Last of all, I really wonder why you're walking a recordset to update data in a subform. This is not normal practice, though it's tangential to your actual question.

Login Screen in Access with forms, macros and queriesms-

I have an embarrassing question regarding Access. I can build relational databases in my sleep but I have always used PHP, mySQL and HTML to build my applications.
I've hated Access with a passion for various reasons ever since I can remember but now I'm stuck using it for a particular project.
I have a number of tables, one of which is customer, which among other things has a username and password field.
When I start the database, I want a login form to appear, which I can do using the AutoExec macro, I've made the form with a username and password field. After that, I get stuck with the logic of querying for the username/password and then showing a new form if correct or an error if not.
Could anyone help me out with making the macro and query work together?
Clarification: I am trying to do this without coding whole Visual Basic macros, if at all possible, I want to be able to do it using the macro builder thingumy.
Thanks
Given a form frmLogin, with 2 text boxes, txtUserName and txtPassword, and a command button, you can try the following
Private Sub Command0_Click()
Dim rec As Recordset2
Set rec = CurrentDb.OpenRecordset("SELECT * FROM Customer WHERE username = """ & txtUserName.Value & """ AND password = """ & txtPassword.Value & """")
If (rec.RecordCount > 0) Then
DoCmd.OpenForm "frmMain"
DoCmd.Close acForm, "frmLogin"
End If
End Sub
Malphas -
It is actually possible to do this without using VBA, but I am wondering whether the reason why you don't want to use VBA is because of the Trust issue. In which case, this won't be possible, because the macro actions Close and Quit are disallowed if the database is not trusted.
Whilst you can to run actions in the AutoExec macro beyond the point where you use the OpenForm command, I think it is neater to continue the next actions on the form itself. First because you can't really do branching in a macro; secondly because it is more modular to keep actions to do with the form actually on the form.
In the example below, my sample login form is called LoginForm, and the username text box is txtUserName, and the password text box is called txtPassword.
The first thing to do is to protect the dialogue from the simple act of letting the user close the dialogue and escape into the database design screen. The best way to do this is to set a flag called ValidLogin when the form loads. You will set this flag during the login process. When the form is closed, check whether the flag is true. If ValidLogin is false, then close the database.
On the OnLoad event of the Login form, click on the ellipsis button, and choose Macros Builder. In the Macro screen, use the following actions (note that the Condition column is hidden by default - but you'll only need for the next two macros):
Line Condition Action/Arguments
1 SetTempVar, Name = ValidLogin, Expression = False
On the OnUnload event of the Login form, do the same as above, and add:
Line Condition Action/Arguments
1 Not [TempVars]![ValidLogin]
Quit, Options = Exit.
If you run this now, as soon as you close the form, the database will close. To be useful, you need to add the following macro actions to the OnClick event of your Login button:
Line Condition Action/Arguments
1 SetTempVar, Name = Valid Login, Expression = DCount("*","Customer","[Username]=[Forms]![LoginForm]![txtUserName] And [Password]=[Forms]![LoginForm]![txtPassword]")>0
2 Not [TempVars]![ValidLogin]
MsgBox, Message = Invalid Login
3 ... StopMacro
4 OpenForm, Form Name = MainForm
5 Close, Object Type = Form, Object Name = LoginForm, Save = No
Note that in all these examples, I have used embedded macros, not named macros, so you can keep them together with the form. Also note the ellipsis (...) in the last macro, which represents the value of the last condition.
A slight tweak to the above as the code above would be open to SQL injection attacks (yes I know it is only access but it never hurts)
Public Function CheckUserPassword(strUserName As String, strPassword As String) As Boolean
Dim rst As DAO.Recordset
Set rst = DBEngine(0)(0).OpenRecordset("tblUsers", dbOpenTable)
With rst
.Index = "UserName"
.Seek "=", strUserName
If .NoMatch = False Then
If !Password = strPassword Then
CheckUserPassword = True
Else
CheckUserPassword = False
End If
Else
CheckUserPassword = False
End If
End With
rst.Close
Set rst = Nothing
End Function