473,416 Members | 1,848 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes and contribute your articles to a community of 473,416 developers and data experts.

VBA Class Basics (Report Class)

NeoPa
32,556 Expert Mod 16PB
Introduction
For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it then makes that (calling) Form visible again. This article is released as a companion to the VBA Class Basics one that focuses on opening Forms. All Forms are shown in Restore mode while Reports are shown in Maximise mode.


Working Attachment
Please find attached, a ZIP file that contains the working example called "UKAUG202311.AccDb". This is the same file already made available for the other (companion) article. Feel free to download it and have a play with it; make sure you understand what it's doing. You may have no desire to do what it does. What I'm hoping to show is the concept behind it and how classes are used in this case - in order that you understand where, and how, they can be used to do things you want to do.


VBA Classes with Objects
This section is repeated verbatim in the other article.
Although VBA classes do not support the generally-understood concept of Encapsulation, they do allow for objects to be contained within the class code, as well as, importantly, their Events to be handled by the class.

There is a caveat to this however, and that is that Events can only be handled by the class, that already have Event procedures in the objects themselves. Thus you could have two different Forms used by two different instances of a class (or even the same instance at different times) where one could have its Event handled by the class but the other not, if the first form had a procedure for the Event but the second did not.


Class/Object Events
This section is repeated in the other article with only line number reference changes.
User Defined Classes can also define their own Events. Events support passing parameters and, by using the ByRef keyword, these can be used to pass information both ways. A class needs to both define the Event, as well as Raise it (using RaiseEvent). Be aware that IntelliSense is a little less helpful than usual with this statement (RaiseEvent)so you may have to type it out in full in order to use it. Examples of defining & raising the Events can be found in the code below at lines #14, #15, #145 & #147.


Class/Object Properties
This section is repeated verbatim in the other article.
Coding Propertys within a Class is done using the three Property procedure types shown below. Each comes with an example definition & usage :
  1. Property Let
    This allows a Class-User to assign a value to this Property in the same way they would assign a value to any normal variable. This does not support objects - just as you can't simply say A = B with object variables (but have to use Set).
    Expand|Select|Wrap|Line Numbers
    1. Definition
    2. Private lngVar As Long
    3.  
    4. Public Property Let Y(Z As Long)
    5.     lngVar = Z
    6. End Property
    7.  
    8. Usage (from outside of the Class module)
    9. Dim X As YourClass
    10.  
    11. X.Y = 326
    Notice how the 326 is passed as Z in the Property Let definition and that the variable is referenced within the Class module as lngVar rather than Y.
  2. Property Get
    This is essentially the reverse of Property Let, except it also works for Objects.
    Expand|Select|Wrap|Line Numbers
    1. Definition
    2. Private lngVar As Long
    3.  
    4. Public Property Get Y() As Long
    5.     Y = lngVar
    6. End Property
    7.  
    8. Usage (from outside of the Class module)
    9. Dim lngA As Long
    10. Dim X As YourClass
    11.  
    12. lngA = X.Y
  3. Property Set
    This is like Property Let except for assigning Objects.
    Expand|Select|Wrap|Line Numbers
    1. Definition
    2. Private frmVar As Form
    3.  
    4. Public Property Set Y(Z As Form)
    5.     Set frmVar = Z
    6. End Property
    7.  
    8. Usage (from outside of the Class module)
    9. Dim X As YourClass
    10.  
    11. Set X.Y = Forms("frmMain")


clsReport Code
Here is the code from that class (clsReport). Feel free to copy it to somewhere more visible, and thus have it to hand, while you go through this section.
NB. When I refer to parts of the code I will do so via the line numbers as shown here below.
Expand|Select|Wrap|Line Numbers
  1. Option Compare Database
  2. Option Explicit
  3.  
  4. '21/1/2004  Added Private Set & Public Get code for rpt1, 2 & 3.
  5. '21/9/2004  Removed ResumeTo functionality. _
  6.             Now handled by the OnTimer() subroutine in the calling form _
  7.             checking for (Visible) which indicates the called report is _
  8.             finished.
  9. '3/11/2023  Added the AllClosed Event to let the calling code (optionally) be
  10. '           notified when all the Reports have been closed.
  11. '           Parameter (strName) defined purely for illustration of
  12. '           the capabilities, but it serves no real purpose.
  13.  
  14. 'Public Event AllClosed()
  15. Public Event AllClosed(ByRef strName As String)
  16.  
  17. Private Const conNumRpts As Integer = 3
  18. Private Const conErrMsg As String = "Maximum number of reports exceeded!"
  19.  
  20. Private strInUse As String * conNumRpts
  21.  
  22. Private frmParent As Form
  23. Private WithEvents rpt01 As Report
  24. Private WithEvents rpt02 As Report
  25. Private WithEvents rpt03 As Report
  26.  
  27. Private Property Set rpt1(rptValue As Report)
  28.     Set rpt01 = rptValue
  29. End Property
  30.  
  31. Public Property Get rpt1() As Report
  32.     Set rpt1 = rpt01
  33. End Property
  34.  
  35. Private Property Set rpt2(rptValue As Report)
  36.     Set rpt02 = rptValue
  37. End Property
  38.  
  39. Public Property Get rpt2() As Report
  40.     Set rpt2 = rpt02
  41. End Property
  42.  
  43. Private Property Set rpt3(rptValue As Report)
  44.     Set rpt03 = rptValue
  45. End Property
  46.  
  47. Public Property Get rpt3() As Report
  48.     Set rpt3 = rpt03
  49. End Property
  50.  
  51. Public Property Set frmFrom(frmValue As Form)
  52.     Set frmParent = frmValue
  53. End Property
  54.  
  55. Private Property Get frmFrom() As Form
  56.     Set frmFrom = frmParent
  57. End Property
  58.  
  59. 'Uninitialised returns True if frmFrom not yet set.
  60. Public Function Uninitialised() As Boolean
  61.     Uninitialised = (frmParent Is Nothing)
  62. End Function
  63.  
  64. 'ShowReport opens report strRpt and hides the calling form.
  65. 'Returns True on success.
  66. Public Function ShowReport(strRpt As String, _
  67.                            Optional ByVal varWhere As Variant = "") As Boolean
  68.     Dim intIdx As Integer
  69.  
  70.     ShowReport = True
  71.     'Error routine only handles Raised error and OpenReport()
  72.     On Error GoTo ErrorSR
  73.     intIdx = InStr(1, strInUse, vbNullChar)
  74.     If Uninitialised() _
  75.     Or intIdx < 1 Then _
  76.         Call Err.Raise(Number:=32767&, Description:=conErrMsg)
  77.     Call Echo(True, "Preparing report [" & strRpt & "].")
  78.     If IsNull(varWhere) Or varWhere = "" Then
  79.         Call DoCmd.OpenReport(ReportName:=strRpt, View:=acViewPreview)
  80.     Else
  81.         Call DoCmd.OpenReport(ReportName:=strRpt _
  82.                             , View:=acViewPreview _
  83.                             , WhereCondition:=varWhere)
  84.     End If
  85.     On Error GoTo 0
  86.     Select Case intIdx
  87.     Case 1
  88.         Set rpt1 = Reports(strRpt)
  89.     Case 2
  90.         Set rpt2 = Reports(strRpt)
  91.     Case 3
  92.         Set rpt3 = Reports(strRpt)
  93.     End Select
  94.     frmFrom.Visible = False
  95.     Mid(strInUse, intIdx, 1) = "*"
  96.     Call DoCmd.Maximize
  97.     Call Echo(True, "Report """ & strRpt & """ ready.")
  98.     Exit Function
  99.  
  100. ErrorSR:
  101.     ShowReport = False
  102.     Call Echo(True, "")
  103.     If ErrorHandler(strName:=strRpt, _
  104.                     strFrom:=frmFrom.Name & ".ShowReport", _
  105.                     lngErrNo:=Err.Number, _
  106.                     strDesc:=Err.Description) = 2 Then Resume
  107. End Function
  108.  
  109. '************************* Contained Object Method(s) **************************
  110. 'For these subroutines to be activated the contained object must have the
  111. ''On Close' property set to a valid subroutine within the contained object.
  112. '*******************************************************************************
  113. 'Equivalent to rpt1_Close()
  114. Private Sub rpt01_Close()
  115.     Set rpt01 = Nothing
  116.     Call CloseReport(1)
  117. End Sub
  118.  
  119. 'Equivalent to rpt2_Close()
  120. Private Sub rpt02_Close()
  121.     Set rpt02 = Nothing
  122.     Call CloseReport(2)
  123. End Sub
  124.  
  125. 'Equivalent to rpt3_Close()
  126. Private Sub rpt03_Close()
  127.     Set rpt03 = Nothing
  128.     Call CloseReport(3)
  129. End Sub
  130.  
  131. 'CloseReport() examines the current state of the reports and, only if all now
  132. '   closed, returns to viewing the parent form.
  133. '   Resume to the calling code is done using the AllClosed Event which can,
  134. '   optionally, be handled by the caller.
  135. Private Sub CloseReport(ByVal intIdx As Integer)
  136.     Dim strParent As String
  137.  
  138.     Mid(strInUse, intIdx, 1) = vbNullChar
  139.     If strInUse = String(conNumRpts, vbNullChar) Then
  140.         Call DoCmd.Restore
  141.         With frmParent
  142.             .Visible = True
  143.             Call DoCmd.SelectObject(acForm, .Name)
  144.         End With
  145.         'RaiseEvent AllClosed
  146. ' All code after here is for illustration of updateable parameter only.
  147.         RaiseEvent AllClosed(strParent)
  148.         If strParent > "" Then _
  149.             Call MsgBox(Prompt:=strParent _
  150.                       , Buttons:=vbInformation Or vbOKOnly _
  151.                       , Title:="clsReport")
  152.     End If
  153. End Sub
  154. '*******************************************************************************
The code above contains much code that is either repeated, or repeated with minor modifications, from the other article.

Lines #17 - #18 defines constants used in the code elsewhere. This version allows for three Reports to be opened simultaneously and managed together by this class. With minor modifications elsewhere, to support the extra objects required, this value can be increased to suit needs.

Line #20 defines a fixed-length String used for maintaining the status of each possible Report object within the class.

Lines #22 - #25 show two different ways to define objects in VBA. #23 - #25 are different & special as they allow Events from the objects (In this case Reports obviously.) to be handled within this class. See lines #109 - #129 of this module for the format of a class's handling of its various WithEvents objects. Notice the names of the Event Procedures include the (internal) names of the specified objects.

Lines #27 - #57 show examples of Property Let/Get/Set procedures. These are explained above under Class/Object Properties.

Lines #59 - #62 show the Uninitialised() function. Any user of the class must set the value of the frmParent Property before anything else can work sensibly. This function is provided to test that.

Lines #64 - #107 show the ShowReport() Method. This roughly mirrors the DoCmd.OpenReport() Method - at least the parameters I ever use. It explicitly handles the Report failing to open but passes any other errors onto the main error handler, which I don't cover here (as irrelevant). However, the code can be found in the attached example database if interested.

Fundamentally, it checks the class instance has been properly initialised then, if it has, Maximises the window before opening the Report, using the parameters as passed. Once this has succeeded it sets the next rpt? (where ?=1, 2 or 3) to this Report and hides the parent/calling Form.

Lines #109 - #153 handle the Close events of the called Reports (internally referenced as rpt0? - hence the names of rpt0?_Close()). Once they close, this procedure first sets the relevant object (rpt0?) to Nothing, then checks if any are still open. If, and only if, none is, then the parent/calling Form (frmParent) is made visible again. For good measure it Restores the window again. The working basis is that Forms look better in Restore mode while Reports look better Maximised.


Conclusion
While the attached example database also includes a clsForm class, along with the clsReport one as shown here, the fundamentals of class usage, & I hope I've kept to the very basics in order to show how straightforward it is getting into the subject, are covered here.

Feel free to leave comments below, but please post any related questions separately (in the Access Questions Forum). Also, feel free to use any parts of this work. Attribution is purely voluntary.
Nov 6 '23 #1
0 31078

Sign in to post your reply or Sign up for a free account.

Similar topics

17
by: Asfand Yar Qazi | last post by:
Basically this: //file 'B.hh' class B { protected: void f() {} }; //file 'C.hh'
9
by: Banaticus Bart | last post by:
I wrote an abstract base class from which I've derived a few other classes. I'd like to create a base class array where each element is an instance of a derived object. I can create a base class...
4
by: Nataraj M | last post by:
Hi, I just don't want anybody derive a class from my class. For example: /////////////////////// //MY CODE class MyClass { .... }; ///////////////////////
10
by: Ray Z | last post by:
hi, there I build a Class Library, I write a class A to implement interface IA. The problem is when I give the dll file to others, thet can get all information about not only IA, but also A. They...
8
by: TS | last post by:
I am trying to get set a property of a control on the inherited class from base class. I imagine i have to use reflection, so could someone give me the code to do it? something like this?...
20
by: Scott M. | last post by:
What are the advantages of defining a class as part of another class definition (nesting classes)?
2
by: RitualDave | last post by:
I get a C2811 error when I compile the following (with the /clr switch): template <class T> ref class Base {}; template <template <class> class TBase> ref class Derived : TBase<int> {};
10
by: =?Utf-8?B?ZGF2ZWJ5dGhlc2Vh?= | last post by:
Hi, I have created a Singleton class to provide some database functionality in my mobile application. I have a public class called Utility which performs various operations on data. Is it ok to...
8
by: MMAS | last post by:
Hey everyone -- Curious about some strange behaviour I'm seeing that seems to be related to my lack of understanding on how generics work in C#. Here's some simplified code (sorry for strange...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.