PDA

View Full Version : collection issue with custom type variable



JimmyTheHand
06-16-2008, 02:16 PM
Hi

See the code below:

Type MyType
a1 As String
a2 As Variant
End Type

Sub test()
Dim Col As Collection, Itm As MyType
Set Col = New Collection
Col.Add Itm
End Sub I want to put custom type variables into a collection, but at the red line I get this horrible error message:

"Only public user defined types defined in public object modules can be used as parameters or return types for public procedures of class modules or as fields of public user defined types"
On my level of knowledge this error message is cryptic. Nevertheless I looked for solutions that I may be able to implement, but they suggest everywhere that I create a dll. Which I don't want to, because I don't know how to do it yet, and right now I think it would be too much fuss to learn it for such a small task.
I hope someone knows an easier solution? Or a workaround?
I would be very grateful for it--:help : pray2::help

Jimmy

Bob Phillips
06-16-2008, 02:37 PM
I know I will be ploughing a lone furrow, but ditch UDTs, ditch collectuions, and build a collection class.

mikerickson
06-16-2008, 06:22 PM
Collections do not accept custom data types.
Neither can UDT's be assigned to Variant variables.
You could use an array if you had to, but it would have to be typed as MyType, not Variant, which limits what you can do with it. (Can't return an array of UDTs from a function.)

I agree with XLD, use a Class rather than UDT.

BTW, what is a "dll"?

JimmyTheHand
06-16-2008, 11:07 PM
I know I will be ploughing a lone furrow, but ditch UDTs, ditch collectuions, and build a collection class.
:wot
Well... umm...All right, Bob...
There's only two things I didn't understand.
#1 - "ploughing a lone furrow"
#2 - collection class

For #1, I have found a "solution" in a reasonably short time, though it's still a bit confusing. According to the idiom dictionary, you think you are in for a long work, alone, with no help from others. My first bet was that you think nobody will share your opinion?
I know it's irrelevant from my original question's point of view, but I'm still curious what your meaning was.

For #2, I guess I just have to find it out for myself. Mike has kindly confirmed this path, and also shed a little light on it by illuminating that "collection class" is not an occult piece of magic artifact, but a type of classes. I've got somewhat familiar with classes these last months.


Collections do not accept custom data types.
Neither can UDT's be assigned to Variant variables.
Can't return an array of UDTs from a function.
Wonder why is that. If memory serves, I had no such problems with Delphi. Anyway, your explanation is much easier to understand than the error message I got. :thumb


BTW, what is a "dll"? "Dynamic link library", I guess. I found such suggestions on forums dealing with VB in general, not Excel and VBA, but thought it still held for my problem.


Bob, Mike, thank you both for putting me on the right path. For the moment I'm going to use an array of UDTs, which is suitable for my purposes, so that I can proceed with my project. In the meantime I will learn about collection classes and replace those arrays when I'm ready.

Jimmy

Bob Phillips
06-16-2008, 11:46 PM
BTW, what is a "dll"?

Dynamic linked library. It is a shared library in MS windows terms, where you put the code that many applications use. They are everywhere in windows, is it not the same on the Mac?

mikerickson
06-16-2008, 11:55 PM
From my VBE Help system:
dynamic-link library (DLL)
Applies to Windows only. A library of routines loaded and linked into applications at run time.
Note The Macintosh operating system convention is a code fragment or shared library.

It sounds like Mac shares routines differently.
I like to write algorithms, but I'm not very computer savy. I don't know much about this stuff.

Bob Phillips
06-17-2008, 12:01 AM
It is very straight-forward. YOu create two classs, one for the object, MType, and one for a collection of MTypes.

The MType class is very simple



Option Explicit

Private mA1 As String
Private mA2 As Variant

Public Property Let A1(ByVal Val As String)
mA1 = Val
End Property
Public Property Get A1() As String
A1 = mA1
End Property

Public Property Let A2(ByVal Val As String)
mA2 = Val
End Property
Public Property Get A2() As String
A2 = mA2
End Property

Public Function Name()
Name = mA1 & " " & mA2
End Function


Note that I have created two properties, the eelements of your UDT, and a simple function to process them. An example of using these would be



Sub TestClass()
Dim mpType As mType

Set mpType = New mType
mpType.A1 = "Jimmy"
mpType.A2 = "The Hand"
MsgBox mpType.Name

Set mpType = Nothing
End Sub

Bob Phillips
06-17-2008, 12:46 AM
And here it gets interesting, when you add the collection class. Unfortunately, you have to hand-crank all of the collection methods, like Add, remove, and enumerate.

I added an id to the MType class first



Option Explicit

Private mcA1 As String
Private mcA2 As Variant
Private mcId As String

Public Property Let Id(ByVal Val As String)
mcId = Val
End Property
Public Property Get Id() As String
Id = mcId
End Property

Public Property Let A1(ByVal Val As String)
mcA1 = Val
End Property
Public Property Get A1() As String
A1 = mcA1
End Property

Public Property Let A2(ByVal Val As String)
mcA2 = Val
End Property
Public Property Get A2() As String
A2 = mcA2
End Property

Public Function Name()
Name = mcA1 & " " & mcA2
End Function


and the collection class, MTYpes, looks like



Option Explicit

Private mcTypes As Collection

Function NewEnum() As IUnknown
Set NewEnum = mcTypes.[_NewEnum]
End Function

Public Function Add(ThisType As MType)
If Not ExistsInCollection(mcTypes, ThisType.Id) Then
mcTypes.Add ThisType, ThisType.Id
End If
End Function

Public Property Get Count() As Long
Count = mcTypes.Count
End Property

Public Property Get Items() As Collection
Set Items = mcTypes
End Property

Public Property Get Item(Index As Variant) As MType
Set Item = mcTypes(Index)
End Property

Public Sub Remove(Index As Variant)
mcTypes.Remove Index
End Sub

Private Sub Class_Initialize()
Set mcTypes = New Collection
End Sub

Private Sub Class_Terminate()
Set mcTypes = Nothing
End Sub


'--------------------------------------------------------------------------
Public Function ExistsInCollection(pColl, ByVal pKey As String) As Boolean
'--------------------------------------------------------------------------
On Error GoTo NoSuchKey
If VarType(pColl.Item(pKey)) = vbObject Then
' force an error condition if key does not exist
End If
ExistsInCollection = True
Exit Function

NoSuchKey:
ExistsInCollection = False
End Function


You can then use it as in this example



Option Explicit

Public Sub AddToDirectoryClass2()
Dim mpTypes As MTypes
Dim mpType As MType

Set mpTypes = New MTypes

Set mpType = New MType
With mpType

.Id = "JTH"
.A1 = "Jimmy"
.A2 = "The Hand"
mpTypes.Add mpType
End With
Set mpType = Nothing

Set mpType = New MType
With mpType

.Id = "RP"
.A1 = "Bob"
.A2 = "Phillips"
mpTypes.Add mpType
End With
Set mpType = Nothing

Call TypeDetails(mpTypes)

mpTypes.Remove "JTH"

Call TypeDetails(mpTypes)

Set mpTypes = Nothing

End Sub

Public Sub TypeDetails(Optional Types As MTypes)
Dim mpType As MType
Dim mpMsg As String

mpMsg = "Number of Types = " & Types.Count & vbNewLine & vbNewLine & _
"Types.Item(1).id = " & Types.Item(1).Id & vbNewLine & vbNewLine
MsgBox mpMsg, vbInformation, "Class demo"

For Each mpType In Types.Items
mpMsg = mpType.Name
MsgBox mpMsg, vbInformation, "Class demo"
Next mpType

End Sub


As I say, a lot more code to set it up, but tons more flexible when done.

JimmyTheHand
06-17-2008, 01:10 AM
As I say, a lot more code to set it up, but tons more flexible when done.
And also a lot of code to prod through. Bob, you gave me reading matter for the next few weeks!! :eek:
I'm going to study this, and when I create my first Collection Class, I'll send you a complimentary copy :thumb

Thanks :friends:,

Jimmy

PS:
OMG, I'm really overwhelmed by this code...
I'll be back with further questions if I get stuck.

Bob Phillips
06-17-2008, 02:20 AM
It's all pretty straight-forward Jimmy, once you get into it. Start with my first post and reconcile that to your MType UDT. Then move on to the second post (that is why I did two postings to differentiate them).

I think we covered this in a previous post of yours, I just didn't give you the code then.

The only cool thing there is the collection enumeration, I haven't seen that published anywhere else, but is a basic requirement in collections IMO, and certainly adds to their flexibility.