I know in the .Net framework you can map any controls events to a singular method, as if you wanted to map a column of buttons in a GridView to one method, you could.
In VBA i have since forgotten this information. Could someone help me out in how i can map a Forms' Control(s) to one method in the Forms Code-Behind?
Current OnClick Events, to be consolidated
Private Sub btnSubmit_Click()
CloseForm Me
End Sub
Private Sub btnCancel_Click()
CloseForm Me
End Sub
There are at least two of these methods per form. On some there are 3 or 4 for various Events but they all have the same body, one line pointing to a global method.
It depends on what you want to do. You can set up the form so that it receives the click events and check the screen.active control or you can set the event line on the property sheet for each control to a function. Frequently, people who are not familiar with the ease of MS Access go a long way around, which is why it is useful to say what you wish to do, there is often an easier way and often a way that does not involve code at all.
On the click line of the property sheet for the control:
=Menu_Or_Exit([Name],"cmdClose")
of course you could pass Me as form, but I have found [Name] to be very useful in a number of ways.
An excerpt from the function:
Case "cmdClose"
DoCmd.Close acForm, FormName
CheckMainMenu
You can keep a menu form, a menu subform, or just copy the button from form to form.
Related
I need to have a popup form resizable for users whose screen is not as large as others - setting the form to Popup and Modal and BorderStyle Resizable has one major limitation - the code in the form that launches the popup now does not wait for the form to return.
So how does one wait for a form to be made invisible? I tried looping with sleep and doevents, but that makes the popup form not very responsive and chews up cpu cycles. I have tried setting the form.gotfocus event of the launching form but that does not trigger and which means I have to split the code that opened the popup form from the code that executes after the popup form is closed.
What is the best solution?
Thanks
I have never had any problems with DoEvents / Sleep 50 loops. CPU load stays minimal and the form responsive.
With a very old computer, perhaps use Sleep 100.
Sample code:
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub TestOpenForm()
If FormOpenWait("frmPopup") Then
MsgBox "Form was hidden.", vbInformation
Else
MsgBox "Form was closed.", vbInformation
End If
End Sub
' Open fName, wait until it is
' - closed : return False
' - hidden : return True
Public Function FormOpenWait(fName As String, Optional sOpenArgs As String = "") As Boolean
If IsFormLoaded(fName) Then DoCmd.Close acForm, fName, acSaveNo
DoCmd.OpenForm FormName:=fName, OpenArgs:=sOpenArgs
' default: signal "closed"
FormOpenWait = False
' Wait until form is closed or made invisible
Do While IsFormLoaded(fName)
If Not Forms(fName).Visible Then
' Signal "hidden"
FormOpenWait = True
Exit Do
End If
' Wait 50ms without hogging the CPU
DoEvents
Sleep 50
Loop
End Function
Public Function IsFormLoaded(fName As String) As Boolean
IsFormLoaded = (SysCmd(acSysCmdGetObjectState, acForm, fName) And acObjStateOpen) > 0
End Function
You can open the form with acDialog option:
DoCmd.OpenForm "MyFormName", WindowMode:=acDialog
It will wait until the form closed or hidden.
The problem here is popup and modal forms don’t’ halt calling code.
But worse is your need to halt calling code. That requires a dialog form.
And more worse is a dialog form does NOT allow re-sizing.
You don’t want to confuse the 3 types of forms here.
Modal forms – they are different then popup forms, and very different from dialog forms.
And same goes for Popup forms. They are not dialog forms, and in fact they are also not model.
You also have to take into consideration if you Access application is set to use tabbed documents, or overlapping windows. (this will limit your choices again).
If you using tabbed interface, then you have to use a popup form if you want re-sizable ability – but this type of form will not halt calling code.
If you using overlapping windows, then I recommend a modal form. (But again it will not halt calling code, but will allow re-size).
While you “could” adopt some looping code in the calling form that “waits” for the second form to be dismissed, such loops are processor hogs and often cause a “poor” response in terms of mouse and typing.
So I would suggest that change your code approach. Have the calling form launch the form as popup (or modal if you not using the tabbed interface).
Then when you close the form, it calls some more code that you want to run in the calling form. This does mean you have to split out the code that you want to run after closing that 2nd form – and have the closing form call + run that code.
A “general” approach should avoid hard coding the forms names since then “many” routines and forms can call your second forms and that facilities re-use of such forms.
So try this:
In the second form, create a module level form variable like this:
Option Compare Database
Option Explicit
Dim frmPrevious As Form
In the forms on-open event of this form, GRAB the calling forms refeance like this:
Set frmPrevious = screen.ActiveForm
Now in the forms close event , do this:
frmPrevious.AfterClose
And in the calling form, create a public function called
AfterClose
So in the public function in the first form, you place the code that you want to run when you close the 2nd form. This is "less" ideal then nice procedural code that calls the 2nd form, waits and continues - but I think it still about the best choice.
And before you close, you can pass or “set” values to return to the calling form like:
frmPreviuos.SomePubicVar = me!LastNameSelected
frmPrevious!Company = me!CompanySelected
frmPrevious.AfterClose
In the above the first line sets a public variable in the calling form (if you want to do that and pass values back to module level vars in the first form). And the next line sets the value of a control in the calling form (if you want to pass values back to some controls on the calling form).
And the 3rd line executes the MyClose code in the calling form. And if you have some kind of “ok” or select button in that second form, then move the above code to behind that button – since you may not want such code running if the form has a cancel button (so the cancel button would simply close the form – but not call + run the above code in the first form). And hitting the X would also be assumed to be a cancel or exit. So your "save" or "ok" or "select" button would have the above code.
I'm creating forms with VBA/Access to access my database.
In a form, I have a *lst_sinistres* listbox that displays the results of my SQL query and when I doubleclick on one of the results it opens me another form with thanks to this code
Private Sub lst_sinistres_DblClick(Cancel As Integer)
DoCmd.OpenForm "F_SINISTRE_MRH", acNormal, , , , , Me.lst_sinistres.Value
End Sub
I wanted to change my form, and add tabs to make it more ergonomic. So I placed my *lst_sinistres* listbox inside a tab.
The problem is that when I doubleclick on one of the results in this listbox (now placed in the tab), the form *F_SINISTRE_MRH* does not open.
Does someone have an idea of where the problem might come?
Thank you
A quirk of VBA control events is that event code can become detached from the control object. Things that cause this tend to be re-naming controls and copy/pasting similar code between controls. To move your listbox onto a tab control you needed to cut and paste it temporarily. That broke the link between the written code and the object name. When the code and object are properly linked, [Event Procedure] shows up in the property sheet (as suggested by #4dmonster).
If you are in the VBA editor, choosing Debug->Compile will search through all the code and re-link event code with like-named controls. This step is worth a try before re-writing because you may end up with orphan blocks of
Private Sub OldControlName_DblClick(Cancel As Integer)
MsgBox "Why don't I work anymore?"
End Sub
that are treated as Form-level subroutines that just happen to never be called.
pT
Is it possible to view the form creation code in Access VBA? I don't mean the event listener code that is viewable in the VBE from View>Code in the form's Design View. I mean the code that is used to create the components, and add them to the form. I would like to programatically set Form properties; doing this from the Properties dialog is quite slow (and annoying).
Yes, it's possible to create a form to design.
Vba include CreateControl Method (see MSDN Office-11 Control )
And you can add to this controls any event procedure like OnClick, OnFocus, etc. (see MSDN Office-11 Event
You can manipulate the width, height, etc.. properties as simple as me.control.width
I developed some time ago a form that could customized OnResize event to create different views depend of screen resolution and use all of this.
In theory you could get the form definition from the system table where it is stored (MSysObjects), but it isn't in a format that is practical to work against.
In theory you could avoid using the graphical designer to layout your form and create all the controls/set their properties dynamically in the form_load event. However, this wouldn't be much of a time-saver.
Assuming the gist of the question is whether there is an XML like declarative way to define a form layout similar to WPF. The answer is no.
All (?) the properties can be set through VBA for both the form and the controls.
Sub FormInDesignView()
Dim frm As Form
Dim ctl As Control
Set frm = Screen.ActiveForm
frm.Caption = "New"
For Each ctl In frm.Controls
ctl.Name = "txt" & ctl.Name
ctl.ForeColor = vbRed
Next
End Sub
No, it is not directly possible to do what you want. But if you insisted, you could use the undocumented Application.SaveAsText/LoadFromText commands and process the resulting text file.
Why you think this is a useful way to work in Access, I haven't a clue -- it's completely antithetical to the purpose and design of Access. Give up on your habits from other development tools and learn the Access way of doing things. You'll be a lot happier and productive in the long run.
I have a form (FORM-A) that requires the user to select a vehicle.
The user should click on a button on FORM-A that say's select vehicle.
A selection form (FORM-B) should open where the user can select a vehicle.
The selected value should be communicated back to FORM-A.
How would you accomplish this in MS Access 2010?
FORM-B is a continuous form that contains a picture of the vehicle and some other information.
From what I understand from your question, you want formB to open a kind of pop-up. When the pop-up is closed, its result is put somehere in the calling form.
Solution proposal:
a) open FormB using syntax docmd.openform "formB", windowmode:=acDialog.
This will prevent execution of the next lines until formB is closed or hidden.
b) in the OK button of FormB, just hide the form, do not close it.
c) when code resumes in formA, you can now
check if formB is still open. If not, it's been cancelled
read the value in hidden formB (still open), then close formB
Otherwise, you could also have formB to update a control in formA before closing. But I don't like that approach because then formB is not reusable, and it creates an unnecessary dependency between formB and formA.
I am not sure why you would need a separate form for this - just have the first textbox be a listing of all the records of vehicles in the database, where you would select one, and the rest of the vehicle information is auto-populated from the vehicle table, but not copied into your parent table. Of course, I am not sure of your table structure either, so there might be a reason for this method that isn't apparent to me.
The benefits of the method above is that if you add more vehicles, your selection box is automatically updated - and you keep the forms you have to load to a minimum (always a good performance move)
You can reference the forms in this manner forms!formName!controlName.
Once you see how this works you will be able to fool with it to get it working with your existing setup. Let’s use 3 controls a text box on Form-A, an image on Form-B and a text box on Form-B. The text box on Form-A will be named txtVehicle, the image on Form-B will be named imgVehicle and the text box on Form-B will be named txtVehicleName.
You can set the name of a control within properties. When you click on imgVehicle it will put the value from txtVehicleName into txtVehicle.
You will have to do a little coding - it's easy though if you have not done it before. Under properties for the image you will see events. If you click on the "On Click" event you will get a drop down list. One of the choices will be [Event Procedure] - choose that. A little button with 3 dots on it will also show up at the end of the row. Click it and you should be taken to a code window with some code like this in it.
Private Sub imgVehicle_Click()
End Sub
Here is where you put your code. Something like this should work. This is it in its most simplistic form.
Private Sub imgVehicle_Click()
Forms!Form-A!txtVehicle=forms!Form-B!txtVehicleName
End Sub
Now although that will work, there are a few things that we should be doing in this method that we are not. We should reference Form-B directly since we are in it, we should verify that Form-A is in fact open.
Private Sub imgVehicle_Click()
If currentproject.allforms(“Form-A”).isloaded then
Forms!Form-A!txtVehicle=me!txtVehicleName
End if
End Sub
Hope that helps
You can create an instance of formB within formA and control it. Below is the VBA code for formA. When clicking on a button on formA, you create a new instance of formB and give it focus. At the same time, you can set properties for its controls. You can use this approach to set the right picture in your control on form B. Hope this helps.
Example:
Option Compare Database
Dim fB As Form_FormB
Private Sub btnA_Click()
Set fB = New Form_FormB
fB.SetFocus
fB.tbxB.Text = "Some text sent from A to B!"
End Sub
If you want both forms to be visible all the time, I suggest using a subform with the list of all the vehicles or just details for the one that the user selected.
I have a form in MS Access which has an image. The image has an Click event which opens a modal form. The modal form has an OK and Cancel button. When you click the OK button, an event is supposed to fire which tells the main form which button was clicked. (This is to simulate the DialogResult functionality in C#). However, the code in the event handler never runs.
The modal form has the following in the general declarations:
Public Event OnDialogBoxClose(NewRecordID As Long, DialogResult As DialogResults)
and the following code where the OK button is clicked:
RaiseEvent OnDialogBoxClose(NewHardwareBaseItemID, dlgresBtnOKClicked)
The main form has the following in the general declarations:
Dim WithEvents RespondQuickAddClose As Form_qckfrmHardwareBaseItemCreate
and the following event handler:
Private Sub RespondQuickAddClose_OnDialogBoxClose(NewRecordID As Long, DialogResult As DialogResults)
MsgBox "Responding to closing of the dialog box" 'Never happens
Me.Requery
End Sub
Can someone explain why the event handler is never called?
Thanks!
Background:
The purpose of all this is to allow a modal dialog box to add an entry, then return the ID of the entry back to the main form to set the value of controls. For instance, imagine you are filling out an insurance form, and you need to select a brand of car this is not there. You click on an icon which pops up with the modal dialog box to allow you to add the car brand. Then when you click OK, it takes you back to the insurance form and selects the brand of car you just created.
This follows an example I found here:
http://database.itags.org/ms-access-database/80292/
You're making your life way too complicated by applying concepts from a different development environment to Access VBA. While VBA does support WithEvents/RaiseEvent, there's no reason to get that complicated here.
The usual way to work with dialogs in Access is that instead of closing them, you hide them. This allows the code after the form was open to run while leaving the values in the form available for use in that code.
Sample code in the OnOpen event of a report that opens a form for collecting values to filter the report:
Private Sub Report_Open(Cancel As Integer)
DoCmd.OpenForm "dlgDateRange", , , , , acDialog, "ThisYear"
If IsLoaded("dlgDateRange") Then
With Forms!dlgDateRange
If .Tag = "Cancel" Then
Cancel = True
Else
Me.Filter = "[InvoiceDate] Between #" & !txtStart & "# AND #" & !txtEnd & "#"
Me.FilterOn = True
Me!lblDateRange.Caption = StrConv(Trim(("from " + varZLStoNull(Format(!txtStart, "mm/dd/yyyy"))) _
& (" to " + varZLStoNull(Format(!txtEnd, "mm/dd/yyyy")))), vbProperCase)
End If
End With
DoCmd.Close acForm, "dlgDateRange"
End If
End Sub
The dialog form has two command buttons, CONTINUE>> and CANCEL. The CANCEL button sets the form's tag to "Cancel" and sets the form's .Visible property to False. The CONTINUE>> button does nothing but set the form's .Visible property to False. Clicking either of those buttons allows the code to continue on the line after the form is open with the acDialog switch.
My philosophy is to make the dialogs as stupid as possible. The calling code has to know what it's looking for in the forms (i.e., you need to know the names of the controls you're reading data out of), but that could be gotten around by adding customer properties to the form. But then you have to know the property names, so you've just moved the ball.
I have also implemented this kind of thing by wrapping the dailog form in a class module, and then the calling context simply initializes an instance of the class and then pulls the values out of it at the appropriate time. But that's actually more complicated that the approach above.
well I don't agree to
"While VBA does support WithEvents/RaiseEvent, there's no reason to
get that complicated here."
I have worked on various VB6 and VBA project. Recently I coded VBA in excel where I raised an event from winform. Few things to be considered when doing so.
If you are calling non-modal winform in VBA with
withevents/raiseevent. It should work normally as expected. No major
workaround is needed
If you are calling modal winform in VBA. Withevents/raiseevents may
not function as per requirement. A quick workaround is to transfer data using public variables declared in the module file.
You will need to use the workaround and I believe it will work absolutely fine.