So I am at an internship for school that is having me code a program using VB.NET. One of the forms has three combo boxes that must have a choice selected in each before moving on. If the user missed one of the comboboxes I am trying to bring it to their attention to go back and make a selection before continuing. I have an if statement, which works exactly how I want it to:
If cboYear.SelectedIndex = -1 Then
warningString = warningString + "Year" & vbNewLine & "Vendor" & vbNewLine & "Report"
txtYear.ForeColor = Color.Red
TextBox7.ForeColor = Color.Red
txtReport.ForeColor = Color.Red
MessageBox.Show(warningString)
ElseIf cboVendorName.SelectedIndex = -1 Then
warningString = warningString + "Vendor" + vbNewLine & "Report"
txtYear.ForeColor = Color.Black
TextBox7.ForeColor = Color.Red
txtReport.ForeColor = Color.Red
MessageBox.Show(warningString)
ElseIf cboReport.SelectedIndex = -1 Then
warningString = warningString + "Report" & vbNewLine
txtYear.ForeColor = Color.Black
TextBox7.ForeColor = Color.Black
txtReport.ForeColor = Color.Red
MessageBox.Show(warningString)
Else
Main.Show()
Me.Hide()
End If
(warningString is a generic string that says something like "Please fill in the following:")
So like I said this works exactly how I want it to, and its pretty easy to follow my logic here. My question is how can I make this code more efficient? I have tried arrays to hold combobox selections, and I have tried a for loop and a select case to try and streamline the code to no avail. The array always breaks out and returns a NullReferenceException before it gets to my Select Case or For loop to see if there is a value in the combobox or not.
If there is someone out there who can help walk me through the logic of getting some kind of loop to work for the above, that would be awesome. I'm not asking for working code or anything like that, however if there is a solution to be found and I get there myself I will post it here for future reference for people. Who knows, this might even be the most efficient way already?
Edit: Plutonix has been gracious enough to have offered some comments on my question, and he brought up a point about the if statements not being mutually exclusive. That is because the comboboxes are being populated by datasets, and each CBO in order determines what information from the datasets will populate the next one. So, depending on what year is selected in the 'Year' combobox, determines which vendors populate the 'Vendor' combobox, and that determines which reports are populated in the 'Report' combobox.
Since each test is doing something different a loop would be clumsy. Even if you only enable B once A is validated, you might need to allow for them to UnDo a previous selection. The code can be condensed though:
Dim IsValid As Boolean = True
txtYear.ForeColor = Color.Black
TextBox7.ForeColor = Color.Black
txtReport.ForeColor = Color.Black
If cboYear.SelectedIndex = -1 Then
warningString = warningString & "Year" & vbNewLine & "Vendor" & vbNewLine & "Report"
txtYear.ForeColor = Color.Red
TextBox7.ForeColor = Color.Red
txtReport.ForeColor = Color.Red
IsValid = False
End If
If cboVendorName.Enabled AndAlso cboVendorName.SelectedIndex = -1 Then
warningString = warningString & "Vendor" & vbNewLine & "Report"
TextBox7.ForeColor = Color.Red
txtReport.ForeColor = Color.Red
IsValid = False
End If
If cboReport.Enabled AndAlso cboReport.SelectedIndex = -1 Then
warningString = warningString & "Report" & vbNewLine
txtReport.ForeColor = Color.Red
IsValid = False
End If
' See note
If IsValid = False Then
MessageBox.Show(warningString)
Else
' DONT use default form instances!
Main.Show()
Me.Hide()
End If
The IF changed a bit: I dont know how you tell which ones are active, the code above is using .Enabled to see if each has been set up for use. That way you wont report errors on CBO 2 and 3 when validating #1.
I would make it a function which Returns IsValid and let the calling code manage the forms to show...and dont use default form instances.
Related
I have two forms frmProductCreate and frmColourCreate.
In frmProductCreate I have:
Combobox: colourID
Button: btnColCreate
The idea is that if a user needs to create a new colour, they can click on the create button which opens frmColourCreate, name the new colour and click save button. Which will save the new colour in the colours table (which is the record source for the cbo ColourID in frmProductCreate). Then requery colourID in frmProductCreate and close frmColourCreate.
What I also want this save button to do is after the requery to select the cbo colourID and go to the last created colour. i.e. the last record. I have tried a few codes but failed to make it work. Any help will be greatly appreciated.
Private Sub btnSavecol_Click()
Dim cancel As Integer
If Me.ColName = "" Then
MsgBox "You must enter a Colour Name."
DoCmd.GoToControl "ColName"
cancel = True
Else
If MsgBox("Are you sure you want to create new Colour?", vbYesNo) = vbNo Then
cancel = True
Else
CurrentDb.Execute " INSERT INTO Colours (ColName) VALUES ('" & Me.ColName & "')"
Me.ColName = ""
DoCmd.Close
If CurrentProject.AllForms("frmProductCreate").IsLoaded = False Then
cancel = True
Else
Forms!frmproductCreate!ColourID.Requery
'Forms!frmproductCreate!ColourID.SetFocus
'Forms!frmproductCreate!ColourID.items.Count = -1
'Forms!frmproductCreate!ColourID.Selected(Forms!frmproductCreate!ColourID.Count - 1) = False
'YourListBox.SetFocus
'YourListBox.ListIndex = YourListBox.ListCount - 1
'YourListBox.Selected(YourListBox.ListCount - 1) = False
End If
If CurrentProject.AllForms("frmProductDetails").IsLoaded = False Then
cancel = True
Else
Forms!frmproductDetails!ColourID.Requery
End If
End If
End If
End Sub
Some remarks:
Whatfor is the variable cancel? Because it is not used, I removed it.
I have no really idea whatfor you need Me.ColName = "".
Why do you close the current form so early? I moved DoCmd.Close to the end.
I made your code a bit more readable, by removing 'arrow-code' (those nested IFs).
Finally try this:
Private Sub btnSavecol_Click()
If Me.ColName.Value = "" Then
MsgBox "You must enter a Colour Name."
DoCmd.GoToControl "ColName"
Exit Sub
End If
If MsgBox("Are you sure you want to create new Colour?", vbYesNo) = vbNo Then Exit Sub
CurrentDb.Execute "INSERT INTO Colours (ColName) VALUES ('" & Me.ColName.Value & "')"
If Not CurrentProject.AllForms("frmProductCreate").IsLoaded Then GoTo Done
Forms!frmproductCreate!ColourID.Requery
'This sets the ComboBox 'ColourID' to the new colour:
'Forms!frmproductCreate!ColourID.Value = Me.ColName.Value
'If you use an automatic generated ID in the table 'Colours', then you will have to get that ID from the color and set it to the ComboBox:
Forms!frmproductCreate!ColourID.Value = DLookup("ColID", "Colours", "ColName = '" & Me.ColName.Value & "'")
Me.ColName.Value = ""
If Not CurrentProject.AllForms("frmProductDetails").IsLoaded Then GoTo Done
Forms!frmproductDetails!ColourID.Requery
Done:
DoCmd.Close
End Sub
I've been fighting with this for a while and I'm not getting why the if statement is returning true when one of the AND statements is obviously false.
strtmp = TypeName(ctl) 'Take for instance (and have verified) this returns String type with the value of Label. However the below is returning true in this case.
If (strtmp = "TextBox") And (arControlName(2) = "Desc") And Trim(Me.Controls(ctl.Name).Value & "") = "" Then
'Do some stuff
End If
My problem is the first statement of the if is somehow equating to true OR "And" is not working as I expect "The AND = TRUE if all conditions are TRUE. The AND=FALSE if any of the conditions are FALSE." OR I'm using it wrong?
Perhaps I am simply loosing my marbles as well :)
EDIT: If the statements are broken out into 3 separate If statements (like below), the code works as expected.
If (strtmp = "TextBox") Then
If (arControlName(2) = "Desc") Then
If Trim(Me.Controls(ctl.Name).Value & "") = "" Then
' Set the value and exit loop
End If
End If
End If
Thanks to the help of the comments that got my brain jogging in a different direction, I've determined the problem.
It apparently has something to do with VBA and not liking to execute certain calls in an If Statement It seems to work fine putting the TypeName(ctl) = "TextBox" in the if statement but not the call to Me.Controls(ctl.Name).Value & "".
strctlTypeName = TypeName(ctl)
strctlVal = Trim(Me.Controls(ctl.Name).Value & "")
If ((strctlTypeName = "TextBox") And (arControlName(2) = "Desc")) And strctlVal = "" Then 'And (Trim(Me.Controls(ctl.Name).Value & "") = "") Then
'Set the value and exit inner for loop
End If
I have a form with multiple list boxes and all work fine save 1! This is the only list box whose source is number data-type. I know this shouldn't matter, but what I'm seeing is that for this list box only the variant returned is always 1, and I cannot understand why the others (data-type text) work properly and this one doesn't. All of my Google searches and MSN searches and here on StackOverflow have not helped my specific issue though there's a LOT out there about ListBoxes. Please help!
Edit: Sorry #Mat's Mug...I was hoping that wouldn't be necessary as it's lengthy with all the checking going on, but here's the gist.
For Each ctl In Form.Controls
With ctl
Select Case .ControlType
Case acListBox
If .Visible = True Then
.SetFocus
ItemCount = .ItemsSelected.Count
If .ItemsSelected.Count > 0 Then
For Each varItm In .ItemsSelected
If .Name = "lstRating" Then
sWhereClause = sWhereClause & "ThisRating=" & .ItemData(varItem) & " Or ThatRating = " & .ItemData(varItem)
Else
sWhereClause = sWhereClause & Mid(.Name, 4, Len(.Name)) & " = """ & .ItemData(varItm) & """"
End If
Next varItm
End If
End If
End Select
End With
Next ctl
Note: When .Name = "lstRating" is True is the line where varItem returned is 1 regardless of what is selected. The list box is populated with values from 1 to 5 in 0.5 increments.
Well, I can't believe I was overlooking it for hours...I was using varItem in the offending line when it's defined at varItm, no "e"! TOTALLY an oversight on my part. Thanks all for looking into this!
I am using VBA and SQL to re-query my main form based on criteria entered in several controls on a pop up form. As far as I can tell the code is running correctly, the database is re-queried based on the criteria I enter, but 2 of my controls on my main form show as #Name? or blank after re-querying based on the criteria. Anyone know how I can fix this???
The code that runs the re-query is:
Public Sub SuperFilter()
On Error GoTo Err_AdvancedFilter_Click
Dim strSQL As String
Dim strCallNumber As String
Dim strAsgnTech As String
Dim strClientID As String
Dim strCallGroup As String
Dim strPriority As String
Dim strOpenStatus As String
If IsNull(Forms![frmTips&Tricks].txtCallNumber) = False Then
strCallNumber = " (((CallInfo.CallNumber) = forms![frmTips&Tricks].[txtCallNumber])) and "
Else
strCallNumber = ""
End If
If IsNull(Forms![frmTips&Tricks].cboAsgnTech) = False Then
strAsgnTech = " (((CallInfo.AsgnTech) = forms![frmTips&Tricks].[cboasgntech])) and "
Else
strAsgnTech = ""
End If
If IsNull(Forms![frmTips&Tricks].cboClientID) = False Then
strClientID = " (((CallInfo.ClientID) = forms![frmTips&Tricks].[cboClientID])) and "
Else
strClientID = ""
End If
If IsNull(Forms![frmTips&Tricks].cboCallGroup) = False Then
strCallGroup = " (((CallInfo.AsgnGroup) = forms![frmTips&Tricks].[cboCallGroup])) and "
Else
strCallGroup = ""
End If
If IsNull(Forms![frmTips&Tricks].cboPriority) = False Then
strPriority = " (((CallInfo.Severity) = forms![frmTips&Tricks].[cboPriority])) and "
Else
strPriority = ""
End If
If Forms![frmTips&Tricks].optOpenStatus.Value = 1 Then
strOpenStatus = " (((CallInfo.OpenStatus) = True))"
Else
strOpenStatus = " (((CallInfo.OpenStatus) is not null ))"
End If
strSQL = "SELECT CallInfo.CallNumber, CallInfo.ClientID,* " & _
"FROM dbo_HDTechs INNER JOIN ([User] INNER JOIN CallInfo ON User.ClientID = CallInfo.ClientID) ON dbo_HDTechs.TechName = CallInfo.AsgnTech " & _
"WHERE " & strCallNumber & strAsgnTech & strClientID & strCallGroup & strPriority & strOpenStatus & _
"ORDER BY CallInfo.RcvdDate;"
Form.RecordSource = strSQL
Me.cboCallNumber.RowSource = strSQL
Form.Requery
If Me.RecordsetClone.RecordCount = 0 Then
MsgBox "No Records Found: Try Diferent Criteria."
Form.RecordSource = "qryservicerequestentry"
Me.cboCallNumber.RowSource = "qryservicerequestentry"
Exit Sub
End If
Me.cmdSuperFilterOff.Visible = True
Exit Sub
Exit_cmdAdvancedFilter_Click:
Exit Sub
Err_AdvancedFilter_Click:
MsgBox Err.Description
Resume Exit_cmdAdvancedFilter_Click
End Sub
The first control in question is a combo box that displays the Client Name from the CallInfo form (Main Form).
Control Source: ClientID
And when expanded lists all available clients to select from the Users form (User ID is linked between the User form and CallInfo form).
Row Source: SELECT User.ClientID FROM [User];
After the re-query, this combobox will be blank, sometimes showing #Name? if you click on it.
The second control in question is a text box that shows the Client's phone number.
Control Source: PhoneNo
After the Re-query, this text box always displays #Name?
The third control in question is a text box that displays the clients office location.
Control Source: Location
What really baffles me is that THIS text box displays correctly after the re-query. I don't know why it would display the correct data when the Phone Number text box does not, seeing as they are so similar and work with similar data....
To Compare, the The form record source is normally based on:
SELECT CallInfo.CallNumber, CallInfo.ClientID, CallInfo.RcvdTech, CallInfo.RcvdDate, CallInfo.CloseDate, CallInfo.Classroom, CallInfo.Problem, CallInfo.CurrentStatus, CallInfo.Resolution, CallInfo.Severity, CallInfo.OpenStatus, CallInfo.AsgnTech, dbo_HDTechs.Email, CallInfo.FullName, CallInfo.AsgnGroup, User.Location, User.PhoneNo, CallInfo.OpenStatus
FROM dbo_HDTechs INNER JOIN ([User] INNER JOIN CallInfo ON User.ClientID = CallInfo.ClientID) ON dbo_HDTechs.TechName = CallInfo.AsgnTech
WHERE (((CallInfo.OpenStatus)=True))
ORDER BY CallInfo.RcvdDate;
Just going on what you wrote, I may take a slightly different approach (just personal preference).
I would change all of your 'IsNull' tests to also check for 'Empty'. i.e.
If IsNull(Forms![frmTips&Tricks].cboClientID) = False AND ...cliientID <> ""
Just today I had an issue relating to form references in a query WHERE clause, so I changed to:
strClientID = " (((CallInfo.ClientID) = '" & forms![frmTips&Tricks].[cboClientID] & "')) and"
Add a Debug.Print of your generated SQL, then look at it and try to run that SQL manually
Good Luck,
Wayne
Solved by designating the form in the control source like: CallInfo.ClientID
I still don't know why the Client Office displayed Correctly... Anybody have a hint? :)
TE
I have a little routine that checks for the time input... ie if a user enters "8", it will change this to 08:00 etc etc... works great.
Now I thought I'll be smart and make sure that the user enters a max of 4 number and if not, a msgbox pops up. so far easy enough but how on earth do I take him back to the textbox so he can correct his entry ? I tried .Setfocus but nothing happens ?? any ideas ?
Private Sub ZB_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If Len(ZB) = 2 Then
ZB = ZB & ":00"
ElseIf Len(ZB) = 1 Then
ZB = "0" & ZB & ":00"
ElseIf Len(ZB) = 4 Then
ZB = Left(ZB, 2) & ":" & Right(ZB, 2)
ElseIf Len(ZB) = 3 Then
ZB = Left(ZB, 1) & ":" & Right(ZB, 2)
ElseIf Len(ZB) > 4 Then
MsgBox "What you trying to say ???"
ZB.SetFocus
Else
End If
End Sub
Santosh's suggestion is great for limiting the characters allowed in the TextBox. That alone may resolve this problem. But here is an answer for others who may not be able to use a character limit as readily as you can in this example.
To return focus to the Textbox ZB, do this:
Cancel = True
ZB.Value = vbNullString
ZB.SetFocus
The Cancel = True is the part you're missing. This essentially cancels out the Exit event, then I force the TextBox value to be blank, and then .SetFocus.