How to iterate through userform textboxes in a VBA sub-routine - vba

In a userform, I want the user to input Time in textboxes named 'UFtime1', 'UFtime2', 'UFtime3' and so on. I have written code that makes the textbox only accept inputs in a certain format, and I want to apply this code to every textbox. I want to use a loop to target the desired textbox, but I can't figure out how to change the name of the textbox based on how many times the loop has iterated.
I have written a subroutine to do this once.
Private Sub UFtime1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Dim dTime As String
On Error Resume Next
dTime = Me.UFtime1.Value
UFtime1.Text = Format(dTime, "hh:mmAM/PM")
If IsDate(UFtime1) Then Exit Sub
Cancel = True
UFtime1 = Null
End Sub
So here, I want to add a loop which essentially changes the 1 in every UFtime1 to a 2, then a 3, and so on with each iteration of the loop

Related

Check if variant is Null or an array

I have a dynamic range that is being used to set a combobox in vba.
The range starts as A3 (which will contain nothing to start) and goes all the way to A3:A9999, depending on how many elements are in the range.
The code then pulls in the data from the range and stores it in a local variant.
My code in VBA is this:
If tempj <> Null Then
cmb_JobNum.List = tempj
End If
When there are 0 elements in the array, tempj = Null, so it does not attempt to set the list.
When there is 1 element in the array, tempj = [Value of cell], so it will set the list to that single element.
When there is 2 or more elements in the array, tempj is now an array, so trying to equate it to a single element throws a 'type mismatch' error. I have no clue how to update the code so that it doesn't get caught out by that error, since every time that equate is run it will crash.
You could try like this:
Dim i As Long
For i = LBound(tempj) To UBound(templ)
cmb_JobNum.AddItem tempj(i)
Next
This code will loop through your array and add every element in it to the combobox. Thus, if array is empy, then no elelements will be added, when there's >0 elements, then all of them will be added.
Here is an example using a dynamic named range to set the fill
Option Explicit
Public Sub test()
With ThisWorkbook.Worksheets("Sheet6") '<== change as appropriate
.ComboBox1.ListFillRange = .Range("dynRange").Address
End With
End Sub
dynRange formula added via name manager (Ctrl + F3)
=OFFSET(Sheet6!$A$3,0,0,COUNTA(Sheet6!$A:$A),1)
Using a worksheet change event to automatically update the combobox:
You could tie this into a Worksheet_Change event on the range A3:A9999 to update automatically the Combobox.
If tying to an event in the code pane of the sheet containing the combobox you could have the following:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A3:A9999")) Is Nothing Then
Application.EnableEvents = False
Me.ComboBox1.ListFillRange = ThisWorkbook.Worksheets("Sheet6").Range("dynRange").Address
Application.EnableEvents = True
End If
End Sub
Example code run:
Code pane for sheet containing Combobox:
Note:
This is assuming an ActiveX combobox but can easily be update for a Form Control ComboBox.
For a form control swop out lines and use:
With Shapes("Drop Down 2").ControlFormat '<== change to appropriate name
.ListFillRange = ThisWorkbook.Worksheets("Sheet6").Range("dynRange").Address
End With
Edit: For UserForm combobox you can populate in the initialize e.g.
Private Sub UserForm_Initialize()
cb1.RowSource = Sheet1.Range("dynRange").Address
End Sub
Figured it out
If VarType(tempj) <> 0 Then
If VarType(tempj) = 8 Then
cmb_JobNum.AddItem tempj
Else
cmb_JobNum.List = tempj
End If
End If

VBA: ComboBox only showing one item after Workbook_Open event

I am attempting to have a Workbook_Open event populate a controls ComboBox
so that when the user goes to the Worksheet("Benchmarking"), they have a pre-populated list to choose from that includes all the items in the array datesArr.
The problem i am having is, upon opening the spreadsheet and navigating to the Worksheet("Benchmarking"), i am only seeing one item in the drop down list:
If i select that item then the list actually populates:
Desired result:
I want the full list to be available from the first time the user tries to make a selection not just after the ComboBox1_Change event is fired.
Having reviewed numerous post e.g. Sometimes the ActiveX Combobox only shows one row, why? , Populating Combo Box on WorkBook Open I have tried several different approaches including the following in the Workbook_Open event code:
.ListFillRange = "DropDownDates"
.List = DateArrToStrAr
I have also looped the array adding the items to ComboBox1. Each time i get the same 1 visible item in drop down result.
Is someone able to tell me where i am going wrong please?
My current code is
1) ThisWorkbook
Private Sub Workbook_Open()
With Worksheets("Benchmarking").OLEObjects("ComboBox1").Object
.Clear
.List = DateArrToStrArr '
End With
End Sub
2) Worksheet("Benchmarking"):
Private Sub ComboBox1_Change() 'QH 2/11/17
Dim datesArr() As String
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Lkup")
datesArr = DateArrToStrArr 'function that reads a named range of dates and converts to string to avoid dd/mm becoming mm/dd
If ComboBox1.Value = vbNullString Then ComboBox1.Value = "01/04/2016"
ComboBox1.List = datesArr
'.....other code
End Sub
Notes:
The array datesArr is populated by the function DateArrToStrArr() which reads in a named range of dates "DropDownDates" (workbook scope) and converts them to a string array. This is then assigned to the ComboBox.
DropDownDates is a dynamic named range with formula =OFFSET(Lkup!$F$16,,,Lkup!$M$12,)
Set-up: Excel 2016 64 bit Windows.
Thanks to #CLR for making me think about recalcs. I decided to hack my way around this with the following:
I have added in Worksheet("Benchmarking") a Worksheet_Activate event and removed the Workbook_Open code. This seems to do the trick
Private Sub Worksheet_Activate()
' ComboBox1.Clear
ComboBox1.List = DateArrToStrArr
End Sub

Listbox Modification in VBA

I created a Userform in Word which imports 3 columns of data from an excel sheet, inserts it into bookmarks and in the name of the word document and saves it as a pdf.
Now I wanted to add a Listbox into the form to be able to add, modify and delete the inputs manually which are usually imported from the excel sheet .
I already figured out how to add data from 3 textboxes into a 3 Column Listbox but even after googling for hours I can't find a good way to modify selected data.
VB.net has the .selectedItem property, VBA does not. Can anybody give me an example how to modify a multi column listbox with the values of 3 textboxes?
Thanks in advance
You need to iterate through ListBox.Selected and check if it is True. Once you get a True one, you can process that item.
Sample code adds some items with columns and sets up a click event to run through the Selected items.
Private Sub ListBox1_Click()
Dim i As Integer
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then
Debug.Print ListBox1.List(i, 0)
End If
Next i
End Sub
Private Sub UserForm_Initialize()
ListBox1.AddItem "test"
ListBox1.AddItem "test1"
ListBox1.AddItem "test2"
ListBox1.ColumnCount = 3
ListBox1.ColumnHeads = True
ListBox1.List(1, 0) = "change to 1,0"
ListBox1.List(1, 1) = "change to 1,1"
ListBox1.List(1, 2) = "change to 1,2"
End Sub
Picture of form with Immediate window after clicking each item in turn.

Pause VBA macro, allow user to make a selection, and restart where it left off

I want to allow the user to make a selection, run some code, pause for another selection, run more code?
I work with documents with large number of tables that eventually convert to HTML. Sometimes the formatting on two like tables doesn't convert the same. Knowing how the converter works, I'd like to copy all of the formatting data from one table and "paste" it onto another one.
I've the idea of a userform to have the user select something, hit a copy button, select something else and hit a paste button.
The timer function allows you to do this. It may not be the best way to code, but it is the answer to your problem:
'1st code here
Start = Timer
Do While Timer < Start + 10
DoEvents
Loop
'do 2nd code here
DoEvents allows the user to select text, etc. After 10 seconds, the code resumes at "2nd code."
You can use global a global variable:
Public myVar as Variant
Sub fillmyVar()
myVar = Selection
End Sub
Sub doSth()
' use myVar and the new selected text
End Sub
Using the answer from Aaron and incorporating it with a ToggleButton in the Userform you can successfully pause the code. With this you can then work in an additional selection to change the operation.
I originally did not use Global or Public Variables but soon learnt that its easier for passing data between Subs and Userforms
Userform:
Public Sub ToggleButton1_AfterUpdate()
'Program is Paused / Selected to Pause
If ProgBar.ToggleButton1.Value = True Then
'Changing the Text of the Toggle button once the program is selected to Pause
'If program paused then button will display continue
ProgBar.ToggleButton1.Caption = "Continue"
'For Sending to Loop Code
ProgramStatus = "0"
Call LoopCode.PrgStat(ProgramStatus)
End If
'Program is running / Selected to run
If ProgBar.ToggleButton1.Value = False Then
'Changing the Text of the Toggle button once the program is selected to continue
'If program running then button will display pause
ProgBar.ToggleButton1.Caption = "Pause"
'For Sending to Loop Code
ProgramStatus = "1"
Call LoopCode.PrgStat(ProgramStatus)
End If
End Sub
In your Module
Public Status As String
Public Sub PrgStat(ByVal ProgStatus As String)
Status = ProgStatus
End Sub
Sub SomeSub()
Do While
' Some Loop Code Running
If Status = "1" Then
'Toggle Not Pressed
End If
If Status = "0" Then
'Toggle Button Pressed
Do While Status = "0"
'Program will stop here until the togglebutton on the
'userform is pressed again which changes Status = 1
'This is where you can make another selection on the
'userform
DoEvents
Loop
End If
Loop
End Sub

What VBA coding in a Userform can I use to find a cell based upon row & column content, and then update that cell?

I am a complete beginner to VBA, truely.
I am trying to create a user form that will update the number of tasks a person completes on a given date as listed on a spreadsheet. I envision the Userform having two bottons (which are hidden and appear as the conditions of the subroutine). I am working on a Mac, by the way, and I know that will have VBA coding implications for use on a PC och vice versa.
The example sheet is this:
The example Userform (a) is this:
For argument's sake, let say I want to update or input the number of tasks that Greg completed on the 7th of May (2013/05/07).
I would like for the Userform to proceed something like this:
Entering person and date:
Then, retrieving number of tasks for Greg on the 7th after button click:
Now, I want to input that I know Greg completed 6 tasks on the 7th and I click the second button (now visible and the first button hidden):
And the result in the spreadsheet:
I ought to input some code here, but my skills and the completeness of the code are wanting. But I will put in what I have:
Option Explicit
'Subroutine when clicking the first ("find") button
Private Sub btnfind_Click()
lbltasks.Vissible = True
txttasks.Visible = True
btnupdate.Visible = True
btnfind.Visible = False
'Defining variables
Dim pr01 As String
Dim dt01 As Date
Dim tsk01 As Integer
'Assigning variables to inputs
pr01 = txtperson.Text
dt01 = txtdate.Text
tsk01 = txttask.Text
'Looking for Name in column "A"
' ? ? ?
'Looking for inut Date in row "1"
' ? ? ?
'Retrieving the existing number of tasks according to name and date
'and showing number in the 'tasks' text input box in the user form
' ? ? ?
End Sub
'Subroutine when clicking the Second ("update") button
Private Sub btnupdate_Click()
'Paste updated Number of tasks in appropriate cells according to name and date
'The new number of tasks should over write what was there previously
' ? ? ?
End Sub
Thanks in advance for any and all help!
This should work. Please study it and use the macro record function in Excel to grasp a lot more:
Option Explicit
Public frmName As Variant 'store row of name
Public frmDate As Variant 'store column of date
'Subroutine when clicking the first ("find") button
Private Sub btnfind_Click()
'Defining variables
Dim pr01 As String
Dim dt01 As Date
Dim tsk01 As Integer
'Assigning variables to inputs
pr01 = UserForm1.TextBox1.Text
dt01 = UserForm1.TextBox2.Text
tsk01 = UserForm1.TextBox3.Text
'Looking for Name in column "A"
With ThisWorkbook.Worksheets("Sheet4")
frmName = .Columns("A").Find(pr01).Row
End With
'Looking for inut Date in row "1"
With ThisWorkbook.Worksheets("Sheet4")
frmDate = .Rows(1).Find(CDate(dt01)).Column
End With
If frmName Is Nothing Or frmDate Is Nothing Then
'not found
Exit Sub
End If
'Retrieving the existing number of tasks according to name and date
'and showing number in the 'tasks' text input box in the user form
With ThisWorkbook.Worksheets("Sheet4")
UserForm1.TextBox3.Text = .Cells(frmName, frmDate)
End With
End Sub
'Subroutine when clicking the Second ("update") button
Private Sub btnupdate_Click()
'Paste updated Number of tasks in appropriate cells according to name and date
'The new number of tasks should over write what was there previously
With ThisWorkbook.Worksheets("Sheet4")
.Cells(frmName, frmDate) = UserForm1.TextBox3.Text
End With
End Sub