In-visible at run time, it can store up to 20 values per control for use in a program.
There are nothing on the form. It's not a container for other controls either.
How does it look inside the properties?
The Code:
Code:
'Default Property Values:
Const m_def_F1a = 0
Const m_def_F1b = 0
Const m_def_F2a = 0
Const m_def_F2b = 0
Const m_def_F3a = 0
Const m_def_F3b = 0
Const m_def_F4a = 0
Const m_def_F4b = 0
Const m_def_F5a = 0
Const m_def_F5b = 0
Const m_def_F6a = 0
Const m_def_F6b = 0
Const m_def_F7a = 0
Const m_def_F7b = 0
Const m_def_F8a = 0
Const m_def_F8b = 0
Const m_def_F9a = 0
Const m_def_F9b = 0
Const m_def_F0a = 0
Const m_def_F0b = 0
'Property Variables:
Dim m_F1a As Variant
Dim m_F1b As Variant
Dim m_F2a As Variant
Dim m_F2b As Variant
Dim m_F3a As Variant
Dim m_F3b As Variant
Dim m_F4a As Variant
Dim m_F4b As Variant
Dim m_F5a As Variant
Dim m_F5b As Variant
Dim m_F6a As Variant
Dim m_F6b As Variant
Dim m_F7a As Variant
Dim m_F7b As Variant
Dim m_F8a As Variant
Dim m_F8b As Variant
Dim m_F9a As Variant
Dim m_F9b As Variant
Dim m_F0a As Variant
Dim m_F0b As Variant
Public Property Get F1a() As Variant
F1a = m_F1a
End Property
Public Property Let F1a(ByVal New_F1a As Variant)
m_F1a = New_F1a
PropertyChanged "F1a"
End Property
Public Property Get F1b() As Variant
F1b = m_F1b
End Property
Public Property Let F1b(ByVal New_F1b As Variant)
m_F1b = New_F1b
PropertyChanged "F1b"
End Property
Public Property Get F2a() As Variant
F2a = m_F2a
End Property
Public Property Let F2a(ByVal New_F2a As Variant)
m_F2a = New_F2a
PropertyChanged "F2a"
End Property
Public Property Get F2b() As Variant
F2b = m_F2b
End Property
Public Property Let F2b(ByVal New_F2b As Variant)
m_F2b = New_F2b
PropertyChanged "F2b"
End Property
Public Property Get F3a() As Variant
F3a = m_F3a
End Property
Public Property Let F3a(ByVal New_F3a As Variant)
m_F3a = New_F3a
PropertyChanged "F3a"
End Property
Public Property Get F3b() As Variant
F3b = m_F3b
End Property
Public Property Let F3b(ByVal New_F3b As Variant)
m_F3b = New_F3b
PropertyChanged "F3b"
End Property
Public Property Get F4a() As Variant
F4a = m_F4a
End Property
Public Property Let F4a(ByVal New_F4a As Variant)
m_F4a = New_F4a
PropertyChanged "F4a"
End Property
Public Property Get F4b() As Variant
F4b = m_F4b
End Property
Public Property Let F4b(ByVal New_F4b As Variant)
m_F4b = New_F4b
PropertyChanged "F4b"
End Property
Public Property Get F5a() As Variant
F5a = m_F5a
End Property
Public Property Let F5a(ByVal New_F5a As Variant)
m_F5a = New_F5a
PropertyChanged "F5a"
End Property
Public Property Get F5b() As Variant
F5b = m_F5b
End Property
Public Property Let F5b(ByVal New_F5b As Variant)
m_F5b = New_F5b
PropertyChanged "F5b"
End Property
Public Property Get F6a() As Variant
F6a = m_F6a
End Property
Public Property Let F6a(ByVal New_F6a As Variant)
m_F6a = New_F6a
PropertyChanged "F6a"
End Property
Public Property Get F6b() As Variant
F6b = m_F6b
End Property
Public Property Let F6b(ByVal New_F6b As Variant)
m_F6b = New_F6b
PropertyChanged "F6b"
End Property
Public Property Get F7a() As Variant
F7a = m_F7a
End Property
Public Property Let F7a(ByVal New_F7a As Variant)
m_F7a = New_F7a
PropertyChanged "F7a"
End Property
Public Property Get F7b() As Variant
F7b = m_F7b
End Property
Public Property Let F7b(ByVal New_F7b As Variant)
m_F7b = New_F7b
PropertyChanged "F7b"
End Property
Public Property Get F8a() As Variant
F8a = m_F8a
End Property
Public Property Let F8a(ByVal New_F8a As Variant)
m_F8a = New_F8a
PropertyChanged "F8a"
End Property
Public Property Get F8b() As Variant
F8b = m_F8b
End Property
Public Property Let F8b(ByVal New_F8b As Variant)
m_F8b = New_F8b
PropertyChanged "F8b"
End Property
Public Property Get F9a() As Variant
F9a = m_F9a
End Property
Public Property Let F9a(ByVal New_F9a As Variant)
m_F9a = New_F9a
PropertyChanged "F9a"
End Property
Public Property Get F9b() As Variant
F9b = m_F9b
End Property
Public Property Let F9b(ByVal New_F9b As Variant)
m_F9b = New_F9b
PropertyChanged "F9b"
End Property
Public Property Get F0a() As Variant
F0a = m_F0a
End Property
Public Property Let F0a(ByVal New_F0a As Variant)
m_F0a = New_F0a
PropertyChanged "F0a"
End Property
Public Property Get F0b() As Variant
F0b = m_F0b
End Property
Public Property Let F0b(ByVal New_F0b As Variant)
m_F0b = New_F0b
PropertyChanged "F0b"
End Property
Private Sub UserControl_InitProperties()
m_F1a = m_def_F1a
m_F1b = m_def_F1b
m_F2a = m_def_F2a
m_F2b = m_def_F2b
m_F3a = m_def_F3a
m_F3b = m_def_F3b
m_F4a = m_def_F4a
m_F4b = m_def_F4b
m_F5a = m_def_F5a
m_F5b = m_def_F5b
m_F6a = m_def_F6a
m_F6b = m_def_F6b
m_F7a = m_def_F7a
m_F7b = m_def_F7b
m_F8a = m_def_F8a
m_F8b = m_def_F8b
m_F9a = m_def_F9a
m_F9b = m_def_F9b
m_F0a = m_def_F0a
m_F0b = m_def_F0b
End Sub
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
m_F1a = PropBag.ReadProperty("F1a", m_def_F1a)
m_F1b = PropBag.ReadProperty("F1b", m_def_F1b)
m_F2a = PropBag.ReadProperty("F2a", m_def_F2a)
m_F2b = PropBag.ReadProperty("F2b", m_def_F2b)
m_F3a = PropBag.ReadProperty("F3a", m_def_F3a)
m_F3b = PropBag.ReadProperty("F3b", m_def_F3b)
m_F4a = PropBag.ReadProperty("F4a", m_def_F4a)
m_F4b = PropBag.ReadProperty("F4b", m_def_F4b)
m_F5a = PropBag.ReadProperty("F5a", m_def_F5a)
m_F5b = PropBag.ReadProperty("F5b", m_def_F5b)
m_F6a = PropBag.ReadProperty("F6a", m_def_F6a)
m_F6b = PropBag.ReadProperty("F6b", m_def_F6b)
m_F7a = PropBag.ReadProperty("F7a", m_def_F7a)
m_F7b = PropBag.ReadProperty("F7b", m_def_F7b)
m_F8a = PropBag.ReadProperty("F8a", m_def_F8a)
m_F8b = PropBag.ReadProperty("F8b", m_def_F8b)
m_F9a = PropBag.ReadProperty("F9a", m_def_F9a)
m_F9b = PropBag.ReadProperty("F9b", m_def_F9b)
m_F0a = PropBag.ReadProperty("F0a", m_def_F0a)
m_F0b = PropBag.ReadProperty("F0b", m_def_F0b)
End Sub
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
Call PropBag.WriteProperty("F1a", m_F1a, m_def_F1a)
Call PropBag.WriteProperty("F1b", m_F1b, m_def_F1b)
Call PropBag.WriteProperty("F2a", m_F2a, m_def_F2a)
Call PropBag.WriteProperty("F2b", m_F2b, m_def_F2b)
Call PropBag.WriteProperty("F3a", m_F3a, m_def_F3a)
Call PropBag.WriteProperty("F3b", m_F3b, m_def_F3b)
Call PropBag.WriteProperty("F4a", m_F4a, m_def_F4a)
Call PropBag.WriteProperty("F4b", m_F4b, m_def_F4b)
Call PropBag.WriteProperty("F5a", m_F5a, m_def_F5a)
Call PropBag.WriteProperty("F5b", m_F5b, m_def_F5b)
Call PropBag.WriteProperty("F6a", m_F6a, m_def_F6a)
Call PropBag.WriteProperty("F6b", m_F6b, m_def_F6b)
Call PropBag.WriteProperty("F7a", m_F7a, m_def_F7a)
Call PropBag.WriteProperty("F7b", m_F7b, m_def_F7b)
Call PropBag.WriteProperty("F8a", m_F8a, m_def_F8a)
Call PropBag.WriteProperty("F8b", m_F8b, m_def_F8b)
Call PropBag.WriteProperty("F9a", m_F9a, m_def_F9a)
Call PropBag.WriteProperty("F9b", m_F9b, m_def_F9b)
Call PropBag.WriteProperty("F0a", m_F0a, m_def_F0a)
Call PropBag.WriteProperty("F0b", m_F0b, m_def_F0b)
End Sub
No extra coding to dimension fields or declaring of values etc.
Plain and simple.
It seems like a Collection could get this one done just as easy, with the added flexibility that they're unlimited (2gig limit), and they can be indexed.
Just saying.
Best Regards,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
It seems like a Collection could get this one done just as easy, with the added flexibility that they're unlimited (2gig limit), and they can be indexed....
Yes, but the difference is in a collection there are more properties that can be set, which in the long run have a larger output in file size. That is why I did not use anything in the form, but instead use an array only.
It will all depends on the person's needs and how much info is needed to be stored at one time.
But thanks. It leave the door open for different programming skills and ideas in the future.
Programmers are very patient people....while programming....but don't expect them to be patient all the time
I should probably let this go, but hey ho. Also, I'm not saying that there aren't coders out there who may really like your idea, and make use of it.
However, I just really don't get it. The one thing you didn't mention in your response (post #3) is that your idea actually stores values you assign at design-time. But isn't this what a Constant Enumeration is? And a Constant Enumeration is certainly more memory efficient than a UserControl.
Also, and this is just my humble opinion, I like to preserve Controls for things I can actually see on my form. This just helps me to stay organized. In fact, I've gone somewhat the opposite direction from what you're suggesting. Two examples are the Timer control and the CommonControls control. Both of these are for tasks ancillary to actual direct user interface. Therefore, I much prefer to accomplish these tasks with API calls, and forego any use of those controls.
Also, if it were me, I'd possibly enhance this idea so that it acted more like a true array, possibly a Variant array so that you could stuff anything you like into your control. (But again, this starts to feel more like a Collection.)
Best Regards,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
...However, I just really don't get it. The one thing you didn't mention in your response (post #3) is that your idea actually stores values you assign at design-time. But isn't this what a Constant Enumeration is? And a Constant Enumeration is certainly more memory efficient than a UserControl...
You're 100% correct.
User Controls tends to make code larger
...and yes, I did not make use of a real array - because I do not really know how
Well, it was an idea though.
...and yes, it's easier to follow the flow when you have everything in front of you on the screen.
Programmers are very patient people....while programming....but don't expect them to be patient all the time
Yes, through your own created properties, you can stuff just about anything you want into a UserControl (pictures, icons, arrays, Unicode strings, RTF strings, etc). That data will typically go into the associated FRX file of an FRM.
In that sense, UserControls can be pretty cool. However, for me personally, I still tend to restrict their use to things that enhance the user-interface of my program.
Best Regards,
Elroy
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
Okay, the concept that your UserControl brought to the table that a Collection lacks is the idea of Persistence. (Constant Enumerations are certainly persistent, as saved in the source code. But I liked the idea of exploring persistence with a Collection.)
Inherently, Collections don't support persistence of any kind. However, with a bit of trickery, and some limitations, you can get them to support it.
The limitations are, I restricted the data to String data. With this limitation, I wrote a UserControl (UC) wrapper for a Collection. This UC has four properties of interest:
collCount
collData
collIndex
collRemove
collIndex and collData are the two most interesting ones. Each collIndex value will have a unique collData value. Furthermore, on the property window, when you change collIndex, you see the corresponding collData.
And you can put an infinite amount of data into this control, and it's persistent.
The collCount is a read-only property that simply tells you how many items are in the collection. This is very useful because the collIndex values do not need to be contiguous.
The collRemove property is just a convenient way to get rid of certain items. In fact, there's no other straightforward way. If you double-click this property on the properties window, it deletes the data for the current index (and also deletes it from the collection).
Below is the code for the user control. I've also attached a simple test project.
Enjoy,
Elroy
p.s. It did pull in a few advanced concepts before it got done.
Code:
Option Explicit
'
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef pDest As Any, ByRef pSource As Any, ByVal ByteLen As Long)
'
Dim coll As New Collection
Dim idx As Long
'
Private Sub UserControl_Initialize()
idx = 1
End Sub
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
Dim sKeys() As String
Dim sData() As String
Dim bb() As Byte
Dim i As Long
Dim s As String
'
' Collections don't support persistence, so we do it the hard way.
'
If coll.Count <> 0 Then
'
' Get an array of keys/indexes and data.
sKeys = CollKeys ' Get all keys.
ReDim sData(coll.Count - 1)
For i = 0 To UBound(sKeys) ' Get all data into an array, based on keys.
sData(i) = coll.Item(sKeys(i))
Next i
'
' Serialize the keys into a byte array and write to property bag.
s = Space$((UBound(sKeys) + 1) * 8)
For i = 0 To UBound(sKeys)
Mid$(s, i * 8 + 1, 8) = Right$("0000000" & Hex$(CLng(sKeys(i))), 8)
Next i
bb = StrConv(s, vbFromUnicode)
PropBag.WriteProperty "collKeys", bb
'
' Serialize data and write to property bag.
s = Join(sData, vbNullString)
PropBag.WriteProperty "collData", s
'
' Serialize data lengths and write to property bag.
s = Space$((UBound(sData) + 1) * 8)
For i = 0 To UBound(sData)
Mid$(s, i * 8 + 1, 8) = Right$("0000000" & Hex$(Len(sData(i))), 8)
Next i
bb = StrConv(s, vbFromUnicode)
PropBag.WriteProperty "collDataLens", bb
Else
PropBag.WriteProperty "collKeys", bb
PropBag.WriteProperty "collData", vbNullString
PropBag.WriteProperty "collDataLens", bb
End If
'
' And now just write the last index we had specified.
PropBag.WriteProperty "collIndex", idx, 1
End Sub
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
Dim sKeys() As String
Dim sData() As String
Dim iDataLens() As Long
Dim bb() As Byte
Dim i As Long, j As Long
Dim s As String
'
' Collections don't support persistence, so we do it the hard way.
'
Set coll = Nothing ' Let's start out fresh.
'
' Fetch keys from property bag.
bb = PropBag.ReadProperty("collKeys", bb)
If IsDimmedByte(bb) Then
ReDim sKeys(UBound(bb) \ 8)
For i = 0 To UBound(bb) Step 8
s = Chr$(bb(i + 0)) & Chr$(bb(i + 1)) & Chr$(bb(i + 2)) & Chr$(bb(i + 3)) & Chr$(bb(i + 4)) & Chr$(bb(i + 5)) & Chr$(bb(i + 6)) & Chr$(bb(i + 7))
sKeys(i \ 8) = CStr(CLng("&h" & s))
Next i
Erase bb
'
' Fetch data lengths from property bag.
bb = PropBag.ReadProperty("collDataLens", bb)
ReDim iDataLens(UBound(bb) \ 8)
For i = 0 To UBound(bb) Step 8
s = Chr$(bb(i + 0)) & Chr$(bb(i + 1)) & Chr$(bb(i + 2)) & Chr$(bb(i + 3)) & Chr$(bb(i + 4)) & Chr$(bb(i + 5)) & Chr$(bb(i + 6)) & Chr$(bb(i + 7))
iDataLens(i \ 8) = CLng("&h" & s)
Next i
Erase bb
'
' Fetch data and parse.
s = PropBag.ReadProperty("collData", vbNullString)
ReDim sData(UBound(iDataLens))
j = 1
For i = 0 To UBound(iDataLens)
sData(i) = Mid$(s, j, iDataLens(i))
j = j + iDataLens(i)
Next i
'
' And now put it all into the collection.
For i = 0 To UBound(sKeys) ' Add all to the collection.
coll.Add sData(i), sKeys(i)
Next i
End If
'
' Read the index so we can return to the same one.
idx = PropBag.ReadProperty("collIndex", 1)
End Sub
Public Property Get collCollection() As Collection
Set collCollection = coll ' This returns the entire collection to the user so it can be directly used.
' However, be VERY careful here. It should be used in a read-only mode because this control won't track changes all that well unless made herein.
End Property
Public Property Get collCount() As Long
collCount = coll.Count
End Property
Public Property Let collCount(i As Long)
' It's read only, but we need this so it'll appear in the Property Window.
End Property
Public Property Get collRemove() As Boolean
collRemove = False
End Property
Public Property Let collRemove(bDelete As Boolean)
If IsInCollection Then coll.Remove CStr(idx)
End Property
Public Property Get collData() As String
If IsInCollection Then collData = coll.Item(CStr(idx))
' If not found just return "".
End Property
Public Property Let collData(ByVal New_Data As String)
If IsInCollection Then coll.Remove CStr(idx)
coll.Add New_Data, CStr(idx)
PropertyChanged "collData"
End Property
Public Property Get collIndex() As Long
collIndex = idx
End Property
Public Property Let collIndex(ByVal New_Index As Long)
idx = New_Index
PropertyChanged "collIndex"
End Property
Private Function IsInCollection() As Boolean
On Error GoTo GetOut
IsObject coll.Item(CStr(idx))
IsInCollection = True
GetOut:
End Function
Private Function CollKeys() As String()
' Returns a string array of all the keys.
Dim sKeys() As String
Dim j As Long
Dim iHold As Long
Dim ptr As Long
Dim sKeyTemp As String
'
If coll.Count = 0 Then Exit Function
'
ReDim sKeys(coll.Count - 1)
j = 0
CopyMemory ptr, ByVal ObjPtr(coll) + &H18, 4 ' First item pointer of collection header.
GoSub MoveKeyToArray
For j = 1 To coll.Count - 1
CopyMemory ptr, ByVal ptr + &H18, 4 ' Next item pointer of collection item.
GoSub MoveKeyToArray
Next j
CollKeys = sKeys
Exit Function
'
MoveKeyToArray: ' j and ptr must be set to call this.
iHold = StrPtr(sKeyTemp) ' Save string pointer because we're going to borrow the string.
CopyMemory ByVal VarPtr(sKeyTemp), ByVal ptr + &H10, 4 ' Key string of collection item.
sKeys(j) = sKeyTemp ' Move key into array.
CopyMemory ByVal VarPtr(sKeyTemp), iHold, 4 ' Put string pointer back to keep memory straight.
Return
End Function
Public Function IsDimmedByte(TheArray() As Byte) As Boolean
' This won't fail on one of the (0 to -1) arrays.
On Error Resume Next
IsDimmedByte = (LBound(TheArray) = LBound(TheArray)) ' Will error (leaving IsDimmedDbl = False) if not dimensioned.
On Error GoTo 0
End Function
EDIT1: Anyone is certainly welcome to further expand this so that the collection covers more basis other than just strings.
EDIT2: I just spotted a small bug. The Let collRemove property should have a PropertyChanged notification in it. That procedure should look like the following. I didn't fix this in the above or the attachment.
Code:
Public Property Let collRemove(bDelete As Boolean)
If IsInCollection Then
coll.Remove CStr(idx)
PropertyChanged "collData"
End If
End Property
Last edited by Elroy; Aug 24th, 2017 at 03:53 PM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
@Elroy, persistence is not an issue with a collection or array in this case is it?
I see little difference adding such a control on a form or adding a collection/array to a form and populating it at runtime, other than unneeded overhead. In fact, I kinda see the control as less resource friendly than the other options. The control is using 20 variants & longs, an hWnd unless made to be windowless, along with all the other properties associated with a control. Then the information is stored in a property bag which uses even more bytes.
The above observations is just that. I would not create a control that simply replicates a simple collection/array and has less flexibility for runtime expansion.
Insomnia is just a byproduct of, "It can't be done"
@Elroy, persistence is not an issue with a collection or array in this case is it?
I see little difference adding such a control on a form or adding a collection/array to a form and populating it at runtime, other than unneeded overhead. In fact, I kinda see the control as less resource friendly than the other options. The control is using 20 variants & longs, an hWnd unless made to be windowless, along with all the other properties associated with a control. Then the information is stored in a property bag which uses even more bytes.
The above observations is just that. I would not create a control that simply replicates a simple collection/array and has less flexibility for runtime expansion.
Yeah, I agree. There's not really a solution to much of anything here. In my post #2, I just suggested that a collection could do everything that his control could do, and that wasn't quite true. His control had the advantage of design-time persistence. In my post #4, I pointed out that a Constant Enumeration does have design-time persistence.
However, I just got it in my head that a user-control should have unlimited properties, with persistence. So, I hauled off and made it so.
Also, in the process, I learned a bit more about property-bags. I've done quite a bit with them, but I hadn't really pushed their limits. Something important I learned was that: Apparently, they can only handle Byte arrays. They can't deal with any other type of array. Since many things can be stuffed into a Byte array, this provides a great deal of flexibility. But it does make us work for it.
Best Regards,
Elroy
EDIT1: Also, I wasn't really thinking about efficiency or the use of resources when I did any of that. Clearly, a series of constants would be FAR more efficient.
EDIT2: Also, with my language, I've sort of confounded Constant Enumerations as opposed to a series of Constants. But I believe you get the gist of what I'm saying.
Last edited by Elroy; Aug 25th, 2017 at 01:07 PM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.