Solved

Multiple Timer Events on Form and Default Starting Position in Text Box

Posted on 2014-12-08
43
290 Views
Last Modified: 2014-12-17
This is a two part question regarding a splash screen and subsequent form that opens in my database.

Part One :

I have an initial splash screen that opens with only a tagline displaying, and after a brief interval the tagline becomes hidden and the logo displays.  I am currently using the "OnTimer" event to hide the tag line and display the logo.  The problem is I need another timer that will allow me to display the logo for a brief interval and then open the search form.  So without multiple splash forms I need something that will have the following functionality:

Spash screen opens (when user opens database) and displays the tag line for a brief interval.  When that interval expires the tagline becomes hidden and then displays the logo.  After another brief interval the splash screen closes and the search form opens.


Part Two :

I have a search form with multiple search fields on it.  One of the fields uses the primary key in the event the user knows what they are looking for (which will be often) they simply enter it and go straight to that record.  The default behavior in access seems to be that when a text box gets the focus the cursor displays in the leftmost position which is exactly what I want.  However it only seems to work programatically because when a user clicks on the text box the cursor displays where they clicked even when the text box is blank.

I want the cursor to default to the left position only when the field is blank regardless of how the user got there be it by clicking, tabbing, or programatically.  If that field isn't blank then the entire value should be highlighted when they tab into the field, or are sent there programatcially, but if they click in the text box the cursor should go to the point they clicked.
0
Comment
Question by:yoducati
  • 17
  • 16
  • 8
  • +1
43 Comments
 
LVL 34

Expert Comment

by:PatHartman
Comment Utility
In Access you can set the behavior on entering a field to one of three options.
1. Select entire field
2. Go to start of field
3. Go to end of field

If the field is empty, 1 acts like 2/3

#1 is the default so if you want something different you need to change it.

In A2013, settings can be found at:
File/Access Options/Client Settings/Behavior entering field

In other versions, the first and second step will vary but they all come down to a similar dialog at the end.
0
 

Author Comment

by:yoducati
Comment Utility
So there isn't a way to program the behavior to be different depending on how the user is interacting with the field?  I was thinking there would be a way to use a combination of the on focus and on click events of that field.  Im just not sure how to write it.  Like in the on focus event it would be something like

If Not(isnull) then
highlight the entire entry
else
put the cursor all the way to the left
end if

and in the on click event it would be something like

If not(isnull) then
go to where the user clicked
else
put the cursor all the way to the left
end if

isn't there a way to write that in vba so it would have that behavior?
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
However it only seems to work programatically because when a user clicks on the text box the cursor displays where they clicked even when the text box is blank.

The only time I've ever seen that happen is if there's an input mask in play -- like those for phone numbers or zipcodes.  I avoid those like the plague as they are hell for users.  It's more work, but a better app that fixes user input in the AfterUpdate event than Nazis the UI with input masks.

On the keyboard tab of Options you can select what will happen when the user enters a control for the whole app.  That's the best place to do it.

For your timer, put a hidden control on your form.  On Open, put FALSE in it.  Have your first timer event occur when the timer interval expires and the control value is false.  Have the timer event change the control to TRUE.  Have the timer event do your second event when the timer interval expires and the control value is true.
0
 
LVL 49

Expert Comment

by:Gustav Brock
Comment Utility
Part One: Avoid such gimmicks. Users are impatient by nature ...

/gustav
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
So there isn't a way to program the behavior to be different depending on how the user is interacting with the field?
There is.
There is SelStart and SelLength.
SelStart is where the cursor will be positioned
SelLength is how many characters will be highlighted.

But I think that will be best strictly OnGotFocus.  You're asking for real hell to try to determine the click location on field entry.  It is also unwise to highlight anything.  You are one errant keystroke away from losing data.
0
 

Author Comment

by:yoducati
Comment Utility
There is an input mask on the field.  Sorry I neglected to mention that.  I didn't realize it would affect the behavior of the cursor.  I need the input mask to control how the data is entered in the field but I dont save it in the table.
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
There is an input mask on the field.  Sorry I neglected to mention that.
Before now, you didn't realize the merry hell that a mask can play -- but I guessed correctly that a mask must be in play.
It's the only way a cursor doesn't wind up at the start of an empty control.

I need the input mask to control how the data is entered in the field
You are a lot better off to create an AfterUpdate event with a Select Case True structure in it to 'fix' the user data than to use a mask.  It annoys the user waaaaaaaaaaaaaaaaaaaaaaaaaaay less than a mask, and can condition them to put the data in in the most time-effective way possible.

Here's mine for a telephone number field
Private Sub cboContactNumber_AfterUpdate()
Dim myLength As Integer
Dim theinput As String
theinput = Me.cboContactNumber.Text
myLength = Len(theinput)
Select Case Nz(myLength, 0)
    Case 0
        Exit Sub
    Case 7
        Me.cboContactNumber.Value = "(780) " & Left(theinput, 3) & "-" & Right(theinput, 4)
    Case 8
        Me.cboContactNumber.Value = "(780) " & Left(theinput, 3) & "-" & Right(theinput, 4)
    Case 10
        'MsgBox right(Left(theinput, 7), 3)
        Me.cboContactNumber.Value = "(" & Left(theinput, 3) & ") " & Right(Left(theinput, 6), 3) & "-" & Right(theinput, 4)
    Case 12
        Select Case True
            Case theinput Like "*(*"
                Me.cboContactNumber.Value = Left(theinput, 5) & " " & Right(Left(theinput, 8), 3) & "-" & Right(theinput, 4)
            Case theinput Like "*-*-*"
                Me.cboContactNumber.Value = "(" & Left(theinput, 3) & ") " & Right(Left(theinput, 7), 3) & "-" & Right(theinput, 4)
            Case theinput Like "* * *"
                Me.cboContactNumber.Value = "(" & Left(theinput, 3) & ") " & Right(Left(theinput, 7), 3) & "-" & Right(theinput, 4)
            Case theinput Like "* *-*"
               Me.cboContactNumber.Value = "(" & Left(theinput, 3) & ") " & Right(Left(theinput, 7), 3) & "-" & Right(theinput, 4)
            Case Else
        End Select

    Case 13
        Me.cboContactNumber.Value = "(" & Right(Left(theinput, 4), 3) & ") " & Right(Left(theinput, 8), 3) & "-" & Right(theinput, 4)
    Case 14
        Me.cboContactNumber.Value = "(" & Right(Left(theinput, 4), 3) & ") " & Right(Left(theinput, 9), 3) & "-" & Right(theinput, 4)
    Case Else
        MsgBox "Enter a phone number in a recognizable format" & vbCrLf & "(123) 456-7890" _
        & vbCrLf & "123-456-7890" & vbCrLf & "123 456 7890" & vbCrLf & "456-7890" & vbCrLf & "456 7890"
End Select
End Sub

Open in new window


It doesn't take the user very long to figure out that hammering in the 10 digits without any niceties will get cranked into proper form.  It's the easiest for them -- no persnickety cursor placement, no dashes or brackets to type -- and it comes out right in the end.  It took a bit to work out all the permutations -- but it beats an input mask, hands down, in terms of user experience.
0
 

Author Comment

by:yoducati
Comment Utility
This sounds awesome because user experience is exactly what has prompted me to be concerned about the cursor placement.  The input mask was intended to make it easier also.  I'll have a look at this and see if I can figure it out for my scenario.  I tried the selStart like you were talking about but I think the input mask is keeping that from working too.
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
The input mask was intended to make it easier also
I'm sure somebody at MS thought that too. But the fact that a big blank control with no mask is a large target that can be clicked on anywhere to get to the start of the field, and a field with a mask suddenly becomes something you have to target with great precision once -- or twice usually, because no matter HOW precise your thought you were you never seem to hit start-of-field -- takes any of the intended ease out of the mask.  And you have to roll-you-own system of letting the user SEE that the control they are aiming at is masked.  It's only once you click in it that you get the rude surprise that the cursor is not where you want/need it to be.
0
 

Author Comment

by:yoducati
Comment Utility
Yeah, I hear ya.  Thats why I decided to modify my original method and just go with

OnClick
If Isnull(me.searchbox) then
 selStart = 0
end if

But Im guessing that the mask makes it think its not blank because it doesnt change the behavior at all.  Or is 0 not the correct reference for the start point?  Ideally I'd like to have the mask so the user knows the format and that they don't have to type the "-" but also have it go to the start if they click in it when its blank.
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
isnull isn't really what you want
Nor is onClick

OnGotFocus
 If nz(me.searchbox)="" then
  selStart = 0
 end if


If a user clicks in a control, adds something, rubs it out, and leaves the control -- the control's value is NOT null -- it's ""

What Nz() does is it coerces a Null to something else.
Coerce Null to an empty string for string values
Coerce number data to some value you KNOW can't be correct
Coerce date data to some value that lies outside any possible date range.
Nz() is one of an Access progammers great friends.
You'll miss it on any other platform!
It's much better for testing as the Boolean testing of something = Null is always fraught with unexpected logical consequences, because Null <> Null in logic.
0
 

Author Comment

by:yoducati
Comment Utility
It still has the same behavior. If I click on it when blank even with he above code in the onfocus event it still won't move to the beginning.
0
 
LVL 49

Expert Comment

by:Gustav Brock
Comment Utility
It's the OnClick event to use for this.

/gustav
0
 

Author Comment

by:yoducati
Comment Utility
Tried it there too.  Doesn't work.
0
 
LVL 49

Expert Comment

by:Gustav Brock
Comment Utility
It does otherwise, so perhaps something else is going on ...

/gustav
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
My bad

  If nz(me.searchbox)="" then
      Me.Searchbox.SelStart = 0
  end if
selStart is a property of a textbox or combobox control

Me.SomeControl.SelStart = 0 'beginning of control field
0
 

Author Comment

by:yoducati
Comment Utility
It doesnt work for me.  I created a new blank form with no code.  I put three text boxes on it.  The first text box has the input mask and this code in the onClick event.


If Nz(Me.Text1) = "" Then
SelStart = 0
End If

No change in behavior.  Cursor goes to where the user clicked.
0
 
LVL 49

Expert Comment

by:Gustav Brock
Comment Utility
It should read:

If Nz(Me!Text1) = "" Then
    Me!Text1.SelStart = 0
End If

/gustav
0
 

Author Comment

by:yoducati
Comment Utility
If Nz(Me.Searchbox) = "" Then
      Me.Searchbox.SelStart = 0
  End If

I get runtime error 2185.  It says I can't reference a property or method for a control unless the control has the focus.  I tried it in onGotFocus, and onClick.
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
You, I guess, are missing something of CRITICAL importance going forward.
At the top of EVERY code module ALWAYS have this statement

Option Explicit

It catches many subtle errors.

In this case SelStart = 0 is not what you want.
With option explicit, your code you go BANG! and say
'variable SelStart not declared' and you'd go WTF!

Without it, the complier silently makes this implicit statement
Dim SelStart as Variant

So, your code is really

Dim SelStart as Variant
If Nz(Me.Text1) = "" Then
 SelStart = 0
End If

It's now not a surprise it doesn't work
0
 
LVL 49

Expert Comment

by:Gustav Brock
Comment Utility
OK, then set focus:

If Nz(Me!Searchbox) = "" Then
      Me!Searchbox.SetFocus
      Me!Searchbox.SelStart = 0
End If

/gustav
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 

Author Comment

by:yoducati
Comment Utility
I don't want the focus to be set to that control whenever its blank though.
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
It's a stunned thing :(

Throw this into code
Option Compare Database
Option Explicit

Private Sub Text0_GotFocus()
If Nz(Me.Text0, "") = "" Then
    Me.Text0.SelStart = 0
Else
    MsgBox Nz(Me.Text0, "")
End If
End Sub


and it doesn't work -- until I put a breakpoint on  Me.Text0.SelStart = 0
then it's a miracle! it works.

I'm remembering why I hated input masks :(
0
 
LVL 49

Expert Comment

by:Gustav Brock
Comment Utility
Then why set SelStart? Just move the focus.

If Nz(Me!Searchbox) = "" Then
       Me!SomeOtherTextbox.SetFocus
End If

/gustav
0
 

Author Comment

by:yoducati
Comment Utility
Gustav, I think you are missing the point of the question.  I want the cursor to start at the beginning of the text box when it is blank if the user clicks in the field.  When there is an input mask in the field the cursor goes to where the user clicked making the data entry difficult because they have to manually move the cursor to the beginning.
0
 

Author Comment

by:yoducati
Comment Utility
Nick67, its looking like you are still saying I should stay away from the input mask.  I can see why if its this unreliable.  Seems like an oversight on the part of whoever programmed this feature in access in the first place.  Is there a way to mimick the input mask part in code?  Not so much checking after the fact, but actually manipulate the field as the user is typing?  Lol.  This is way more complicated than it should be for behavior that should be intuitive.
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
Nick67, its looking like you are still saying I should stay away from the input mask.
Yup
I coded this up.
Option Compare Database
Option Explicit

Private Sub Text0_GotFocus()
Dim theMask As String
If Nz(Me.Text0, "") = "" Then
    Me.Text0.SelStart = 0
    theMask = "!\(999"") ""000\-0000;;_"
    Me.Text0.InputMask = theMask
Else
    MsgBox Nz(Me.Text0, "")
End If
End Sub
Private Sub Text0_LostFocus()
 Me.Text0.InputMask = ""
End Sub


No mask on the textbox to start.
Loses the mask when it loses focus.
Set to SelStart off the nose,
Then apply the mask.
Guess where the cursor ends up?
Right where it was clicked.
PITA!

Not so much checking after the fact, but actually manipulate the field as the user is typing?
You thought AfterUpdate validation was tough?
Wait til you start messing the keypress event!
Don't go there.

I rarely say 'impossible'
Not worth the effort to implement -- THAT I say when warranted.

It's warranted.
0
 

Author Comment

by:yoducati
Comment Utility
Lol.  Ok.  Maybe I could just put a label next to the search that says to leave out special characters, and then use your afterUpdate method above to make sure they did?
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
I call this code in AfterUpdate
If it returns true, I throw the focus back to the control with SetFocus

if IllegalUsed(me.somecontrol.value) = true then
     me.SomeControl.setFocus
end if


Public Function IllegalUsed(UserText As String) As Boolean

If Nz(UserText, "") = "" Then Exit Function


Select Case True
    Case UserTextLike "*\*"
        IllegalUsed = True
    Case UserText Like "*/*"
        IllegalUsed = True
    Case UserTextLike "*:*"
        IllegalUsed = True
    Case UserText Like "*" & Chr(13) & "*"
        IllegalUsed = True
    Case UserText Like "*" & Chr(34) & "*"
        IllegalUsed = True
    Case UserText Like "*>*"
        IllegalUsed = True
    Case UserTextLike "*<*"
        IllegalUsed = True
    Case Else
        IllegalUsed = False
        
End Select
       
If IllegalUsed = True Then
    MsgBox "You have used an illegal character (\/:*?" & Chr(34) & "<>) in your text." & vbCrLf & "This will problems." & vbCrLf & "Edit the text to avoid the illegal keystroke.", vbCritical + vbOKOnly + vbMsgBoxSetForeground, "bad file name"
Else
    Exit Function
End If


End Function

Open in new window

0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
This one is used for text that can potentially part of a Windows Path.
The colon can only appear once in a path.
The rest cause grief off the nose.

Alter as your circumstances dictate
0
 

Author Comment

by:yoducati
Comment Utility
Now I am thinking even more "in the weeds".  Is there a way I can use the combination of the two methods to check and see if what the user entered = the format I want it to be?  Rather than type it for them with an input mask, or check for special characters afterwards, can I just say something like :

If me.searchbox.value <> !>99\-LLL\-999999 then
msgbox "you must enter the asset number in the established format"
end if
0
 
LVL 26

Accepted Solution

by:
Nick67 earned 250 total points
Comment Utility
There is, but I am not the guy for you on that.
'Regex VBA' are the Google keywords
Start here
https://www.udemy.com/blog/vba-regex/

Powerful stuff.
Gives me a headache, though.

You may want to give it a go, and then if you can't get it, post a new question -- because RegEx is way beyond the scope of what you first asked here -- and you'll need other eyeballs than mine on regex questions.
0
 
LVL 34

Assisted Solution

by:PatHartman
PatHartman earned 250 total points
Comment Utility
I think the problem comes down to training.  Train the users to tab from field to field rather than clicking around with the mouse.  If they do that, the input masks are more likely to work correctly.  You should still validate in the BeforeUpdate event so you can prevent bad data though by cancelling the event.

If the format is fixed, I would break the mushed field into its component parts.  Concatenating different attributes into a single field simply leads to lots of coding for no value added.  You can concatenate them in the BeforeUpdate event so you don't have to change your schema and you have to populate the unbound fields in the form's Current event so:

Current:
If Me.NewRecord = False Then
    Me.fld1 = Left(somefield, 2)
    Me.fld2 = Mid(somefield, 3, 3)
    Me.fld3 = Right(somefield, 6)
End If
BeforeUpdate
Me.somefield = Me.fld1 & "-" & Me.fld2 & "-" & Me.fld3
0
 
LVL 49

Expert Comment

by:Gustav Brock
Comment Utility
There is too much confusion here:

> I don't want the focus to be set to that control whenever its blank though.

Then:

> I want the cursor to start at the beginning of the text box when it is blank if the user clicks in the field.

It doesn't match.

Further, this code in general does work (I tested once again):

If IsNull(Me.Searchbox) Then
       Me.Searchbox.SelStart = 0
End If

If not, something else beyond what we know about is going on. And no SetFocus is needed as the control has focus when clicked. And this is, of course, with a defined (and permanent) input mask - if no input mask, setting SelStart serves no purpose.

/gustav
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
/gustav

Add an unbound textbox to a form
Give it a telephone number input mask.
Try your damnedest in code to ensure that the cursor will ALWAYS be at the beginning of the textbox when CLICKED ANYWHERE by a user (tab doesn't count) if the box has a null or empty string value.

Nick67
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
/gustav

I am not sure .SelStart will do anything anyway, thinking about it.
The mask is in the control, but no value.
As far as VBA is concerned, the cursor is at 0 since there is not yet any text.

Nick67
0
 
LVL 49

Expert Comment

by:Gustav Brock
Comment Utility
That's how I tested.
Only if I double-click, I can position the cursor away from position 0.
If you don't set SelStart, the cursor will remain where you click for any value including Null.

It works with A2013 and it did with Access 2.0 (just found some old code) so I guess it should work with any version.

/gustav
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
Clearly this is an old grief and not likely to be fixed.
http://support2.microsoft.com/?kbid=268102

MS suggested fix?
Sendkeys "{Home}"

Use of SendKeys & Access with Windows 7+ is not recommended.
The NumLock toggles on each use.
Drives users insane.
0
 

Author Comment

by:yoducati
Comment Utility
Lol.  This is hurting my head now.  The Regex stuff is over my head.  My primary focus is always user experience so I don't mind doing extra programming if it will make even a small thing "the way it should be" for the user.  I always try to the best of my ability to avoid creating situations that I know I wouldn't like as a user only to answer them with "don't do that then" if they do something that gets a response they don't like.  Oddly enough its bothers me more than it does the user and I have yet to be in that situation and not come up with a solution that makes it "right". It kills me that it looks like this will be that situation over something should in my mind be the default behavior.  Access creates these input masks presumably to help the user and they end up being such a pain developers try to program around them to create the interaction they should have by default.

As far as tabbing into the control goes, that is part of the functionality but this particular control is in the header of the form, while the search fields are in the body.  It doesnt really make sense to "tab" into it because its set aside for when you know the item you are searching for.  Its sort of a Go to/search form combination.  I can play around some more with setting the focus on certain events to handle most of the issue.  I keep coming back to not being able to control where the cursor goes when they click on it and have no way to handle that right now other than to tell them "don't do that".

 Im headed home for today so I will play with this some more tomorrow.  Thanks to all of you for the input.
0
 

Author Comment

by:yoducati
Comment Utility
Yeah I had researched the send keys method earlier.  Thats what I had used in my 2003 database and it worked fine.  Thats why I have been killing myself trying to recreate that functionality.  Well the flip side is that the older versions didn't have the built in tabbed navigation controls which make building navigation really slick in 2010 versions so really its a good trade off.
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
@TheHiTechCoach had a solution on a different site
Put a transparent control over the input masked one.
When it gets the focus, throw the focus to the masked one.

That's a kludge, though.

Best not to show the users a mask at all
0
 
LVL 26

Expert Comment

by:Nick67
Comment Utility
really slick in 2010 versions so really its a good trade off.
For me, because I have one huge app, the only good tradeoff was built-in PDF support.
And it wasn't enough to offset the pathetic help system.
The Regex stuff is over my head
I didn't say it was easy :)

But it really is just a way to remove the scutwork of a huge bunch of
If someString like *Something* then...
statements knocked together into a function to return a result and permit you to pass in an easy set of parameters.

You haven't really said what kind of mask you've created, but the AfterUpdate code doesn't necessarily have to be intimidating.  I put the phone number one together as a Select Case as both test and fix together -- and as a result, it's the most complex example I can think of off-hand.  A sequential set of If, thens can do the job, too
0
 

Author Comment

by:yoducati
Comment Utility
Hi guys.  Sorry I let this one slip for a bit.  I have my hands full at work now.  I never got this to work so I'm going to focus on other things in the system for a while.  This one had my attention initially because I assumed it would be simple.  Thanks to everyone for your input.  I think I am actually going to explore the regex stuff if I ever get the time to do so.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

In Debugging – Part 1, you learned the basics of the debugging process. You learned how to avoid bugs, as well as how to utilize the Immediate window in the debugging process. This article takes things to the next level by showing you how you can us…
A simple tool to export all objects of two Access files as text and compare it with Meld, a free diff tool.
Familiarize people with the process of retrieving data from SQL Server using an Access pass-thru query. Microsoft Access is a very powerful client/server development tool. One of the ways that you can retrieve data from a SQL Server is by using a pa…
In Microsoft Access, when working with VBA, learn some techniques for writing readable and easily maintained code.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now