I have a module that is getting values from a datagrid and puts in the tags from each rows into the array of strings. I'm calling that array string on another module but i'm getting object not set to instance of an object. Why? What i'm trying to accomplish is combine all the tag into a array of strings or collection and be able to access it on another module.
'my main module
Public Class myMainModule
Public Shared myArray() As String
......
.......
Public sub doSomething()
Dim myArray As New List(Of String)
For Each row As DataGridViewRow In mydatagrid.Rows
If row.Cells("mycheckbox").Value = True Then
myArray.Add(row.Tag)
End If
Next
End Sub
End Class
'....then i'm calling it from another module:
Public Class myOtherModule
Public sub doit()
For Each value As String In myMainModule.myArray
Debug.Print(value)
Next
End Sub
End Class
You need to initialize your Array before you try to call it. Currently it is Nothing.
Public Class MyMainModule
Public Shared MyArray() As String
Public Shared Sub DoSomething()
Dim myList As New List(Of String)
For Each row As DataGridViewRow In mydatagrid.Rows
If row.Cells("mycheckbox").Value = True Then
myList.Add(row.Tag)
End If
Next
MyArray = myList.ToArray()
End Sub
End Class
Public Class MyOtherModule
Public Sub Foo()
MyMainModule.DoSomething()
For Each value As String In MyMainModule.MyArray
Debug.Print(value)
Next
End Sub
End Class
The other thing too is that you need to watch out for naming. I believe you got confused because you had a field called myArray, but also had a local variabled called myArray. You were working with the local variable that you newed up as List(Of T), not an array.
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."
In VB script, I'm trying to resize an array inside of an object (named itemList()). ReDim works for normal arrays, but I get an error when resizing an array inside of an object. I'm trying to imitate a struct, so my goal is to have some type of object/struct that has a dynamic array inside..
Class Person
Public name
Dim itemList()
End Class
Set person1 = new Person
person1.itemList(0) = "football" 'Works fine
ReDim person1.itemList(7) 'Error: "Expected "("
You cannot resize member variables of an object that way. A better approach to handling a list of items is to initialize the member variable as an empty array and append to it:
Class Person
Public name
Public itemList
Private Sub Class_Initialize()
itemList = Array()
End Sub
Public Sub Take(item)
ReDim Preserve itemList(UBound(itemList)+1)
itemList(UBound(itemList)) = item
End Sub
End Class
Set person1 = new Person
person1.Take "football"
I'm working on a program to parse a file name based on a drag drop, and process and remove a list of words that may be found in the file. I had the program working, but in a not so elegant manner, as well as a manner that would introduce issues later on in the program.
I'm trying create a list of a custom class or structure.
Here's what I have:
Public Class moviePath
Public currentPath As String
Public currentNameExt As String
Public currentName As String
Public currentExt As String
Public correctedName As String
Public correctYear As String
End Class
The issue is then when I attempt to create a usable variable based on this:
Dim workingList as New List(Of moviePath)
I'm left with no good way to correctly add data to the list using subs such as this:
Sub scanParent(ByVal sDir As String)
Dim f As String
Dim i As Integer = 0
Try
For Each f In Directory.GetFiles(sDir)
workingList(i).currentName = (Path.GetFileNameWithoutExtension(f))
workingList(i).currentNameExt = (Path.GetFileName(f))
workingList(i).currentPath = (Path.GetFullPath(f))
i += 1
Next
Catch excpt As System.Exception
MessageBox.Show("It didn't work " & excpt.ToString)
End Try
End Sub
Hopefully those tidbits make sense. scanParent sub is called passing the path to a folder as the argument (ie C\somefolder) and I intend to populate an array of sorts with information about files and folders. My reasoning is that I would like to be able to remove words from movie titles, in order use a opensource library (not sure if correct language) that parses IMDB to pull in movie info.
The main thing that I need is for each item in the class moviePath to be addressable and tied to each other item at that position in the list.
EDIT: ie. moviePath(0).currentPath would be in reference to the same file moviePath(0).currentName
For Each f In Directory.GetFiles(sDir)
dim info as new moviePath
info.currentName = (Path.GetFileNameWithoutExtension(f))
info.currentNameExt = (Path.GetFileName(f))
info.currentPath = (Path.GetFullPath(f))
workingList.add(info)
Next
You should be using the List(T).Add method for this.
Sub scanParent(ByVal sDir As String)
Dim f As String
Try
For Each f In Directory.GetFiles(sDir)
Dim newPath As New moviePath()
newPath.currentName = (Path.GetFileNameWithoutExtension(f))
newPath.currentNameExt = (Path.GetFileName(f))
newPath.currentPath = (Path.GetFullPath(f))
workingList.Add(newPath)
Next
Catch excpt As System.Exception
MessageBox.Show("It didn't work " & excpt.ToString)
End Try
End Sub
I agree with Plutonix. In addition to the fix by Bradley, also pass the FileName to your movePath class like this:
Public Class moviePath
Public Sub New(ByVal FullFilePath As String)
Me.currentPath = FullFilePath
Me.currentName = Path.GetFileNameWithoutExtension(FullFilePath)
Me.currentNameExt = Path.GetFileName(FullFilePath)
End Sub
Public currentPath As String
Public currentNameExt As String
Public currentName As String
Public currentExt As String
Public correctedName As String
Public correctYear As String
End Class
Now your loop becomes simply:
For Each f In Directory.GetFiles(sDir)
workingList.add(New moviePath(f))
Next
I have the following declared in a module (simplified for example):
Public Structure ActiveDeviceInfo
Dim InStream As String
Dim InMsg() As String
Dim OutMsg() As String
Public Sub Initialize()
ReDim InMsg(30)
ReDim OutMsg(30)
End Sub
End Structure
then right after that I create the instance for the module. I need it to have the scope of the whole module instead of the individual subroutines.
Public ActiveRelay As New ActiveDeviceInfo
ActiveRelay.Initialize()
I'm getting the 'Declaration Expected' error on the Initialization call.
Any ideas on how to fix this?
You could add it in the static constructor for the module:
Public Module Module1
Public ActiveRelay As New ActiveDeviceInfo
Sub New()
ActiveRelay.Initialize()
End Sub
'Struct Here
End Module
Just inside the module definition I would put:
Dim ActiveRelay As New ActiveDeviceInfo
And then in individual subroutines just call:
ActiveRelay.Initialize()
If you want to call an initialized when an object is created one could switch to a Class with a constructor.Something like:
Dim ActiveRelay As New ActiveDeviceInfo
Public Class ActiveDeviceInfo
Dim InStream As String
Dim InMsg() As String
Dim OutMsg() As String
Public Sub Initialize()
ReDim InMsg(30)
ReDim OutMsg(30)
End Sub
Sub New()
Initialize()
End Sub
End Class
This would run New() when the class is instantiated.