Save combobox value as global variable and select row of selected value - vba

I want to save selected combobox value as global variable and select row of selected value.
I have an Excel file, where I want to make calculations based on inputs in sheet1 and data on sheet2.
Inputs are provided by combobox1 (list of names from column A in sheet 2), combobox2 (case yes/no) and combobox3 (values 1,2,3).
After I select value in combobox1 (for example: ABC which is value A7 from sheet2), I want to calculate from data in row 7 in sheet2:
B7 (sheet2) + C7 (sheet2) * combobox3 value + D7 (sheet2) * (combobox2(yes = 2 / no = 0).
Can anyone help me with that?
Public SelectedComboBox1 As String
Public SelectedComboBox2 As String
Public SelectedComboBox3 As integer
Public calculate2 As Integer
Private Sub ComboBox1_DropButtonClick()
Sheet1.ComboBox1.List = Sheet2.Range("A3:A46").Value
SelectedComboBox1 = Me.ComboBox1.Value
End Sub
Private Sub ComboBox2_DropButton()
With Me.ComboBox2
.AddItem "YES"
.AddItem "NO"
End With
SelectedComboBox2 = Me.ComboBox2.Value
End Sub
Private Sub ComboBox3_DropButton()
With Me.ComboBox3
.AddItem "1"
.AddItem "2"
.AddItem "3"
End With
SelectedComboBox3 = Me.ComboBox3.Value
End Sub
Public Sub Calculate2_click()
calculate2 = Sheet2.Range("B7") * Sheet2.Range("C7") * SelectedComboBox3+Sheet2.Range("D7")*??
Sheet1.Range("H10").Value = calculate2
End Sub

It seems like you added a ActiveX combobox. You might want to use a form-combobox instead for Excel Sheets. Nevertheless: in the Editor you can add varioous actions to events in the combobox. What you did is add a reaction to the button-down-click Event. There you told excel to fill the list and set the SelectedCombobox variable to the - as of yet undefined - value of the combobox.
What you might want is one sub to fill the list as you did and another sub reacting to the change event of the combobox. That sub will be called as soon as someone changes the value of the box:
Private Sub ComboBox1_DropButtonClick()
Sheet1.ComboBox1.List = Sheet2.Range("A3:A46").Value
End Sub
Private Sub ComboBox1_Change()
SelectedComboBox1 = Me.ComboBox1.Value
End Sub
This should get you a good start. There are plenty of resources out-there that teach you how to write effective macros in Excel.
If you just need a result that uses the value of these three comboboxes, you could also connect a simple form-comboboxes with respective cells and claculate the result out of those cells.
But if you still want to use vba, think about using just one button to trigger a sub and access the values immediately:
Private Sub Button1_click
cells("A1").value=Me.ComboBox1.Value * Me.ComboBox2.Value...
End Sub

Related

Change list in ComboBox2 based on selected value in ComboBox1

I have the following Excel spreadsheet:
A B
1 Filter Selected 1 Filter Selected 2
2 Product A
3
4 List of ComboBox1 List of ComboBox2
5 Product A Brand A =IF($A$2=$A$5,"Brand A","Brand B")
6 Product B Brand A =IF($A$2=$A$5,"Brand A","Brand B")
7 Product C Brand A =IF($A$2=$A$5,"Brand A","Brand B")
8
In range A5:A7 you can find a list that I use in the the ComboBox1 within a UserForm. In range B5:B7 you can find a list that I use in the ComboBox2 within the UserForm. Once the user selects a value in one of the ComboBoxes it gets typed into either cell A2 or cell B2.
As you can see for the list of ComboBox2 I use an IF-Condition based on the selections of ComboBox1 so if the user selects Product A in CombobBox1 the list in range B5:B7 will be changed to Brand A.
However, this change is not immediately transferred to the ComboBox2 so instead of Brand A it is still showing Brand B unless I re-open the UserForm.
The code for my UserForm is:
Sub UserForm_Activate()
ComboBox1.List = Sheet1.Range("A5:A7").Value
ComboBox2.List = Sheet1.Range("B5:B7").Value
ComboBox1.Value = Sheet1.Range("A2")
ComboBox2.Value = Sheet1.Range("B2")
End Sub
Sub ComboBox1_Change()
Sheet1.Range("A2").Value = ComboBox1.Value
End Sub
Sub ComboBox2_Change()
Sheet1.Range("B2").Value = ComboBox2.Value
End Sub
Sub UserForm_Close()
Unload UserForm1
End Sub
What do I have to change in this code so the list in ComboBox2 is immediately updated after a value is selected in ComboBox1?
In the ComboBox1_Change event try to calculate the sheet to make sure the values in the formulas are updated before you reload the list in ComboBox2.
Sub ComboBox1_Change()
Sheet1.Range("A2").Value = ComboBox1.Value
Sheet1.Calculate 'update formula values
ComboBox2.List = Sheet1.Range("B5:B7").Value 'reload the values into the list
End Sub

Run time error 424 Object Required working with UserForm

I'm trying to link a user form I built in VBA editor for MS Excel 2010 to the data in an excel worksheet, but I'm getting a
run-time error 424: Object required.
I referred to the active worksheet explicitly in my code to try and remedy this, but it still comes up with the same error. My code is:
Private Sub GetData()
Dim r As Long
r = ActiveSheet.Range("B2").Value
If IsNumeric(RowNumber.Text) Then
r = CLng(RowNumber.Text)
Else
ClearData
MsgBox "Invalid row number"
Exit Sub
End If
If r > 1 And r <= LastRow Then
cboFilterResultId.Text = FormatNumber(Cells(r, 1), 0)
txtFolderPaths.Text = Cells(r, 2)
txtFileName.Text = Cells(r, 3)
txtDeletedDate.Text = Cells(r, 4)
txtReason.Text = Cells(r, 5)
txtcboAdd.Text = Cells(r, 6)
txtcboView.Text = Cells(r, 7)
txtcboChange.Text = Cells(r, 8)
DisableSave
ElseIf r = 1 Then
ClearData
Else
ClearData
MsgBox "Invalid row number"
End If
End Sub
Where RowNumber is a textbox where the user can enter the row number for the data they want.
Please help!
I rarely use ActiveSheet just in case that isn't the sheet I'm after. Generally better to be explicit which sheet you're referring to:
r=ThisWorkbook.WorkSheets("Sheet1").Range("B2")
Right, pulling data from a worksheet to a userform... as you haven't said which line your error occurs on and you haven't given us the code for ClearData or DisableSave I'll start from scratch.
Example Form Design
I create a blank userform and add three text boxes and a spin button to it:
txtRowNumber holds the row number that the data is pulled from.
TextBox1 and TextBox2 will hold my sample values.
In the Tag property of TextBox1 I enter 1 and in the Tag property of TextBox2 I enter 2. These are the column numbers that the data will be pulled from.
In reality I usually add extra stuff, for example, 8;CPER;REQD. I'd then use some code to pull it apart so it pastes in column 8, must have a percentage and is a required entry.
spnButton is used to quickly move up or down a row.
We'll need two procedures to populate the form from the given row number and to clear all controls on the form (ready for the next row to be brought in).
Any textbox or combobox that has something in it's Tag property is cleared:
Private Sub ClearForm()
Dim frmCtrl As Control
For Each frmCtrl In Me.Controls
If frmCtrl.Tag <> "" Then
Select Case TypeName(frmCtrl)
Case "TextBox", "ComboBox"
frmCtrl.Value = Null
Case Else
'Do nothing.
End Select
End If
Next frmCtrl
End Sub
Any control that has a Tag value (it's assumed the value is correct) is populated from the specified RowNumber and column (from the Tag value). The value is always taken from the sheet called MyDataSheet in the workbook containing the VBA code (ThisWorkbook) no matter which is currently active:
Private Sub PopulateForm(RowNumber As Long)
Dim frmCtrl As Control
For Each frmCtrl In Me.Controls
With frmCtrl
If .Tag <> "" Then
.Value = ThisWorkbook.Worksheets("MyDataSheet").Cells(RowNumber, CLng(.Tag))
End If
End With
Next frmCtrl
End Sub
Whenever txtRowNumber changes the form should update with values from the indicated row. To do this we'll need to clear the form of current data and then repopulate it:
Private Sub txtRowNumber_Change()
ClearForm
PopulateForm CLng(Me.txtRowNumber)
End Sub
The spin button should increase/decrease the value in .txtRowNumber. I've added checks that it doesn't go below 1. You should also add checks that it doesn't go higher than the last populated row.
Private Sub spnButton_SpinDown()
With Me
.txtRowNumber = CLng(.txtRowNumber) + 1
End With
End Sub
Private Sub spnButton_SpinUp()
With Me
If CLng(.txtRowNumber) > 1 Then
.txtRowNumber = CLng(.txtRowNumber) - 1
End If
End With
End Sub
Finally, the form should be populated when it is first opened:
Private Sub UserForm_Initialize()
With Me
.txtRowNumber = 2
.spnButton = .txtRowNumber
PopulateForm .txtRowNumber
End With
End Sub

Excel VBA: Accessing the individual fields in a selected ListBox row

I am trying to access the individual cells in a selected/highlighted ListBox "lstData" row so I can reference their values elsewhere.
When I set a watch for Me.lstData.SelectedItem, I get Expression not defined in context. Same with Me.lstData.SelectedIndex and Me.lstData.Rows(1). The only thing that kind of works for me is Me.lstData.Value, but it ONLY returns the leftmost cell. When I try to plug it into the =OFFSET function
=Offset(Me.lstData.Value, ,1,1)
to access the cell immediately to the right, I get Expression not defined in context again.
How can I reference the other selected cells?
I don't think you can use Offset on a ListBox form control. The way to reference a 'cell' in a multi-column ListBox is by indexing the List property.
Here, i returns the row of the selected item, and 1 represents the second column (base 0) of the listbox:
Option Explicit
Private Sub CommandButton1_Click()
Dim i As Long
With Me.ListBox1
i = .ListIndex
MsgBox .List(i, 1)
End With
End Sub
Private Sub UserForm_Initialize()
With Me.ListBox1
.AddItem "A"
.List(0, 1) = "Alpha"
.AddItem "B"
.List(1, 1) = "Beta"
End With
End Sub

VBA code simplification

I have the following macro
Private Sub ComboBox1_Change()
If ComboBox1 = "Berlin" Then
Range("C20").Activate
Else
If ComboBox1 = "Paris" Then
Range("C100").Activate
Else
If ComboBox1 = "London" Then
Range("C150").Activate
End If
End If
End If
End Sub
This macro takes the value from a dropdown menu and goes to the cell, where the value is. First question is:
How can I take the values from the cells and not write them specifically in the code?
Second question is:
How can I simplify the procedure and not write for every value an IF?
First, you probably don't actually want to Activate the range! See this answer:
How to avoid using Select in Excel VBA macros
Secondly, your code...
Your Code
Private Sub ComboBox1_Change()
If ComboBox1 = "Berlin" Then
Range("C20").Activate
Else
If ComboBox1 = "Paris" Then
Range("C100").Activate
Else
If ComboBox1 = "London" Then
Range("C150").Activate
End If
End If
End If
End Sub
Using ElseIf
Private Sub ComboBox1_Change()
If ComboBox1 = "Berlin" Then
Range("C20").Activate
ElseIf ComboBox1 = "Paris" Then
Range("C100").Activate
ElseIf ComboBox1 = "London" Then
Range("C150").Activate
End If
End Sub
See documentation: https://msdn.microsoft.com/en-us/library/office/gg251599.aspx
Not hard-coding the values
Private Sub ComboBox1_Change()
Dim rng as Range
Set rng = Nothing
Set rng = ActiveSheet.Range("C:C").Find(ComboBox1.Text)
If Not rng Is Nothing Then
' As I say, you probably don't actually want to use Activate!
rng.Activate
End If
End Sub
See more about the Range object here:
https://msdn.microsoft.com/en-us/library/office/ff838238.aspx
It has useful methods like Address or Value for common use in VBA. The Find function returns a Range object or Nothing if the given value isn't found in the given range.
How can I simplify the procedure and not write for every value an IF?
If you need to test your ComboBox repeatedly (like your If-ElseIf structure), you can use the SELECT CASE to simplify your code:
Private Sub ComboBox1_Change()
Select Case ComboBox1
Case Is = "Berlin"
Range("C20").Activate
Case Is = "Paris"
Range("C100").Activate
Case Is = "London"
Range("C150").Activate
Case Else
Range("C1").Activate
End Select
End Sub
This looks at the value of ComboBox1 and picks the appropriate section to run. For example, if ComboBox1 = "Paris", it skips to the "Paris" case and only runs that section (Range("C100").Activate).
This makes it much easier to add more items to your options, and it reduces the clutter of lots of If-ElseIf-Else lines.
Edit: As mentioned by Wujaszkun, adding the Case Else section handles a ComboBox1 value that was not one of the specified cases.

Formatting dates in a combobox dropdown list

I have created a simple userform with a combobox populated with a range of dates (rngWeekList) but I am having serious headaches trying to get the list in the dropdown box to appear in "dd-mmm-yy" format. Here is my code:
Private Sub UserForm_Initialize()
' Populate the list with the date range
ComboBox1.List = Worksheets("Cover").Range("rngWeekList").Value
' Set the defulat selection (based off rngWeekIndex)
ComboBox1.ListIndex = Worksheets("Cover").Range("rngWeekIndex").Value - 1
' Format
ComboBox1 = Format(ComboBox1, "dd-mmm-yy")
End Sub
Private Sub ComboBox1_Change()
' Format
ComboBox1 = Format(ComboBox1, "dd-mmm-yy")
End Sub
This manages to format the selected item in the combobox correctly (e.g. "02-Jul-14") but when I open the dropdown list, all the list entries shown are formatted in the default "m/d/yyyy". Is there a way to change the formatting for the list entries? It is confusing for users who are used to seeing the day before the month.
Thanks in advance for your help, it is much appreciated.
Ed
I managed to fix it by looping through each item in the comboboax and formatting it (feel free to correct me if there is a more elegant way to do it!)
Private Sub UserForm_Initialize()
Dim i As Integer
' Populate the list with the date range
ComboBox1.List = Worksheets("Cover").Range("rngWeekList").Value
'Format all items
For i = 0 To ComboBox1.ListCount - 1
ComboBox1.List(i) = Format(DateValue(ComboBox1.List(i)), "dd-mmm-yy")
Next i
' Set the default selection (based off rngWeekIndex)
ComboBox1.ListIndex = Worksheets("Cover").Range("rngWeekIndex").Value - 1
End Sub
Private Sub ComboBox1_Change()
' Format the selection
ComboBox1 = Format(ComboBox1, "dd-mmm-yy")
End Sub
Sorry for posting, but I really thought I was stuck.
Thanks again,
Ed