VBA Userform Text Box Scroll Start at top - vba

I have an Excel user form with multiple multi-line text boxes that need scroll bars. When I click in a textbox to scroll, it starts at the bottom of the text. When this happened with just one textbox on the user form I used this:
Userform1.TextBox1.SelStart = 0
and everything worked. If I try to use that on multiple text boxes in the same form, the scroll bar never appears for any of the boxes. Does anyone know how to fix this?
Update:
Found a quirk that my help narrow down the problem: with multiple textboxes, selstart=0 works on the first box, but then I need a much bigger number for the selstart of the next textbox. Example. The code below puts the scrollbar at the top of both textboxes. The form is shown through a double click on sheet 1 and the the values of the textboxes are create in the initialize sub.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
UserForm1.Show
End Sub
--------------
Private Sub UserForm_Initialize()
UserForm1.TextBox1.Value = Sheets("Sheet1").Cells(1, 1).Value
UserForm1.TextBox1.SelStart = 0
UserForm1.TextBox2.Value = Sheets("Sheet1").Cells(2, 1).Value
UserForm1.TextBox2.SelStart = 200
End Sub
But I could only find that textbox2 had to start at 200 through guess and check. I dont know how to determine where that textbox should start.

I had a breakthrough. If I use SetFocus then do selstart= 0 everything seems to work.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
UserForm1.Show
End Sub
Private Sub UserForm_Initialize()
UserForm1.TextBox1.Value = Sheets("Sheet1").Cells(1, 1).Value
UserForm1.TextBox1.SetFocus
UserForm1.TextBox1.SelStart = 0
UserForm1.TextBox2.Value = Sheets("Sheet1").Cells(2, 1).Value
UserForm1.TextBox2.SetFocus
UserForm1.TextBox2.SelStart = 0
End Sub

Related

Textbox Exit Event for unknown Textbox

I am working on a userform which contains numerous (an unknown number) of textbox controls. The number of textboxes on the form is based on certain parameters being met elsewhere within the project.
The number of textboxes on the form could get up to 100 or so and my users are expected to fill in each of them. However, in many cases the value for one textbox will be the same as the textbox positioned directly above it.
I therefore wish to implement functionality to allow the user to enter a "." followed by tabbing out of the field in order to copy the value from the textbox above it.
There are a couple of ways I could go about this initial requirement:
Private Sub TextBox2_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If TextBox2.Value = "." Then
TextBox2.Value = TextBox1.Value
End If
End Sub
This works absolutely fine.. however given that there is no indication here that the textbox2 is below textbox1 (Other than me knowing where I put it) we could do something like:
Private Sub TextBox2_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If TextBox2.Left = TextBox1.Left And TextBox2.Value = "." Then
TextBox2.Value = TextBox1.Value
End If
End Sub
And again this works absolutely fine.
My problem is this, with up to 100 textbox controls I do not particularly want to write and maintain an Exit event for each possible textbox control.
I will probably phrase this incorrectly, but is there a way to trigger the exit event dynamically by passing the name of the textbox the user has tabbed out of?
Or am I lumbered within dozens of identical subs handling the exit of each textbox specifically?
EDIT:
Reading the post linked from Word Nerd, I have the following included with the userform initialize event
Dim tbCollection As Collection
Private Sub UserForm_Initialize()
Dim Ctrl As MSForms.Control
Dim obj As clsTextBox
Set tbCollection = New Collection
For Each Ctrl In usfEnterTime.Controls
If TypeOf Ctrl Is MSForms.TextBox Then
Set obj = New clsTextBox
Set obj.Control = Ctrl
tbCollection.Add obj
End If
Next Ctrl
Set obj = Nothing
Then we have the class module clsTextBox
Private WithEvents MyTextBox As MSForms.TextBox
Public Property Set Control(tb As MSForms.TextBox)
Set MyTextBox = tb
End Property
Private Sub MyTextBox_Change()
If MyTextBox.Value = ". " Then
If MyTextBox.Top = 24 Then
MsgBox "Nothing to copy from"
MyTextBox.Value = ""
Exit Sub
Else
For Each Ctrl In usfEnterTime.Controls
If Ctrl.Left = MyTextBox.Left And Ctrl.Top = MyTextBox.Top - 18 Then
MyTextBox.Value = Ctrl.Value
Application.SendKeys "{TAB}"
Exit Sub
End If
Next Ctrl
End If
Else
Exit Sub
End If
End Sub
My initial requirement was to use the EXIT event to implement a "." + TAB out of textbox to copy from above, however it appears the TextBox control does not have the EXIT event available. So I am using the change event, application.sendkeys and expecting my users to use ". " (Note blank space) to mimic the same functionality and tab to the next textbox in the tab order index using the spacebar instead. As you can see I am simply looping through all controls and checking the relative TOP and LEFT positions to determine which textbox to copy from. 24 is the position of the top most textbox control and so I am capturing this and displaying a msgbox to advise the user there will be nothing to copy from. -18 represents the gap between the tops of two textbox controls.
Working perfectly, thanks to Word Nerd for linking through to the other post.

When I double click on a cell to open a form, a checkbox on the form behind my cursor is checked/unchecked. How can I prevent this from happening?

I have a form that appears on a double click event of a specific cell.
The form contains a list box with a bunch of checkboxes in it and in my _Activate() sub, the checkboxes are set to true or false based on values on the active sheet.
The trouble is that when the form opens up behind the cursor, the second click of the double click that opens the form is also checking/unchecking a checkbox in the form.
I've tried sticking "DoEvents" in the activate sub before the code sets the checkbox values but it hasn't made a difference - The checkbox behind my cursor where the form opens will be checked/unchecked.
I don't expect that the code will help much but it is essentially as below:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
If Target = Range("aParticularRangeName") Then
frmSelectStuff.Show
End If
End Sub
Public Sub UserForm_Activate()
Dim iRegions As Integer
Dim sRecheck As Variant
Dim sRecheckList() As String
sRecheckList = Split(ActiveCell.Value, "; ")
For Each sRecheck In sRecheckList
For iRegions = 0 To lbRegionsTemp.ListCount - 1
If sRecheck = lbRegionsTemp.List(iRegions) Then lbRegionsTemp.Selected(iRegions) = True
Next
Next
End Sub
What about using Cancel = True?
If Target = Range("aParticularRangeName") Then
Cancel = True
frmSelectStuff.Show
End If

How make VBA run on clicking any checkbox in a userform?

I have a userform with a multiple frames, all filled with multiple checkboxes. I've named the checkboxes to their corresponding Excel cells. Now I want to make VBA run on clicking any of these checkboxes on run time. I know I can do this by creating a click-sub for every individual checkbox, but there must be a cleaner way to do this.
So far I've tried to put this code in the userform_Click and userform_Mousedown events, but they don't run when I click the checkboxes. Does anyone have an idea how to do this?
Dim iControl As Control
For Each iControl In Me.Controls
If TypeName(iControl) = "CheckBox" Then
If iControl.Value = True And Range(iControl.Name).Value = "" Then
Range(iControl.Name).Value = Format(Now, "dd.mm.yyyy")
ElseIf iControl.Value = True And Range(iControl.Name).Font.Color = vbWhite Then
Range(iControl.Name).Font.Color = vbBlack
ElseIf iControl.Value = False And Range(iControl.Name).Value <> "" Then
Range(iControl.Name).Font.Color = vbWhite
End If
End If
Next
As SilentRevolution said - you need an event to fire when you click the button. You're just after a single procedure to fire all check box click events.
So:
Create a class module called cls_ChkBox.
In the class module you'll add the Click event code:
Option Explicit
Private WithEvents chkBox As MSForms.CheckBox
Public Sub AssignClicks(ctrl As Control)
Set chkBox = ctrl
End Sub
Private Sub chkBox_Click()
ThisWorkbook.Worksheets("Sheet1").Range(chkBox.Name).Value = Format(Now, "dd.mm.yyyy")
End Sub
Now you just need to attach the chkBox_Click event to each check box on your form. In your user form add this code:
Option Explicit
Private colTickBoxes As Collection
Private Sub UserForm_Initialize()
Dim ChkBoxes As cls_ChkBox
Dim ctrl As Control
Set colTickBoxes = New Collection
For Each ctrl In Me.Controls
If TypeName(ctrl) = "CheckBox" Then
Set ChkBoxes = New cls_ChkBox
ChkBoxes.AssignClicks ctrl
colTickBoxes.Add ChkBoxes
End If
Next ctrl
End Sub
Each check box is given its own instance of the class, which is stored in the colTickBoxes collection.
Open the form and the cell in Sheet1 will update to show the date depending on the name of the check box.
You need an event to run code, if there is no event, the macro cannot start. I don't know if there is a single event that triggers for any button or checkbox that is clicked.
If the code you want to execute is the same every time except the control, you could write a private sub in the userform module which is called for each event, the private sub can take an input between the () for example.
Private Sub CheckBox1_Click()
Call ExecuteCode(Me.CheckBox1)
End Sub
Private Sub CheckBox2_Click()
Call ExecuteCode(Me.CheckBox2)
End Sub
Private Sub CheckBox3_Click()
Call ExecuteCode(Me.CheckBox2)
End Sub
Private Sub ExecuteCode(IControl As Control)
If TypeName(IControl) = "CheckBox" Then
If IControl.Value = True And Range(IControl.Name).Value = "" Then
Range(IControl.Name).Value = Format(Now, "dd.mm.yyyy")
ElseIf IControl.Value = True And Range(IControl.Name).Font.Color = vbWhite Then
Range(IControl.Name).Font.Color = vbBlack
ElseIf IControl.Value = False And Range(IControl.Name).Value <> "" Then
Range(IControl.Name).Font.Color = vbWhite
End If
End If
End Sub
I just learned this today and thought it might help? Most of the questions, and responses for that matter, to questions regarding checkboxes, listboxes, etc. seem to not distinguish between those forms are inserted directly on the worksheet or are imbedded in a UserForm.
This may work for a checkbox - it works for a ListBox on a UserForm. If you want code to run after a selection, the code you must write has to be in module of the UserForm. I had no clue how to access. Once you have inserted a UserForm in your VBE, add the ListBoxes or whatever to the UserForm. Right click on the UserForm in the upper left project window and select "view code." Here is where you'll place the code, in my case a "change event" such that after a selection is made from the ListBox, other code is automatically run. Her for example:
Sub lstBoxDates_Change()
Dim inputString1 As String
inputString1 = Format(UserForm1.lstBoxDates.Value, "mm-dd-yyyy")
Call EnterDates(inputString1)
Unload Me
End Sub
To explain: Again this code is in the UserForm Module. I named my ListBox,
lstBoxDates. In my main code that I call - EnterDates, I use the variable name = inputString1. The value or date that I have selected from the ListBox is captured from the UserForm1 by UserForm1.lstBoxDates.Value - and I format that to a date, otherwise you see just a number. This is for only one selection.
Because I Dim here, no need to Dim in your main code. The sub for the main code
needs to accept the variable you are passing to it:
Sub EnterDates(inputString1)
This is very generalized but maybe something will click so you can get what you are after. I hope so, for I've worked on this a full two days!!

VBA combobox additem and getting a runtime error 70

I have created a userform that has two buttons on it. One is called CmdCon6 and the other is called CmdLbs6. When clicked, they are suppose to close the current userform, pull up another userform, and pull values from the 4th column in sheet18 and add them to a combobox named x48 (both of the new userforms have a combobox named x48)in the new userform. The range of cell values to be added to the combobox x48 will flucuate, but never exceed 20 (hence why I added a loop). Everything works great and does what it is suppose to do when I click the CmdCon6 button, but when I click the CmdLbs button, it gives me a run-time error '70' Permission denied and highlights the 20th line of code (line between the If and end if in the Sub CmdLbs_Click()).
I have tried to change the name of the combobox x48 in the frmInputLbs6 userform and keep it as x48 for the frmInputCon6 userform, but I still received the same error.
Any suggestions to fix this issue? I'm stumped, and can't think of a way around it. Thanks in advance!
Private Sub CmdCon6_Click()
Unload Me
For x = 1 To 20
If Sheet18.Cells(x, 4).Value <> "" Then
frmInputCon6.x48.AddItem Sheet18.Cells(x, 4)
End If
Next x
frmInputCon6.Show
End Sub
Private Sub CmdLbs6_Click()
Unload Me
For x = 1 To 20
If Sheet18.Cells(x, 4).Value <> "" Then
frmInputLbs6.x48.AddItem Sheet18.Cells(x, 4)
End If
Next x
frmInputLbs6.Show
End Sub
Controls on UserForms are private by default. You need to access them through the Controls collection:
Private Sub CmdLbs6_Click()
Unload Me
For x = 1 To 20
If Sheet18.Cells(x, 4).Value <> "" Then
frmInputLbs6.Controls("x48").AddItem Sheet18.Cells(x, 4)
End If
Next x
frmInputLbs6.Show
End Sub
I'd also note that although you mention that "they are suppose to close the current userform", this isn't what happens. Your forms also aren't actually being fully unloaded until the other form is closed. The .Show method defaults to modal so in the code above frmInputCon6 doesn't fully unload until after frmInputLbs6 is closed.
Just something to keep in mind, because it really messes up your event stack. You can see the results by with this simple test code. Add UserForm1 and UserForm2, and put a button on each of them and the following code:
UserForm1:
Private Sub CommandButton1_Click()
Unload Me
UserForm2.Show
End Sub '<--Put a breakpoint here.
Private Sub UserForm_Terminate()
Debug.Print "UserForm1 closed"
End Sub
UserForm2:
Private Sub CommandButton1_Click()
Unload Me
UserForm1.Show
End Sub '<--Put a breakpoint here.
Private Sub UserForm_Terminate()
Debug.Print "UserForm2 closed"
End Sub
Put a breakpoint on the End Subs of each Click() event, fire up one of the forms and hit the buttons to hop back and forth a few times. Then close one of the forms and count how many times you hit the breakpoints before you actually exit.

Clear textbox within multi-page userform when textbox is clicked on

I'm having a slight problem with some VBA coding on a multi-page userform I'm creating. I have some textboxes on each page of the userform, and I had code that I had been using with regular userforms to clear the textboxes provided in the following answer to another thread (https://stackoverflow.com/a/8921247/2477891)
The code looks like this:
Sub TB_enter(TB_name)
If Len(Me.Controls(TB_name).Tag) = 0 Then
Me.Controls(TB_name).Tag = Me.Controls(TB_name).Value
Me.Controls(TB_name).Value = vbNullString
End If
End Sub
Sub TB_exit(TB_name)
'When you click out of the textbox and no information has been entered, returns original text
If Len(Me.Controls(TB_name).Value) = 0 Then
Me.Controls(TB_name).Value = Me.Controls(TB_name).Tag
Me.Controls(TB_name).Tag = vbNullString
End If
End Sub
Along with the following code used for the textboxes to clear them:
Private Sub AdNtbx_Enter()
TB_enter ActiveControl.Name
End Sub
Private Sub AdNtbx_Exit(ByVal Cancel As MSForms.ReturnBoolean)
TB_exit ActiveControl.Name
End Sub
My problem is that they are no longer working because they are on multi-pages, and the following line comes up with an error:
Me.Controls(TB_name).Value = vbNullString
Does anyone have any suggestions as to what could be the problem/solution?
I'd really appreciate it.
Thanks!
I believe this is what you are looking for :
Set Page1 = ThisWorkbook.VBProject.VBComponents("UserForm1").Designer.Controls("Multipage1").Pages("Page1")
Page1.textbox1.Text = vbNullString
You can edit ThisWorkbook, UserForm1 etc.. properties to suit your needs, but with this code you will be able clear textboxes on multipage object