Error "Can't set focus"

John Sh

Member
Local time
Today, 12:16
Joined
Feb 8, 2021
Messages
552
In the code below, the sequence of events is as follows;
Load event runs through all commands and set's focus to cboFamily.
cboFamily gotfocus event does it's stuff.
cboFamily_afterupdate runs and set's focus to cboGenus.
cboGenus goes through to cboGenus.dropdown.
If I'm stepping through, the dropdown list appears. If not, cboGenus.itemdata(0) is selected.
Stepping through, the sequence of events is;
cboFamily_afterupdate end sub.
cboFamily_gotfocus end if then end sub.
At this point the error message appears.
Clicking debug shows the error line as "cboFamily.setfocus" in the load event.
txtfamily and txtGenus are initially not visible and sit directly behind cboFamily and cboGenus respectively.

Code:
Option Compare Database
Option Explicit

Private Sub cboFamily_AfterUpdate()
    Me.txtFamily = Me.cboFamily
    Me.cboGenus.Requery
    Me.cboGenus.setFocus
End Sub

Private Sub cboFamily_GotFocus()
    Do
        If Nz(Me.cboFamily.ItemData(0), "") = "" Then
            Forms("Discrepancies").txtgetFamily = Left(Forms("Discrepancies").txtgetFamily, Len(Forms("Discrepancies").txtgetFamily) - 1)
            Me.cboFamily.Requery
        End If
    Loop While Nz(Me.cboFamily.ItemData(0), "") = ""
    Me.cboFamily = Me.cboFamily.ItemData(0)
    If Nz(Me.cboFamily.ItemData(1), "") = "" Then
        cboFamily_AfterUpdate
    Else
        Me.cboFamily.Dropdown
    End If
End Sub

Private Sub cboGenus_AfterUpdate()
    Me.btnShow.Caption = "Double click the ""Copy Genus"" data" & vbCrLf & _
                         "or the ""Copy Family"" data." & vbCrLf & _
                         "Right click to copy the correct spelling." & vbCrLf & _
                         "You can then paste onto the main form."
    Me.lblGenus.Caption = "Copy Genus."
    Me.txtGenus = Me.cboGenus
    Me.lblFamily.Caption = "Copy Family."
    Me.txtFamily.Visible = True
    Me.txtFamily.setFocus
    Me.cboFamily.Visible = False
    Me.txtGenus.Visible = True
    Me.txtGenus.setFocus
    Me.cboGenus.Visible = False
End Sub

Private Sub cboGenus_GotFocus()
    Me.cboGenus = Me.cboGenus.ItemData(0)
    If Nz(Me.cboGenus.ItemData(1), "") > "" Then
        Me.cboGenus.Dropdown
    Else
        cboGenus_AfterUpdate
    End If
End Sub

Private Sub CloseBtn_Click()
    DoCmd.Close acForm, Me.Name
End Sub

Private Sub Form_Load()
    Me.Visible = True
    Me.lblFamily.Caption = "Family."
    Me.lblGenus.Caption = "Genus."
    Me.txtFamily.Visible = False
    Me.cboFamily.Visible = True
    Me.txtGenus.Visible = False
    Me.cboGenus.Visible = True
    Me.btnShow.Caption = "Use the information on this form" & vbCrLf & _
                        "to correct the spelling of" & vbCrLf & _
                        "Family and Genus data on the main form."
    Me.cboFamily.Requery
    Me.cboFamily.setFocus
End Sub

Screenshot_46.jpg
 
Last edited:
Possibly because control is not yet available in Load event. Try Open or Current.
 
Possibly because control is not yet available in Load event. Try Open or Current.
I don't think so because the load event has already passed control to the cboFamily_gotfocus event and on from there, before returning to the load event which, to all intents and purposes, was done and dusted.
 
Are you able to post a sample db?
Yes, I can do that but it's a bit complicated. The cboFamily query is fed by the first 5 characters of a possibly mis-spelt family name from a different form. Hence the loop in cboFamily_gotfocus. This reduces the number of characters in the search until a match is found.

Query for cboFamily
Code:
SELECT Taxon.family
FROM Taxon
GROUP BY Taxon.family
HAVING (((Taxon.family) ALike [Forms]![Discrepancies]![txtGetFamily] & "%")) 'This is initially left(string,5)
ORDER BY Taxon.family;

Query for cboGenus
Code:
SELECT Taxon.genus
FROM Taxon
GROUP BY Taxon.family, Taxon.genus
HAVING (((Taxon.family)=[Forms]![getTaxon]![cboFamily]))
ORDER BY Taxon.genus;
 

Attachments

File has only 1 table and no other objects and no code. Possibly need to also provide frontend?
 
File has only 1 table and no other objects and no code. Possibly need to also provide frontend?
I provided all the code in my OP and the two queries in a subsequent post. Not sure what else you need.
My whole system runs to almost 36000 lines of code but what you have should stand alone .
 
I noticed that you were playing with the visibility of some of the controls and you DID say it was a complex sequence of steps. I'm wondering if at the time you wanted to set focus somewhere that the somewhere was not visible.

There is another issue that I'm less sure about, but I'll try to explain ...

Event code cannot interrupt other event code (particularly when all of the events are in the same class module). Event code is single-threaded and runs at non-interrupt priority. It is treated as a subroutine, priority-wise.

When you make a control visible, then set focus to it, and THEN make it not visible again, and you have laid down a linear sequence of visibility code, you are potentially triggering three .GotFocus events and a similar number of .LostFocus events. If you have any event code potentially running under those events for the affected controls, you have queued up a bunch of events to be run, each in turn. I would HOPE they are executed in the right order, but NONE of them will execute until that triggering routine does an EXIT SUB or END SUB depending on how you want to get out of there.
 
I noticed that you were playing with the visibility of some of the controls and you DID say it was a complex sequence of steps. I'm wondering if at the time you wanted to set focus somewhere that the somewhere was not visible.

There is another issue that I'm less sure about, but I'll try to explain ...

Event code cannot interrupt other event code (particularly when all of the events are in the same class module). Event code is single-threaded and runs at non-interrupt priority. It is treated as a subroutine, priority-wise.

When you make a control visible, then set focus to it, and THEN make it not visible again, and you have laid down a linear sequence of visibility code, you are potentially triggering three .GotFocus events and a similar number of .LostFocus events. If you have any event code potentially running under those events for the affected controls, you have queued up a bunch of events to be run, each in turn. I would HOPE they are executed in the right order, but NONE of them will execute until that triggering routine does an EXIT SUB or END SUB depending on how you want to get out of there.
Hi Docman
The hidden controls do not become visible until after the genus has been selected, which is after the error occurs, so there "shouldn't" be any interruption to the flow. I'm working on a stand alone version of the form and will post that asap. There will be a few work arounds, particularly with the first query. I'll try and post that sometime today.
the initial visibilty is set up in the load event and not changed until the cboGenus_afterupdate event is triggered.
 
Here is a stand alone version of the form.
I have added the textbox "txtInput" to simulate the input from a previous form with a spelling mistake.
Open the form "getTaxon" and you will see the error.
 

Attachments

I don't understand calling AfterUpdate event from GotFocus. Comment out that line in cboFamily_GotFocus and the error does not occur.

When I first started testing, code was bugging on Me.cboFamily.SetFocus in Load event. Now it is bugging on Me.cboGenus.SetFocus in cboFamily_AfterUpdate unless I comment the call to AfterUpdate.
 
I don't understand calling AfterUpdate event from GotFocus. Comment out that line in cboFamily_GotFocus and the error does not occur.

When I first started testing, code was bugging on Me.cboFamily.SetFocus in Load event. Now it is bugging on Me.cboGenus.SetFocus in cboFamily_AfterUpdate unless I comment the call to AfterUpdate.
Calling afterupdate happens if there is only one result from the requery, otherwise the dropdown occurs.
Commenting out that call does stop the error but the rest of the program does not run properly.
The result of the requery does not appear in the cboGenus combo and the change over from combo's to textboxes leaves the family box empty.
I have used this construct many times in the past as a way to eliminate keystrokes and have never had this sort of a problem.

I am, by no means, an expert on Access, so is there some obscure thing in the afterupdate event that can lead to this?
It also seems that the previous events are not closing after passing control to the next event. I.e. calling the cbogenus_Afterupdate causes the cboFamily_Afterupdate event to re-trigger at the last command, likewise the cboFamily_afterupdate, via the sequence previously described, re-triggers the load event at the last command

My other question is, if I can set focus to a control that already has focus why is it causing a problem in this instance and the control in question does not have focus to start with.
If I put a couple of "on error resume next" lines in the code it work seamlessly, but I would much prefer to find the root cause of the error.

I thank you for your input.
John

Ps. I am using Office Professional Plus 2021.
 
If I put a couple of "on error resume next" lines in the code it work seamlessly, but I would much prefer to find the root cause of the error.

Which is why you DON'T use "On Error Resume Next" except when you KNOW you are going to suppress everything. Normally you NEVER use that construct. Because until it is debugged, you want to see every error. And AFTER it is debugged, you STILL want to see any error (that you didn't realize you had missed.) But if you fixed everything properly, you WON'T see any errors because you either have avoided them or set up error handlers to properly handle them.

I am, by no means, an expert on Access, so is there some obscure thing in the afterupdate event that can lead to this?
It also seems that the previous events are not closing after passing control to the next event. I.e. calling the cbogenus_Afterupdate causes the cboFamily_Afterupdate event to re-trigger at the last command, likewise the cboFamily_afterupdate, via the sequence previously described, re-triggers the load event at the last command

If you CALL an event routine (which IS legal), you haven't finished the calling routine yet. If there was more code after that call before the event routine's END SUB/EXIT SUB, it gets done ONLY after the return from the called event. Calling an event routine from another event routine ALSO means you haven't released the event you were processing before the call. Anything that was in the event queue is still waiting.

And, in fact, anything that Access itself (more properly, MSACCESS.EXE) wanted to do as part of the routine is ALSO on hold. Further, your call to an AfterUpdate event COULD trigger another update if your code dirties the form that you just updated. Which, if the AfterUpdate event dirties the form AGAIN, ... here we go round the mulberry bush.

Event loops are NO FUN. Takes a CTRL/PAUSE to stop it and probably will require manual termination. But you haven't mentioned THAT particular foible yet, so maybe you have avoided it. Just understand that there is something not quite kosher in directly calling event code. The usual approach is that you split out the code that you wanted to run and make it a public or private entry point in a general or class module, the exact combination being a matter of practicality based on your needs. But you call the separate code from where you need it, more than one polace if that is appropriate. You DON'T want it in any event that potentially could trigger the aforementioned event loop, and directly calling event code risks that, depending on the specific event.
 
In addition to the fact that you can't set the focus to controls where enabled=false or visible=false, it's also possible that your requerying/rowsource stuff is producing an error which makes something else invisible per your if/end if code.

Regardless, this is exactly the type of thing that stepping through the code in Break mode using F8 should reveal the exact state of affairs.

Take time to do this debugging, and while the code is in Break mode on a given line - but BEFORE the error occurs - ask the immediate window a bunch of relevant questions, like ?formname.controlname.enabled [hit Enter] or ?formname.controlname.visible

This last bit is just my personal opinion, so don't everybody jump on me - but I prefer to specify even in cases where something has a default property. I.E. instead of coding Me.txtbox = Me.combobox, use the .Value property appropriately.
I have a very specific reason for this - it's because over the years I've noticed that people who are newer to the game, if they omit the explicit property .value, they avoid learning what is really going on - which then will make a difference some day, (like when you have to differentiate between .value and .text), or just for readability
 
I won't jump on your style, Isaac. You are a belt-and-suspenders man. I can touch-type pretty well but I avoid .Value for controls and .Controls for forms and .Fields for Recordsets because they are the defaults and I am not against short-cuts.
 
I write
Code:
ASC
after an Order By clause, too. My coworker does too and he's much more of a SQL expert than I.

I dunno, just something about explicit vs. having to remember the defaults - I guess you could say it's a shortcut while you're typing it, but not thereafter while having to read it. But I'm nitpicking now - I do see what you mean. I shouldn't fault a guy for taking a decent shortcut :)

My typing skill also makes me tend toward verboseness, because it costs me nothing. I should remember that probably factors in. :)
 
Another reason I avoid certain defaults is because they always tempt me to go wrong. For instance the .Fields collection, like ALL Access collections, allows me to name something ( x.Fields("Quantity" ) or identify something by an index ( x.Fields( 4 ) ) when all I really wanted was X.Quantity or (at worst) X![Quantity]
 
But you call the separate code from where you need it, more than one polace if that is appropriate. You DON'T want it in any event that potentially could trigger the aforementioned event loop, and directly calling event code risks that, depending on the specific event.
If I'm understanding you, I need a call to a sub / function that in turn calls the afterupdate event.
If so, should the sub be private in the same procedure or public in a module with reference to the form?
I have implemented this, below, and the load event error has gone but the error in cboFamily_AfterUpdate event error persists.
I even included "if cbogenus.visible = true then me.cbogenus.setfous" just to ensure the combo was available.
I also changed the order of things n cbofamily_gotfocus

Code:
Private Sub cboGenus_GotFocus()
    Me.cboGenus = Me.cboGenus.ItemData(0)
    If Nz(Me.cboGenus.ItemData(1), "") > "" Then
        Me.cboGenus.Dropdown
    Else
       GoUpdateGenus
    End If
End Sub

Private Sub GoUpdateGenus()
    cboGenus_AfterUpdate
End Sub

Private Sub cboFamily_GotFocus()
    Do
        If Nz(Me.cboFamily.ItemData(0), "") = "" Then
            Me.txtInput = Left(Me.txtInput, Len(Me.txtInput) - 1)
            Me.cboFamily.Requery
        End If
    Loop While Nz(Me.cboFamily.ItemData(0), "") = ""
    Me.cboFamily = Me.cboFamily.ItemData(0)
    If Nz(Me.cboFamily.ItemData(1), "") > "" Then    'This was = "" so the dropdown command was after else
        Me.cboFamily.Dropdown
    Else
        GoUpdateFamily
    End If
End Sub

Private Sub GoUpdateFamily()
    cboFamily_AfterUpdate
End Sub
 
Another reason I avoid certain defaults is because they always tempt me to go wrong. For instance the .Fields collection, like ALL Access collections, allows me to name something ( x.Fields("Quantity" ) or identify something by an index ( x.Fields( 4 ) ) when all I really wanted was X.Quantity or (at worst) X![Quantity]
I never thought about it that way before, fair point
 

Users who are viewing this thread

Back
Top Bottom