Excel VBA: Checking to make sure all controls aren't empty - vba

In my program, I have a snippet of code in a userfrom that looks at its own controls and loops through to see if all of them are empty. This is for the purpose of using all of the non-null controls' values as search parameters. They are three list boxes and three combo boxes. If it finds a control that is not empty, it sects the function to false and exits. This is because my search found a criteria it can use. I have it setup thus:
Function IsAllEmpty() As Boolean
'presumes true until we find evidence of a control being not empty
IsAllEmpty = True
'function elsewhere that sets my control background to normal
ClearControlFormatting
Dim ctrl As Control
'checks every control in the form
For Each ctrl In Me.Controls
'that is tagged with "searchme" (there are 6, three listbox, three combobox)
If ctrl.Tag = "SEARCHME" Then
'if the value of the control isn't null or len = 0
If Not IsNull(ctrl) Or Len(ctrl) <> 0 Then
ctrl.BackColor = vbGreen
IsAllEmpty = False 'in my other code, I can continue the search if this is triggered
MsgBox "Everything is good (no sarcasm) on this control!"
Exit Function
Else: MsgBox "EVERYTHING IS EMPTY, CARL. THAT KILLS PEOPLE."
End If
End If
Next
'If something is empty, tell the user to correct it
If IsAllEmpty = True Then
MsgBox "YOU NEED TO FILL OUT YOUR SEARCH, PAUL."
End If
End Function
I have tried various things to get this to work:
nesting the Not IsNull(ctrl) statement the only one in the if, the If Len(ctrl) <> 0 part (IDK WHY)
Removing the Len(ctrl) <> 0 part
Editing both parts of the Or statement to evaluate for ctrl.Value = "" instead
Removed the "SEARCHME" tags from the comboboxes, in case their dynamic values were interfering.
However, every time, I have watched this function highlight all of my controls green, and then proceed to continue attempting a search. (The function call down in the search says if all the cells come back null, exit the sub).
I'm at a loss, and would greatly appreciate the help! Thanks!
P.S.: If it helps, the above code is a modified version of the following, meant to check to see if any empty controls exist at all. When I used this on my controls, it found them all to be empty and worked like designed.
Function CheckForEmpty() As Boolean
CheckForEmpty = True
ClearControlFormatting
Dim ctrl As Control
'Checks each control that needs to be filled for null or 0 length value
'For every one it finds, it marks red
CheckForEmpty = True
For Each ctrl In Me.Controls
If ctrl.Tag = "FILL" Then
If IsNull(ctrl) Or Len(ctrl) = 0 Then
ctrl.BackColor = vbRed
CheckForEmpty = False
End If
End If
Next
'If something is empty, tell the user to correct it
If CheckForEmpty = False Then
MsgBox "Please fill out red boxes!"
End If
End Function

In this line, change to be explicit that you're looking for the value:
If Not IsNull(ctrl) Or Len(ctrl) <> 0 Then
change to:
If (Not IsNull(ctrl.Value)) OR (Len(ctl.Value & "") <> 0) Then
First, I added the .Value qualifier to the control. This is the default property, but sometimes (when assigning to a variant or checking null, for example), it might be checking that the Control itself is null because VBA isn't always smart enough to read your thoughts and you're technically telling it to check the control, and not it's value: be explicit.
Second, I explicitly split the two checks into two separate checks using parentheses. Not sure it's strictly required, but best to be clear and far easier to read and now we don't have to worry about the fact that it maybe was reading the boolean logic incorrectly.
Third, I added a ZLS concatenation to .Value to force it to ZLS if null before checking the length (you get an 'Invalid Use of Null' error if trying to check the Len() of a null value).
As Tom mentions, in this case ctrl will never be null (as it's part of the form's collection, which won't have null references in it), so the whole thing can be simplified to:
If Len(ctrl.Value & "") <> 0 Then 'ctrl has no value entered
Lastly, wrap it up in a Trim() function just in case there's a single (or double, or more) space in there, and you have:
If Len(Trim(ctrl.Value & "")) <> 0 Then 'ctrl has no meaningful value entered

Related

How to access Form.Textbox.Text property when the source query returns no results?

I am making a continuous form for searching that self-updates as the user types in multiple search boxes.
The code works up until the user types in parameters that don't correspond to any records.
The query then can't find anything and I get the error
"Can't use the property or method when the control doesn't have the focus"
I could not figure out what element of the form is doing it. Adding the .SetFocus to the textbox control didn't help.
Any ideas on how to either
Set focus to the textbox again and prevent it from being lost, or
Figure out what is stealing the focus and disable it?
The following sub is called in the textbox_Change sub. I added a workaround.:
Private Sub RefreshTB(textbox As Control)
'This is to prevent Acces from removing trailing spaces
'If the textbox isn't empty and there is a space at the end, don't requery. This preserves trailing spaces as Access trims them on Me.requery
If Len(textbox.Text) <> 0 And InStr(Len(textbox.Text), textbox.Text, " ", vbTextCompare) Then
Exit Sub
End If
'If the last character isn't a space, requery on change to show new results of the query
Me.Requery
'The workaround: If the query returns no results, detect that, warn the user and clear search box. Requery to show some results again.
If DCount("*", "DatasetsFilterQ") = 0 Then
If MsgBox("No results found. The last TextBox you searched in will be cleared.", vbOKOnly, "No Records") = vbOK Then
textbox = ""
Me.Requery
End If
Exit Sub
End If
textbox.SetFocus
textbox.SelStart = Len(Nz(textbox.Text))
End Sub
I tried a filter but ran into the same error when passing .text value to the function.
You can't set SelStart to Null, so avoid that with Nz:
textbox.SelStart = Len(Nz(textbox.Value))

Make Text Box visible with condition

I am new at VBA and I am trying some code and I could not find a solution or where I am doing wrong.
What I want: The combination of two different text boxes make another text box visible(so it starts in useform not visible). With one condition I could do it using select case(LLL) but when I try it with another variant it does not work(XXX). There is no error message, the code runs but does not show the text box.
Sub Visible()
If userform.TextBox5.Value = "XXX" And userform.TextBox10.Value = "245" Then
userform.TextBox1.Visible = True
userform.T_1.Visible = True
Else
GoTo LLL
End If
LLL:
Select Case True
Case userform.TextBox5.Value = "LLL", userform.TextBox10.Value >= "145"
If userform.Option000.Value = True Then
userform.TextBox1.Visible = True
userform.T_1.Visible = True
Else
userform.TextBox1.Visible = False
userform.T_1.Visible = False
End If
End Select
I understand some of your questions I must say that my code is quite big one cause it is linked to SAP in order to get some values from there and due to its size the complete code is splitted in modules and I am only sharing the module where I am facing problems.
There is one case for select case statement cause it was the only way that it worked close for what I need. I have a lot of variables for the fields TextBox5 and TextBox10 the values of these textboxes come from SAP and when I combine them, other Text Boxes shall be visible depending on the variables given. The problem is that for just one combination (this one is the one that I applied the select case statement) I need another variable (option000) so that TextBox1 and T_1 become visible. When I tried to do it only with if statements it did not worked.

Word VBA Font.Hidden property becomes unreadable if selection is in table and selection is big

This is very easy to replicate....Please follow my steps with MS Word.
In a Word file, create a fairly large table (of about five columns and twenty rows). Populate all cells with some junk text.
Or, pick a "good sized" table in a file that you already have.
Select (or "Highlight") a few rows of the table, such as three rows.
Go to the Font section of the Word Ribbon. Notice that the Hidden
property of the selection is showing as "not checked" which means
visible. This is what you expect to see (for now).
Optionally, also go to the Immediate Window of the VB Editor and
type "? Selection.Range.Font.Hidden". Word will respond "0", meaning
the .Hidden property is false. This is another way of verifying what
you saw in Step 2.
Now select an additional few rows of the table. Go to Step 2 and repeat.
By the time your Selection gets up to about 12 rows (your results may vary somewhat), the Hidden checkbox shows a solid block to indicate "mixed hidden-ness", and "? Selection.Range.Font.Hidden" shows 9999999 to indicate 'undefined" state.
WHY does the .Hidden property become unreliable/unreadable when the selection is in a table and the selection is relatively many rows? This does not happen when the Selection in a non-table. This is messing up a program of mine that is otherwise very good.
Thanks to all who puzzled over this bug in MS Word. My workaround is as follows. I make the assumption that the hidden-ness (or other property of the selection like .Font or .Underline) of the the selection is "uniform" ... that I can try to read the property of the first 10 characters rather than the entire selection, and still get the right answer. If you do not know that your entire selection has the same properties as the first 10 characters of your selection, this solution won't help you.
Function DigDeeperInto(fullSelection As Selection) As String
' This returns the truth of the hidden-ness of the *front end* of a Selection.
' This is used because Word sometimes mis-reads the hidden-ness of a whole Selection.
Dim shortRange As Range ' will hold the just the front end of the full Selection
Dim theTruth As String
Set shortRange = fullSelection.Range
shortRange.SetRange Start:=shortRange.Start + 1, End:=shortRange.Start + 10
If shortRange.Font.Hidden = wdUndefined Then theTruth = "UnDef" ' this Function failed
If shortRange.Font.Hidden = 0 Then theTruth = "Visible"
If shortRange.Font.Hidden = -1 Then theTruth = "Hidden"
DigDeeperInto = theTruth
End Function
After selecting a Selection, and assuming that Selection.Font.Hidden will not be reported correctly, I call the DigDeeperInto(Selection) function. It looks at only the first 10 characters and returns a string "Visible", "Hidden", or "UnDef". If it still returns "UnDef" (which does not happen for me, luckily), that would indicate DigDeeperInto() failed to solve the problem.
For what it's worth this is not specific to tables; the exact same thing happens in a document that has 51 blank (but otherwise identical) paragraphs. If you select 50 paragraphs you can get real results for:
?selection.Range.Paragraphs.Count ' just to confirm the selection
?selection.Font.name
?selection.Range.Font.Hidden
BUT as soon as you select the 51st paragraph things lose definition, so to speak.
I imagine that looping over your table row by row (as suggested by #jsotola) would be a good workaround.
To answer the question as to WHY this happens, well the best anyone outside of MS can do (I think) is speculate. If I were to speculate I would suggest that there is some sort of internal limit or limitation when it comes to processing or storing detailed information for so many paragraphs. Is it a bug, I think so (but that is just IMHO).
Function to replace the buggy built-in function
Example of a function that will return True, False or wdUndefined (9999999) depending on whether font is Hidden, Visible or a mixture of Hidden & Visible (i.e. undefined), respectively.
Note that it is entirely possible for wdUndefined to be a valid result as an otherwise visible paragraph may have a single character hidden by font and therefore that paragraph's font would neither be entirely visible, not hidden - so it is 'undefined' - hence wdUndefined is very valid.
Example usage and output:
?selection.Paragraphs.Count
2016
?fontIsHidden '(automatically operates on the active selection)
False
The function:
' Put this code into a STANDARD module
Function fontIsHidden() As Variant ' Variant to return True, False, wdUndefined
Dim paraSelected As Paragraph
Dim NotFirstPara As Boolean
Dim result As String
For Each paraSelected In Selection.Range.Paragraphs
' This could be done with Table.Rows instead of Paragraps
' (but would error if there was no table)
If NotFirstPara Then
If paraSelected.Previous.Range.Font.Hidden <> paraSelected.Range.Font.Hidden Then
result = wdUndefined ' this para is different to the previous paras
Exit For
End If
Else
' Setup for the first paragraph
Select Case paraSelected.Range.Font.Hidden
Case False ' 0
result = False
Case True ' -1
result = True
Case wdUndefined
result = "Undefined" ' some text in the para is visible and some is hidden
End Select
NotFirstPara = True
End If
Next paraSelected
fontIsHidden = result
End Function

why would a boolean revert to an original value?

I know this might be a more of a general question, but I've looked at my code a 100 times and am not sure what's wrong. I set a global flag so that it can be used in different forms of my application.
Dim OverPopulated as Boolean
I have a function where I first set it to FALSE, and after it goes through some validating it gets set to TRUE.
Now i do a bunch of stuff, go through different forms, and the value stays correct the entire time. Basically I need this value for another form, so when I check
if OverPopulated = false then
MsgBox "You Can't do this and that"
exit sub
End if
Then all of the sudden it gets set to FALSE. I've went through every instance of OVERPOPULATED in my application and put a break point to it to make sure that nowhere do i set it to FALSE, except for the one time I set it to FALSE before my validation.
I only have it in 2 other forms in my applications. There is one place where the flag is being run twice through the same statement (just like the one above). The first time it goes through, the value is correct, then it goes through again and the value is set to FALSE.
Any ideas? if this is too vague, please let me know, I'll try to edit it.
EDIT: I deleted a lot of the code but here's how it looks.....
Dim OverPopulated as Boolean
' modular level
Private Sub ValidatePopulation()
Dim admDate as date
OverPopulated = False
admDate = Format(Now(), "mm/dd/yyyy")
Select Case revPURP
Case 0, 1, 2
'Check make sure these fields
'some if statements, checking, validation
Case Else ' no need to do a
End Select
OverPopulated = True 'I MAKE SURE IT GETS HERE and is set to TRUE!!!
End sub
Now, in other functions I used it like this...
If OverPopulated = False Then
If optStat (0).Value = True Or optStat (1).Value = True Then
MsgBox "You are not able to do this”, vbCritical, "Incorrect review status...."
TabPop.Tab = 6
End If
Exit sub
Else
'Proceed with SAVE
End If
So I have this. and I have another statement just like this somewhere else. This one gets hit twice. The first time I go through it line by line and it's FALSE, then the 2nd time around the value is TRUE.
It looks like for some reason the value was getting reset to FALSE. I took out the Dim OverPopulated as Boolean from my form code, and placed it in a GLOBAL module where all the other globals are stored. This seems to have fixed the issue of the value remaining the same while I'm manuevering in the application. Thank you for all your comments.
Global OverPopulated as Boolean

Check the Datagridview is empty in vb.net

I want to check if a DataGridView is empty. If it is empty, then the window should be closed. I used this code, but it throws "NullReferenceException was unhandled". How should I fix it?
If DataGridViewReInfor.CurrentCell.Value Is Nothing Then
Me.Close()
Else
MessageBox.Show("Cell contains a value")
End If
DataGridView is like matrix containing Rows, Columns and Cells. A cell is represented by a specific row in a specific column.
The following, that you have done, is checking whenever a value in a specific cell is null:
If DataGridViewReInfor.CurrentCell.Value Is Nothing Then
Note: Before checking if the Value is Nothing, you need to check if the CurrentCell is Nothing. And this may be the reason you got the exception.
If DataGridViewReInfor.CurrentCell Is Nothing Then
But if you purpose is to check whenever your DataGridView contains rows, you need to ask on the rowcount:
If DataGridViewReInfor.RowCount>0 Then
or Rows.Count
If DataGridViewReInfor.Rows.Count > 0 Then
You get the exception because either a variable or a property of an object you were accessing was Nothing. This is an exception that's trivial to find with a debugger (just hover over your expressions), in this case I'm fairly sure that CurrentCell is Nothing because there is no selection. This is the sort of thing that you should train yourself to check first because few of the common exceptions are actually surprising.
As for checking whether the DataGridView is empty: If there is no IsEmpty property you may have to look at other things. Maybe looking at RowCount and ColumnCount would help here.
You can use DataGridView1.RowCount, but you have to be careful. You have to inactive users can add rows, before and after the check, with this, you are going to delete the rows it has editing.
Example.
DataGridView1.AllowUsersToAdd = false
If DataGridView1.Rows.Count = 0 Then
MsgBox("You should add one row.")
DataGridView1.AllowUserToAddRows = True
Exit Sub
End If
DataGridView1.AllowUserToAddRows = True