get Access VBA have a Sender - ms-access

In Access I have a form that has about 200 text boxes on it. I Know that in C# on every on click event there is textbox1_Click(object sender).
how can I in VBA have reference the current sender without saying Me.txt_Whatever?
this is what I have so far
Private Sub txtHotMix_DblClick(Cancel As Integer, sender As Object)
Dim txt As TextBox
Set txt = sender
MsgBox txt.Name
End Sub

I think the ActiveControl property of the Screen object is what you're after (https://msdn.microsoft.com/en-us/library/bb225491(v=office.12).aspx):
In a module:
Option Compare Database
Option Explicit
Public Sub ctrl_Print(objCtrl As Control)
MsgBox objCtrl.Value, vbOKOnly, "Control Value"
End Sub
You would still have to add a click event to every control to call this sub, like this:
Option Compare Database
Option Explicit
Private Sub Text0_Click()
Call ctrl_Print(Screen.ActiveControl)
End Sub

Related

Button to turn change AllowEdits to true in Access using VB

I am trying create a button which changes the value of AllowEdits to False and another for true for a subform. I am using the below code. I get a Runtime error 424 each time I run it.
Option Compare Database
Private Sub Toggle_Edit_Click()
Dim strForm As String
strFormName = Me.Name
Call ToggleEdit(Me)
End Sub
and
Option Compare Database
Public strFormName As String
Sub ToggleEdit(myForm As Form)
Call Message
ctrlControl.AllowEdits = True
End Sub
and if you were interested
Sub Message()
MsgBox "Remember not to overwrite incorrect records"
End Sub
Please add Option Explicit at top of your modules!
I think AllowEdits is a Form property, not a Control property.
Option Explicit
Sub ToggleEdit(myForm As Form)
myForm.AllowEdits = Not myForm.AllowEdits
End Sub
If the code is behind the form itself, you can use Me.
Sub ToggleEdit() 'no parameter
Me.AllowEdits = Not Me.AllowEdits
End Sub
If you want to act at control level, use Locked or Enabled properties.

MS Access 2016 VBA Code Reuse in Buttons

I have an Access database frontend that houses 16 different forms. All of them have three buttons in common namely Show All, Clear and Refresh, that perform that exact same function using their respective subforms. For instance, for viewing data from a table named tbl_Students the 'On Click' event of these buttons on the Students Form have the following code:
Option Explicit
'Show all records button
Private Sub cmdShowAll_Click()
Dim task As String
task = "SELECT * FROM tbl_Students"
Me.frm_Students_subform.Form.RecordSource = task
Me.frm_Students_subform.Form.Requery
End Sub
'Clear displayed records button
Private Sub cmdClear_Click()
Dim task As String
task = "SELECT * FROM tbl_Students WHERE (StudentID) is null"
Me.frm_Students_subform.Form.RecordSource = task
Me.frm_Students_subform.Form.Requery
End Sub
'Refresh records button
Private Sub cmdRefresh_Click()
Me.frm_Students_subform.Form.Requery
End Sub
Currently, I'm using the exact same code, but with different respective subform names, in all my 16 forms. Is there a better, more efficient way to do it, with code reuse? Thanks.
Consider creating one generalized subroutine in a standard module that all 16 forms call passing needed parameters. Specifically use CurrentProject and Controls to reference objects dynamically by string.
Module save in a named standard module (not behind any form)
Option Explicit
Public Sub ProcessForms(task As String, mainform As String, subform As String)
On Error GoTo ErrHandle
CurrentProject.AllForms(mainform).Controls(subform).Form.RecordSource = task
CurrentProject.AllForms(mainform).Controls(subform).Requery
Exit Sub
ErrHandle:
Msgbox Err.Number & " - " & Err.Description, vbCritical, "RUNTIME ERROR"
Exit Sub
End Sub
Example Form single line calls
Option Explicit
'Show all records button
Private Sub cmdShowAll_Click()
Call ProcessForms("SELECT * FROM tbl_Students", _
"frm_students", "frm_Students_subform")
End Sub
'Clear displayed records button
Private Sub cmdClear_Click()
Call ProcessForms("SELECT * FROM tbl_Students WHERE (StudentID) IS NULL", _
"frm_students", "frm_Students_subform")
End Sub
'Refresh records button
Private Sub cmdRefresh_Click()
' Re-assigns same recordsource in line with others
Call ProcessForms(Me.Controls("frm_Students_subform").Form.RecordSource, _
"frm_students", "frm_Students_subform")
End Sub

How best to call a public sub routine declared in a form used as the source object a subform control from the main form?

I have a form MyForm1 with a module having the method.
Public Sub CreateSQL(ProductID as variant)
Me.Recordsource = " SELECT * FROM ProductOrders " _
" WHERE ProductID = " & Nz(ProductID ,0)
Me.Requery
End Sub
I use this as a subform to a form named MyMainForm.
When I change the value of a control on MyMainForm it successfully executes the following line:
Me.Subform1.Form.CreateSQL ProductID:=Me.cboProductID
My Questions:
Why are the members not listed on the intellisense list that appears after I type Me.Subform1.Form.?
Is there a way of getting them to be listed?
Is there a property that will let me access the "Form_MyForm1" class of the form referenced in the subform control "Source object property" (ie the Me.Subform1.form ) ?
It's like I need to be able to write:
Me.Subform1.Form_MyForm1.CreateSQL ProductID:=Me.cboProductID
Does such a property already exist? If so how do I access it? Is it in the properties collection?
PS: If you need more information please see the same questions posted in a long Stack overflow question here
Harvey
Don't know.
Not that I know of.
Make the subfunction Public.
But it looks like you could save yourself a lot of trouble by using the Master/Child link option of a form and its subform control.
Instead to the mainform calling the method Me.Subform1.Form.CreateSQL
You should create an object variable in the subform that points to the main form and responds to events eg:
Dim WithEvents cvMyParentForm As Form
Property Set MyParentForm(MyParentForm As Form)
Set cvMyParentForm = MyParentForm
End Property
Property Get MyParentForm() As Form
Set MyParentForm = cvMyParentForm
End Property
When the main form opens use the Form_Open event to "initialise" the subforms
Private Sub Form_Open(Cancel As Integer)
If Me.Subform1.Form.MyParentForm Is Nothing Then
Set Me.Subform1.Form.MyParentForm = Me
End If
End Sub
then you can get the subform to respond to the FORM events that are raised by the mainform.
If you need to have the subform respond to any events that you declare in the main form you will need to chnaeg the above code to use the Form_MyMainFormname type
Dim WithEvents cvMyParentForm As Form_MyMainFormName
Property Set MyParentForm(MyParentForm As Form_MyMainFormName)
Set cvMyParentForm = MyParentForm
End Property
Property Get MyParentForm() As Form_MyMainFormName
Set MyParentForm = cvMyParentForm
End Property
Private Sub cvMyParentForm_Current()
'MsgBox "Sub form current event - does syncing"
Me.Form.Recordset.FindFirst "ID = " & Nz(cvMyParentForm.ID, 0)
If Me.Form.Recordset.NoMatch Then
MsgBox "Humph"
Else
End If
End Sub
Private Sub cvMyParentForm_MyEvent()
MsgBox "A user define event 'MyEvent' was fired on the main form"
End Sub

Form transition and data refresh

I have a form with a button and when I push it, it opens another form. When I close this second form I need to refresh the first form.
So I need to insert the first form name in a global variable to access the form name from the second form to refresh the first form.
I tried create this:
global formname as form
formname = activeform.name
but I receive an error saying: The option is read only.
On the Click event of the button you can pass the name of the form as the OpenArgs property of DoCmd.OpenForm.
Private Sub Command4_Click()
DoCmd.OpenForm "frmStaff", , , , , , Me.Name
End Sub
On the Close event of the second form you can check this (string) value:
Private Sub Form_Close()
If Me.OpenArgs <> "" Then
'MsgBox Me.OpenArgs
Forms(Me.OpenArgs).Refresh 'or .Requery
End If
End Sub
Why don't you just go into the VBA code behind and refresh it with the close sub? I don't understand the need for a global variable to be passed between the forms - You should be able to just do something like this in your second form:
Private Sub Form_Close()
Form_YourFormHere.Refresh
End Sub
If you must use this approach, try this in the first form's module:
Public formname as Form
Private Sub Command1_Click()
Set formname = Me
End Sub
or
Public formname as String
Private Sub Command1_Click()
formname = Me.name
End Sub
A form is an object type, and can only be assigned to a variable using a Set statement, otherwise VBA will think that you are trying to assign the value of the object to the variable.
You said that you wanted the form name, however your variable was a Form type, not a String. The first code snippet will achieve the result you appeared to be trying to achieve, and the second will achieve the result you said you wanted to achieve.
A different approach would probably be better and more reliable, though.

Access 2007 ReportEvents class is not firing events

I'm having an issue with report events that I haven't
encountered before in Access prior to Access 2007.
I'm using using Access 2007 for a Front-end to a SQL Back-end.
I have a Class, ReportEvents, that I use for the reports.
In a report's Report_Open event I instantiate and then use this class to
handle events like activate, Close, NoData and I also put common code
such as exporting data to excel instead of a report.
This code was working fine in a previous Access 2003 application (mdb) I was using,
but it isn't working as expected in 2007 (accdb). In my tests the call to a non event public sub, ProvideXLOption works like a charm, but none of the events are being fired
from the ReportEvents class. I didn't change the code I just imported it into the
project. I set up break points but they aren't being hit. I changed all of them to
public events and then called them within the test reports event and they worked fine.
I set up another report in Access 2007 with the same results. I've checked
the startup settings in Access and they are fine. I even removed and re-added
the database location from the trusted locations without any luck.
Has Microsoft modified the Events Code or is this just a simple code error on my part that I'm not seeing? It's gotta be something simple. My brain is just toast (my son decided to stay awake after last night's feeding).
Class ReportEvents Code:
Option Compare Database
Option Explicit
Private WithEvents rpt As Access.Report
Const strEventKey As String = "[Event Procedure]"
Public Property Set Report(Rept As Access.Report)
Set rpt = Rept
With rpt
.OnActivate = strEventKey
.OnClose = strEventKey
If LenB(.OnNoData) = 0 Then
.OnNoData = strEventKey
End If
End With
End Property
Public Sub Terminate()
On Error Resume Next
Set rpt = Nothing
End Sub
Private Sub rpt_Activate()
LoadPrintRibbon
End Sub
Private Sub rpt_Close()
Me.Terminate
End Sub
Private Sub rpt_NoData(Cancel As Integer)
Dim strMsg As String
strMsg = "No Records were found that match your criteria."
MsgBox strMsg, vbInformation, rpt.Name & _
": No Match. Report Cancelled"
Cancel = True
End Sub
Private Sub LoadPrintRibbon()
#If AccessVersion >= 12 Then
If rpt.RibbonName <> "PrintPreview" Then
rpt.RibbonName = "PrintPreview"
End If
#End If
End Sub
';;Provides user with option to send data to Excel instead of a report
Public Sub ProvideXLOption(Cancel As Integer)
'... some XLOption Code
End Sub
In the Test Report Code:
Private Sub Report_Open(Cancel As Integer)
Dim rptEvts As ReportEvents
Set rptEvts = New ReportEvents
Set rptEvts.Report = Me
';;Let User User Choose to Export Data to Excel or Display the report
rptEvts.ProvideXLOption Cancel
End Sub
I figured it out. It was a scope issue The ReportEvents class variable rptEvts, was inside the Report_Open sub. Because of this it wouldn't exist when the other events happened. It should be at the module level and not within the procedure.
Dim rptEvts As ReportEvents
Private Sub Report_Open(Cancel As Integer)
Set rptEvts = New ReportEvents
Set rptEvts.Report = Me
';;Let User User Choose to Export Data to Excel or Display the report
rptEvts.ProvideXLOption Cancel End Sub
End Sub
It's amazing what a little rest will do for you.