This is far beyond my skill set, frankly, I have never done anything like this and don't know if it is possible. The procedure below builds an array based on the values of column B6.
Private Sub dsbPositionBoard_Startup() Handles Me.Startup
'This event runs when the dsbPositionBoard starts. The procedure
'checks for the values in column A of the allPositionsAnualized sheet
'and populates the combobox with those values. If there are no values the box
'is disabled.
Dim xlRng As Excel.Range
Dim strRngArr As String
Dim strChkRange As String
Try
xlWB = CType(Globals.ThisWorkbook.Application.ActiveWorkbook, Excel.Workbook)
xlWS = DirectCast(xlWB.Sheets("allPositionsAnnualized"), Excel.Worksheet)
xlRng = DirectCast(xlWS.Range("B6", xlWS.Range("B6").End(Excel.XlDirection.xlDown)), Excel.Range)
strRngArr = String.Empty
strChkRange = CStr(xlWS.Range("B6").Value)
If (String.IsNullOrEmpty(strChkRange)) Then
cmbSelectPosition.Enabled = False
Else
'Build a string array delimited by commas
For i As Integer = 1 To xlRng.Rows.Count
Dim xlRngCell As Excel.Range = DirectCast(xlRng.Rows(i), Excel.Range)
strRngArr &= DirectCast(xlRngCell.Value.ToString, String) & ","
Next
strRngArr = strRngArr.Remove(strRngArr.Length - 1, 1)
cmbSelectPosition.Items.AddRange(strRngArr.Split(","c))
xlRng = Nothing
xlWS = Nothing
End If
Catch ex As Exception
MsgBox("There no positions available to select", CType(vbOKOnly, MsgBoxStyle), "Empty Selection")
End Try
End Sub
Now, the function below is used to select the value of cell range, pass it to a helper cell (B37) and then select the corresponding sheet. The value that this function passes to the helper cell has an equal value in the array above.
Private Function MoveBtwSheets(range As String) As String
'This function is used to toggle between the position board
'and the employee board. The function is utilized to select
'the employees listed in the position board, click on the radio button
' and open that employees information in the employee board
'#parameter range: Selects the cell with the employee name
Dim xlCalc As Excel.Worksheet
strMessage = "This employee does not exist. Please verify the employee name"
strCaption = "Selection Error"
msgBoxType = MessageBoxIcon.Error
msgBoxBtns = MessageBoxButtons.OK
xlWB = CType(Globals.ThisWorkbook.Application.ActiveWorkbook, Excel.Workbook)
xlCalc = CType(xlWB.Worksheets("calculationSheets"), Excel.Worksheet)
xlWSEE = CType(xlWB.Worksheets("employeeBoard"), Excel.Worksheet)
xlWSPOS = CType(xlWB.Worksheets("positionBoard"), Excel.Worksheet)
Application.ScreenUpdating = False
Try
xlCalc.Range("B36").Value = xlWSPOS.Range(range).Value
With xlWSEE
.Select()
.Range("E37").Select()
End With
Application.ScreenUpdating = True
Catch ex As Exception
MessageBox.Show(strMessage, strCaption, msgBoxBtns, msgBoxType)
End Try
Return ""
End Function
So what I wanted to do add to my function is a way to search my array for the value on B37 and then display that value in the combobox in the first procedure. Basically, instead of me dropping down and selecting the item from the array, function would search the array for me and select that item.
If I am not very clear, I can clarify or post screen shots.
This would be a great time to use LINQ. In your initial method (dsbPositionBoard_Startup()), you can add each string in Column A into a List(Of String). Then you can query the list using the value of B37 as your search parameter.
Declare the list at the top of your class (outside of any methods)
Private _myList As New List(Of String)
Add this code to your first method
strRngArr = strRngArr.Remove(strRngArr.Length - 1, 1)
cmbSelectPosition.Items.AddRange(strRngArr.Split(","c))
_myList.Add(strRngArr.Split(","c))
xlRng = Nothing
xlWS = Nothing
Now add a function along the following lines:
Private Function QueryValues(ByVal myParameter as String) As String
Dim results = From result In _myList Where result = myParameter Select result Distinct
Return results(0)
End Function
Call that function (add some error handling/null reference checks though) with your parameter being the value of cell B37 (or any cell value as string).
Related
I'm working on an application in VBA that takes in information from an excel sheet, populates a dropdown combobox, then based on the selected information from the dropbox, retrieves the full information for matching values. There are 6 dropboxes and I'm looking for a way to find out which dropboxes have a value (not empty) without rewriting dozens of if statements with the same code but different conditions (i.e combo 1 and 3 have values, so the program will only look for the records based on those two selected fields)
I know this can be achieved with re-writing if statements, but I'm hoping there's an easier way that doesn't take hours?
Private Sub Search_Page1_Click()
Dim year As String
Dim location As String
Dim snap As String
Dim city As String
Dim group As String
Dim endyear As String
year = Multipage1.Cmb_Year.Value
location = Multipage1.Cmb_Location.Value
snap = Multipage1.Cmb_Snapshot.Value
city = Multipage1.Cmb_City.Value
group = Multipage1.Cmb_Group.Value
endyear = Multipage1.Cmb_LeaseEnd.Value
If year = Empty And location = Empty And snap = Empty And city = Empty
And group = Empty And endyear = Empty Then
MsgBox ("Please fill in at least one field")
End If
End Sub
If you can work with a Collection of ComboBox controls, then whip up a custom function like and call it like:
Dim populatedBoxes as New Collection
Set populatedBoxes = GetPopulatedThings(Multipage1, "ComboBox")
Dim cb as MSForms.ComboBox
For Each cb in populatedBoxes
MsgBox cb.Value
Next
In your code, you could replace:
If year = Empty And location = Empty And snap = Empty And city = Empty And group = Empty And endyear = Empty Then
With this:
Set populatedBoxes = GetPopulatedThings(Multipage1, "ComboBox")
If populatedBoxes.Count = 0 Then Exit Sub
Here's the function:
Private Function GetPopulatedThings(container As Object, Optional ctrlType As String = "ComboBox") As Collection
Dim c As New Collection
Dim ctrl As MSForms.Control
For Each ctrl In container.Controls
If TypeName(ctrl) = ctrlType Then
Select Case ctrlType
Case "ComboBox"
If ctrl.ListIndex > -1 Then
c.Add ctrl
End If
Case Else
' TBD
' Additional cases will require separate logic...
End Select
End If
Next
Set GetPopulatedThings = c
End Function
I want to get the shape information out of a state (UML Standard Stencil). You can see in the picture the title "Aktiv" and "Eintritt/" etc. I have no clue where to get this as a variable.
Edit:
To make it clear, I don't know how I can get the information out of a UML shape in Visio. Here is an example code:
Private Sub test()
Dim s As Shape
Dim vsoPage As Visio.Page
Dim getStateName As String
'I need the name for example "Aktiv" from the state
'and the name of the "Sub" information as "Eintritt" etc.
Set vsoPage = ThisDocument.Pages(1)
For Each s In vsoPage.Shapes
getStateName = s.????
Next s
End Sub
Okay I found a solution, I don't know if there is a nicer one though.
Private Sub test()
Dim s As Shape
Dim vsoPage As Visio.Page
Dim getStateTitle As String
Dim getStateSubTitle As String
Set vsoPage = ThisDocument.Pages(1)
For Each s In vsoPage.Shapes
If Contains(s) = False Then
'Not a Stateshape
Else
getStateTitle = getStateTitle & s.Shapes.Item(1).Text & vbCrLf
getStateSubTitle = getStateSubTitle & s.Text & vbCrLf
End If
Next s
End Sub
with
Public Function Contains(s As Shape) As Boolean
Dim DummyString As String
On Error GoTo err
Contains = True
DummyString = s.Shapes.Item(1)
Exit Function
err:
Contains = False
End Function
So the state shape contains actually two shapes thus you can get the information from Item 1 or 2.
Trying to search on a ListBox. Specifically, I want to look at an array of items from the Cell, and for each one that matches an entry in the ListBox, I want it to select that List.
I copy-pasted some code that was supposed to let me find a string, but it keeps telling me:
Compile Error: Method or Data Member not found.
Any suggestions?
Relevant Code:
Public local_Target As Range
' local_Target is assigned in the sheet function to pass it here
Private Sub Network_ListBox_Enter()
' Get data in cell (if any)
Dim current_data As String
Dim entries() As String
current_data = local_Target.Value
If current_data = "" Then
Exit Sub
Else
entries = Split(current_data, vbNewLine)
End If
For Each Item In entries
FindMyString Item
Next Item
End Sub
Private Sub UserForm_Terminate()
Dim index As Integer
Dim result As String
' Iterate through the listbox and create the result, then assign to
' Target.value
For index = 0 To Network_ListBox.ListCount - 1
If Network_ListBox.Selected(index) Then
' stuff
If result = "" Then
result = Network_ListBox.List(index)
' ElseIf index = Network_ListBox.ListCount - 1 Then
' result = result + Network_ListBox.List(index)
Else
result = result + vbNewLine + Network_ListBox.List(index)
End If
End If
Next index
local_Target.Value = result
End Sub
Sub FindMyString(ByVal searchString As String)
' Ensure we have a proper string to search for.
If searchString <> "" Then
' Find the item in the list and store the index to the item.
Dim index As Integer
index = Me.Network_ListBox.FindString(searchString)
' Determine if a valid index is returned. Select the item if it is valid.
If index <> -1 Then
Network_ListBox.SetSelected index, True
'Else
' MessageBox.Show ("The search string did not match any items in the ListBox")
End If
End If
End Sub
I checked Intellisense and I don't think that Method is supported in VBA. Other documentations I've found refers to .Net Framework only as well. So maybe, it is not really supported in VBA, but regardless, you can create a function to do just that. Something like below.
Private Function SearchString(mysearch As String, mylist As Variant) As Long
Dim itm As Variant, idx As Long: idx = 0
If IsArray(mylist) Then
For Each itm In mylist
If mysearch = itm Then
SearchString = idx: Exit Function
End If
idx = idx + 1
Next
End If
SearchString = -1
End Function
And you can use it like this:
Private Sub CommandButton1_Click()
Dim i As Long
'do the search
i = SearchString("WhatImSearching", Me.ListBox1.List)
'select the item that match your search
If i <> -1 Then Me.ListBox1.Selected(i) = True
End Sub
I'm not saying that the function I created above is the most efficient way.
That is just an example to give you an idea for a workaround. HTH.
Important: This works in single column ListBox which have a 1D array list. If you need to work on multi-column ListBox, you'll have to tweak the function a little.
I am totally new in VBA and coding in general, am trying to get data from cells from the same workbook (get framework path ...) and then to start application (QTP) and run tests.
I am getting this error when trying to get values entered in excel cells:
Run Time Error '424' object required
I believe I am missing some basic rules but I appreciate your help. Please see below the part of code in question:
Option Explicit
Private Sub RunTest_Click()
Dim envFrmwrkPath As Range
Dim ApplicationName As Range
Dim TestIterationName As Range
'Dim wb As Workbook
'Dim Batch1 As Worksheets
Dim objEnvVarXML, objfso, app As Object
Dim i, Msgarea
Set envFrmwrkPath = ActiveSheet.Range("D6").Value ' error displayed here
Set ApplicationName = ActiveSheet.Range("D4").Value
Set TestIterationName = ActiveSheet.Range("D8").Value
The first code line, Option Explicit means (in simple terms) that all of your variables have to be explicitly declared by Dim statements. They can be any type, including object, integer, string, or even a variant.
This line: Dim envFrmwrkPath As Range is declaring the variable envFrmwrkPath of type Range. This means that you can only set it to a range.
This line: Set envFrmwrkPath = ActiveSheet.Range("D6").Value is attempting to set the Range type variable to a specific Value that is in cell D6. This could be a integer or a string for example (depends on what you have in that cell) but it's not a range.
I'm assuming you want the value stored in a variable. Try something like this:
Dim MyVariableName As Integer
MyVariableName = ActiveSheet.Range("D6").Value
This assumes you have a number (like 5) in cell D6. Now your variable will have the value.
For simplicity sake of learning, you can remove or comment out the Option Explicit line and VBA will try to determine the type of variables at run time.
Try this to get through this part of your code
Dim envFrmwrkPath As String
Dim ApplicationName As String
Dim TestIterationName As String
Simply remove the .value from your code.
Set envFrmwrkPath = ActiveSheet.Range("D6").Value
instead of this, use:
Set envFrmwrkPath = ActiveSheet.Range("D6")
You have two options,
-If you want the value:
Dim MyValue as Variant ' or string/date/long/...
MyValue = ThisWorkbook.Sheets(1).Range("A1").Value
-if you want the cell object:
Dim oCell as Range ' or object (but then you'll miss out on intellisense), and both can also contain more than one cell.
Set oCell = ThisWorkbook.Sheets(1).Range("A1")
Private Sub CommandButton1_Click()
Workbooks("Textfile_Receiving").Sheets("menu").Range("g1").Value = PROV.Text
Workbooks("Textfile_Receiving").Sheets("menu").Range("g2").Value = MUN.Text
Workbooks("Textfile_Receiving").Sheets("menu").Range("g3").Value = CAT.Text
Workbooks("Textfile_Receiving").Sheets("menu").Range("g4").Value = Label5.Caption
Me.Hide
Run "filename"
End Sub
Private Sub MUN_Change()
Dim r As Integer
r = 2
While Range("m" & CStr(r)).Value <> ""
If Range("m" & CStr(r)).Value = MUN.Text Then
Label5.Caption = Range("n" & CStr(r)).Value
End If
r = r + 1
Wend
End Sub
Private Sub PROV_Change()
If PROV.Text = "LAGUNA" Then
MUN.Text = ""
MUN.RowSource = "Menu!M26:M56"
ElseIf PROV.Text = "CAVITE" Then
MUN.Text = ""
MUN.RowSource = "Menu!M2:M25"
ElseIf PROV.Text = "QUEZON" Then
MUN.Text = ""
MUN.RowSource = "Menu!M57:M97"
End If
End Sub
I am currently trying to make a form in vba to request a pin from the user, and am trying to have it display the users corresponding initials, but my vlookup keeps not returning any values.
I have a worksheet titled 'userinfo'
Column A is pins, Column B is initials
I am trying to figure out a way for VBA to take the input from the prompt box, vlookup the data, and paste that resulting data into a cell.
EG
Sheet 1 = Maintenance
Press [Record Maintenance]
Box pops up prompting the users pin
User types pin
If pin is in the table for userinfo $A:$B, then copy column 2
Paste column 2 into Cell K7 on sheet 1 (maintenance)
To use VLOOKUP within VBA code it is necessary to set reference style to R1C1, then it should work.
In my opinion to use excel built-in functions like VLOOKUP will result in quicker code. On the other hand to search cells for a value in for-each loop is bad practise and if you have large amount of data it will take a lot of time.
Here a sample code.
It uses two sheets: UserInfo, Maintenance. The formula is set up based on template string and finally Evaluate() is called to get the result of it. HTH.
Public Sub test()
Dim pin
pin = VBA.InputBox("Enter PIN", "PIN")
If (pin = "") Then Exit Sub
Dim userInfoSheet As Worksheet
Set userInfoSheet = Worksheets("UserInfo")
Dim dataRange As Range
Set dataRange = userInfoSheet.Columns("a:b")
Dim initailsColumn As Byte
initailsColumn = dataRange.Columns(2).Column
Dim originalReferenceStyle
originalReferenceStyle = Application.ReferenceStyle
Application.ReferenceStyle = xlR1C1
Dim lookup As String
Const EXACT_MATCH As Integer = 0
lookup = "=VLOOKUP({PIN}, {DATA_RANGE}, {INITIALS_COLUMN}, {MATCH_TYPE})"
lookup = VBA.Replace(lookup, "{PIN}", pin)
lookup = VBA.Replace(lookup, "{DATA_RANGE}", dataRange.Worksheet.Name & "!" & dataRange.Address(ReferenceStyle:=xlR1C1))
lookup = VBA.Replace(lookup, "{INITIALS_COLUMN}", initailsColumn)
lookup = VBA.Replace(lookup, "{MATCH_TYPE}", EXACT_MATCH)
Dim result As Variant
result = Application.Evaluate(lookup)
Application.ReferenceStyle = originalReferenceStyle
If (Not VBA.IsError(result)) Then
Dim maintenanceSheet As Worksheet
Set maintenanceSheet = Worksheets("Maintenance")
maintenanceSheet.Range("k7").Value = result
Else
Dim parsedError As String
parsedError = ParseEvaluateError(result)
MsgBox "Error: " & parsedError, vbExclamation, "Error"
End If
End Sub
Private Function ParseEvaluateError(ByRef errorValue As Variant) As String
Dim errorNumber As Long
Dim errorMessage As String
errorNumber = VBA.CLng(errorValue)
Select Case errorNumber
Case 2000:
errorMessage = "#NULL!"
Case 2007:
errorMessage = "#DIV/0!"
Case 2015:
errorMessage = "#VALUE!"
Case 2023:
errorMessage = "#REF!"
Case 2029:
errorMessage = "#NAME?"
Case 2036:
errorMessage = "#NUM!"
Case 2042:
errorMessage = "#N/A"
Case Else
errorMessage = "Unknow"
End Select
ParseEvaluateError = errorMessage
End Function
Here is an alternative to Daniel's solution. There is nothing wrong with Daniel's but I wanted to show a solution without using the Vlookup function. By eliminating the Vlookup function you will not have to handle the different error messages that the function can return. This is strictly personal preference.
Option Explicit
Sub TEST()
Dim PIN As Variant
Dim WRKSHT_USERINFO As Excel.Worksheet
Dim WRKSHT_MAINTENANCE As Excel.Worksheet
Dim COLUMN_WITH_INITIALS As Long
Dim CELL_WITH_INITIALS_MATCHING_PIN As Range
Dim DESTINATION_CELL As Range
PIN = VBA.InputBox("Enter PIN", "PIN")
If PIN = vbNullString Then Exit Sub
Set WRKSHT_USERINFO = ThisWorkbook.Sheets("userinfo")
Set WRKSHT_MAINTENANCE = ThisWorkbook.Sheets("Maintenance")
Set DESTINATION_CELL = WRKSHT_MAINTENANCE.Range("K7")
COLUMN_WITH_INITIALS = 2 ''Column B
Set CELL_WITH_INITIALS_MATCHING_PIN = Get_Cell_With_Initials(WRKSHT_USERINFO, PIN, COLUMN_WITH_INITIALS)
If CELL_WITH_INITIALS_MATCHING_PIN Is Nothing Then
MsgBox "No Records Found For PIN: " & PIN
Exit Sub
Else
WRKSHT_MAINTENANCE.Range(DESTINATION_CELL.Address).Value = CELL_WITH_INITIALS_MATCHING_PIN.Value
End If
End Sub
Function Get_Cell_With_Initials(ByRef WRKSHT_USERINFO As Excel.Worksheet, ByVal PIN As Variant, ByVal COLUMN_WITH_INITIALS As Long) As Range
Dim SEARCH_OBJECT As Object
Dim ROW_WITH_VALUE As Long
Set SEARCH_OBJECT = Cells.Find(What:=PIN, After:=WRKSHT_USERINFO.Cells(1, 1), LookIn:=xlValues, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False)
If SEARCH_OBJECT Is Nothing Then
Exit Function
Else
ROW_WITH_VALUE = SEARCH_OBJECT.Row
End If
Set Get_Cell_With_Initials = WRKSHT_USERINFO.Cells(ROW_WITH_VALUE, COLUMN_WITH_INITIALS)
End Function