No Class or High Class

G

Greg Maxey

For the most part, Class modules are still a mystery to me. What
little knowledge I have of them was imparted by Jezebel when I was
working on a project to list, count and sort spelling errors.

Earlier today and OP wanted to simply list all spelling errors
contained in a document in a separate document. I thought of my
earlier project and passed on the link.

I then started thinking about a simpler code to do exactly what the OP
requested "and" prevent duplicates. Here is the result of those
thoughts:

Sub NoClass()
Dim DupChk As Object
Dim oCol As Collection
Dim oSpError As Word.Range
Dim i As Long
Set oCol = New Collection
'Add to collection
For Each oSpError In ActiveDocument.Range.SpellingErrors
On Error Resume Next
Set DupChk = oCol(oSpError.Text)
On Error GoTo 0
If DupChk Is Nothing Then
oCol.Add oSpError
End If
Set DupChk = Nothing
Next
'Publish results
Documents.Add
For i = 1 To oCol.Count
ActiveDocument.Range.InsertAfter oCol(i) & vbCr
Next i
End Sub

That seems straightforward and does the job.

To do the same thing with a class, I first inserted a class module,
named it clsError and pasted in this code:

Private mName As String
Public Property Get Name() As String
Name = mName
End Property
Public Property Let Name(NewValue As String)
mName = NewValue
End Property

In the project module, I used this code:

Sub HighClass()
Dim oError As clsError
Dim oCol As Collection
Dim oSpError As Word.Range
Set oCol = New Collection
'Add to collection
For Each oSpError In ActiveDocument.Range.SpellingErrors
On Error Resume Next
Set oError = oCol(oSpError.Text)
On Error GoTo 0
If oError Is Nothing Then
Set oError = New clsError
oError.Name = oSpError.Text
oCol.Add oError, oError.Name
End If
Set oError = Nothing
Next
'Publish results
Documents.Add
With ActiveDocument.Range
For Each oError In oCol
.InsertAfter oError.Name & vbCr
Next
End With
End Sub

This works equally as well.

What again is the benefit of using a Class? Is there any benefit in
this example?

Thanks.
 
G

Greg Maxey

Please ignore the moronic post above. Due to a massive brain
flatuation, I was convinced that the No Class method worked. It
doesn't.

Sorry for wasting your time.
 
K

Karl E. Peterson

Greg said:
Please ignore the moronic post above. Due to a massive brain
flatuation, I was convinced that the No Class method worked. It
doesn't.

That aside...
Sorry for wasting your time.

It's a valid question, that many folks struggle with initially...

There are numerous ways to approach any problem, and there are certainly
non-class-based approaches you could have taken here. Frankly, it does seem
like bringing classes into this is reaching for the heavy artillery, so
perhaps it isn't the best example.

Classes offer *lots* of other benefits, though. There are obvious ones,
like the ability to have code associated with unique data sets. This is
very powerful, for things like validity checking and reaction. Which leads
to what's probably the most *powerful* use -- the ability to raise and/or
sink events. Once you embrace this capability, the possibilities
immediately seem endless.
 
K

Karl E. Peterson

Karl said:
There are numerous ways to approach any problem, and there are
certainly non-class-based approaches you could have taken here.
Frankly, it does seem like bringing classes into this is reaching for
the heavy artillery, so perhaps it isn't the best example.

Here's a simple variation of your initial try, that works:

Sub NoClass()
Dim oCol As Collection
Dim oSpError As Word.Range
Dim i As Long
Set oCol = New Collection

'Add to collection
On Error Resume Next
For Each oSpError In ActiveDocument.Range.SpellingErrors
If Len(oCol(oSpError.Text)) = 0 Then
If Err.Number = 5 Then
Debug.Print oSpError.Text
oCol.Add oSpError.Text, oSpError.Text
End If
End If
Next

'Publish results
Documents.Add
For i = 1 To oCol.Count
ActiveDocument.Range.InsertAfter oCol(i) & vbCr
Next i
End Sub

Later... Karl
 
G

Greg Maxey

Karl,

I had come up with this earlier before I started exploring the class
method:


Sub ListErrorsNoDups()
Dim oErr As Word.Range
Dim oCol As Collection
Dim i As Long
Dim bDup As Boolean
Set oCol = New Collection
For Each oErr In ActiveDocument.Range.SpellingErrors
bDup = False
For i = 1 To oCol.Count
If oCol(i) = oErr Then bDup = True
Next i
If Not bDup Then oCol.Add oErr
Next
Documents.Add
For i = 1 To oCol.Count
ActiveDocument.Range.InsertAfter oCol(i) & vbCr
Next i
End Sub


I like you method better.


Would you have anything that demonstrated this raise and sink events
idea that you mentioned?
 
K

Karl E. Peterson

Hi Greg --
Would you have anything that demonstrated this raise and sink events
idea that you mentioned?

Lots! Most of it, though, is geared towards VB5/6 as that's where I do most
of my work. As far as raising events goes, I do have a few that are very
useful in VBA. For example, I have an INI class that will raise an event
for each section in an INI file, and for each entry in an INI file section.
Very useful for exploring one of those to see what's there...

http://vb.mvps.org/samples/kpIni

Another one geared directly at VBA provides a timer object, and raises
events at a specified interval...

http://vb.mvps.org/samples/TimerObj

Here's another that drills into a directory, and optionally its
subdirectories, and raises an event for each file/folder found...

http://vb.mvps.org/samples/DirDrill

Sinking events is very often associated with windows in my world. For
instance, I have a class that will search a listbox as the user types. In
order to do that, you pass the ListBox to the class, and it monitors
keystrokes...

http://vb.mvps.org/samples/ListSearch

You can have classes arranged hierarchically, such that they send
information "up the chain." For instance, taking this to the extreme, I
have a set of classes that break down a Long integer into its constituent
16-bit Integers, and further into each Byte within that. When one of the
smaller portions changes, it fires an event so the larger whole is aware.
This sample's classes both raise and sink events...

http://vb.mvps.org/samples/Twiddle

Now, if you want to really get adventurous, you can start subclassing, and
rerouting system callbacks to appropriate class instances, then re-raising
those as events for your client objects, then . . . <vbg>
 
G

Greg Maxey

Karl,

Thanks for these links. I sense it may be really deep end stuff and over my
head. Still, I'll dive into a few and see if any of it sticks.
 
K

Karl E. Peterson

Greg said:
Thanks for these links. I sense it may be really deep end stuff and
over my head. Still, I'll dive into a few and see if any of it
sticks.

It's the concept of communication that's important. Not sure if you can do
it in Word, but I've set up a class in Excel to sink events raised by the
Application. If I read the Object Browser correctly, it should be doable in
Word as well. Just create a new class, and add this up top:

Private WithEvents app As Application

Then, select "app" in the left-side dropdown, and take a look at all the
events offered in the right-side dropdown! Here, you can react to all sorts
of useful things. The only difference between this case, and the ones I
described earlier, is that it was my classes raising the events as well. It
goes two ways.

Later... Karl
 
J

Jonathan West

What again is the benefit of using a Class?

That is a very good question to ask.

First of all, there are some people who are so enamoured of classes that
they believe you should never ever write purely procedural code and that
*everything* should be a class. They are attached to that position with a
fervour that borders on the religious. If that is an arrangement that
happens to work for them, all well and good. Their certainty can be
infectious, but it is wiser to avoid it and look at the actual evidence.

For simpler tasks (which, let us be blunt, includes the vast majority of
Word macros) procedural code is perfectly adequate. There are very few cases
where my answer to a question in these groups starts with the words "first,
create a class module".

So it is worth looking at what classes are good for.

Of course, you *use* classes all the time, you just don't think of them as
such. The whole of the Word object model is an intricate interlinked series
of classes. The Application object is a class, which has lots of properties
and methods and events. One of those properties is the ActiveDocument
property which is a Document class, again with its own set of properties,
methods and events. You probably haven't been thinking of them as classes
because they aren't written in VBA and you can't see the code, but the way
you use them is almost exactly the same as how you would use your own
custom-built class.

This gives us a clue as to when it would be useful to write a class. The key
is when you are likely to want to re-use the code in a variety of projects
and different ways.

Properties of a class can look on the surface much the same as items in a
user-defined type. The difference is that with a class, you can if you
choose have a change to one property trigger a change to others. For
instance, in the PageSetup object in Word, if you set the PageHeight
property to be some value, the PageSize property is automatically set to
Custom, rather than A4 or Letter or whatever it was before. You can do the
same sort of thing in the property procedures of your own class module.

Events are also potentially very useful things to have. An event is
essentially a way of saying "tell anybody who is listening that xyz has
happened, and wait until they have done whatever they need to do as a
result". It may be that other process is listening to that event, in which
case the code in the class carries on immediately. This gives you great
flexibility on how you use a class, once you have taken the trouble to
create it.

I don't often write classes, but I am a regular consumer of them, and owe a
considerable debt of gratitude to Karl for some of his published classes
which I use on a regular basis. Almost every commercial project I do makes
use of one or more of his Drvinfo, FileInfo, kpIni, NCMetrics, PrnInfo,
RegSettings and StrBldr code samples, all of which make use of class
modules. RegSettings and NCMetrics are used in almost everything I do, the
others are used as needed. (see http://vb.mvps.org/samples/ for the list of
Karl's samples)

If you want a tutorial on how to create classes (I have been concentrating
in this post on "why" rather than "how"), take a look at these two excellent
articles by Ken Getz and Mike Gilbert. It appears they are no longer
available on the Microsoft website, but the Wayback Machine rides to the
rescue!

Class Modules: Simplify and Accelerate Your Development Processes
http://web.archive.org/web/20050306011820/http://www.microsoft.com/OfficeDev/Articles/classmod.htm

Advanced Class Modules
http://web.archive.org/web/20050306005832/http://www.microsoft.com/OfficeDev/Articles/AdvClMod.htm


--
Regards
Jonathan West - Word MVP
www.intelligentdocuments.co.uk
Please reply to the newsgroup
Keep your VBA code safe, sign the ClassicVB petition www.classicvb.org
 
J

Jean-Guy Marcil

Greg Maxey was telling us:
Greg Maxey nous racontait que :
Karl,

Thanks for these links. I sense it may be really deep end stuff and
over my head. Still, I'll dive into a few and see if any of it
sticks.

As a practical example, recently I had a contract that required creating a
Meeting Agenda Template.

Their meeting documents were complex and numerous, so, in the agenda, they
always had hyperlinks to point to those reference documents.
But, when adding a hyperlink to a reference document, that reference
document needed to be "treated" (Information from the agenda had to be adder
to that document).
Also, a list needed to be created at anytime listing the currently attached
documents, their agenda paragraphs text and list number, etc.

I wrote code to automate those procedures as much as possible.

I created a class I called "Attachment" (or something like that)
This class had four methods:
Attach a document
Detach document
Detach all documents
List all document currently attached to the agenda
Some of them accepted a Range parameter (the Attach and Detach ones).

So, wherever in my code I need to do these things, all I needed to do was,
for example:

Dim myAttach As New Attachment
myAttach.Add_Attach Selection.Paragraphs(1).Range

where Add_Attach is a method of the Attachment class.

The method I used the most through out the code was the one for listing the
attachments.

I needed that every time I attached a document (to make sure it was not
already attached), when I detached, When I validated the whole document,
when I created PDF files from the Agenda (so I could get to the Attachments
easily and convert them as well), etc.

It made my code in the standard module easier to read, less cluttered and
overall shorter.
And if the client had wanted to attach the documents in a different manner,
all I would have to do is modify the code in the class and leave the code in
the standard module intact.

I hope I did not contribute to your headaches and made sense here...

--

Salut!
_______________________________________
Jean-Guy Marcil - Word MVP
(e-mail address removed)
Word MVP site: http://www.word.mvps.org
 
G

Greg Maxey

Jonthan/Karl

Yes it was and thank you both for answering. Karl I looked at some of
your examples and as feared they are deep end stuff. Perhaps after
reviewing the two articles that Jonathan referenced I will understand a
bit better.

Jonathan, I am looking at the first article now and must say the
section on

"Creating Object Collections" is a little incomplete and if I was
completely ignorant of VBA then I would have had to give up in
frustration.

First it doesn't declare a Collection. It doesn't initiate the
collection. It doesnt' initiate an new instance of the class for the
second new student

Sub TestclsStudentCollection()
Dim Students As Collection
Dim oNewStudent As Student
Set Students = New Collection
Set oNewStudent = New Student
With oNewStudent
.FirstName = "Bart"
.LastName = "Simpson"
.BirthDate = "12/31/1958"
End With
Students.Add oNewStudent, oNewStudent.FirstName
Set oNewStudent = New Student
With oNewStudent
.FirstName = "Lisa"
.LastName = "Simpson"
.BirthDate = "07/14/1962"
End With
Students.Add oNewStudent, oNewStudent.FirstName
Students.Item("Lisa").Speak
End Sub
 
J

Jonathan West

Greg Maxey said:
Jonthan/Karl

Yes it was and thank you both for answering. Karl I looked at some of
your examples and as feared they are deep end stuff. Perhaps after
reviewing the two articles that Jonathan referenced I will understand a
bit better.

Jonathan, I am looking at the first article now and must say the
section on

"Creating Object Collections" is a little incomplete and if I was
completely ignorant of VBA then I would have had to give up in
frustration.

If you were completely ignorant of VBA, I wouldn't have pointed you to the
article in the first place :)
First it doesn't declare a Collection. It doesn't initiate the
collection. It doesnt' initiate an new instance of the class for the
second new student

I agree that the Collection declaration and initialisation are missing. But
see my comments below about the Student instances
Sub TestclsStudentCollection()
Dim Students As Collection 'This is the collection declaration
'which is missing from the article
Dim oNewStudent As Student
Set Students = New Collection 'This initializes the collection 'currently contains nothing
Set oNewStudent = New Student 'this defines an instance of a Student
With oNewStudent 'this block assigns values to the
.FirstName = "Bart" 'student properties
.LastName = "Simpson"
.BirthDate = "12/31/1958"
End With
Students.Add oNewStudent, oNewStudent.FirstName
'the line above adds the Student instance to the collection,
'assigning the student's Firstname to the item name.
'Since the instance is now in the collection, the original
'reference to it can be dropped, and oNewStudent reused.
Set oNewStudent = New Student 'Which is precisely what happens here.
With oNewStudent 'The properties are assigned to the
.FirstName = "Lisa" 'new instance
.LastName = "Simpson"
.BirthDate = "07/14/1962"
End With
Students.Add oNewStudent, oNewStudent.FirstName
'and it is added to the Collection
Students.Item("Lisa").Speak
End Sub


--
Regards
Jonathan West - Word MVP
www.intelligentdocuments.co.uk
Please reply to the newsgroup
Keep your VBA code safe, sign the ClassicVB petition www.classicvb.org
 
G

Greg Maxey

JGM,

Thanks for the post. Right now my skull is cracking with frustration of
content controls and XML mapping. All new stuff to me. When I get my head
clear I will come back to these class pieces and try to get a better
understanding. Appreciate your time and input.
 
G

Greg Maxey

Jonathan,

I follow all of your comments. I am both honored and appalled that you
don't feel that I am completely ignorant of VBA ;-)

Thanks for the help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top