Why doesn't this code open the form with the items selected already? I set the selection flag to true with this code.
Private Sub UserForm_Initialize()
Dim i, InStrRes, k
With ActiveCell
If .Value <> "" Then
For i = 0 To Me.lstDV.ListCount - 1
InStrRes = InStr(1, ActiveCell.Value, Me.lstDV.List(i))
If InStrRes <> 0 And InStrRes <> Null Then
Me.lstDV.Selected(i) = True
End If
Next i
End If
End With
End Sub
Private Sub UserForm_Initialize()
Dim i, InStrRes, k
With ActiveCell
If .Value <> "" Then
For i = 0 To Me.lstDV.ListCount - 1
Me.lstDV.Selected(i) = False '<~~ add this code. Should be set to false in advance.
InStrRes = InStr(1, ActiveCell.Value, Me.lstDV.List(i))
'If InStrRes <> 0 And InStrRes <> Null Then
If InStrRes Then
Me.lstDV.Selected(i) = True
End If
Next i
End If
End With
End Sub
The presumption must be that the listbox hasn't been loaded at the time it is initialized. I tried the Activate event with similar lack of success. Please try this code instead.
Sub ShowMyForm()
Dim MyForm As New TryForm
Dim CellVal As Variant
CellVal = ActiveCell.Value
With MyForm
If Len(CellVal) Then
On Error Resume Next
.lstDV.ListIndex = Application.Match(CellVal, Range(.lstDV.RowSource), 0) - 1
End If
.Show
' code continues here when the form is closed
End With
Unload MyForm
End Sub
This code must be in a standard code module, not the form's code sheet. It calls the form TryForm (replace with the name you gave to your form), and modifies it before showing. Note that you still have full access to the form to take out values you may want after it is hidden. Just avoid Unload Me anywhere in the form's code because the unloading is done by the above code after you have taken everything you wanted.
Note that the form's Initialize event is triggered by the New key word in Dim MyForm As New TryForm, long before you gain access. The Activate event follows with some delay. Please make sure that the procedures you may run with these events don't interfere with what the above code does.
Related
Dears,
I am preparing a simple userform to let a teacher to enter each student’s name and height in a class. There are two textboxes (textbox_name and textbox_height) and one “add to record” command button. I tried to make some validation control to prevent empty string to be entered. My validation control is in case textbox is empty, when the click the “add to record” button, the corresponding empty textbox turns pink; and when both textboxes are empty, both textboxes should turn pink, however only the first textbox turns pink in my below codes. Can you tell me why and how to correct it? Thanks.
Private Sub Cmd_addtorecord_Click()
If TextBox_Name = "" Then
TextBox_Name.BackColor = rgbPink
Exit Sub
End If
If TextBox_height = "" Then
TextBox_height.BackColor = rgbPink
Exit Sub
End If
'....
End sub
You can do it like this:
Private Sub Cmd_addtorecord_Click()
'ensure required fields have content
If FlagEmpty(Array(TextBox_Name, TextBox_height)) > 0 Then
MsgBox "One or more required values are missing", vbExclamation
Exit Sub
End If
'....
End Sub
'check required textboxes for content, and flag if empty
' return number of empty textboxes
Function FlagEmpty(arrControls) As Long
Dim i As Long, numEmpty As Long, clr As Long
For i = LBound(arrControls) To UBound(arrControls)
With arrControls(i)
clr = IIf(Len(Trim(.Value)) > 0, vbWhite, rgbPink)
.BackColor = clr
If clr = rngpink Then numEmpty = numEmpty + 1
End With
Loop
FlagEmpty = numEmpty
End Function
You're Exiting the sub before you get to the second textbox. Change your code to something like this:
Private Sub Cmd_addtorecord_Click()
If TextBox_Name = "" or TextBox_height = "" Then
If TextBox_Name = "" Then
TextBox_Name.BackColor = rgbPink
End If
If TextBox_height = "" Then
TextBox_height.BackColor = rgbPink
End If
Exit Sub
End If
'....
End sub
This is what I have in my Payment Form. I use a Combobox to pull the user info into the payments Form. The trouble I am having is it keeps showing TRUE in the Paid column. In another column to the right of Paid it shows 30 days out when next payment is due.
I've tried this code but it puts it in all the cells in the column
If CheckBox1.Value = True Then
Range("I:I").Value = Date
Else: Range("I:I").Value = ""
End If
End Sub```
'Dim xRg As Range
'Updated by Extendoffice 2018/1/30
Private Sub Userform_Initialize()
Set xRg = Worksheets("Customer").Range("A2:F8")
ComboBox1.List = xRg.Columns(1).Value
End Sub
Private Sub ComboBox1_Change()
TextBox1.Text = Application.WorksheetFunction.VLookup(ComboBox1.Value, xRg, 2, False)
TextBox2.Text = Application.WorksheetFunction.VLookup(ComboBox1.Value, xRg, 3, False)
TextBox3.Text = Application.WorksheetFunction.VLookup(ComboBox1.Value, xRg, 4, False)
TextBox4.Text = Application.WorksheetFunction.VLookup(ComboBox1.Value, xRg, 5, False)
TextBox5.Text = Application.WorksheetFunction.VLookup(ComboBox1.Value, xRg, 6, False)
End Sub
Private Sub cbCancel_Click()
Unload Me
End Sub
Private Sub cbAdd_Click()
'dimmin Var
Dim Data As Worksheet
'Setting Var
Set Data = ThisWorkbook.Sheets("Payments")
NextRow = Data.Cells(Rows.Count, 1).End(xlUp).Row + 1
Data.Cells(NextRow, 1) = Me.ComboBox1.Value
Data.Cells(NextRow, 2) = Me.TextBox1.Value
Data.Cells(NextRow, 3) = Me.TextBox2.Value
Data.Cells(NextRow, 4) = Me.TextBox3.Value
Data.Cells(NextRow, 5) = Me.TextBox4.Value
Data.Cells(NextRow, 7) = Me.CheckBox1.Value
Me.TextBox1.Value = ""
Me.TextBox2.Value = ""
Me.TextBox3.Value = ""
Me.TextBox4.Value = ""
Me.ComboBox1.Value = ""
Me.CheckBox1.Value = ""
End Sub
Private Sub CommandButton2_Click()
Dim ctl As Control
For Each ctl In Me.Controls
If TypeName(ctl) = “TextBox” Or TypeName(ctl) = “ComboBox” Then
ctl.Value = “”
End If
Next ctl
End Sub```
User forms aren't designed or intended to control worksheet contents. Look upon your workbook like an airport with the passenger halls in the center and walkways leading to satellites with departure gates. One such satellite is is your payments form, another is your worksheet. To move data from one to the other you need to go through the hub. The hub in this picture is a standard code module, and it needs to be given control of your project. Use the code below as a frame. Paste it to a standard code module.
Sub MakePayment()
Dim FrmPayment As New PaymentForm
Dim xRg As Range
With FrmPayment
Set xRg = Worksheets("Customer").Range("A2:F8")
.ComboBox1.List = xRg.Columns(1).Value
.Show
If Val(.Tag) = 1 Then
' write to the sheet
End If
End With
Unload FrmPayment
Set FrmPayment = Nothing
End Sub
The scheme is simple. There is a user form named PaymentForm (better than "UserForm1"). When the above sub is run a new instance of that form is created, the combo box is loaded and control handed to the form (.Show). When the form is closed code execution resumes at that point, data will be removed from the form and written to the worksheet. Then the form is unloaded.
To let this work you mustn't unload the form in the form's code module. Instead use Me.Hide I suggest to use the Form's Tag property to send a signal back to the calling procedure. If it's 1 the data should be processed, otherwise nothing is to be done. Set the Tag value in the CommandOK procedure. If the user cancelled the property will be empty and Val(.Tag) will return 0.
Note that the Initialize event procedure runs when the form's instance is created, meaning at Dim FrmPayment As New PaymentForm. Your procedure tries to access the remote satellite (the worksheet) directly. Not good. Better to load the Cbx just before showing the form (but long after initialization) as I have done in my above code. At that point you have access to all controls of the form and you can also endow the "PAID" textbox with a value of your choice.
Me.Hide (in the form's module) hides the form and hands control back to the calling procedure. At that point all form controls and their values are accessible through the object FrmPayment and so is the worksheet. You can transfer data from one satellite to the other - at the hub.
I didn't test the above code but it's simple and I expect it to have no errors. However, before you try it in your project make sure to disable the event procedures in your code that would interfere in the system, such as the Initialize event.
I have this code but it only work for my first row.
It is suppose to look if the checkbox on B, C or D is checked, and if so, a date + username will automaticaly fill in F and G.
here is a picture of my table:
This is what my code looks like:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Range("B2") Or Range("C2") Or Range("D2") = True Then
Range("G2").Value = Environ("Username")
Range("F2").Value = Date
Else
Range("F2:G2").ClearContents
End If
End Sub
Enter this code in a regular module, select all your checkboxes and right-click >> assign macro then choose ReviewRows.
This will run the check whenever a checkbox is clicked - a bit of overhead since all rows will be checked, but should not be a big deal.
Sub ReviewRows()
Dim n As Long
For n = 1 To 100 'for example
With Sheet1.Rows(n)
If Application.CountIf(.Cells(2).Resize(1, 3), "TRUE") > 0 Then
If Len(.Cells(6).Value) = 0 Then 'only enter if currently empty?
.Cells(6) = Date
.Cells(7) = Environ("Username")
End If
Else
.Cells(6).Resize(1, 2).ClearContents
End If
End With
Next n
End Sub
If you want to be more precise then Application.Caller will give you the name of the checkbox which was clicked, and you can use that to find the appropriate row to check via the linkedCell.
Sub ReviewRows()
Dim n As Long, shp As CheckBox, c As Range, ws As Worksheet
Set ws = ActiveSheet
On Error Resume Next 'ignore error in case calling object is not a checkbox
Set shp = ActiveSheet.CheckBoxes(Application.Caller) 'get the clicked checkbox
On Error GoTo 0 'stop ignoring errors
If Not shp Is Nothing Then 'got a checkbox ?
If shp.LinkedCell <> "" Then 'does it have a linked cell ?
With ws.Range(shp.LinkedCell).EntireRow
If Application.CountIf(.Cells(2).Resize(1, 3), "TRUE") > 0 Then
If Len(.Cells(6).Value) = 0 Then 'only enter if currently empty?
.Cells(6) = Date
.Cells(7) = Environ("Username")
End If
Else
.Cells(6).Resize(1, 2).ClearContents
End If
End With
End If 'has linked cell
End If 'was a checkbox
End Sub
However this appraoch is sensitive to the exact positioning of your checkbox
You have a long way to go!
Unfortunately, If Range("B2") Or Range("C2") Or Range("D2") = True Then is beyond repair. In fact, your entire concept is.
Start with the concept: Technically speaking, checkboxes aren't on the worksheet. They are on a layer that is superimposed over the worksheet. They don't cause a worksheet event, nor are they responding to worksheet events. The good thing is that they have their own.
If Range("B2") Or Range("C2") Or Range("D2") = True Then conflates Range with Range.Value. One is an object (the cell), the other one of the object's properties. So, to insert sense into your syntax it would have to read, like, If Range("B2").Value = True Or Range("C2").Value = True Or Range("D2").Value = True Then. However this won't work because the trigger is wrong. The Worksheet_Change event won't fire when when a checkbox changes a cell's value, and the SelectionChange event is far too common to let it run indiscriminately in the hope of sometimes being right (like the broken clock that shows the correct time twice a day).
The answer, therefore is to capture the checkbox's click event.
Private Sub CheckBox1_Click()
If CheckBox1.Value = vbTrue Then
MsgBox "Clicked"
End If
End Sub
Whatever you want to do when the checkbox is checked must be done where it now shows a MsgBox. You can also take action when it is being unchecked.
I have created a UserForm in VBA Excel that has a ListBox with the ListStyleOption selected. The MultiSelectMulti option is activated.
Whenever I close the UserForm or Workbook and then reopen, all the previous selections are gone. Is there a way to retain selections made in listbox?
Thanks.
Yes, it's possible, but you have to save the listbox items and their selected state in the workbook or some data support such as a file or database. When showing your form, you'll just read back the saved items and selected states.
Assuming you can save the list's content in the workbook, you can use something like the following:
Public Sub SaveList(ByVal plstListBox As MSForms.ListBox, ByVal prngSavePoint As Excel.Range)
On Error GoTo errHandler
Dim lRow As Long
Dim bScreenUpdating As Boolean
Dim bEnableEvents As Boolean
bScreenUpdating = Application.ScreenUpdating
bEnableEvents = Application.EnableEvents
Application.ScreenUpdating = False
Application.EnableEvents = False
prngSavePoint.CurrentRegion.Clear
If plstListBox.ListCount > 1 Then
For lRow = 0 To plstListBox.ListCount - 1
prngSavePoint.Cells(lRow + 1, 1).Value = plstListBox.Selected(lRow)
prngSavePoint.Cells(lRow + 1, 2).Value = plstListBox.List(lRow)
Next
End If
Cleanup:
On Error Resume Next
Application.EnableEvents = bEnableEvents
Application.ScreenUpdating = bScreenUpdating
Exit Sub
errHandler:
MsgBox Err.Description, vbExclamation + vbOKOnly, "Error"
Resume 'Cleanup
End Sub
Public Sub LoadList(ByVal plstListBox As MSForms.ListBox, ByVal prngSavePoint As Excel.Range)
Dim lRow As Long
Dim vntSavedList As Variant
plstListBox.Clear
If Not IsEmpty(prngSavePoint.Cells(1, 1).Value) Then
vntSavedList = prngSavePoint.CurrentRegion.Value
For lRow = 1 To UBound(vntSavedList, 1)
plstListBox.AddItem vntSavedList(lRow, 2)
plstListBox.Selected(lRow - 1) = vntSavedList(lRow, 1)
Next
End If
End Sub
To save (e.g. you could have a Save List button on your form), pass a reference to your listbox, and a reference to the top left cell of a free zone somewhere in your workbook. Beware that the code will write from this point down, on 2 columns, and overwrite everything that may be in its path. You must also be sure that this cell is isolated, i.e. not immediately adjacent to other content in any direction.
Example: SaveList ListBox1, Sheet1.Cells(1, 1)
You could have a Load List button on your form. To load back your list: LoadList ListBox1, Sheet1.Cells(1, 1)
The important listbox properties used in this answer are Selected and List, which give the selected state and label of any item in the list. These are zero-based indexed properties.
basically I have a userform which I would like to use to enter 2 data into another macro which I already have. The userform is as below:
Basically, I would like the OK button to be clicked and the data in the two boxes will be entered into another macro that I have. It would also be great if the OK button can help in a sense that it will prompt a warning if one of the boxes is not filled up.
So far, I do not have much of a code for this..
Private Sub UserForm_Click()
TextBox1.SetFocus
Sub Enterval()
End Sub
Private Sub TextBox1_Change()
Dim ID As String
ID = UserForm3.TextBox1.Value
End Sub
Private Sub TextBox2_Change()
Dim ID2 As String
ID2 = UserForm3.TextBox2.Value
End Sub
Private Sub OKay_Click()
Enterval
End Sub
Would appreciate any tips and help. Thanks!
My other macro
Private Sub CommandButton1_Click()
Dim Name As String
Dim Problem As Integer
Dim Source As Worksheet, Target As Worksheet
Dim ItsAMatch As Boolean
Dim i As Integer
Set Source = ThisWorkbook.Worksheets("Sheet1")
Set Target = ThisWorkbook.Worksheets("Sheet2")
Name = Source.Range("A3")
Problem = Source.Range("I13")
Do Until IsEmpty(Target.Cells(4 + i, 6)) ' This will loop down through non empty cells from row 5 of column 2
If Target.Cells(4 + i, 6) = Name Then
ItsAMatch = True
Target.Cells(4 + i, 7) = Problem ' This will overwrite your "Problem" value if the name was already in the column
Exit Do
End If
i = i + 1
Loop
' This will write new records if the name hasn't been already found
If ItsAMatch = False Then
Target.Cells(3, 6).End(xlDown).Offset(1, 0) = Name
Target.Cells(4, 6).End(xlDown).Offset(0, 1) = Problem
End If
Set Source = Nothing
Set Target = Nothing
End Sub
Thats the macro i have. As u said, i change the
othermacro
to CommandButton1_Click()
but it doesn't work
Quoting geoB except for one thing: when you .Show your UserForm from a main Sub, you can also .Hide it at the end and the macro that called it will continue its procedures.
Sub Okay_Click()
Dim sID1 As String, sID2 As String
' A little variation
If Me.TextBox1 = "" Or Me.TextBox2 = "" Then
MsgBox "Please fill all the input fields"
Exit Sub
End If
Me.Hide
End Sub
To address your TextBox, you can write in your main Sub UserForm3.TextBox1 for example
There is no need for an Enterval function. Instead, assume the user can read and follow instructions, then test whether that indeed is the case. Note that in your code ID and ID2 will never be used because they exist only within the scope of the subroutines in which they are declared and receive values.
To get started:
Sub Okay_Click()
Dim sID1 As String, sID2 As String
sID1 = UserForm3.TextBox1.Value
sID2 = UserForm3.TextBox2.Value
If Len(sID1 & vbNullString) = 0 Then
MsgBox "Box A is empty"
Exit Sub
End If
If Len(sID2 & vbNullString) = 0 Then
MsgBox "Box B is empty"
Exit Sub
End If
'Now do something with sID1, sID2
otherMacro(sID1, sID2)
End Sub
For your other macro, declare it like this:
Sub otherMacro(ID1, ID2)
...
End Sub
Also, the SetFocus method should occur in the form open event.