Combo box VBA Excel - vba

I am using around 8-10 comboboxes(form control),each one having the same list of items populated. Based on the user's selection from the dropdown, a certain value is displayed in a different cell. I wanted to know if there is way to do this without using a loop(for dropdowns) as all have the same function. Here is the code I am using:
Dim ws As Sheets
Set ws = ThisWorkbook.Sheets(Array("S1 Fuel Consumption", "EF_Stat", "Summary"))
Dim i As Integer
For i = 1 To 8
With ws(1).Shapes("Fuel " & i).ControlFormat ~~> 'This is the loop I'm talking about(for 8 shapes)
Select Case .ListIndex
Case 1
ws(3).Range("B" & i).Value = Empty
Case 2
ws(3).Range("B" & i).Value = ws(2).Range("B4").Value
Case 3
ws(3).Range("B" & i).Value = ws(2).Range("C4").Value
Case 4
ws(3).Range("B" & i).Value = ws(2).Range("D4").Value
End Select
End With
Next i

Assign the same macro to all of the comboboxes and use:
With WS(1).Dropdowns(Application.Caller)
to get a reference to the combobox that triggered the macro.
If you need to figure out the 'i' value you were using in the loop originally, you can do something like this:
Dim ws As Sheets
Dim sCaller As String
Dim i As Integer
Dim rgOutput As Range
Set ws = ThisWorkbook.Sheets(Array("S1 Fuel Consumption", "EF_Stat", "Summary"))
sCaller = Application.Caller
Set rgOutput = ws(3).Range("B" & Replace(sCaller, "Fuel ", ""))
Select Case ws(1).DropDowns(sCaller).ListIndex
Case 1
rgOutput.Value = vbNullString
Case 2
rgOutput.Value = ws(2).Range("B4").Value
Case 3
rgOutput.Value = ws(2).Range("C4").Value
Case 4
rgOutput.Value = ws(2).Range("D4").Value
End Select

Related

End(xlDown) for single rows

I have a macro that is working 99% of the time, but giving me trouble with one portion. I have data that is split into different size groups depending on certain parameters. The groups range from 1 row to as many at 10+. I am trying to copy each of the "groups" and paste into a template sheet and save which I've figured out.
Row Column B Column C
1 ASDF a
2 SDF a
3 WIRO a
4 VNDH a
5
6 FIJDK b
7 DFKIEL b
8
9 DLFKD c
10
11 OYPTK d
12 SSAODKJ d
13 SKJSJ d
Where I'm having trouble is Row 9 where Column b B = DLFKD and Column C = C
Desired Output:
Copy only row 9
Actual Output:
Copying Rows 9- 11
Existing Macro:
Data begins on Row 5.
Sub templatecopy()
Dim x As Workbook
Dim y As Workbook
Dim N As Long
Dim name As String
'## Open both workbooks first:
Set x = ActiveWorkbook
'Set R
R = 5
'start Loop
Do Until N = 96
Set y = Workbooks.Open("F:\Logistics Dashboard\Customs Macro\Cover Sheet Template.xlsx")
'set N
N = Range("B" & R).Cells(1, 1).End(xlDown).Row
'Now, copy Container Numbers from x and past to y(template):
x.Sheets("Sheet1").Range("B" & R & ":C" & N).Copy
y.Sheets("Sheet1").Range("A14").PasteSpecial
'save as Name of Vessel
name = "F:\Logistics Dashboard\Customs Macro\" & y.Sheets("Sheet1").Range("A14").Value & ".xlsx"
ActiveWorkbook.SaveAs Filename:=name
'Close template after saving to reset:
y.Close
'set R equal to new row to start
R = N + 2
Loop
End Sub
The issue is with how I am setting "N". Its having trouble distinguishing Row 9 where its just one row of data.
With the correct sheet selected this line of code should select the ranges on your sheet:
Thisworkbook.Worksheets("Sheet1").range("B:C").specialcells(xlcelltypeconstants,23).select
You'll need to add another line to account for formula as well as constants.
Public Sub FindRegionsOnSheet()
Dim sAddress As String
Dim aAddress() As String
Dim vItem As Variant
Dim x As Long
Dim wbTarget As Workbook
Dim wsSource As Worksheet
Dim wsTarget As Worksheet
Set wsSource = ThisWorkbook.Worksheets("Sheet1")
Set wbTarget = Workbooks.Open("F:\Logistics Dashboard\Customs Macro\Cover Sheet Template.xlsx")
Set wsTarget = wbTarget.Worksheets("Sheet1")
'Find all ranges of constant & formula values in column B:C.
With wsSource.Columns(2).Resize(, 2)
On Error Resume Next
sAddress = .SpecialCells(xlCellTypeConstants, 23).Address(0, 0) & ","
sAddress = sAddress & .SpecialCells(xlCellTypeFormulas, 23).Address(0, 0)
If Right(sAddress, 1) = "," Then sAddress = Left(sAddress, Len(sAddress) - 1)
On Error GoTo 0
End With
'Place within an array.
If Not sAddress = vbNullString Then
If InStr(1, sAddress, ",") = 0 Then
ReDim aAddress(0 To 0)
aAddress(0) = "'" & wsSource.Name & "'!" & sAddress
Else
aAddress = Split(sAddress, ",")
For x = LBound(aAddress) To UBound(aAddress)
aAddress(x) = "'" & wsSource.Name & "'!" & aAddress(x)
Next x
End If
End If
''''''''''''''''''''''''''''''''''''''''
'Not sure how what you're doing once moved to the Target book......
'Think this is correct, but test first...
''''''''''''''''''''''''''''''''''''''''
For Each vItem In aAddress
wsTarget.Cells.Clear
Range(vItem).Copy Destination:=wsTarget.Range("A14")
wbTarget.SaveCopyAs "F:\Logistics Dashboard\Customs Macro\" & wbTarget.Sheets("Sheet1").Range("A14") & ".xlsx"
Next vItem
wbTarget.Close
End Sub
The 23 in the SpecialCells indicates what types of cells to include in the result:
XlSpecialCellsValue constants Value
xlErrors 16
xlLogical 4
xlNumbers 1
xlTextValues 2
These values can be added together to return more than one type (total = 23). The default is to select all constants or formulas, no matter what the type.... so probably don't need the 23 at all.

Replacing a Case Statement with a Loop

I have this code but its hard coded. I need it to be automated in a loop or something else instead of a case statement till the empty column stops but more column will be added in a form. So the range can go from B2 to the late column in the excel sheet only if the column header is there and then it stops. It will shows the content in each column. Please note the excel sheet is called Area
Can this be done?
Private Sub ComboBox3_Change()
Dim i As Long
i = ComboBox3.ListIndex
ComboBox4.Clear
Select Case i
Case Is = 0
With Worksheets("Area")
ComboBox4.List = .Range("**B2:B**" & .Range("**b**" & Rows.Count).End(xlUp).Row).Value
End With
Case Is = 1
With Worksheets("Area")
ComboBox4.List = .Range("**C2:C**" & .Range("**c**" & Rows.Count).End(xlUp).Row).Value
End With
Case Is = 2
With Worksheets("Area")
ComboBox4.List = .Range("**D2:D**" & .Range("**d**" & Rows.Count).End(xlUp).Row).Value
End With
Case Is = 3
With Worksheets("Area")
ComboBox4.List = .Range("**E2:E**" & .Range("**e**" & Rows.Count).End(xlUp).Row).Value
End With
Case Is = 4
With Worksheets("Area")
ComboBox4.List = .Range("**F2:F**" & .Range("**f**" & Rows.Count).End(xlUp).Row).Value
End With
End Select
End Sub
Something like this should work for you:
Private Sub ComboBox3_Change()
Dim ws As Worksheet
Dim ColNum As Long
Set ws = ActiveWorkbook.Sheets("Area")
ColNum = Me.ComboBox3.ListIndex + 2
Me.ComboBox4.Clear
If ColNum < 2 Then Exit Sub 'Nothing selected
Me.ComboBox4.List = ws.Range(ws.Cells(2, ColNum), ws.Cells(ws.Rows.Count, ColNum).End(xlUp)).Value
End Sub
If you want to enumerate the column number into column name use Chr(65) where 65 is the ASCII value for A.
In your case add 66 to your integer i like Chr(66+i) which returns B
Also, there is a function to convert column number into column name in excel, =SUBSTITUTE(ADDRESS(1,col_number,4),"1","") although I haven't tried it in VBA.
In your specific case, you don't need a case statement at all
Private Sub ComboBox3_Change()
Dim i As Long
i = ComboBox3.ListIndex
ComboBox4.Clear
With Worksheets("Area")
ComboBox4.List = .Range("**E2:E**" & .Range("**e**" & Rows.Count).End(xlUp).Row).Offset(0,i).Value
End Sub
might need some tweaking since I can't test it out. But offset by 0 rows and i columns is the best solution for you

Automatic update of textbox value based on last value in worksheet

I have these in a worksheet
Then on a userform, I want that as I change the chapter, the No. part automatically updates that if on the worksheet, Chapter 1 last No. is 1 so No. on the userform automatically updates to 2, then same with Chapter 2 and 3.
This is what I tried:
Dim label As Control
For ctr = 1 To InfoForm.Chapter.ListCount - 1
For Each label In InfoForm.Controls
If TypeName(label) = "Label" Then
i = i + 1
Dim WhatChapter As String
WhatChapter = InfoForm.Chapter
lastNum = Cells(.Rows.Count, "A").End(xlUp).Row
If WhatChapter = "Chapter " & ctr Then
If Cells(lastNum, i).Value = "No." Then
Num.Value = 1
Else
Num.Value = Cells(lastNum, i).Value
End If
End If
End If
Next
Next ctr

Windows Script to open Excel file and run macro

Sorry I am very new to VBA so am learning as I go along. I have tried to search for an answer to this but everything I find seems to think that the macro will be in the file I want to open.
Once a month I get a file that contains some data. Up to now I had to look at the data then do a VLOOKUP to add some additional data before saving it.
I have now written a VBA macro to add the additional information I want and it works as intended. However what I would like to do is have a Windows script that will open the file I receive, run the macro I have written, then save the file as a csv.
Can anyone point me in the right direction? If needed my macro is below
Sub AddBandInfo()
Dim i As Long
For i = 2 To 50000
Dim band As String, result As Double
band = Range("B" & i).Value
If band = "A" Then result = 1144.02
If band = "B" Then result = 1334.7
If band = "C" Then result = 1525.36
If band = "D" Then result = 1716.04
If band = "E" Then result = 2097.38
If band = "F" Then result = 2478.72
If band = "G" Then result = 2860.08
If band = "H" Then result = 3432.08
If band = "" Then result = 0.01
Range("C" & i).Value = result
Next i
Dim r As Long
For r = Sheet1.UsedRange.Rows.Count To 1 Step -1
If Cells(r, "C") = "0.01" Then
Sheet1.Rows(r).EntireRow.Delete
End If
Next
End Sub
Thanks
Create a .txt-file and rename it to .vbs.
Start your code with:
Set objXLS = CreateObject("Excel.Application")
Set myWkbk = objXLS.Application.Workbooks.Open("C:\mypath\myfile.xlsx")
Set myWksh = myWkbk.Worksheets("yoursheet")
With myWksh
'your
'code
'here
End With
Set objXLS = Nothing
All done. :)
We can improve AddBandInfo speed and performance by
Toggling Application.ScreenUpdating
Looping from the last row to the first row (doing this allows use to delete the rows as we go)
If 50000 isn't the actual last row use
For i = Range("B" & Rows.Count).End(xlUp).Row To 2 Step -1
Public Sub AddBandInfo()
Dim i As Long
Application.ScreenUpdating = False
For i = 50000 To 2 Step -1
Dim band As String, result As Double
band = Range("B" & i).Value
Select Case Cells(i, 2).Value
Case "A"
Range("C" & i).Value = 1144.02
Case "B"
Range("C" & i).Value = 1334.7
Case "C"
Range("C" & i).Value = 1525.36
Case "D"
Range("C" & i).Value = 1716.04
Case "E"
Range("C" & i).Value = 2097.38
Case "F"
Range("C" & i).Value = 2478.72
Case "G"
Range("C" & i).Value = 2860.08
Case "H"
Range("C" & i).Value = 3432.08
Case Else
Rows(i).EntireRow.Delete
End Select
Next
Application.ScreenUpdating = True
End Sub
Assuming AddBandInfo is saved in C:\somedirectory\somefile.xlsx and that you want a vbscript to open the Workbook and then run AddBandInfo:
Const WorkBookPath = "C:\somedirectory\somefile.xlsx"
Dim xlApplication, xlWorkbook
Set xlApplication = CreateObject("Excel.Application")
Set xlWorkbook = xlApplication.Workbooks.Open(WorkBookPath)
xlApplication.Run "'" & xlWorkbook.Name & "'!AddBandInfo()"
xlWorkbook.Save , False
xlApplication.Quit
Set xlApplication = Nothing

Compare sheet 1 col 1 to sheet 2 col 1 place value in sheet 1 col 6

First time posting a question, so please correct me if I do anything I'm not supposed to!
I have a macro written on a button press to compare 2 columns on 2 sheets and output either the value from sheet 2 col 1 in sheet 1 col 6 OR output "None" in sheet1 col 6 if there isn't a match.
My code is buggy and takes a long time to run (around 5000 entry's on sheet 1 and 2000 on sheet 2).
My code works partly; it only matches around 2/3rd's of the col 1's on either sheet.
Sub Find_Sup()
Dim count As Integer
Dim loopend As Integer
Dim PartNo1 As String
Dim PartNo2 As String
Dim partRow As String
Dim SupRow As String
Dim supplier As String
Let partRow = 2
Let SupRow = 2
'Find total parts to check
Sheets("Linnworks Supplier Update").Select
Range("A1").End(xlDown).Select
loopend = Selection.row
Application.ScreenUpdating = False
'main loop
For count = 1 To loopend
jump1:
'progress bar
Application.StatusBar = "Progress: " & count & " of " & loopend & ": " & Format(count / loopend, "0%")
Let PartNo2 = Worksheets("Linnworks Supplier Update").Cells(SupRow, 1).Value
Let supplier = Worksheets("Linnworks Supplier Update").Cells(SupRow, 2).Value
If PartNo2 = "" Then
SupRow = 2
Else
jump2:
Let PartNo1 = Worksheets("Linnworks Stock").Cells(partRow, 1).Value
'add part numbers than do match
If PartNo2 = PartNo1 Then
Let Worksheets("Linnworks Stock").Cells(partRow, 5).Value = supplier
Let partRow = partRow + 1
Let count = count + 1
GoTo jump2
Else
Let SupRow = SupRow + 1
GoTo jump1
End If
End If
Next
Application.StatusBar = True
End Sub
I have done some coding in C and C++ and a little VB.NET. Any help streamlining this code or pointing me in the right direction would be very gratefully received!
I realise there are similar questions but all other options I've tried (nested for each loops) don't seem to work correctly.
This is the closest I've managed to get so far.
Many Thanks for reading
try something like this instead and leave feedback so I can edit the answer to match perfectly
Sub Main()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = Sheets("Linnworks Supplier Update")
Set ws2 = Sheets("Linnworks Stock")
Dim partNo2 As Range
Dim partNo1 As Range
For Each partNo2 In ws1.Range("A1:A" & ws1.Range("A" & Rows.Count).End(xlUp).Row)
For Each partNo1 In ws2.Range("A1:A" & ws2.Range("A" & Rows.Count).End(xlUp).Row)
If StrComp(Trim(partNo2), Trim(partNo1), vbTextCompare) = 0 Then
ws2.Range("E" & partNo1.Row) = partNo2.Offset(0, 1)
ws2.Range("F" & partNo1.Row) = partNo2
End If
Next
Next
'now if no match was found then put NO MATCH in cell
for each partno1 in ws2.Range("E1:F" & ws2.Range("A" & Rows.Count).End(xlUp).Row)
if isempty(partno1) then partno1 = "no match"
next
End Sub