If vbYes = MsgBox("Do you have Federal Employee Health Benefits (FEHBB), such as Blue Cross Blue Shield?", vbYesNo + vbQuestion) Then
End If
If vbYes = MsgBox("Would you like to terminate/suspend your Federal Employee Health Benefits (FEHB) while on orders?", vbYesNo + vbQuestion) Then
FEHBCancel = InputBox("Please initial here to cancel/suspend your FEHB.")
Else
NoFEHB = InputBox("Please initial here indicating that you do not have Federal Employee Health Benefits.")
End If
Above seemed to run through, but the problem I'm running into now is when I ask the first msgbox "Do you have FEHB..." if I select "No", I want it to move on to a new msgbox "please initial here indicating that you do not have...". If the answer is "YES", then I'd like to it go to msgbox "do you want to terminate", another Yes/No msgbox. And from there, potentially another box if they select "no" they don't want to terminate.
Below is some VBA code that shows how this should be done. When doing this sort of thing, it often helps to draw out on a piece of paper the logic process, and when coding the If statements, always indent each nested level to maintain readability.
Sub sMsg()
Dim strTerminate As String, strPayFor As String, strNoFEHBB As String
If vbYes = MsgBox("Do you have FEHBB?", vbYesNo) Then
If vbYes = MsgBox("Do you want to terminate", vbYesNo) Then
strTerminate=InputBox("Please initial to terminate")
Else ' No they don't want to terminate
strPayFor=InputBox("Please initial to pay")
End If
Else ' do not have FEHBB
strNoFEHBB = InputBox("Please initial here")
End If
End Sub
Regards,
Related
I have a database that generates test questions in a random order. When I get the answer form (frmAnswers) to open, all I can do is have it scroll through all the questions using either the Enter or esc keys. I have a MsgBox that pops up just to let me know some of the variables are set properly, but the code will not pause to accept input from the OptionGroup in the form.
Here is what I assume is the relevant code:
Set rsCourse = CurrentDb.OpenRecordset(strCourse)
DoCmd.OpenForm ("frmAnswers")
rcdCnt = 1
While Not rsCourse.EOF
With rsCourse
Screen.ActiveForm.ctlQ_No = rcdCnt
Screen.ActiveForm.ctlQuestion = .Fields("Question")
Screen.ActiveForm.ctlAns_A = .Fields("Ans A")
Screen.ActiveForm.ctlAns_B = .Fields("Ans B")
Screen.ActiveForm.ctlAns_C = .Fields("Ans C")
Screen.ActiveForm.ctlAns_D = .Fields("Ans D")
Forms!frmAnswers!optAnswer.SetFocus
Select Case Forms.frmAnswers.optAnswer
Case Is = 1: strAns = "A"
Case Is = 2: strAns = "B"
Case Is = 3: strAns = "C"
Case Is = 4: strAns = "D"
Case Is = Null: srtAns = "Nothing"
End Select
If strAns = .Fields("Correct Answer") Then
Exit Sub
Else
MsgBox "The correct answer is " & .Fields("Correct Answer") _
& Chr(13) & Chr(10) & "You answered " & strAns
End If
End With
rcdCnt = rcdCnt + 1
If rcdCnt > 100 Then
Exit Sub
End If
rsCourse.MoveNext
Wend
I have searched many sites, to include Microsoft, pcreview, accessmvp, etc., and have yet to find anything that helps. I have tried;
Select Case
Case 1
Case 2
Etc.
End Select
as well as the code in my example. Nothing seems to pause the code except the MsgBox.
I have also tried putting this code as a Function:
Call TestClick(strCourse)
With the function:
Function TestClick(strCourse)
with the above code in the function. It returns a compile error: "Object required" at the Set rsCourse line.
I have also tried this as a subroutine with the same error.
For clairification, here is the code I have for the form that calls the frmAnswers Form:
DoCmd.OpenForm ("frmIntroduction_VBA")
If IsNull(Me.cboTrainee_Name) Then ' No Name
MsgBox "You must enter your name to continue!", vbOKOnly ' Tell user
Me.cboTrainee_Name.SetFocus ' Focus the control
Exit Sub ' Exit the method
End If ' End the IsNull test
Trainee_Name = Forms!frmIntroduction_VBA!cboTrainee_Name
If IsNull(Me.cboCourse) Then ' Check if a course is selected
If IsNull(Me.cboVol) Then
MsgBox "You must select either a Course or Volume Review to continue!" ' Tell user
Me.cboCourse.SetFocus
Exit Sub
End If
End If
If IsNull(Me.cboCourse) Then
strCourse = Me.cboVol.Value
Else
strCourse = Me.cboCourse.Value
End If
I would like this to actually call another Sub for the frmAnswers form, but do not know how to pass the rsCourse variable to the Sub.
I am sure this is a fairly easy issue to resolve, but I am no expert by any means. Once I get this problem solved, I will continue on and try to have VBA create a recordset with test results to be appended to an existing table.
Thank you all for any assistance you can provide.
This is just one of a million different ways of doing this. My feelings aren't hurt if other people chime in with other ways. But this solution may be most in-line with the road you're already headed down:
You need a way to pass your strCourse to the form.
-One way would be to declare a String variable strCourse in the frmAnswers class module and set it from the frmIntroduction_VBA after you open frmAnswers.
-Another way would be to create an invisible field on frmAsnwers called strCourse and set it after you open the form with form!frmAnswers!strCourse=strCourse.
-The easiest way I think for you would just be to refer to the frmIntroduction_VBA form from the frmAnswers form. That's what we'll do here.
First things first: Open frmAnswers.
DoCmd.OpenForm("frmAnswers")
Now let's move all the rest of your code into the frmAnswers form itself. Here's the frmAnswers class module:
Option Explicit
'The following will be variables that will persist as long as the form is open
dim rsCourse as Recordset
dim strCourse as String
dim rcdCnt as Long
dim strCorrectAnswer as String
Private Sub Form_Load() 'This basically initializes the variables and loads the first question
If IsNull(Forms!frmIntroduction_VBA!cboCourse) Then
strCourse = Forms!frmIntroduction_VBA!cboVol
Else
strCourse = Forms!frmIntroduction_VBA!cboCourse
End If
Set rsCourse = CurrentDb.OpenRecordset(strCourse)
rcdCnt = 0
LoadNextQuestion
End Sub
Private Sub LoadNextQuestion() 'reusable code to load questions
rcdCnt=rcdCnt+1
If (rcdCnt>100) OR rsCourse.EOF Then
rs.Close
DoCmd.Close acForm, "frmAnswers"
Exit Sub
End If
With rsCourse
ctlQ_No = rcdCnt
ctlQuestion = !Question
ctlAns_A = ![Ans A]
ctlAns_B = ![Ans B]
ctlAns_C = ![Ans C]
ctlAns_D = ![Ans D]
strCorrectAnswer = ![Correct Answer]
optAnswer = Null 'clears previous answer
optAnswer.SetFocus
.MoveNext
End With
End Sub
Private Sub btnSubmit_Click()
Dim strAnswer As String
strAnswer = "Nothing"
Select Case optAnswer
Case 1:
strAnswer = "A"
Case 2:
strAnswer = "B"
Case 3:
strAnswer = "C"
Case 4:
strAnswer = "D"
End Select
If strAns = strCorrectAnswer Then
MsgBox "Correct!"
Else
MsgBox "The correct answer is " & strCorrectAnswer & "." _
& Chr(13) & Chr(10) & "You answered " & strAns &"."
End If
LoadNextQuestion
End Sub
Start with that and play around with it. If you're not sure why I did something a certain or if I missed some fundamental aspect of what you're doing, leave it in a comment and we'll keep refining it.
I am writing this little login validation application as a step of my VBA learning process. The application should check whether the login name is "sa" and the password is "XEL". The application should allow the user to enter the username and password for a maximum of three times. If in the all of the three attempts, a wrong usename and password is entered, the application should display an error and close. And blow is my code:
Private Sub Command6_Click()
Me.Text0.SetFocus
cID = Text0.Text
Me.Text4.SetFocus
cPswd = Text4.Text
For i = 1 To 3
validpswd = False
If cID = "sa" And cPswd = "XEL" Then
validpswd = True
MsgBox "Successful"
Exit For
Else
MsgBox "Try again"
Exit For
End If
Next i
'MsgBox ("byebye")
'DoCmd.Close acForm, "Used Car Sales", acSaveYes
End Sub
Now it does the checking/validating part. But it doesn't do the three times max limitation, I am kind of confused as how to put the last message box code and close command into the whole code blocks. Any helps are appreciated.
Thank you very much.
What I see wrong is you are having them type in the username/password then click a button. That button then checks to see if the username/password matches the predefined values three times in a row. That is a problem because the user wouldn't be able to actually try three times.
To fix it, you create a Module/Form level variable and initialize it in the form load to 0. then you check in the button click if that variable is greater than 2. If it is, then you run your close procedure. If it isnt, then it checks your username and password to see if they are correct, if they aren't then it increments the Module level variable by 1. Example below.
EDIT: added a check since it doesn't quite catch it after the 3rd try. Feels a bit ugly, but it works.
EDIT2: Dyslexia moment, fixed the greater then, less then signs for the if statements and the associated values
Dim Tries as Long
Private Sub Form_Load()
Tries = 0
End Sub
Private Sub Command6_Click()
If Tries < 3 Then
cID = Text0.Text
cPswd = Text4.Text
validpswd = False
If cID = "sa" And cPswd = "XEL" Then
validpswd = True
MsgBox "Successful"
Else
Tries = Tries + 1
If Tries > 2 Then
MsgBox ("byebye")
DoCmd.Close acForm, "Used Car Sales", acSaveYes
else
MsgBox "Try again"
end if
End If
'MsgBox ("byebye")
'DoCmd.Close acForm, "Used Car Sales", acSaveYes
End If
End Sub
Thanks all. This is what I did eventually. I am sure there is other better way to do this and please comment to let me know as well
If try < 3 Then
If cID <> "sa" Or cPswd <> "XEL" Then
try = try + 1
MsgBox "Try again"
Else
MsgBox "Successful"
try = 0
End If
If try = 3 Then
MsgBox ("Too many tries")
DoCmd.Close acForm, "Login Test", acSaveYes
End If
End If
I am trying to use the .FindNext (and .FindPrevious) function on an update form "next button" to find the record that meets certain criteria.
Private Sub NextRecord_Click()
Dim foundmatch As Boolean
For x = 0 To 3 Step 1
With Me.RecordsetClone
.FindNext "[Sensitivity] = " & [TempVars]![AccessLevel] + x
If .NoMatch Then
foundmatch = False
Else
Me.Bookmark = .Bookmark
foundmatch = True
Exit For
End If
End With
Next
If foundmatch = False Then
MsgBox "No More Records"
End If
End Sub
Upon a user entering the database the users accesslevel is assigned to a temp variable (1 to 4), and each project has a sensitivity rating of 1 to 4. The code below was used and worked for both next and previous only in finding records when the sensitivity and accesslevel were equal but not for sensitivities below the users access level which they are qualified to see.
Private Sub PrevRecord_Click()
Dim Stringy As String
Stringy = "[Sensitivity] = " & [txtaccess]
With Me.RecordsetClone
.FindPrevious Stringy
If .NoMatch Then
MsgBox "No More Records"
Else
Me.Bookmark = .Bookmark
End If
End With
End Sub
Note: The form is pulled from a query with Sensitivity one of the fields, and [txtaccess] is a text box on the field with the default value set at [TempVars]![AccessLevel]. I've also tried changing it to:
Stringy = "[Sensitivity] >= " & [txtaccess]
but that doesn't work either
I was able to fix the problem by setting applying a filter for sensitivity on the actual forms On_Load event rather than the command button. It now works using a next record command button added with the default code/settings!
So this code is meant to serve as a simple search system to go to certain records in a recordset. I originally had it so they had to click the btnGoToID button in order to perform the search. I decided to just make it a little more user friendly and make it so the search field listened for the Enter button and that would perform the search as well.
The issue that I am running into when the code gets to strID = Trim(Nz(Me.txtSearch.Value, "")) the value will randomly come back as an empty string even though visually I can see that there is a value in the textbox.
I haven't been able to narrow down any pattern for when this issue occurs. At this point I don't really even know how to troubleshoot this problem, nor the words to search for that could yield any results in Google. All I can say is that it SEEMS like changing between records will affect whether or not the search goes through.
This has always worked up until I put in the txtSearch_KeyPress sub procedure.
'============================================================================
' txtSearch_KeyPress
'============================================================================
Private Sub txtSearch_KeyPress(KeyAscii As Integer)
'If user pressed enter
If KeyAscii = 13 Then
Call btnGoToID_Click
End If
End Sub
'============================================================================
' btnGoToID_Click
'============================================================================
' <<Purpose>>
' Allow the user to search for a specific ID
'============================================================================
Private Sub btnGoToID_Click()
On Error GoTo Err_Handler
Dim rs As Recordset
Dim strID As String
Set rs = Me.RecordsetClone
strID = Trim(Nz(Me.txtSearch.Value, ""))
If (strID <> "") Then
'Go to the ID
rs.FindFirst "ID = '" & strID & "'"
If rs.NoMatch Then
MsgBox "ID does not exist"
Else
'If we have a match, set the record as the current record
Me.Bookmark = rs.Bookmark
End If
Else
MsgBox "Please enter a valid ID.", vbOKOnly, "Invalid ID"
End If
Exit_Handler:
On Error Resume Next
Me.txtSearch.Value = ""
rs.Close
Set rs = Nothing
Exit Sub
Err_Handler:
Call LogError(Err.Number, Err.Description, "txtSearch on " & Me.Name)
Resume Exit_Handler
End Sub
After the conversation in the comments I have narrowed down this question to be a whole lot simpler. This yields an "Invalid use of null" error message even after there are several characters in the text field. Why would that happen, and what can I do to make it pick up the values in the textbox?
'============================================================================
' txtUnitNoToSearch_KeyPress
'============================================================================
Private Sub txtUnitNoToSearch_KeyPress(KeyAscii As Integer)
MsgBox Me.txtUnitNoToSearch
End Sub
I think your problem is related to the fact that a text box has 2 properties, .Value and .Text, which appear similar but behave differently.
While you have an edit in progress in the text box, the changing content is available via the .Text property. However, the content of the .Value property has not yet been updated to match.
After the text box's After Update event, .Value will contain the new content. And if focus has moved away from the text box, its .Text property will no longer even be available.
Sorry, I couldn't think how to explain that better. But I think the situation will be clearer with this KeyPress event procedure:
Private Sub txtUnitNoToSearch_KeyPress(KeyAscii As Integer)
Debug.Print "Text: '" & Me.txtUnitNoToSearch.Text & "'"
Debug.Print "Value: '" & Me.txtUnitNoToSearch.Value & "'"
End Sub
Watch the output from Debug.Print in the Immediate window as you make changes to the context of the text box. (Ctrl+g will open the Immediate window.)
One final point is that just Me.txtUnitNoToSearch gets you its default property which is .Value. Keep that in mind as you work through the rest of your code.
Is it possible to create something like the immediate window on a form?
I've tried sending various updates to a text box, but the update rate on text box seems to be much slower than what you get with Debug.Print to the immediate window.
Would be good to tell the user what operations are currently being carried out whilst they wait for something to be processed (and without skipping some operations because they are processed quicker than the update rate would seemingly allow).
You can set the textbox (or label) text and then call the DoEvents method.
This last call is important because is supossed you are executing a long process and screen will redraw only on idle time.
Alternatively, you can use the status bar to notify your progress:
SysCmd acSysCmdSetStatus, "Doing some long task, please wait..."
'Do your work
SysCmd acSysCmdSetStatus, ""
If you can measure your progress, it's possible to include a progress bar. I.e. processing a recordset:
bk = rs.Bookmark
rs.MoveLast
r = SysCmd(acSysCmdInitMeter, caption, rs.RecordCount)
rs.Bookmark = bk
Do Until rs.EOF
'Do something
i = i + 1
If i Mod 10 = 0 Then 'Do not update the meter for every processed record
SysCmd acSysCmdUpdateMeter, i
End If
rs.MoveNext
Next
SysCmd acSysCmdRemoveMeter
In the past I had tried using a single multi-line Text Box as a scrolling status window but it seemed to be inordinately fussy when it came to the text selection status (.SelText, .SelLength, .SelLength). In the end I just went with five (5) single-line Text Box controls and "scrolled" them myself.
In the following screenshot the Text Box controls are named txtStatus4, txtStatus3, ... txtStatus0 (from top to bottom)
and the code to update that status "window" (actually a Frame control) is
Private Sub UpdateStatus(StatusText As String)
Dim i As Long
For i = 4 To 1 Step -1
Me.Controls("txtStatus" & i).Value = Me.Controls("txtStatus" & i - 1).Value
Next
Me.txtStatus0.Value = StatusText
Me.Repaint
End Sub
Just in case anyone ever looks for this again, there IS a way to do what the OP asked, without multiple textboxes.
Screenshot of solution
On your form, add a textbox. A regular textbox will do. Give it a name, like txtLog. Size it to be big enough to display a bunch of text.
Here's a sub to handle the updating:
Private Sub WriteToLogText(strText As String, Optional blnClear As Boolean = False)
txtLog.SetFocus
If blnClear = True Then
txtLog = strText
Else
txtLog = txtLog.Text & Chr(13) & Chr(10) & strText
End If
End Sub
Then call the sub to write your text:
strMsg = "Warning: Commodity '" & Trim(drs("RawCommodity")) & "' is not mapped."
WriteToLogText strMsg