I inherit from an Object class, my class clsMatrizDb to handle an Array(,); but when I do it generates the following
public objPubMatriz as clsMatrizDb(,)
objPubMatriz (0,0) = 1
I get an error saying that you can't convert from integer to clsXArrayDb
My class is inheriting like this
Public Class clsMatrizDb
Inherits Object
Private vIntRow As Integer
Private vIntColumn As Integer
Public Sub New()
MyBase.New
Me.vIntRow = 0
Me.vIntColumn = 0
End Sub
Public Sub New(ByVal pvIntRow As Integer, ByVal pvIntColumn As Integer)
Me.vIntRow = pvIntRow
Me.vIntColumn = pvIntColumn
End Sub
End Class
I'm missing something?
My comments ended up too long, so here's my explainer:
I agree with cleaning up comments made.
There is no need for Inherits Object. An instance of a class is an Object by default.
The default value of an Integer value is 0 so no need to set this explicitly in the New() sub. If you like, set it explicitly in the variable declarations.
There is no need to call MyBase.New because you are actually not inheriting from a base/abstract class.
You have stated that the error is converting from integer to clsXArrayDb but you don't mention this class at all. Do you mean clsMatrizDb?
The error you are getting is because you are trying to assign the integer value, 1 to an instance (object) of type clsMatrizDb.
If you want to create an instance of clsMatrizDb with Row and Column values initialised as 0, 0 then you just need to declare:
public objPubMatriz as New clsMatrizDb()
If you want to create an instance of clsMatrizDb with different Row and Column values (for example 2 and 4) then you would declare:
public objPubMatriz as New clsMatrizDb(2,4)
To be able to assign an integer value to your clsMatrizDb object, you will either need a default property as described by TnTinMn... which overrides a need for you to have a constructor that takes the Row and Column values. You would code:
public objPubMatriz as New clsMatrizDb()
objPubMatriz(2,4) = 1
The default property would be declared as:
Default Public Property Item(ByVal pvIntRow As Integer, ByVal pvIntColumn As Integer) As Integer
and you would set the values for vIntRow and vIntColumn as part of this property implementation.
If you want to keep the parameterised constructor then you will need to add a Value property to the class:
public property Value as Integer
With usage:
public objPubMatriz as New clsMatrizDb(2,4)
objPubMatriz.Value = 1
Related
What I'm trying to do is create an array from a Class that holds a list of information.
What I've tried so far is this - First, create the Class:
Public Class PowerArray
Public Name As String
Public Action As String
Public Cost As Integer
Public Pool1 As String
Public Pool2 As String
Public Range As String
Public Duration As String
Public Tags As ArrayList = New ArrayList
Public Desc As String
End Class
Then, define a new object that uses PowerArray as type, contained in a Public Class so it can be called in any sub:
Public Class GVar
Public Shared CharPowers(100) As PowerArray
Public Shared PCount As Integer = 0
End Class
But when I try to write to that object, it keeps throwing a Null Reference Exception.
Example:
Trying to write an entry to CharPowers(GVar.Pcount) (where PCount is currently 0, and "txt.PowerName.Text" is any string):
GVar.CharPowers(GVar.PCount).Name = txtPowerName.Text
...throws the exception. This happens no matter which value I try to write to.
I haven't had any major hangups going this route when defining a new object inside a sub using that type (not as an array, but just a simple object), so I'm guessing it's the object being an array that's throwing a fit. I just can't figure out how or why. It clearly exists, it's defined on startup.
Your array in GVar is an array of elements typed as PowerArray with a value of Nothing. You must create an instance of PowerArray and assign it to an element is the array before you can set a field of a PowerArray object.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim PA As New PowerArray
GVar.CharPowers(GVar.PCount) = PA
GVar.CharPowers(GVar.PCount).Name = TextBox1.Text
MessageBox.Show(GVar.CharPowers(GVar.PCount).Name)
End Sub
Are you planning on incrementing PCount? You would not need to keep track of where you are in the array if you used List(Of PowerArray).
EDIT
Public Class PowerArray
Public Property Name As String
Public Property Action As String
Public Property Cost As Integer
Public Property Pool1 As String
Public Property Pool2 As String
Public Property Range As String
Public Property Duration As String
Public Property Tags As New List(Of Object)
Public Property Desc As String
End Class
Public Class GVar
Public Shared Property CharPowers As New List(Of PowerArray)
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim PA As New PowerArray
PA.Name = TextBox1.Text
GVar.CharPowers.Add(PA)
For Each item As PowerArray In GVar.CharPowers
MessageBox.Show(item.Name)
Next
End Sub
Seems I tripped over an answer. In particular:
Public Class GVar
Public Shared CharPowers(100) As PowerArray
Public Shared PCount As Integer = 0
Shared Sub New()
For i = 0 To CharPowers.GetUpperBound(0)
CharPowers(i) = New PowerArray
Next
End Sub
End Class
I'm trying to create a class with arrays in it, and I'm having issues creating the class for it...
CLASS:
Private pST(0 To 2) As String
Public Property Get ST() As String
ST() = pST()
End Property
Public Property Let ST(value() As String) '<---- ERROR HERE
pST() = value()
End Property
CODE RUN:
Sub test()
Dim foo As cPurchaseOrder
Set foo = New cPurchaseOrder
foo.ST(0) = "test"
Debug.Print foo.ST(0)
End Sub
THE ERROR:
Compile error:
Definitions of property procedures for the same property are inconsistent, or property procedure has an optional parameter, a ParamArray, or an invalid Set final parameter.
THE QUESTION:
How can I properly initialize a class with arrays as variables?
EDIT: in relation to Mat's Mug response
CLASS CHANGED:
Private pST As Variant
Public Property Get STContent(ByVal index As Long) As String
STContent = pST(index)
End Property
Public Property Let STContent(ByVal index As Long, ByVal value As String)
pST(index) = value
End Property
Private Sub Class_Initialize()
ReDim pST(0 To 2)
End Sub
CODE RUN TO TEST:
Sub test()
Dim foo As cPurchaseOrder
Set foo = New cPurchaseOrder
foo.STContent(0) = "test" '<--- Type mismatch here
Debug.Print foo.STContent(0)
End Sub
Your getter would need to return a String() array for the types to be consistent:
Public Property Get ST() As String()
However I wouldn't recommend exposing an array like this. First because assigning typed arrays is rather painful, second because the setter (Property Let) is actually cheating here:
Public Property Let ST([ByRef] value() As String)
Unless you specify ByVal explicitly, a parameter is always passed ByRef in VBA... except there's this quirk about Property Let - the RHS/value parameter is always passed ByVal at run-time.
And arrays can only ever be passed ByRef.
Therefore, a property that gets (or assigns, actually) a whole array doesn't make much sense.
A better way would be to encapsulate the array (I'd make it a Variant though), and expose its contents (not the array itself) through an indexed property:
Private internal As Variant 'String array
'...
Public Property Get Content(ByVal index As Long) As String
Content = internal(index)
End Property
Public Property Let Content(ByVal index As Long, ByVal value As String)
internal(index) = value
End Property
You have a lot of issues there.
First, your Property Get needs to return a String array. Second, your array needs to be dynamic, or you need to rewrite the whole thing so that you pass an index value to it, otherwise there is no way to indicate which value you are passing to the array. So, for example, using a dynamic array:
Private pST() As String
Public Property Get ST() As String()
ST = pST
End Property
Public Property Let ST(value() As String)
pST() = value()
End Property
and the calling code:
Sub test()
Dim foo As cPurchaseOrder
Set foo = New cPurchaseOrder
Dim asData() As String
ReDim asData(0)
asData(0) = "test"
foo.ST = asData
Debug.Print foo.ST()(0)
End Sub
Unfortunately, I couldn't be sure form the original what the intent was.
It is getting late here but give it a try. In the module:
Option Explicit
Sub Test()
Dim foo As cPurchaseOrder
Set foo = New cPurchaseOrder
foo.AddValueToSt "test", 1
Debug.Print foo.ST(1)
End Sub
In the Class:
Option Explicit
Private pST
Public Property Get ST() As Variant
ST = pST
End Property
Public Property Let ST(value As Variant)
pST = value
End Property
Public Function AddValueToSt(value As Variant, position As Long)
pST(position) = value
End Function
Private Sub Class_Initialize()
ReDim pST(2)
End Sub
This is my way to use the Factory Method Pattern. When I say "my way", for me this pattern is translated to "Whenever some OOP requires more than 5 minutes of thinking simply add a function."
I'm designing a dynamic buffer for outgoing messages. The data structure takes the form of a queue of nodes that have a Byte Array buffer as a member. Unfortunately in VBA, Arrays cannot be public members of a class.
For example, this is a no-no and will not compile:
'clsTest
Public Buffer() As Byte
You will get the following error: "Constants, fixed-length strings, arrays, user-defined types and Declare statements not allowed as Public members of object modules"
Well, that's fine, I'll just make it a private member with public Property accessors...
'clsTest
Private m_Buffer() As Byte
Public Property Let Buffer(buf() As Byte)
m_Buffer = buf
End Property
Public Property Get Buffer() As Byte()
Buffer = m_Buffer
End Property
...and then a few tests in a module to make sure it works:
'mdlMain
Public Sub Main()
Dim buf() As Byte
ReDim buf(0 To 4)
buf(0) = 1
buf(1) = 2
buf(2) = 3
buf(3) = 4
Dim oBuffer As clsTest
Set oBuffer = New clsTest
'Test #1, the assignment
oBuffer.Buffer = buf 'Success!
'Test #2, get the value of an index in the array
' Debug.Print oBuffer.Buffer(2) 'Fail
Debug.Print oBuffer.Buffer()(2) 'Success! This is from GSerg's comment
'Test #3, change the value of an index in the array and verify that it is actually modified
oBuffer.Buffer()(2) = 27
Debug.Print oBuffer.Buffer()(2) 'Fail, diplays "3" in the immediate window
End Sub
Test #1 works fine, but Test #2 breaks, Buffer is highlighted, and the error message is "Wrong number of arguments or invalid property assignment"
Test #2 now works! GSerg points out that in order to call the Property Get Buffer() correctly and also refer to a specific index in the buffer, TWO sets of parenthesis are necessary: oBuffer.Buffer()(2)
Test #3 fails - the original value of 3 is printed to the Immediate window. GSerg pointed out in his comment that the Public Property Get Buffer() only returns a copy and not the actual class member array, so modifications are lost.
How can this third issue be resolved make the class member array work as expected?
(I should clarify that the general question is "VBA doesn't allow arrays to be public members of classes. How can I get around this to have an array member of a class that behaves as if it was for all practical purposes including: #1 assigning the array, #2 getting values from the array, #3 assigning values in the array and #4 using the array directly in a call to CopyMemory (#3 and #4 are nearly equivalent)?)"
So it turns out I needed a little help from OleAut32.dll, specifically the 'VariantCopy' function. This function faithfully makes an exact copy of one Variant to another, including when it is ByRef!
'clsTest
Private Declare Sub VariantCopy Lib "OleAut32" (pvarDest As Any, pvargSrc As Any)
Private m_Buffer() As Byte
Public Property Let Buffer(buf As Variant)
m_Buffer = buf
End Property
Public Property Get Buffer() As Variant
Buffer = GetByRefVariant(m_Buffer)
End Property
Private Function GetByRefVariant(ByRef var As Variant) As Variant
VariantCopy GetByRefVariant, var
End Function
With this new definition, all the tests pass!
'mdlMain
Public Sub Main()
Dim buf() As Byte
ReDim buf(0 To 4)
buf(0) = 1
buf(1) = 2
buf(2) = 3
buf(3) = 4
Dim oBuffer As clsTest
Set oBuffer = New clsTest
'Test #1, the assignment
oBuffer.Buffer = buf 'Success!
'Test #2, get the value of an index in the array
Debug.Print oBuffer.Buffer()(2) 'Success! This is from GSerg's comment on the question
'Test #3, change the value of an index in the array and verify that it is actually modified
oBuffer.Buffer()(2) = 27
Debug.Print oBuffer.Buffer()(2) 'Success! Diplays "27" in the immediate window
End Sub
#Blackhawk,
I know it is an old post, but thought I'd post it anyway.
Below is a code I used to add an array of points to a class, I used a subclass to define the individual points, it sounds your challenge is similar:
Mainclass tCurve
Private pMaxAmplitude As Double
Private pCurvePoints() As cCurvePoint
Public cDay As Date
Public MaxGrad As Double
Public GradChange As New intCollection
Public TideMax As New intCollection
Public TideMin As New intCollection
Public TideAmplitude As New intCollection
Public TideLow As New intCollection
Public TideHigh As New intCollection
Private Sub Class_Initialize()
ReDim pCurvePoints(1 To 1500)
ReDim curvePoints(1 To 1500) As cCurvePoint
Dim i As Integer
For i = 1 To 1500
Set Me.curvePoint(i) = New cCurvePoint
Next
End Sub
Public Property Get curvePoint(Index As Integer) As cCurvePoint
Set curvePoint = pCurvePoints(Index)
End Property
Public Property Set curvePoint(Index As Integer, Value As cCurvePoint)
Set pCurvePoints(Index) = Value
End Property
subclass cCurvePoint
Option Explicit
Private pSlope As Double
Private pCurvature As Double
Private pY As Variant
Private pdY As Double
Private pRadius As Double
Private pArcLen As Double
Private pChordLen As Double
Public Property Let Slope(Value As Double)
pSlope = Value
End Property
Public Property Get Slope() As Double
Slope = pSlope
End Property
Public Property Let Curvature(Value As Double)
pCurvature = Value
End Property
Public Property Get Curvature() As Double
Curvature = pCurvature
End Property
Public Property Let valY(Value As Double)
pY = Value
End Property
Public Property Get valY() As Double
valY = pY
End Property
Public Property Let Radius(Value As Double)
pRadius = Value
End Property
Public Property Get Radius() As Double
Radius = pRadius
End Property
Public Property Let ArcLen(Value As Double)
pArcLen = Value
End Property
Public Property Get ArcLen() As Double
ArcLen = pArcLen
End Property
Public Property Let ChordLen(Value As Double)
pChordLen = Value
End Property
Public Property Get ChordLen() As Double
ChordLen = pChordLen
End Property
Public Property Let dY(Value As Double)
pdY = Value
End Property
Public Property Get dY() As Double
dY = pdY
End Property
This will create a tCurve with 1500 tCurve.Curvepoints().dY (for example)
The trick is to get the index process correct in the main class !
Good luck !
Not the most elegant solution, but modeling from the code you provided...
In clsTest:
Option Explicit
Dim ArrayStore() As Byte
Public Sub AssignArray(vInput As Variant, Optional lItemNum As Long = -1)
If Not lItemNum = -1 Then
ArrayStore(lItemNum) = vInput
Else
ArrayStore() = vInput
End If
End Sub
Public Function GetArrayValue(lItemNum As Long) As Byte
GetArrayValue = ArrayStore(lItemNum)
End Function
Public Function GetWholeArray() As Byte()
ReDim GetWholeArray(LBound(ArrayStore) To UBound(ArrayStore))
GetWholeArray = ArrayStore
End Function
And in mdlMain:
Sub test()
Dim buf() As Byte
Dim bufnew() As Byte
Dim oBuffer As New clsTest
ReDim buf(0 To 4)
buf(0) = 1
buf(1) = 2
buf(2) = 3
buf(3) = 4
oBuffer.AssignArray vInput:=buf
Debug.Print oBuffer.GetArrayValue(lItemNum:=2)
oBuffer.AssignArray vInput:=27, lItemNum:=2
Debug.Print oBuffer.GetArrayValue(lItemNum:=2)
bufnew() = oBuffer.GetWholeArray
Debug.Print bufnew(0)
Debug.Print bufnew(1)
Debug.Print bufnew(2)
Debug.Print bufnew(3)
End Sub
I added code to pass the class array to another array to prove accessibility.
Even though VBA won't allow us to pass arrays as properties, we can still use Functions to pick up where properties fall short.
I've been searching all over but nothing seems to do the trick for me. Here is the problem:
I want to store an array of "keys"
Here is my simple class:
Private pkeys_length As Integer
Private pkeys() As String
Public Property Get keys_length() As Integer
keys_length = pkeys_length
End Property
Public Property Let keys_length(arg As Integer)
pkeys_length = arg
End Property
Public Property Get Keys() As String
Keys = pkeys()
End Property
Public Property Let Keys(ByVal arg As String)
ReDim pkeys(0 To pkeys_length) As String
pkeys = arg
End Property
And here is what I am trying to store:
Dim str_pkeys() As String
Dim pkey_count As Integer
pkey_count = CountPrimaryKeys(stbl)
'Store the keys of that table
ReDim str_pkeys(pkey_count) As String
keyset_1.keys_length = pkey_count
str_pkeys = FindPrimaryKeys(keyset_1.Table)
keyset_1.Keys = str_pkeys
As it stands, it Gives the error Compile Error: Type mismatch
I have had several problems while storing the array, I'm not sure if I am actually getting anywhere. This is the only error I haven't been able to fix. All I need to be able to do is store the array of strings in the class.
Anyone familiar with how to go about this?
I think you need to use String() in your Get property and remove the ByVal in the Let:
Private pkeys_length As Integer
Private pkeys() As String
Public Property Get keys_length() As Integer
keys_length = pkeys_length
End Property
Public Property Let keys_length(arg As Integer)
pkeys_length = arg
End Property
Public Property Get Keys() As String()
Keys = pkeys
End Property
Public Property Let Keys(arg() As String)
ReDim pkeys(0 To pkeys_length) As String
pkeys = arg
End Property
Apart from this a small design suggestion: do you really need a Set for the array length? Why not include this in the set of the array - and only provide the Get instead?
I have a Class ABC. And i want to write two properties for
it. One i have already mentioned in the code. The other one will be a single dimensional array.
Public Class ABC
Private m_Type As String
Private SomeArray........need to write a property for array which will be of type `int`
Public Property Type() As String
Get
Return m_Type
End Get
Set(ByVal value As String)
m_Type = value
End Set
End Property
End Class
I am not sure how to define a property for array which can be used in a List(Of ABC). The property for array can be a read only array as i will be
hard coding the data for it.
So basically when i do this,
Dim SomeList As New List(Of ABC)
And inside a for loop i need something like this,
SomeList.Item(index).SomeArray......this will give me all the items inside the array
You can declare an array property the same way as you declare a different property type:
Public Class ABC
Private _Type As String
Private _SomeArray As Int32()
Public Property SomeArray As Int32()
Get
Return _SomeArray
End Get
Set(ByVal value As Int32())
_SomeArray = value
End Set
End Property
Public Property Type() As String
Get
Return _Type
End Get
Set(ByVal value As String)
_Type = value
End Set
End Property
End Class
for example, if you want to loop all Integers in one array of the list:
Dim index As Int32 = 0
Dim someList As New List(Of ABC)
For Each i As Int32 In someList(index).SomeArray
Next
If you're not going to be doing anything special in the Gets and Sets, you could simplify your code a little, as in the following (which initializes the read only array to contain the numbers 1, 2, 3 and 4):
Public Class ABC
Public Property Type As String
Public ReadOnly Property SomeArray As Integer() = {1,2,3,4}
End Class