screen.previouscontrol problem. (1 Viewer)

John Sh

Member
Local time
Today, 21:30
Joined
Feb 8, 2021
Messages
410
This sub is on a form to catch the previous control and works correctly if the control is a command button.
If the control is a textbox "Ctl" holds the contents of the box as a string.
Code:
Private Sub btnAbout_Click()
    Dim ctl As Control
    Set ctl = Screen.PreviousControl
'    getHelp (Screen.PreviousControl)
End Sub
 

sonic8

AWF VIP
Local time
Today, 13:30
Joined
Oct 27, 2015
Messages
998
If the control is a textbox "Ctl" holds the contents of the box as a string.
That is not possible, as the variable ctl is declared as control.
I assume you arrived at this incorrect conclusion by looking at or handling ctl in some way that caused it to return its default property's value, the Value property.

Show or explain how you arrived at your conclusion, and we'll probably be able to explain where it went wrong.
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 07:30
Joined
May 21, 2018
Messages
8,529
Code:
Gethelp Screen.PreviousControl
will pass the control as a reference
Code:
GetHelp (Screen.PreviousControl)
will pass what is in parentheses by value. It will evaluate Screen.PreviousControl.DefaultProperty or in a case of a textbox it will evaluate the expression to the value of the textbox.
However this will pass by reference
Code:
Call GetHelp (Screen.previousControl)

Yes it is confusing and dumb, but that is the way it is.
Why?
4) Pass an argument which would normally be byref as byval: Result = MyFunction(Arg1, (Arg2)) ' Arg1 is passed byref, arg2 is passed byval

In Summary
Call GetHelp (Screen.previousControl) ... By ref (assume procedure argument by ref)
GetHelp Screen.previousControl .. By ref (assume procedure argument by ref)
GetHelp (Screen.previuosControl) .. By val
 
Last edited:

John Sh

Member
Local time
Today, 21:30
Joined
Feb 8, 2021
Messages
410
That is not possible, as the variable ctl is declared as control.
I have attached a small form.
click either the button or the text box then click help. I will let the results speak for themselves.
John
 

Attachments

  • Database1.zip
    24.3 KB · Views: 57

John Sh

Member
Local time
Today, 21:30
Joined
Feb 8, 2021
Messages
410
In Summary
Call GetHelp (Screen.previousControl) ... By ref (assume procedure argument by ref)
GetHelp Screen.previousControl .. By ref (assume procedure argument by ref)
GetHelp (Screen.previuosControl) .. By val

Thank you for that, it answers my question, but confused I am. What about the 'Set ctl =" returning a string?
Is there a more confusing way around that.
 

Edgar_

Active member
Local time
Today, 06:30
Joined
Jul 8, 2023
Messages
430
I commented some lines in your BtnStart_Click procedure:
Rich (BB code):
Private Sub BtnStart_Click()
    Dim Ctl As Control
'    On Error GoTo error
    Set Ctl = Screen.PreviousControl
    Stop
'    If InStr(Ctl, "Now") > 0 Then
'        MsgBox "now Ctl is a string ---- " & Ctl
'    End If
'    Exit Sub
'error:
'    MsgBox "now Ctl is an object ---- " & Ctl.Name
End Sub
I added the Stop to check what Ctl is at that point. The debugger says the type is Control/TextBox when the textbox is previous:
1699419105357.png

And when the button is previous, the type is Control/CommandButton
1699419155489.png


If you go into the object browser looking for the default value of the Control class, you will see that it has no default property. If you look for the CommandButton class, it also has no default property. However, if you look for the TextBox class, you'll see it does have a default property, look:
1699419570850.png


Predeterminado means Default. That Cyan icon helps see what the default member is. So, since the TextBox class does have a Default property, which is Value, when you use Set Ctl = Screen.PreviousControl, VBA will determine you need txt1.Value when you try to use the MsgBox function. Since the CommandButton class has no such thing, it refers to the CommandButton itself, and it throws an error because it needs a string for the MsgBox.

By the way, what are you planning to do with the reference to the control? Set its color?
 
Last edited:

John Sh

Member
Local time
Today, 21:30
Joined
Feb 8, 2021
Messages
410
By the way, what are you planning to do with the reference to the control?
It's all part of a context sensitive help system.
I have written a system that controls a number of tables with scientific data in them. The major forms have some 90 text/ combo boxes on a single form with up to 20 buttons in the header and more in the footer.
There are some 60 different forms in the system and, as you can imagine, working your way through this lot can be intimidating. Hence the context sensitive help.
Basically one can access the help files, a word document with many bookmarks and hyperlinks, by either clicking a "Help"
button which looks at the previous control or the "F1" key that looks at the current control.
I only started writing this a couple of days ago so it is in it's infancy and I am in a steep learning curve.
This is the guts of it. I just have to add a whole bunch more "IF" and "Case" statements plus a lot more writing in the word doc.
There is a trap for "F1" in each form and code for the "Help" button. Lots of cut and paste.
John

Code:
Public Sub getHelp(Ctl As Control)
    Dim str As String
    Dim sName As String
    Dim num As Integer
    Dim sSect As String
    sSect = IIf(Ctl.Section = 0, "Detail", "Header")
    num = Ctl.TabIndex
    If sSect = "Header" Then
        Select Case Ctl.Parent.Name
        Case "Herbarium Collection"
            Select Case Ctl.TabIndex
                Case 0 To 5: str = "Recordcontrol"
                Case 6: str = "Copy"
                Case 7 To 9: str = "Recordlocate"
                Case 10 To 12: str = "Labelsgroup"
                Case 13 To 20: str = "User"
            End Select
        Case "National Parks Collection"
            Select Case Ctl.TabIndex
                Case 0 To 3: str = "Recordcontrol"
                Case 4 To 6: str = "Recordlocate"
                Case 7 To 9: str = "Usere"
            End Select
        End Select
    End If
    If Nz(str, "") = "" Then
        strMessage = "This is a work in progress"
        strImage = "i"
        bOK = True
        Messenger
        Exit Sub
    End If
Application.FollowHyperlink TempVars!LYN & "The Don McNair Herbarium Data Set.docx", str
End Sub
 

Edgar_

Active member
Local time
Today, 06:30
Joined
Jul 8, 2023
Messages
430
In that particular code, I see you're using the Ctl variable to get the section, tabindex and parent members.

However, in the example db you posted, you're looking for the condition that your PreviousControl's something has the word "Now" in it. But that something can be many things depending on the control. If it's a combo box bound to a foreign key, you'll likely get a number, not a string, if it's a button, you'll get the button object itself (maybe you need its caption?), if it's a subform, you'll get its Controls collection, and you probably need something else, its name perhaps? So you'll have to write a condition for each type of control.

You can use the TypeName function like If TypeName(ctl) = acTextBox Then or a select case for that.
 

John Sh

Member
Local time
Today, 21:30
Joined
Feb 8, 2021
Messages
410
In that particular code, I see you're using the Ctl variable to get the section, tabindex and parent members.

However, in the example db you posted, you're looking for the condition that your PreviousControl's something has the word "Now" in it. But that something can be many things depending on the control. If it's a combo box bound to a foreign key, you'll likely get a number, not a string, if it's a button, you'll get the button object itself (maybe you need its caption?), if it's a subform, you'll get its Controls collection, and you probably need something else, its name perhaps? So you'll have to write a condition for each type of control.

You can use the TypeName function like If TypeName(ctl) = acTextBox Then or a select case for that.
The code sample was just to demonstrate the way "Ctl" reacted to the text box or button. It had nothing to do with the help function.
Had you left the code as it was, the message boxes had the results in them.
The type of control is irrelevant for my purpose. The help function relies in the tabindex, the form name and "Header"/ "Detail".
It does involve a lot of extra work sorting out the tab order. The default is across then down. I need down then across.
I guess the system is only as good as the time one put's into it.
John
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 07:30
Joined
May 21, 2018
Messages
8,529
What about the 'Set ctl =" returning a string?
Is there a more confusing way around that.
That is definitely not what is happening.
What is happening is the VBA will do its best to Cast/evaluate values to the proper type.
The instr function takes a string
Code:
Private Sub BtnStart_Click()
    Dim Ctl As Control
    On Error GoTo error
    Set Ctl = Screen.PreviousControl
    msgbox TypeName(ctl)
   If InStr(Ctl, "Now") > 0 Then
        MsgBox "now Ctl is a string ---- " & Ctl
    End If
    Exit Sub
error:
    MsgBox "now Ctl is an object ---- " & Ctl.Name
End Sub

Since a textbox has a default Value property, CTL does not become a string but it gets evaluated in the function.
msgbox TypeName(ctl)
Proves it is set as an object as we would expect.

A cmd button does not have a value or even a default property (which is strange) so it cannot evaluate it to a string.
InStr(Ctl, "Now")

You will see this in VBA where you would think the code would fail but VBA guesses what you are trying to do and evaluates or casts it to a correct format.

Some examples to show how confusing this can be
 
Last edited:

John Sh

Member
Local time
Today, 21:30
Joined
Feb 8, 2021
Messages
410
That is definitely not what is happening.
Seems the more one gets clarity, the more confused one gets.
If you look at Ctl directly after the "set" It has a string enclosed in inverted commas so it would appear to be getting "Ctl.value".
I've oft said that Access is consistently inconsistent, I'll stick with that.
Thank you for casting some light on this. it's very helpful.
John
 

gemma-the-husky

Super Moderator
Staff member
Local time
Today, 12:30
Joined
Sep 12, 2006
Messages
15,656
In your original upload, the "error" you are reporting is incorrect.

Try the error handler below

If you just click help, you get error 2483, as there is no previous control.
If you click the text box, then help it works
if you click the other button then click help, you get a different error.

error:
' MsgBox "now Ctl is an object ---- " & Ctl.Name
MsgBox "Error: " & Err & " Desc: " & Err.Description
 

John Sh

Member
Local time
Today, 21:30
Joined
Feb 8, 2021
Messages
410
In your original upload, the "error" you are reporting is incorrect.
Thank you Gemma.
The information from MajP solved my problem.
I was calling the "GetHelp" function incorrectly.

In Summary
Call GetHelp (Screen.previousControl) ... By ref (assume procedure argument by ref)
GetHelp Screen.previousControl .. By ref (assume procedure argument by ref)
GetHelp (Screen.previuosControl) .. By val
 

gemma-the-husky

Super Moderator
Staff member
Local time
Today, 12:30
Joined
Sep 12, 2006
Messages
15,656
@John Sh
Yes, I saw the post by @MajP. It was a very clear explanation of the effect of an innocuous pair of brackets.
 

Users who are viewing this thread

Top Bottom