I have 160 variables named resq1, resq2, ..., resq160. Values for these are assigned manually. I would like to check if values are assigned to all of them. Is it possible to loop through values of multiple variables.
There are examples of how to create multiple variables with dynamic names, but I was unable to find solution for this problem.
This doesn't work
Dim cond As Boolean = True
Dim resq(160) As String
Dim i As Integer
For i = 1 To 160
If resq(i) = "" Then
cond = False
End If
Next
Thanks
Edit2: For the example code you are creating the values incorrectly, You would proceed as this:
Dim resq(10) As String 'Set the array
Dim cond As Boolean = True
resq(0) = 12
resq(1) = 10
resq(2) = 7
For Each item As String In resq
If item <> Nothing Then
'Do something with your data here
Else
cond = False
End If
Next
If cond = True Then
'Do something when all variables have values
Else
'Do something when not all variables have values
End If
Remeber that resq1 is NOT the same as resq(1), The first is a seperate variable and the 2nd is the first instance of the array called resq.
Edit: To check that all the variables have an initial value you can use this code (also slightly improved since the previous code would not go through all the variables you have set):
Dim cond As Boolean = True
Dim resq(160) As String
For Each item As String In resq
If item = Nothing And item <> "" Then
cond = False
End If
Next
If you want it to also check if the value is "" you can remove the 2nd part of the if statement and just use:
Dim cond As Boolean = True
Dim resq(160) As String
For Each item As String In resq
If item = Nothing Then
cond = False
End If
Next
Related
I'm trying to mix a column on a datagridview with 2 control types (Checkbox & TextBox), the data is coming from a Stored Procedure that I'm also writing so I have a little flexibility.
in the stored procedure I'm returning a blank column to act as a Selection column in the GridView, but I am encountering problems when trying to convert cells to the other type based on criteria......
I keep the problem is with the datatypes when converting between the control types, I have tried all sorts of different ways to convert value first, controls first, etc but nothing is working 100%.....
currently, I have the SP returning the string False in a column then in using this with the criteria to create a checkbox..... it works fine but the Value remains a string even after converting it to a Boolean, the datatype is also a Boolean on the checkbox but the value is String..... this has gone over my head now and I'm at a loss......
NewCntrl2 = New DataGridViewCheckBoxCell
NewCntrl2.Value = Convert.ToBoolean(DGV.Cells(0).Value)
NewCntrl2.ValueType = GetType(System.Boolean)
DGV.Cells(0) = NewCntrl2
this is the code converting the textbox-column cell to a checkbox cell
any ideas why the value of the checkbox is still a string ('False')...
the problem with what it's doing now is when I handle the cell click event I cannot check or uncheck the box using the Not Value technique
----EDIT----
This is the sub I'm using, it creates several different types of controls.
Public Sub posted_CreateControls()
Dim Cell_0 As String
Dim Cell_1 As String
Dim Cell_2 As String
Dim NewCntrl As DataGridViewButtonCell
Dim NewCntrl2 As DataGridViewCheckBoxCell
For Each Rw As DataGridViewRow In dgvPosted.Rows
With Rw
Cell_0 = .Cells(1).Value.ToString
Cell_1 = .Cells(2).Value.ToString
Cell_2 = .Cells(3).Value.ToString
'this column starts with a value 'False' returned by the SP,
'we don't want checkboxes on all rows and using false string was the only method
'i could find to easily do this
'if both assign and unassign id are present then we need a checkbox
Select Case Cell_0
Case String.Empty
.Cells(0).Value = String.Empty
Case Else
If Not Cell_1 = String.Empty Then
NewCntrl2 = New DataGridViewCheckBoxCell
NewCntrl2.Value = Convert.ToBoolean(.Cells(0).Value)
NewCntrl2.ValueType = GetType(System.Boolean)
.Cells(0) = NewCntrl2
Else
.Cells(0).Value = String.Empty
End If
End Select
'Create an Assign button for each row in columnindex 0(Assign) if ColumnIndex(2)(Edit) contains M, L or I
Select Case Cell_2
Case "M", "L", "I", "P"
NewCntrl = New DataGridViewButtonCell
.Cells(1) = NewCntrl
NewCntrl.Tag = Cell_0
NewCntrl.Value = "Assign"
End Select
'Create an UnAssign button in columnindex 1(UnAssign) if the value of columnindex 1(Unassign) is not empty
If Not Cell_1 = vbNullString Then
NewCntrl = New DataGridViewButtonCell
.Cells(2) = NewCntrl
NewCntrl.Tag = Cell_1
NewCntrl.Value = "UnAssign"
End If
'Create an Edit button on columnindex 2(Edit) if ColumnIndex 2(Edit) is not M, L or empty string
Select Case Cell_2
Case "M", "L", "P", vbNullString
'Do Nothing
Case Else
NewCntrl = New DataGridViewButtonCell
.Cells(3) = NewCntrl
NewCntrl.Tag = Cell_2
NewCntrl.Value = "Edit"
End Select
End With
Next
NewCntrl = Nothing
End Sub
This creates the checkboxes how I want them but the values remain as a string that is causing the cell. Click event to fail because I'm trying to set the checkbox value to true and the .value = not .value part is failing because for some reason the value remains a string but the checkboxes value type is in fact Boolean.....
Instead of returning false try returning:
`select CAST(0 as bit) as somefield`
Which will return a boolean field. I'd also recommend adding a check box column instead of adding the individual cells.
For example cell "A1" is linked to cell "B1", so in formula bar for cell "A1" we have:
=B1
How can I check whether value in cell "A1" contains letter B?
I tried the following:
Dim Criteria_3 As Boolean
Dim Value As Range
Set Value = Selection
Dim x As Variant
Set x = Cells
Dim text As String
For Each x In Value
If IsNumeric(x) Then
Criteria_3 = VBA.InStr(1, x.Formula, text) > 0
As soon as value of "Text" is "" it does not work and I really struggle to fined the right solution.
your question is not really conclusive, so here are two options:
To check wheter the value contains B:
blnCheck = 0 < InStr(1, rngCell.Value, "B")
To check wheter the Formula contains B:
blnCheck = 0 < InStr(1, rngCell.Formula, "B")
Regarding your null string problem:
As soon as value of "Text" is "" it does not work and I really struggle to fined the right solution.
That's because you're using VBA.InStr(1, x.Formula, text) and in this case 1 is an invalid index on a string of length 0. You can omit that, or you can code around it like:
If Len(Trim(x.Formula)) = 0 Then
'## Do nothing
Else
Criteria_3 = VBA.InStr(1, x.Formula, text) > 0
End If
To your specific question of identifying when a value contains any alpha character(s):
You can use a function like this to test whether a value contains any letter, by evaluating the Ascii code for each character, and break when True:
Function ContainsAnyLetter(val) As Boolean
Dim ret As Boolean
Dim str$, ch$
Dim i As Long
str = LCase(CStr(val))
For i = 1 To Len(str)
ch = Mid(str, i, 1)
If 97 <= Asc(ch) And Asc(ch) <= 122 Then
ret = True
Exit For
End If
Next
ContainsAnyLetter = ret
End Function
In your code, you could call it like:
Criteria_3 = ContainsAnyLetter(x.Value) '## or x.Formula, depending on your needs
You can use LIKE
https://msdn.microsoft.com/en-us/library/swf8kaxw.aspx
Something like if rngCell.value like "*B*" then
if your goal is to check whether the cell contains any valid range reference, then you could go like this
Option Explicit
Sub main()
Dim cell As Range
For Each cell In Worksheets("Sheet001").Range("A1:A20") '<== jus a test range, set it as per your needs
MsgBox IsCellReference(cell.Formula)
Next cell
End Sub
Function IsCellReference(text As String) As Boolean
On Error Resume Next
IsCellReference = Not Range(Replace(text, "=", "")) Is Nothing
End Function
I have an Excel VBA UserForm Combobox for scanning asset tags to compare against a site baseline held in Sheet1. There can be upto 50,000+ assets. The named ranges are all correct.
I want the loop to fill the "Found" Asset attribute Textboxes for Type, Serial, MakeModel, Location & PrinterHost.
The code is below without the additional index match lookups for extra asset attributes as the process will be the same. Help appreciated as I'm not sure where I'm going wrong. Thanks in advance.
Private Sub ComboScanTag_Change()
Dim x As Integer
Dim AssetCount As Long
Dim BASELINE As Range
Dim AssetID As Range
Dim FoundType As Variant
Dim FoundSerial As Variant
Dim FoundMakeModel As Variant
Dim FoundLocation As Variant
Dim FoundPrinterHostName As Variant
If Me.ComboScanTag.Value = "" Then 'ScanTag has no value
MsgBox "Asset not Found - Re-Scan or enter New Asset details"
Me.ComboScanTag.SetFocus
End If
If Me.ComboScanTag.Value <> "" Then 'ScanTag has a value
Application.ScreenUpdating = False 'Turn off screen updating to speed app
For x = 1 To AssetCount 'Number of loop iterations from Baseline Assets Count D1 cell
FoundType = Application.Index("BASELINE", Application.Match(Me.ComboScanTag.Value, "AssetID", False), 3)
If Not IsError(FoundType) = False Then 'if error value in lookup return 0
Me.txtFoundType.Value = FoundType 'Fill textbox FoundType with lookup value from baseline
Else
On Error GoTo 0 'reset error handler
FoundSerial = Application.Index("BASELINE", Application.Match(Me.ComboScanTag.Value, "AssetID", False), 11)
If Not IsError(FoundSerial) = False Then
Me.txtFoundSerial.Value = FoundSerial
End If
Next x
End If
Application.ScreenUpdating = True
End Sub
AssetCount is not initialized. You need to initialize it before you use it like AssetCount = 10.
BASELINE and AssetID are not set as well.
If BASELINE and AssetID are named ranges, you cannot use it the way you do in Application.Index or Application.Match.
You need to pass it as object and not as string like this:
Set BASELINE = ThisWorkbook.Names("BASELINE").RefersToRange
Set AssetID = ThisWorkbook.Names("AssetID").RefersToRange
Then you can use it like this in Application.Index and Match:
With Application
FoundType = .Index(BASELINE, .Match(Me.ComboScanTag.Value, AssetID, False), 3)
End With
I am running a query using a regular expression function on a field where a row may contain one or more matches but I cannot get Access to return any matches except either the first one of the collection or the last one (appears random to me).
Sample Data:
tbl_1 (queried table)
row_1 abc1234567890 some text
row_2 abc1234567890 abc3459998887 some text
row_3 abc9991234567 abc8883456789 abc7778888664 some text
tbl_2 (currently returned results)
row_1 abc1234567890
row_2 abc1234567890
row_3 abc7778888664
tbl_2 (ideal returned results)
row_1 abc1234567890
row_2 abc1234567890
row_3 abc3459998887
row_4 abc9991234567
row_5 abc8883456789
row_6 abc7778888664
Here is my Access VBA code:
Public Function OrderMatch(field As String)
Dim regx As New RegExp
Dim foundMatches As MatchCollection
Dim foundMatch As match
regx.IgnoreCase = True
regx.Global = True
regx.Multiline = True
regx.Pattern = "\b[A-Za-z]{2,3}\d{10,12}\b"
Set foundMatches = regx.Execute(field)
If regx.Test(field) Then
For Each foundMatch In foundMatches
OrderMatch = foundMatch.Value
Next
End If
End Function
My SQL code:
SELECT OrderMatch([tbl_1]![Field1]) AS Order INTO tbl_2
FROM tbl_1
WHERE OrderMatch([tbl_1]![Field1])<>False;
I'm not sure if I have my regex pattern wrong, my VBA code wrong, or my SQL code wrong.
Seems you intend to split out multiple text matches from a field in tbl_1 and store each of those matches as a separate row in tbl_2. Doing that with an Access query is not easy. Consider a VBA procedure instead. Using your sample data in Access 2007, this procedure stores what you asked for in tbl_2 (in a text field named Order).
Public Sub ParseAndStoreOrders()
Dim rsSrc As DAO.Recordset
Dim rsDst As DAO.Recordset
Dim db As DAO.database
Dim regx As Object ' RegExp
Dim foundMatches As Object ' MatchCollection
Dim foundMatch As Object ' Match
Set regx = CreateObject("VBScript.RegExp")
regx.IgnoreCase = True
regx.Global = True
regx.Multiline = True
regx.pattern = "\b[a-z]{2,3}\d{10,12}\b"
Set db = CurrentDb
Set rsSrc = db.OpenRecordset("tbl_1", dbOpenSnapshot)
Set rsDst = db.OpenRecordset("tbl_2", dbOpenTable, dbAppendOnly)
With rsSrc
Do While Not .EOF
If regx.Test(!field1) Then
Set foundMatches = regx.Execute(!field1)
For Each foundMatch In foundMatches
rsDst.AddNew
rsDst!Order = foundMatch.value
rsDst.Update
Next
End If
.MoveNext
Loop
.Close
End With
Set rsSrc = Nothing
rsDst.Close
Set rsDst = Nothing
Set db = Nothing
Set foundMatch = Nothing
Set foundMatches = Nothing
Set regx = Nothing
End Sub
Paste the code into a standard code module. Then position the cursor within the body of the procedure and press F5 to run it.
This function is only returning one value because that's the way you have set it up with the logic. This will always return the last matching value.
For Each foundMatch In foundMatches
OrderMatch = foundMatch.Value
Next
Even though your function implicitly returns a Variant data type, it's not returning an array because you're not assigning values to an array. Assuming there are 2+ matches, the assignment statement OrderMatch = foundMatch.Value inside the loop will overwrite the first match with the second, the second with the third, etc.
Assuming you want to return an array of matching values:
Dim matchVals() as Variant
Dim m as Long
For Each foundMatch In foundMatches
matchValues(m) = foundMatch.Value
m = m + 1
ReDim Preserve matchValues(m)
Next
OrderMatch = matchValues
This loop
For Each foundMatch In foundMatches
OrderMatch = foundMatch.Value
Next
assigns all the results to the same variable OrderMatch in turn, which always replaces the old value of OrderMatch. Therefore the function will always return the last match.
If you want to return all the values, return an array for instance
Public Function OrderMatch(field As String) As String()
Dim results() As String
Dim i As Long
... get matches
ReDim results(0 To foundMatches.Count - 1) As String
If regx.test(field) Then
For i = 0 To foundMatches.Count - 1
results(i) = foundMatches(i).Value
Next
End If
OrderMatch = results
End Function
(I am currently working with Access XP, so I don't know whether the indexes go from 1 to Count or from 0 to Count-1.)
UPDATE
And always specify the return type of functions. This is more informative for people who want to use the function (including you if you have to resuse this function in 6 months) and prevents from supid coding errors. If really Variant is meant, specify ... As Variant so that your intention becomes clear.
I'm writing a script that will count a numbers of days between few separate dates. I have a data in cell like:
1-In Progress#02-ASSIGNED TO TEAM#22/01/2013 14:54:23,4-On
Hold#02-ASSIGNED TO TEAM#18/01/2013 16:02:03,1-In Progress#02-ASSIGNED
TO TEAM#18/01/2013 16:02:03
That's the info about my transaction status. I want to count the numbers of days that this transaction was in "4-On Hold". So in this example it will be between 18/01/2013 and 22/01/2013.
I wrote something like this(sorry for ma native language words in text)
Sub Aktywnywiersz()
Dim wiersz, i, licz As Integer
Dim tekstwsadowy As String
Dim koniectekstu As String
Dim pozostalytekst As String
Dim dataztekstu As Date
Dim status4jest As Boolean
Dim status4byl As Boolean
Dim datarozpoczecia4 As Date
Dim datazakonczenia4 As Date
Dim dniw4 As Long
wiersz = 2 'I start my scrypt from second row of excel
Do Until IsEmpty(Cells(wiersz, "A")) 'this should work until there is any text in a row
status4jest = False 'is status 4-On Hold is now in a Loop
status4byl = False 'is status 4-On Hold was in las loop
dniw4 = 0 ' numbers od days in 4-On Hold status
tekstwsadowy = Cells(wiersz, "H").Value2 'grabing text
tekstwsadowy = dodanieprzecinka(tekstwsadowy) 'in some examples I had to add a coma at the end of text
For i = 1 To Len(tekstwsadowy)
If Right(Left(tekstwsadowy, i), 1) = "," Then licz = licz + 1 'count the number of comas in text that separates the changes in status
Next
For j = 1 To licz
koniectekstu = funkcjaliczeniadni(tekstwsadowy) 'take last record after coma
Cells(wiersz, "k") = koniectekstu
dataztekstu = funkcjadataztekstu(koniectekstu) 'take the date from this record
Cells(wiersz, "m") = dataztekstu
status4jest = funkcjaokreslenia4(koniectekstu) 'check if there is 4-On Hold in record
Cells(wiersz, "n") = status4jest
If (status4byl = False And staus4jest = True) Then
datarozpoczecia4 = dataztekstu
status4byl = True
ElseIf (status4byl = True And staus4jest = False) Then
datazakonczenia4 = dataztekstu
status4byl = False 'if elseif funkcion to check information about 4-On Hold
dniw4 = funkcjaobliczeniadniw4(dniw4, datazakonczenia4, datarozpoczecia4) 'count days in 4-On Hold
Else
'Else not needed...
End If
tekstwsadowy = resztatekstu(tekstwsadowy, koniectekstu) 'remove last record from main text
Next
Cells(wiersz, "L") = dniw4 ' show number of days in 4-On Hold status
wiersz = wiersz + 1
Loop
End Sub
Function funkcjaliczeniadni(tekstwsadowy As String)
Dim a, dl As Integer
dl = Len(tekstwsadowy)
a = 0
On Error GoTo errhandler:
Do Until a > dl
a = Application.WorksheetFunction.Find(",", tekstwsadowy, a + 1)
Loop
funkcjaliczeniadni = tekstwsadowy
Exit Function
errhandler:
funkcjaliczeniadni = Right(tekstwsadowy, dl - a)
End Function
Function dodanieprzecinka(tekstwsadowy As String)
If Right(tekstwsadowy, 1) = "," Then
dodanieprzecinka = Left(tekstwsadowy, Len(tekstwsadowy) - 1)
Else
dodanieprzecinka = tekstwsadowy
End If
End Function
Function resztatekstu(tekstwsadowy, koniectekstu As String)
resztatekstu = Left(tekstwsadowy, Len(tekstwsadowy) - Len(koniectekstu))
End Function
Function funkcjadataztekstu(koniectekstu As String)
funkcjadataztekstu = Right(koniectekstu, 19)
funkcjadataztekstu = Left(funkcjadataztekstu, 10)
End Function
Function funkcjaobliczeniadniw4(dniw4 As Long, datazakonczenia4 As Date, datarozpoczecia4 As Date)
Dim liczbadni As Integer
liczbadni = DateDiff(d, datarozpoczecia4, datazakonczenia4)
funkcjaobliczaniadniw4 = dniw4 + liczbadni
End Function
Function funkcjaokreslenia4(koniectekstu As String)
Dim pierwszyznak As String
pierwszyznak = "4"
If pierszyznak Like Left(koniectekstu, 1) Then
funkcjaokreslenia4 = True
Else
funkcjaokreslenia4 = False
End If
End Function
And for now I get
Run-time error "13"
in
dataztekstu = funkcjadataztekstu(koniectekstu) 'take the date from this record
I would be very grateful for any help.
You are getting that error because of Type Mismatch. dataztekstu is declared as a date and most probably the expression which is being returned by the function funkcjadataztekstu is not a date. You will have to step through it to find what value you are getting in return.
Here is a simple example to replicate that problem
This will give you that error
Option Explicit
Sub Sample()
Dim dt As String
Dim D As Date
dt = "Blah Blah"
D = getdate(dt)
Debug.Print D
End Sub
Function getdate(dd As String)
getdate = dd
End Function
This won't
Option Explicit
Sub Sample()
Dim dt As String
Dim D As Date
dt = "12/12/2014"
D = getdate(dt)
Debug.Print D
End Sub
Function getdate(dd As String)
getdate = dd
End Function
If you change your function to this
Function funkcjadataztekstu(koniectekstu As String)
Dim temp As String
temp = Right(koniectekstu, 19)
temp = Left(temp, 10)
MsgBox temp '<~~ This will tell you if you are getting a valid date in return
funkcjadataztekstu = temp
End Function
Then you can see what that function is returning.
I tried running your code, but it is a little difficult to understand just what it is that you want to do. Part of it is the code in your language, but the code is also hard to read beacuse of the lack of indentation etc. :)
Also, I do not understand how the data in the worksheet looks. I did get it running by guessing, though, and when I did I got the same error you are describing on the second run of the For loop - that was because the koniectekstu string was empty. Not sure if this is your problem, so my solution is a very general.
In order to solve this type of problem:
Use Option Explicit at the top of your code module. This will make you have to declare all variables used in the module, and you will remove many of the problems you have before you run the code. Eg you are declaring a variable status4jest but using a different variable called staus4jest and Excel will not complain unless you use Option Explicit.
Declare return types for your functions.
Format your code so it will be easier to read. Use space before and after statements. Comment everything! You have done some, but make sure a beginner can understand. I will edit you code as an example of indentation.
Debug! Step through your code using F8 and make sure all variables contain what you think they do. You will most likely solve your problem by debugging the code this way.
Ask for help here on specific problems you run into or how to solve specific problems, do not send all the code and ask why it is not working. If you break down your problems into parts and ask separately, you will learn VBA yourself a lot faster.
A specific tip regarding your code: look up the Split function. It can take a string and make an array based on a delimiter - Example: Split(tekstwsadowy, ",") will give you an array of strings, with the text between the commas.
Did I mention Option Explicit? ;)
Anyway, I hope this helps, even if I did not solve the exact error you are getting.