How can I assign a variable to the pointer of a control element parameter in Visual Basic? - pass-by-reference

In Visual Basic, control elements such as textboxes seem to act like objects, and therefore if I assign a variable to such an element, it seems to be assigned by reference. For example:
TextBox1.Text = "old text"
Dim ctrlEl as Object = TextBox1
ctrlEl.Text = "new text"
Debug.print(TextBox1.Text)
'prints "new text"
However, if I assign any particular property of that control, it seems to be assigned by value. Like this:
TextBox1.Text = "old text"
Dim ctrlElText as Object = TextBox1.Text
ctrlElText = "new text"
Debug.print(TextBox1.Text)
'prints "old text"
But what I need is to assign ctrlElText to TextBox1.Text by reference, so that modifying ctrlElText would update the TextBox1.Text as well. How can I do that?

Related

Call property set function within class in Kotlin

I'd like for every time my class sets a property for it to call the set function for that property.
here's what I'm trying to do:
var text = ""
set(value) {
field = value
//Do some other things
....
}
...
fun someFunction() {
...
//This should do everything in the set function, not just set the value
text = "new text"
...
}
I've tried doing this.text = "new text", but that still just set the value of text to new text. Is there a way to call that set function from within my class, or do I have to create a separate setText function, like I would do in Java?
You already call the setter. It just happens that you only call field = value inside it. Try using println function inside it and see that the setter is indeed called.

How to get the value of a Text box - LibreOffice Base

What i want to do is fairly simple.
I have a form in LibreOffice Base with a text box to enter some data and a button to execute a macro.
Now i want to get with the macro on the clicking button the entered value of the text box and print it with the Print("...") function.
This what i got so far. Not much, but maybe a start:
Sub TestMacro
dim oForm as object
dim oTextbox as object
dim content as object
oForm = thisComponent.drawpage.forms.getByName("form_a")
oTextbox = oForm.getByName("testbox")
content = oTextbox.getText()
Print(content)
End Sub
Any kind of help is appreciated!
I found the answer on my own. The key was to let the subroutine have a parameter as the macro is used on the execution on the button. Over the event you can get the Parent which is the form, from that on you can get the text box and the Current Value of it. Works just fine for me.
Here is the code
Sub TestMacro(oEvent as object)
DIM oForm AS OBJECT
DIM oField as object
DIM oTField as object
'gets the button
oTField = oEvent.Source.Model
'gets the parent of the button which is the form
oForm = oTField.Parent
'gets the text field based on its name
oField = oForm.getByName("testbox")
'prints the value of the textfield
Print(oField.getCurrentValue)
End Sub
Using Access2Base API will make it easy.

Create a string with a variable interpolated, assign a value to that variable afterwards and have the string print with the assigned value?

What I'm hoping for is something to this effect:
str = "This is a #{testing}"
testing = "test"
console.log(str)
# => "This is a test"
The use case doesn't make switching the order of the variable definitions efficient, so I would like to avoid that if possible.

Working with Classes in vb6 with user selected fields

I found out how to create the properties of the class, like this:
private m_Name as string
public property get Name() as string
Name = m_Name
end sub
public property let Name(sval as string)
m_name = sval
end sub
The user will create a document and choose some fields (Name, Birthday, Phone....) inside this document, as I can't know exactly which fields will be chosen by the user, I thought create a class would be the best option.
After I create the class like above, how may I make a loop through this class to check which fields has been chosen by the user?
Any better option for my situation, please, let me know...
If I understood you correctly, you want to know which fields (out of a number of existing fields) user used/initialized?
I see several ways to do it:
1) If your variables do not have default values and must have a non-empty/non-zero values, then you can simply check if a variable is empty or zero. If it is, it hasn't been initialized.
If m_name = "" Then MsgBox "Variable is not initialized"
2) for each field you have, create a boolean fieldName_Initialized so for each field, you would have something like this:
private m_Name as string
private m_name_Initialized as Boolean
public property get Name() as string
Name = m_Name
end sub
public property let Name(sval as string)
m_name = sval
m_name_Initialized = True
end sub
3) you could have a list and add variable names to the list as they become initialized:
Make sure to add Microsoft Scripting Runtime to your References for Dictionary to work.
Dim initialized As Dictionary
Set initialized = New Dictionary
private m_Name as string
private m_name_Initialized as Boolean
public property get Name() as string
Name = m_Name
end sub
public property let Name(sval as string)
m_name = sval
initialized.Add "m_name", True
end sub
Then, to check if the var has been initialized:
If initialized.Exists("m_name") Then
' Var is initialized
4) similar to #3, except use an array of booleans. Tie specific var to a specific index, like m_name is index 0. This way you skip the hassle of controlling variable names (adds to maintenance cause as far as I know you can't get the name of the variable)
Personally, #1 is the most simple, but may not be possible in a certain situations. If #1 does not apply, I would personally pick #2, unless someone can figure out how to get a string representation of a variable name from the variable itself, then #3 is preferred.
I guess what you need is a kind of Nullable-behaviour. Yes you can do this ins VB6 with the datatype Variant. Then you can use the function "IsEmpty()" to check if a property was already set or not.
a little code-example:
Option Explicit
Private m_Vars()
'0 : Name
'1 : Birthday
'2 : Phone
Private Sub Class_Initialize()
ReDim m_Vars(0 To 2)
End Sub
Public Property Get Name() As String
Name = m_Vars(0)
End Property
Public Property Let Name(RHS As String)
m_Vars(0) = RHS
End Property
Public Property Get Birthday() As Date
Birthday = m_Vars(1)
End Property
Public Property Let Birthday(RHS As Date)
m_Vars(1) = RHS
End Property
Public Sub DoSomething()
Dim i As Integer
For i = 0 To UBound(m_Vars)
Dim v: v = m_Vars(i)
If IsEmpty(v) Then
MsgBox "is empty"
Else
MsgBox v
End If
Next
End Sub
If I understand correctly, the user will add tags or something to something like a document (e.g. [Name]) and you want to know how to map your class members to these tags. To do this, you dont really want to loop thru the class members, but the document tags to find out what is needed. When you find a "tag", submit it to your class to fill in the blank.
Part 1 is a parser to find the tags...my VB6 is very rusty, so pseudocode for this:
Const TagStart = "[" ' "$[" is better as it is not likely to appear
Const TagStop = "]" ' "]$" " " "
' make this a loop looking for tags
i = Instr(docScript, TagStart)
j = Instr(docScript, TagStop)
thisTag = Mid(docScript, TagStart, TagEnd )
' not correct, but the idea is to get the text WITH the Start and Stop markers
' like [Name] or [Address]
' get the translation...see below
docText = MyClass.Vocab(thisTag)
' put it back
Mid(docScript, TagStart, TagEnd) = docText
It is actually better to look for each possible legal tag (ie Instr(docScript, "[Name]")) which are stored in an array but you may have to do that in 2 loops to allow that a given tag could be requested more than once.
Part 2 supply the replacement text from MyClass:
Friend Function Vocab(tag as string) As String
Dim Ret as string
Select Case tag
Case "$[NAME]$"
ret = "Name: " & m_Name
' if the caption is part of the "script" then just:
'ret = m_Name
Case "$[ADDRESS]$"
ret = "Address: " & m_Addr
' if not found, return the tag so you can add new Vocab items
' or user can fix typos like '[NMAR]'
Case Else
ret = tag
...
End Select
Return Ret
End Function
The parsing routines in Part 1 could also be a method in your class to process the document "script" which calls a private Vocab.
Edit
a fraction of a 'script' might look like this:
Customer's Name:| $[CUST_FNAME]$ $[CUST_LNAME]$ (ignore the pipe (|) it was a table cell marker)
The parser looks thru the string to find "$[", when it does, it isolates the related tag $[CUST_FNAME]$. If you have a large number, the first part (CUST) can be used as a router to send it to the correct class. Next, call the method to get the translation:
newText = Cust.Vocab(thisTag)
Cust Class just looks at the tag and returns "Bob" or whatever and the parsing loop replaces the tag with the data:
Customer's Name:| Bob $[CUST_LNAME]$
Then just continue until all the tags have been replaced.
With "just" 22 vocab items, you could create a dedicated class for it:
Vocab.Translate(tag ...) as string
Case "$[CUST_FNAME]$"
return Cust.FirstName
...or
Are you trying to work out a way to do this via a DOC object from office? The above is more of from the ground up document composition type thing. For office I'd think you just need some sort of collection of replacement text.
HTH
If the user has a form that they do something to create their document, why not use simple checkbox controls, one for each possible field? If you want to use a loop to check for selected fields make the checkboxes a control array and loop though the array. You can assign the field name to the Tag property, then if the checkbox is checked add the field to an array.

Dynamic property names in VBA

I have a custom class module in VBA (Access) that is supposed to handle a large amount of external data. Currently I have two functions Read(name) and Write(name, value) that allows to read and set dynamic properties.
Is there a way to define a more syntactic way to read and write those data? I know that some objects in VBA have a special way of accessing data, for example the RecordSet, which allows to read and set data using myRS!property_name. Is there a way to do exactly the same for custom class modules?
The exclamation mark syntax is used to access members of a Scripting.Dictionary instance(you'll need to add a reference to Microsoft Scripting Runtime through Tools > References first). To use this syntaxyou'll need to be storing the information internally in a dictionary.
The quickest way to use it in a class is to give your class an object variable of type Scripting.Dictionary and set it up as follows:
Option Explicit
Dim d As Scripting.Dictionary
Private Sub Class_Initialize()
Set d = New Scripting.Dictionary
End Sub
Private Sub Class_Terminate()
Set d = Nothing
End Sub
Public Property Get IntData() As Scripting.Dictionary
Set IntData = d
End Property
Now you can access properties using myinstance.IntData!MyProperty = 1... but to get to where you want to be you need to use Charlie Pearson's technique for making IntData the default member for your class.
Once that's done, you can use the following syntax:
Dim m As MyClass
Set m = New MyClass
Debug.Print "Age = " & m!Age ' prints: Age =
m!Age = 27
Debug.Print "Age = " & m!Age ' prints: Age = 27
Set m = Nothing
Okay, thanks to Alain and KyleNZ I have now found a working way to do this, without having a collection or enumerable object below.
Basically, thanks to the name of the ! operator, I found out, that access via the bang/pling operator is equivalent to accessing the default member of an object. If the property Value is the default member of my class module, then there are three equivalent statements to access that property:
obj.Value("param")
obj("param")
obj!param
So to make a short syntax working for a custom class module, all one has to do is to define a default member. For example, I now used the following Value property:
Property Get Value(name As String) As String
Value = SomeLookupInMyXMLDocument(name)
End Property
Property Let Value(name As String, val As String) As String
SetSomeNodeValueInMyXMLDocument(name, val)
End Property
Normally, you could now access that like this:
obj.Value("foo") = "New value"
MsgBox obj.Value("foo")
Now to make that property the default member, you have to add a line to the Property definition:
Attribute Value.VB_UserMemId = 0
So, I end up with this:
Property Get Value(name As String) As String
Attribute Value.VB_UserMemId = 0
Value = SomeLookupInMyXMLDocument(name)
End Property
Property Let Value(name As String, val As String) As String
Attribute Value.VB_UserMemId = 0
SetSomeNodeValueInMyXMLDocument(name, val)
End Property
And after that, this works and equivalent to the code shown above:
obj("foo") = "New value"
MsgBox obj("foo")
' As well as
obj!foo = "New value"
MsgBox obj!foo
' Or for more complex `name` entries (i.e. with invalid identifier symbols)
obj![foo] = "New value"
MsgBox obj![foo]
Note that you have to add the Attribute Value.VB_UserMemId = 0 in some other editor than the VBA editor that ships with Microsoft Office, as that one hides Attribute directives for some reason.. You can easily export the module, open it in notepad, add the directives, and import it back in the VBA editor. As long as you don't change too much with the default member, the directive should not be removed (just make sure you check from time to time in an external editor).
See this other question: Bang Notation and Dot Notation in VBA and MS-Access
The bang operator (!) is shorthand for
accessing members of a Collection or
other enumerable object
If you make your class extend the Collection class in VBA then you should be able to take advantage of those operators. In the following question is an example of a user who extended the collection class:
Extend Collections Class VBA