I have a sub which instantiates a new form, makes it visible. However the new form lasts only for a very brief moment. This is my code:
Private Sub txtProject_ID Click()
Dim frmReq as Form
Set frmReq = New Form_Request
frmReq.Visible = True
End Sub
I tried to set break points on this and found out the form becomes visible when I set its visibility to true. However it disappears as soon as the Sub ends.
Edit:
How to create multiple instances of the pop up form?
In Access VBA you use
DoCmd.OpenForm "Request"
If you need to open it invisible you do
DoCmd.OpenForm "Request", WindowMode:=acHidden
' Initialize stuff while invisible
Forms!Request!foo = "bar"
' show form
Forms!Request.Visible = True
To open multiple instances (would have helped to mention that in the question) and pass a parameter, create a public initialization function in the form:
Public Sub InitForm(ReqId As Long)
' e.g.
Me.Filter = "Request_ID = " & ReqId
Me.FilterOn = True
'show me
Me.Visible = True
End Sub
and call it like this (see bottom of https://msdn.microsoft.com/en-us/library/office/ff845819.aspx)
Option Compare Database
Option Explicit
' This variable must be on *module* level!
Dim frmReq as Form
Private Sub txtProject_ID Click()
Set frmReq = New Form_Request
Call frmReq.InitForm(Me!txtProject_ID)
End Sub
The variable/object of scope is limited to sub procedure so it needs to be form level.
I have a MS Access form which displays list of records in grid . Each row is having a detail buttton.
When clicked on it , it opens up a new form with details of that particular selected row.
When click on close button of detail form , the values get saved to database.
Now , on click of close , i would like to execute Form Load of main form . This is because i need to refresh some values after update is made in detail form
I have tried some thing like this :
Call Forms!frm_Package!Form_Load
Please suggest on how to accomplish this . I have tried various ways but could not get it worked.
Please let me know if any further information is required.
The reason you could not "re-call" the Load is because it is a Private Sub and only when you are inside the Form you can access the method.
One way to hack "external procedure call" is to move the code inside the Form Load into a Public Sub (withing the same Form) and then calling the newly created Sub from outside the form. Like,
Private Sub Form_Load()
MsgBox "Hello World"
End Sub
TO
Private Sub Form_Load()
newPubMethod
End Sub
Public Sub newPubMethod()
MsgBox "Hello World"
End Sub
Now you will be able to call this Public Sub newPubMethod even from outside the Form with the right quantifiers.
Private Sub exitButtonName_Click()
Forms("CallingFormName").newPubMethod
End Sub
I use this code to do this kind of things. I hide the main form when i open a popup form ... i do my work and then i return to the main form.
Private Sub Form_Open(Cancel As Integer)
If gIsLoaded("mainForm") Then Form_mainForm.Visible = False
End Sub
Private Sub Form_Close()
' -- here you will put the code you need!!!
If gIsLoaded("mainForm") Then Form_mainForm.Visible = True
End Sub
Function gIsLoaded(strName As String, Optional _
lngtype As AcObjectType = acForm) As Boolean
gIsLoaded = (SysCmd(acSysCmdGetObjectState, _
lngtype, strName) <> 0)
End Function
I have text boxes on several forms in my application that have a "zoom" capability -- double-click on them and a pop-up form appears which you can resize and edit to your hearts content. This is coded via a class module "appZoomText" which acts as an 'event sink' for the text box events.
I'm trying to create a content menu and ribbon item which replicates the double click behaviour (for those of my users who don't read documentation but might wonder what a zoom icon does if they see it.)
On entry to a zoomable text box, this code is executed:
dim mclsZoomtext as appZoomtext
set mclsZoomtext = new appZoomtext
Set mclsZoomText.pTextBox = ActiveControl
In the class module, the following code is executed in Set pTextBox
Private WithEvents myTextBox As Access.TextBox
Set myTextBox = pTextBox
myTextBox.OnDblClick = "[Event Procedure]"
The double-click code for myTextBox is:
Private Sub myTextBox_DblClick(intCancel As Integer)
OpenZoomForm 'Opens the relevant form with the right contents -- works fine
End Sub
The relevant menu item is enabled in Set ptextBox and disabled when pTextBox is exited (this is working fine).
The code invoked when the context menu item is clicked is:
Public Function OnActionZoom() As Boolean
Dim ctl As Control
Set ctl = GetCurrentControl
'GetCurrentControl returns the current Control object on a form or subform and works fine
CallByName ctl.Parent, ctl.Name & "_DblClick", VbMethod
OnActionZoom = True
End Function
I get an error 2465 ("can't find the field referred to") on the CallByName line. I'm assuming that this is because the DblClick code is in the event sink not the form. ctl.parent and ctl.name are set correctly.
How can I code this to invoke the event sink code?
Update: I've tried creating an empty (Public) Field_DblClick sub in the form; doesn't help - this empty sub runs but the event in the class module doesn't fire. Neither does making myTextBox_DblClick Public instead of Private.
In this instance I could just invoke OpenZoomForm directly, or maybe I could have a single public instance of appZoomText that gets associated with different textboxes as required (I haven't tried this).
However, I need to use a similar method to create a menu item to drill-down in a number of comboboxes and textboxes -- double-clicking in the combo-box/textbox opens an edit form for the item in the ox -- but the edit form isn't always the same, and I can't have a single public instance of each event sink.
Similar code:
Combobox_Enter or TextBox_Enter:
dim mclsClass as ClassX
set mclsClass as new ClassX
set mclsClass.ComboBox = ActiveControl 'Or set mclsClass.textbox = activecontrol
in ClassX:
Private Withevents myComboBox as ComboBox
Public Property Set ComboBox (pctlComboBox as ComboBox)
set myComboBox = pctlComboBox
myComboBox.OnDblClick = "[Event Procedure]"
End Property
Private WithEvents myTextBox as TextBox
Public Property Set TextBox(pctltextBox as TextBox)
set myTextBox= pctltextBox
myTextBox.OnDblClick = "[Event Procedure]"
End Property
Public Sub myComboBox_DblClick(intCancel As Integer)
If Not IsNull(KeyID(myComboBox.Text)) Then 'Check that there is a record to edit
EditFormX(myComboBox) 'EditFormX depends on the Class
'Some more code in here depending on the user's edit
myComboBox.Requery
End If
End Sub
Public Sub mytextBox_DblClick(intCancel As Integer)
If Not IsNull(KeyID(myTextBox.Text)) Then 'Check that there is a record to edit
EditFormX(myTextBox) 'EditFormX depends on the Class
'Some more code in here depending on the user's edit
myTextBox.Requery
End If
End Sub
For CallByName to work, you need to ensure the following:
1) The method being called is public not private.
2) All required parameters are passed.
As such, you need to make the event handlers public (as you are now doing), and pass an additional argument to CallByName for the DblClick handers' Cancel parameter. Since you aren't doing anything with that parameter inside the methods themselves, passing just 0 will do:
CallByName Ctl.Parent, Ctl.Name + "_DblClick", 0
Update 1 - example of this working [note this proves too simple in the OP's case - see Update 2 below]
a) Create a new Access project.
b) Add a new blank form to the project, and a TextBox to the form.
c) Double click the text box's On DblClick event in the Properties window, choosing the Code Builder option if prompted.
d) Add the following code for the handler:
Private Sub Text1_DblClick(Cancel As Integer)
MsgBox "Hello World!"
End Sub
e) Amend the method's header so that it reads Public Sub not Private Sub
f) View (open) the form, and focus the text box by clicking inside it.
g) Go back into the VBA editor, and add a new standard module.
h) Add the following sub-routine to the module:
Sub Test()
Dim Ctl As Access.Control
Set Ctl = Screen.ActiveControl
CallByName Ctl.Parent, Ctl.Name + "_DblClick", VbMethod, 0
End Sub
i) With the caret inside the Test routine, press F5 or click the Run button
On this, the 'Hello World' message appears for me.
Update 2
With the use of WithEvents now explicit, a demo of something that may work in your situation:
1) In Access, create a new database and add a blank form to it.
2) Add a text box and a combo box to the form, and call then txtTest and cboTest; next, add three command buttons, calling them cmdCreateControllers, cmdDestroyControllers and cmdExecuteController respectively, and setting their captions to 'Create controllers', 'Destroy controllers' and 'Execute controller'. Also set cmdDestroyControllers and cmdExecuteController's Enabled properties to False.
3) In the VBA editor, add a class module, rename it IController, and add the following code:
Option Explicit
Sub Execute()
End Sub
This is our interface type (i.e., abstract class definition).
4) Via Tools|References..., add a reference to 'Microsoft Scripting Runtime', of whose Dictionary class we will shortly be using.
5) Add a standard module, and the following code to it:
Option Explicit
Private mControllers As New Scripting.Dictionary
Sub RegisterController(Obj As Object, Controller As IController)
mControllers.Add Obj, Controller
End Sub
Sub UnregisterController(Obj As Object)
mControllers.Remove Obj
End Sub
Function GetController(Obj As Object) As IController
Set GetController = mControllers(Obj)
End Function
Function IController_Initialize(Controller As IController, _
OldObj As Object, NewObj As Object) As Object
If Not (NewObj Is OldObj) Then
If Not (OldObj Is Nothing) Then UnregisterController OldObj
If Not (NewObj Is Nothing) Then RegisterController NewObj, Controller
End If
Set IController_Initialize = NewObj
End Function
The last function here is a helper one for IController implementations. Let's now create a couple -
6) Add another class module, rename it MyTextBoxController, and add the following code:
Option Explicit
Implements IController
Private WithEvents mTextBox As Access.TextBox
Property Set TextBox(NewValue As Access.TextBox)
Set mTextBox = IController_Initialize(Me, mTextBox, NewValue)
If Not (mTextBox Is Nothing) Then mTextBox.OnDblClick = "[Event Procedure]"
End Property
Private Sub mTextBox_DblClick(Cancel As Integer)
IController_Execute
End Sub
Private Sub IController_Execute()
MsgBox "Hello from the example text box controller!"
End Sub
7) Add another class module, rename it MyComboBoxController, and add the following code:
Option Explicit
Implements IController
Private WithEvents mComboBox As Access.ComboBox
Property Set ComboBox(NewValue As Access.ComboBox)
Set mComboBox = IController_Initialize(Me, mComboBox, NewValue)
If Not (mComboBox Is Nothing) Then mComboBox.OnDblClick = "[Event Procedure]"
End Property
Private Sub mComboBox_DblClick(Cancel As Integer)
IController_Execute
End Sub
Private Sub IController_Execute()
MsgBox "Hello from the example combo box controller!"
End Sub
8) Go back the form and handle cmdCreateControllers' Click event as thus:
Option Explicit
Private mTextBoxController As MyTextBoxController, mComboBoxController As MyComboBoxController
Private Sub cmdCreateControllers_Click()
If mTextBoxController Is Nothing Then Set mTextBoxController = New MyTextBoxController
Set mTextBoxController.TextBox = txtTest
If mComboBoxController Is Nothing Then Set mComboBoxController = New MyComboBoxController
Set mComboBoxController.ComboBox = cboTest
cmdDestroyControllers.Enabled = True
cmdExecuteController.Enabled = True
End Sub
9) Handle the other two buttons' Click events like this:
Private Sub cmdDestroyControllers_Click()
cmdCreateControllers.SetFocus
cmdDestroyControllers.Enabled = False
cmdExecuteController.Enabled = False
Set mTextBoxController.TextBox = Nothing
Set mComboBoxController.ComboBox = Nothing
End Sub
Private Sub cmdExecuteController_Click()
Dim Name As String
Name = InputBox("Enter the name of the control whose controller you want to execute:")
If Name = "" Then Exit Sub
GetController(Me.Controls(Name)).Execute ' add error handling as desired!
End Sub
10) Open the form, and double click either the text box or the combo box - nothing should happen.
11) Click Create Controllers, and double click again: a message box should show.
12) Click Execute Controller, and enter txtTest: a message box should again show.
13) Unhook the custom event sinks and unregister them as object controllers by clicking Destroy Controller; having done that, double clicking either of the subject controls should once more do nothing.
I've found the following works for the "zoomable" boxes, where the name of the relevant class and the textbox control within it are always the same.
Within the form:
Public mclsZoomText As appZoomText
and on entry to the control:
set mclsZoomtext = new appZoomtext
Set mclsZoomText.pTextBox = ActiveControl
Within the class:
Public WithEvents myTextBox As Access.TextBox
Public Sub myTextBox_DblClick(intCancel As Integer)
OpenZoomForm
End Sub
and when the zoom option is invoked from the menu:
Public Function OnActionZoom() As Boolean
Dim ctl As Control
dim intX as Integer
Set ctl = GetCurrentControl
'GetCurrentControl returns the current Control object on a form or subform
Call ctl.Parent.mclsZoomText.myTextBox_DblClick(intX)
OnActionZoom = True
End Function
For the more complex case this answer is excellent.
I am writing my first classes.
One is cCRElist which is essentially a collection of cCRE instances (some specialized events).
I want there to be a sub or function inside cCRElist that will load all the CRE's from the worksheet into one big collection I can work with. I created the function and it worked OK when I called it from a normal code module, but then I tried to move the code into the class. Now I am having trouble calling the function LoadFromWorksheet(myWS as Worksheet).
The error is "object does not support this property or method". I have tried making it a sub, a function, making it public, not public, I have tried turning into a Property Let instead of a sub. Obviously I have a flimsy grasp on what that does. I have tried
Call CREList.LoadFromWorksheet(myWS)
and
CREList.LoadfromWorksheet myWS
Same error every time.
Here is the test code that uses the class and calls the function:
Sub TestClassObj()
Dim CRElist As cCRElist
Set CRElist = New cCRElist
Dim myWS As Worksheet
Set myWS = ThisWorkbook.ActiveSheet
CRElist.LoadFromWorksheet (myWS)
End Sub
Here is a snippet of the class cCRElist:
' **** CLASS cCRElist
Option Explicit
' This is a collection of CRE objects
Private pCRElist As Collection
Private Sub Class_Initialize()
Set pCRElist = New Collection
End Sub
Public Property Get CREs() As Collection
Set CREs = pCRElist
End Property
Public Property Set Add_CRE(aCRE As cCRE)
pCRElist.Add aCRE
End Property
Function LoadFromWorksheet(myWS As Worksheet)
Dim CRE As cCRE
Dim iFirst As Long
Dim iLast As Long
Dim i As Long
Set CRE = New cCRE
iFirst = gHeader_Row + 1
iLast = FindNewRow(myWS) - 1
' update data in CRE then add
For i = iFirst To iLast
If myWS.Cells(i, gCRE_Col) <> "" Then ' This is a CRE row
Set CRE = New cCRE
With CRE
.CRE_ID = myWS.Cells(i, gCRE_Col)
If Not IsDate(myWS.Cells(i, gCRE_ETA_Col)) Then
.ETA = "1/1/1900"
Else
.ETA = Trim(myWS.Cells(i, gCRE_ETA_Col))
End If
<... snipped ...>
End With
pCRElist.Add_CRE CRE
End If
Next
End Sub
' **** END OF CLASS cCRElist
Thanks for your expertise.
Here is what worked based on help I got in the comments. First, I did the "break in class module". In the test code, I changed the function call from:
CRElist.LoadFromWorksheet(myWS)
to
CRElist.LoadFromWorksheet myWS
Inside the class, i had to change
Set pCRElist.Add_CRE CRE
to
pCRElist.Add CRE
Then I was able to get rid of extraneous CLASS functions Add_CRE and Count.
Thanks for everyone's input. I couldn't figure out how to mark comments as accepted answers so I did this. Let me know if I need to do something differently.
Now it works!
i am trying to access a class object in different form to call its method ..can u plz tell me how can i do it..?
here is my code..
Dim a As customers
Private Sub Command1_Click()
Dim txt1 As String
Dim txt2 As String
Set a = New customers
txt1 = Text1.Text
txt2 = Text2.Text
a.userid = txt1
a.log_in txt1, txt2
End Sub
its a code i have written in form 1....for login..
made an object for customer n called loging procedure...
in that if it sucesfully logs in i m opening a new form
homw.show only..
and in home......
option is there
view profile
in which i am showing another form profile
and in its load method want to call a's another method for displaying profile..
how it can know whose profile it should display....here i m getting cofused
as m new to vb help me out...plz..
Implement an init method on the second form and use it in Command1_Click like this
...
a.userid = txt1
a.log_in txt1, txt2
Dim oFrm As Form2
Set oFrm = New Form2
oFrm.Init a
End Sub
In Init you can call Show to display the instance of Form2. You can also move everything you do in Form_Load to this simple Init method -- like filling comboboxes etc.