473,614 Members | 2,101 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

VBA Class Basics (Report Class)

NeoPa
32,566 Recognized Expert Moderator MVP
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.Ac cDb". 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.OpenRepor t() 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 31135

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

Similar topics

17
2517
by: Asfand Yar Qazi | last post by:
Basically this: //file 'B.hh' class B { protected: void f() {} }; //file 'C.hh'
9
4986
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 pointer which points to an instance of a derived class, but when I pass that base class pointer into a function, it can't access the derived object's public functions. Although, the base class pointer does call the appropriate virtual function...
4
1832
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
3267
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 can even see my protected members of class A. How could I hide these informations about class A, just give them the interface informations. thanks.
8
3070
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? this.GetType().GetMember("panel1").SetValue(xx).Left = 44;
20
1437
by: Scott M. | last post by:
What are the advantages of defining a class as part of another class definition (nesting classes)?
2
2196
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
1513
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 use the utility class in my Singleton class? Here is some code to hopefully make it clearer what i want to do - namespace MyApp { class SingletonConnection
8
3144
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 formatting) to show what my issue is. I have a generic abstract class here: public abstract class MyGenericAbstractClass<Twhere T : MyInterface
0
8620
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8571
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
8423
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7047
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, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5537
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 then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4048
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4115
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
1705
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
1420
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.