Using a counter in VBA - excel

I'm working making a loop to get data out of a combo form.
Analysis_1 is the first variable
Analysis_1_ComboB is the first ComboBox from the screen
Analysis_1 = Me.Analysis_1_ComboB.Column(0)
Analysis_2 = Me.Analysis_2_ComboB.Column(0)
Analysis_3 = Me.Analysis_3_ComboB.Column(0)
etc etc
as single lines, it is working I do want to work with a loop
for counter = 1 to 9
Analysis_&Counter = Me.Analysis_&Counter&_ComboB.Column(0)
next counter
unfortunately, this is not working, who can help me out here?

Unfortunately, you cannot dynamically specify variable names. (You can usually find a way to dynamically access various objects, especially if they are accessible be a "Name" index.)
The best way to achieve what you want to do is make your variables an array, e.g.:
Dim Analysis(1 To 9) As String
For counter = 1 To 9
Analysis(counter) = Me.Controls("Analysis_" & counter & "_ComboB").Column(0)
Next counter
MsgBox "Value from Analysis_5_ComboB is " & Analysis(5)
(This code assumes that your ComboBoxes are on a UserForm and therefore dynamically accessible via the form's Controls collection.)

Related

Utilizing a while loop to create combo boxes within Excel Spreadsheet

I need combo boxes to be placed in specific positions in relation to the cells on this Worksheet. I was attempting to utilize a while loop to change a variables value and utilize that variable to dynamic change a cell. However, my code doesn't seem to be working. The loop will run through once, but will give me a "object does not support this property or method" error on the successive loop.
Dim t As Integer
Dim wotype as object
t = 1
Do While t < 43
wotype = ActiveSheet.Shapes.AddFormControl(xlDropDown, Left:=Cells(4, t).Left, Top:=Cells(3, t).Top, Width:=25.29, Height:=Rows(3).RowHeight)
t = t + 3
Loop
When assigning an object to a variable, you need to use the Set keyword...
set wotype = ActiveSheet.Shapes.AddFormControl(xlDropDown, Left:=Cells(4, t).Left, Top:=Cells(3, t).Top, Width:=25.29, Height:=Rows(3).RowHeight)
Although, in this case, since you're not subsequently referring to your variable, your code can be re-written as follows...
Dim t As Integer
t = 1
Do While t < 43
ActiveSheet.Shapes.AddFormControl xlDropDown, Left:=Cells(4, t).Left, Top:=Cells(3, t).Top, Width:=25.29, Height:=Rows(3).RowHeight
t = t + 3
Loop

Having trouble using For/Next with variables

I am using an excel Userform and on the form I have created several label fields that are named in sequential order. For example:
Label1, Label2...LabelX
I want to assign the .caption for them from an array that I have built separately. Using a For/Next loop makes the most sense in my head, but since it is a label, I am having trouble. I cannot even get the code to take in a way that makes sense. Below is what I was trying...
For i = 1 To 100
Labeli.Caption = Array(i)
Next i
If there is a way to keep it inside of the loop, it would make the code a lot less cumbersome. Thank you in advance for your assistance.
Try this:
i = 1
For Each itm In Me.Controls
If itm.Name = "Label" & i Then
itm.Caption = Array(i)
i = i + 1
End If
Next
You cannot form an Object Name like Labeli where i is a Variable. But you can loop through all the controls and check if that Label have a Name like Label1 and so on.
Another Method:
For i = 1 To 100
Me.Controls("Label" & i).Caption = Array(i)
Next
What you can to is "build" the name of the Labels like this:
Userform.Controls("Label" & i).Caption
Userform is a Reference to the Userform, if you write it the codebehind of the Userform you can use Me.
But if you have a hundred Labels, there may be better ways to create your Userform, this looks a bit like a XY-Problem

Choosing a listbox from multiple list boxes

I am somewhat new to excel vba and I am in search of an answer on how to choose a list box by using a variable.
For instance the code I found is as follows:
Me.ListBox2.AddItem Me.LB_JobList.List(iCtr)
Instead of ListBox2 I would like the 2 to be another number selected by the user from a combo box.
Current code is:
FrameNumber = CMB_FrameNumber.Value 'number selected by user
lb = ("ListBox" & FrameNumber) 'this would = ListBox#
Therefore I would like something similar to
Me.lb.AddItem Me.LB_JobList.List(iCtr)
The comment above is good, but if you want to do something a little safer (in case you have more numbers available than controls, say), you could loop through the available controls and check against their name.
For Each contr In UserForm1.Controls
If TypeName(contr) = "ListBox" And contr.Name = ("ListBox" & FrameNumber) Then
lb = contr
End If
Next

Variable that contains different value for each loop

I would like to download prices from the internet. The concept works, when I define symb as a constant value (e.g. K15). But now, I want to download data from different links, where the part symb changes according to the value of the cells G13 to G22 in my spreadsheet. (In other words, I want to go through each row from G13 to G22 - each containing a different value for symb - and download the data from the respective link).
I tried that with a simple loop, defining the variable symb in each one of the loops:
For i = 1 To 10
Symb = Worksheets("Futures").Range("G12").Offset(i, 0).Value
Set qt = querysheet.QueryTables.Add( _
Connection:="URL;" & "http://download.finance.yahoo.com/d/quotes.csv?s=" & Symb & ".cbt&f=sl1d1t1c1ohgv&e=.csv", _
Destination:=querysheet.Cells(5 + i, 1))
Next i
Obviously, it doesn't work like this. I assume that it is not possible to define a variable within the loop, is it? Can somebody give me a hint how I can make that work?
There's something worng with your Connection String. When I get rid of the .cbt in the URL string, it works. Or, you may have forgotten to include some letters, so debug it in your browser and get the Connection string correct and it should work.
You may also want to modify the destination, like so, and refresh the table:
Set qt = querySheet.QueryTables.Add( _
Connection:="URL;" & "http://download.finance.yahoo.com/d/quotes.csv?s=" & Symb & "&f=sl1d1t1c1ohgv&e=.csv", _
Destination:=querySheet.Cells(5, 1))
qt.Refresh
you could use an array like this
symb(1 to 10) as String
for i=1 to 10
symb(i)=cells(i,1)
next i

VBA subroutine slows down a lot after first execution

I have a subroutine that generates a report of performance of different portfolios within 5 families. The thing is that the portfolios in question are never the same and the amount in each family neither. So, I copy paste a template (that is formated and...) and add the formated row (containing the formula and...) in the right family for each portfolio in the report. Everything works just fine, the code is not optimal and perfect of course, but it works fine for what we need. The problem is not the code itself, it is that when I execute the code the first time, it goes really fast (like 1 second)... but from the second time, the code slows down dramatically (almost 30 second for a basic task identical to the first one). I tried all the manual calculation, not refreshing the screen and ... but it is really not where the problem comes from. It looks like a memory leak to me, but I cannot find where is the problem! Why would the code runs very fast but sooooo much slower right after... Whatever the length of the report and the content of the file, I would need to close excel and reopen it for each report.
**Not sure if I am clear, but it is not because the code makes the excel file larger or something, because after the first (fast) execution, if I save the workbook, close and reopen it, the (new) first execution will again be very fast, but if I would have done the same excat thing without closing and reopening it would have been very slow...^!^!
Dim Family As String
Dim FamilyN As String
Dim FamilyP As String
Dim NumberOfFamily As Integer
Dim i As Integer
Dim zone As Integer
Sheets("RapportTemplate").Cells.Copy Destination:=Sheets("Rapport").Cells
Sheets("Rapport").Activate
i = 3
NumberOfFamily = 0
FamilyP = Sheets("RawDataMV").Cells(i, 4)
While (Sheets("RawDataMV").Cells(i, 3) <> "") And (i < 100)
Family = Sheets("RawDataMV").Cells(i, 4)
FamilyN = Sheets("RawDataMV").Cells(i + 1, 4)
If (Sheets("RawDataMV").Cells(i, 3) <> "TOTAL") And _
(Sheets("RawDataMV").Cells(i, 2) <> "Total") Then
If (Family <> FamilyP) Then
NumberOfFamily = NumberOfFamily + 1
End If
With Sheets("Rapport")
.Rows(i + 8 + (NumberOfFamily * 3)).EntireRow.Insert
.Rows(1).Copy Destination:=Sheets("Rapport").Rows(i + 8 + (NumberOfFamily * 3))
.Cells(i + 8 + (NumberOfFamily * 3), 6).Value = Sheets("RawDataMV").Cells(i, 2).Value
.Cells(i + 8 + (NumberOfFamily * 3), 7).Value = Sheets("RawDataMV").Cells(i, 3).Value
End With
End If
i = i + 1
FamilyP = Family
Wend
For i = 2 To 10
If Sheets("Controle").Cells(16, i).Value = "" Then
Sheets("Rapport").Cells(1, i + 11).EntireColumn.Hidden = True
Else
Sheets("Rapport").Cells(1, i + 11).EntireColumn.Hidden = False
End If
Next i
Sheets("Rapport").Cells(1, 1).EntireRow.Hidden = True
'Define printing area
zone = Sheets("Rapport").Cells(4, 3).End(xlDown).Row
Sheets("Rapport").PageSetup.PrintArea = "$D$4:$Y$" & zone
Sheets("Rapport").Calculate
Sheets("RANK").Calculate
Sheets("SommaireGroupeMV").Calculate
Sheets("SommaireGroupeAlpha").Calculate
Application.CutCopyMode = False
End Sub
I do not have laptop with me at the moment but you may try several things:
use option explicit to make sure you declare all variables before using them;
from what I remember native vba type for numbers is not integer but long, and integers are converted to long, to save the computation time use long instead of integers;
your Family variables are defined as strings but you store in them whole cells and not their values i.e. =cells() instead of =cells().value;
a rule of a thumb is to use cells(rows.count, 4).end(xlup).row
instead of cells(3, 4).end(xldown).row.;
conditional formatting may slow down things a lot;
use for each loop on a range if possible instead of while, or even copy range to variant array and iterate over that (that is the fastest solution);
use early binding rahter of late binding, i.e., define objects in a proper type as soon a possible;
do not show printing area (page breaks etc.);
try to do some pofiling and look for the bottlenecks - see finding excel vba bottlenecks;
paste only values if you do not need formats;
clear clipboard after each copy/paste;
set objects to Nothing after finishing using them;
use Value2 instead of Value - that will ignore formatting and take only numeric value instead of formatted value;
use sheet objects and refer to them, for example
Dim sh_raw As Sheet, sh_rap As Sheet
set sh_raw = Sheets("RawDataMV")
set sh_rap = Sheets("Rapport")
and then use sh_raw instead of Sheets("RawDataMV") everywhere;
I had the same problem, but I finally figured it out. This is going to sound ridiculous, but it has everything to do with print page setup. Apparently Excel recalculates it every time you update a cell and this is what's causing the slowdown.
Try using
Sheets("Rapport").DisplayPageBreaks = False
at the beginning of your routine, before any calculations and
Sheets("Rapport").DisplayPageBreaks = True
at the end of it.
I had the same problem. I am far from expert programer. The above answers helped my program but did not solve the problem. I'm running excel 2013 on a 5 year old lap top. Open the program without running it, go to File>OptionsAdvanced, Scroll down to Data and uncheck "Disable undo for large Pivot table refresh...." and "Disable undo for large data Model operation". You could also try leaving them checked but decreasing their value. One or both of these seem to be creating a ever increase file that slows the macro and eventual grinds it to a stop. I assume closing excel clears the files they create so that's why it runs fast when excel is closed and reopened at least for a while. Someone with more knowledge will have to explain what these changes will do and what the consequences are of unchecking them. It appears these changes will be applied to any new spread sheets you create. Maybe these changes would not be necessary if I had a newer more powerful computer.

Resources