Arthur Fuller
artful at rogers.com
Sat Jun 7 15:22:37 CDT 2003
Static functions contain variables whose value is preserved between calls. More precisely, static variables retain their values. By default all variables in a static function are static variables. You could declare a static variable in a non-static function, but I don't know why you would. Here is my template for static functions. This code lives in every app I write and I follow the directions: Static Function CurrentX(Optional lngNew As Long) As Long 'Copy this template each time you need a new set/get function 'Then Replace "X" with the name of your object, i.e.,"Employee" 'Replace all in current proc and you're done. Dim lngCurrent As Long If lngNew <> 0 Then lngCurrent = lngNew CurrentX = lngCurrent #If conDebug = 1 Then Debug.Print "Current X: ", CurrentX #End If End Function In the old days, these were called get/set functions, because you can use them to get or set their variable(s). To set the variable, you do this: CurrentEmployee(123) To get the variable, you do this: CurrentEmployee() So, given this setup, suppose you have a report that depends on a form being open with a combo box item selected. You could pass in a WhereCondition when you invoke the report, or you could write the report data source as follows: SELECT * FROM myTables WHERE EmployeeID = CurrentEmployee() Imagine, if you will, a listbox that shows the employees, and whose hidden first column is the PK EmployeeID. When the user clicks "Preview Report" or whatever, you write one line of code: CurrentEmployee(Me.cboEmployeeList) And then call your report: DoCmd.OpenReport ReportName:=rptMyReport, View:=acPreview 'or whatever you prefer My preference for this path is based on these criteria: 1. Transparent code -- intuitively obvious even to the casual viewer 2. Everything SQL can do VBA code should not bother doing There's a third reason, but first I must explain another variation on the static func declared above. If you read it carefully, you will realize that when the app opens CurrentEmployee() = 0. Each time you call it in set mode, you assign a value > 0. As presented above, the function renders it impossible to reset the value to zero. Why would you want to do this? I'll answer that in a moment, but first let's add a reset method, as it were. We could just drop the IF, but that would render the GET mode useless, so instead we need another method. I use -1 as the reset value, so the function evolves to: Static Function CurrentX(Optional lngNew As Long) As Long 'Copy this template each time you need a new set/get function 'Then Replace "X" with the name of your object, i.e.,"Employee" 'Replace all in current proc and you're done. Dim lngCurrent As Long Select Case lngNew Case Is < 0 lngCurrent = 0 Case Is > 0 lngCurrent = lngNew Case Else 'just return the current value End Select CurrentX = lngCurrent #If conDebug = 1 Then Debug.Print "Current X: ", CurrentX #End If End Function Now we have a way to pass in a "reset to zero" message. Why would we want to do this? Because we can rewrite the query above using a slick trick that deals with the zero value, and that lets us multiply the utility of the query. I.e. we can now use it in 3 ways: 1. Suppose the combo-box employee selector allows extended select. we can print one report for each selected employee. Walk the selected items and reset CurrentEmployee() in the loop and print the report, nothing to it. 2. Suppose a form walks the employee table. In the OnCurrent call CurrentEmployee(Me.EmployeeID) and every report that uses this approach is ready to print. Nothing to it. 3. Reset the value to zero and this means print the whole bloddy thing, for all employees. But to do this we need to modify the query, just a tad, adding a cool OR test: SELECT * FROM myTables WHERE EmployeeID = CurrentEmployee() OR CurrentEmployee() = 0 Save this to a named query. Base your forms and/or reports on said query. Refresh CurrentEmployee() as needed. Nothing to it. Bryan Carbonell graciously showed me how to talk to Pegasus. The client needs to send email reports to about 300 people, each email is unique, the result of a report with a specified PK. Thanks to Bryan and static functions, the solution is about 10 lines of code, maybe 20, I didn't actually count them, but it's trivial. The code resets the static function, outputs the report to a file, attaches the file to a new email message and sends it. With all the benefits if CopyToSelf, select-all, just one, every odd numbered item, &c. Bryan's nice sample code aside (but not without many thanks), the point is that if you create a query whose parms are derived from static functions you can forget all about what form is open &c. You can be in debug window and type: CurrentX(123) :123 'Assuming the recordsource is a query referencing CurrentEmployee() DoCmd.OpenForm FornName:="frmEmployeeEdit" DoCmd.OpenReport ReportName:="rptEmployeeSickDays" In both cases, to see one Employee you call CurrentEmtployee(####). If you want the whole list, reset the value of CurrentEmployee() to zero. CurrentEmployee(-1) Sorry for the length of the message. But this approach has proven invaluable to me. Everything I can blame on SQL I tend to shift in that direction. Then when something goes amiss, I change some SQL and not some code scattered all throughout my app. I guess it's a question of where you prefer to perform your fixes. I like minimal code and maximal SQL. That's just my take on it, and I know that many listers disagree. (They are entitled to their worthless opinions :-) Arthur -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://databaseadvisors.com/pipermail/accessd/attachments/20030607/9820ad00/attachment-0001.html>