VBA; what it means, when there are arguments in the brackets after the subroutine title? - vba

I've written about 10 easy macros in the last 18 months, and I would like to understand more than I do in VBA programming.
In none of the subroutines I've written were there arguments in the brackets after the subroutine title.
I have found this code (found here) on stackoverflow.
It's used to find the last row that contains data in the Excel sheet.
But it's got some arguments/parameters (please explain the difference) in the brackets after the subroutine name, which I've never seen before.
What do these arguments stand for? I'm unable to figure this out.
Sub GetLastRow(strSheet, strColumn)
Dim MyRange As Range
Dim lngLastRow As Long
Set MyRange = Worksheets(strSheet).Range(strColum & "1")
lngLastRow = Cells(Rows.Count, MyRange.Column).End(xlUp).Row
End Sub
Another thing I don't understand is why the "MyRange" variable needed to be created.
Was this necessary or is there a way to simplify this code, get rid of "MyRange" variable and use Worksheets("MBank_Statsy").UsedRange property??
Below you can see the worksheet that I would like to apply this code to.

I think the comments upon your question have probably given you all the info you need on why things are done the way they are, but if you're interested, the entire subroutine could be reduced to:
Function GetLastRow(strSheet, strColumn)
GetLastRow = Cells(Rows.Count, Worksheets(strSheet).Range(strColumn & "1").Column).End(xlUp).Row
End Function
Note: this is now a function. To find out the last used cell in Sheet1, column 'C' for instance, you would do something like this:
lastrowused = GetLastRow("Sheet1","C")
I suspect that the original routine started out with more going on (perhaps it found the last cell and did something to it) and has been stripped down to just retrieving the last row but no thought was given to reducing unnecessary instructions.

Related

Add-in function Range.Delete method fails

First, I would like to apologize for my bad language, I hope you'll understand my problem.
I looked after a way to get generic function in Excel and I found the add-in method. So I tried to use it in developping custom functions whitch may help me in my everyday work. I developed a first function which work. So I thought that my add-in programmation and installation was good. But when I try to implement worksheet interractions nothing appened.
My code has to delete rows identified by a special code in a cell of those ones. I get no error message and the code seems to be totally executed. I tried other methods like Cells.delete, Cells.select, worksheet.activate or range.delete but I encounter the same issue.
This is my function's code :
Public Function NotBin1Cleaning(rSCell As Range) As Integer
Dim sht As Worksheet
Dim aLine As New ArrayList
Dim iLine As Integer
Dim iCpt As Integer
Dim iFail As Integer
Dim i As Integer
Dim oRange As Object
Set sht = rSCell.Parent
iLine = sht.Cells.Find("*PID*").Row
For Each rCell In Range(sht.Cells(iLine, 1), sht.Cells(sht.Cells(iLine, 1).End(xlDown).Row, 1))
If sht.Cells(rCell.Row, 2) > 1 Then
iLine = rCell.Row
iCpt = iLine + 1
Do Until sht.Cells(iCpt, 2) = 1
If Not sht.Cells(iCpt, 1) = rCell Then Exit Do
iCpt = iCpt + 1
Loop
If sht.Cells(iCpt, 1) = rCell Then
sht.Range(sht.Cells(iLine, 1), sht.Cells(iCpt - 1, sht.Cells(iCpt, 1).End(xlToRight).Column)).Delete xlUp
iFail = iFail + 1
End If
End If
Next
NotBin1Cleaning = iFail
End Function
it's the line:
sht.Range(sht.Cells(iLine, 1), sht.Cells(iCpt - 1, sht.Cells(iCpt, 1).End(xlToRight).Column)).Delete xlUp
which isn't producing any effect.
I would be really thankful for your help.
This issue is described on the Microsoft support site as part of the intentional design
section below, more detail here (emphasis mine)
A user-defined function called by a formula in a worksheet cell cannot change the environment of Microsoft Excel. This means that such
a function cannot do any of the following:
Insert, delete, or format cells on the spreadsheet.
Change another cell's value.
Move, rename, delete, or add sheets to a workbook.
Change any of the environment options, such as calculation mode or screen views.
Add names to a workbook.
Set properties or execute most methods.
The purpose of user-defined functions is to allow the user to create a
custom function that is not included in the functions that ship with
Microsoft Excel. The functions included in Microsoft Excel also cannot
change the environment. Functions can perform a calculation that
returns either a value or text to the cell that they are entered in.
Any environmental changes should be made through the use of a Visual
Basic subroutine.
Essentially, this means that what you're trying to do won't work in such a concise manner. The limitation, as I understand from further reading, is because Excel runs through cell equation/functions several times to determine dependencies. This would lead to your function being called two or more times. If you could delete rows, there is the potential of accidentally deleting more then twice the numbers of rows intended, due to the excess number of runs.
However, an alternative could be to have the function output a unique string result that shouldn't be found anywhere else in your workbook (maybe something like [#]><).
Then you can have a sub, ran manually, which finds all instances of that unique string, and deletes those rows. (Note: if you included any of the typical wildcard symbols in your string, you will have to precede them with a ~ to find them with the .Find method.) You can even set up the sub/macro with a shortcut key. Caution: if you duplicate a shortcut key Excel already uses, it will run the macro instead of the default. If there will be other users using this workbook, they could experience some unexpected results.
If you decide to go this route, I would recommend using this line:
Public Const dummy_str = "[#]><" ' whatever string you decided on.
in your module with your code. It goes outside any functions or subs, so it'll be global, and then you can refer to the const just as you would any other string variable.
When you write:
sht.Range(sht.Cells(iLine, 1),....
This first parameter should be the row number, but you're refering to a Cell instead. You should change sht.Cells(iLine, 1) for iLine.
BUT
Instead of all this, its easier to use the method Row.Delete:
Rows(iLine).EntireRow.Delete

Excel Selecting a Row

I am Trying to create a macro that will take the 1st Cell of a selection and merge it with the 6th Cell. I am getting error 400.
Sub SignPage()
Dim ws As Worksheet, BasePoint As Range, row As Long, singlecell As Long,
singleCol As Long, sLong As Long, sShort As String
Set BasePoint = Selection
row = BasePoint.row
Range(Cells(row, BasePoint.Columns(1)), Cells(row, BasePoint.Columns(6))).Merge
End Sub
This should be enough:
Selection(1).Resize(, 6).Merge
Explanation: Selection can span several cells, so Selection(1) takes the top left cell - thus, we always refer to one cell.
The point is that you should refer to the first column of Basepoint and take its column. This could be achieved, if you amend your line like to this:
Range(Cells(row,BasePoint.Columns(1).Column),Cells(row,BasePoint.Columns(6).Column)).Merge
As an advice:
do not use names like row, column, Cells, Range etc. as a variable, the Excel object module library inside VBA uses them as well. In your case, you have BasePoint.row. If you did not have the variable row, then the VBEditor would have written BasePoint.Row automatically.
try to avoid Selection, although it depends on the context - How to avoid using Select in Excel VBA
as #Mat's Mug mentioned in the comments, it is a good habit to show the "parent" of Cells and Ranges, when you are using them.
Thus in your case, something like this:
With Worksheets(1)
.Range(.Cells(row, BP.Columns(1).Column), .Cells(row, BP.Columns(6).Column)).Merge
End With
Then it would always refer to the first worksheet (or whichever you need to) and not to the ActiveSheet, which would be referred, if the Parent in not mentioned. (I have written BP instead of BasePoint to make sure it goes on one line.)

Excel VBA Copy-paste-move

I am only new to VBA coding so I don't have much of a clue of what I am doing unfortunately. I was hoping that I could get a hand here.
What I want to do is.
Step One: Copy a line (which has formulas) and paste it in the same position but as values only.
Step Two: Move a selection of cells down one line.
Step Three: Copy a line (with formulas) and past it on another line with the formulas.
This is all done on the same sheet.
If I could get some help with this or some direction to some tutorials that would be really appreciated.
Normally I wouldn't do this without your showing some effort, but why not? The below are about as simple as I can get. Please still though, use the macro recorder to see how this all works. It's how a lot of us get started.
Sub StepOne()
Dim myRow As Long
myRow = 1 ' We will "copy/paste" on Row 1
' To avoid using the clipboard, you can simply set two ranges' values equal. This will
' clear out any formulas and leave the values.
Rows(myRow).Value = Rows(myRow).Value
End Sub
And the second:
Sub StepTwo()
Dim rng As Range
'Change this as required. Note the use of `Set` with a `Range` type.
Set rng = Range("A1:A10")
rng.Cut rng.Offset(1, 0)
End Sub
And the last one:
Sub StepThree()
' Not tellin :P! You should be able to get this. Hint: look at StepOne.
End Sub
Edit: Ah, I realize now that Step Three is a little more involved than setting two ranges equal since you want to maintain the formula. However, I'll leave this as a learning opportunity for you to investigate. If you can't figure it out, let me know and I can guide you. :D

VBA Range Output to Cell

I'm struggling a bit with VBA syntax tonight, and would appreciate your help.
I have a Userform that takes input through RefEdit fields, and stores that as a variable (range). (This is done through
set DurationRange = range(me.refedit1.value)
which was an earlier question of mine tonight.
This user form takes this range input, and outputs the range into a different sheet for further processing. What I would like to do is basically output the variable again.
I'm trying that with this code:
with worksheets("Data Output")
.range("a1").offset(0, counter) = "Durations" 'this line just creates a header cell
.range("a2").offset(0, counter) = DurationsRange 'this line should output the range into cell a2
End with
But although this outputs the string, it does nothing for the range. What is the proper method to output a range? I know I could do a for each loop, but I have so many ranges that that seems incredibly inefficient.
There are some possible answers:
1st. if your DurationRange is a single cell range than you need to improve your code only in this line:
.range("a2").offset(0, counter) = DurationsRange.Value 'Value property is important here
2nd. if your DurationRange consists of one single column and some rows then you could possibly use this solution:
.range("a2").offset(0, counter).Resize(DurationRange.Rows.Count) = DurationsRange.Value 'Value property is important here, too
Obviously, there are some other options which could be solved in similar way to 2nd example above.

Subscript out of range Error after renaming sheets

I have done a small project, which consists of 5 excel sheet in, code is working fine and I am getting exact result also, but if I rename sheets from sheet1 to some other name I am getting Subscript out of range Error.
What is the reason for this and what needs to be done to overcome this. Please help.
Below is the code
Public Sub amount_final()
Dim Row1Crnt As Long
Dim Row2Crnt As Long
With Sheets("sheet4")
Row1Last = .Cells(Rows.Count, "B").End(xlUp).Row
End With
Row1Crnt = 2
With Sheets("sheet3")
Row2Last = .Cells(Rows.Count, "B").End(xlUp).Row
End With
There is nothing wrong with the code per se. You will get Subscript out of range error if Excel is not able to find a particular sheet which is quite obvious since you renamed it. For example, if you rename your sheet "Sheet3" to "SheetXYZ" then Excel will not be able to find it.
The only way to avoid these kind of errors is to use CODENAME of the sheets. See Snapshot
Here we have a sheet which has a name "Sample Name before Renaming"
So consider this code
Sheets("Sample Name before Renaming").Range("A1").Value = "Blah Blah"
The same code can be written as
Sheet2.Range("A1").Value = "Blah Blah"
Now no matter how many times you rename the sheet, the above code will always work :)
HTH
Sid
The basic issue is that you are referring to sheets using their common names and not their codenames. Whenever you refer to Sheets("sheet4"), you are relying on the sheet having that name in Excel. Codenames are the names assigned in Visual Basic so the end user does not interact with them/as a developer you can change the Excel names any time you like
Using code names is covered at around 9:40 in this Excel help video. You'll note they are quicker to type than the Excel names as do not require the 'Sheets()' qualifier
I couldn't see Sheets("Sheet1") in your code sample but you can switch to codenames for all sheets very quickly by finding/replacing all examples of e.g. 'Sheets("Sheet2").' with 'Sheet2.'
Refer to each sheet by their code names instead. They are set to Sheet1, Sheet2 etc as default, but you can rename them in the Properties window for each sheet if you want. This way you can write your code like below instead, regardless of what you name the sheets.
With Sheet1
Row1Last = .Cells(Rows.Count, "B").End(xlUp).Row
End With
Row1Crnt = 2
With Sheet2
Row2Last = .Cells(Rows.Count, "B").End(xlUp).Row
End With
etc...
I wanted to share my experience battling this problem. Here is the mistake I committed:
Dim DailyWSNameNew As String
lastrow = Sheets("DailyWSNameNew").Range("A65536").End(xlUp).Row + 1 -- This is wrong as I included a placeholder worksheet name in quotes
Correction:
lastrow = Sheets(DailyWSNameNew).Range("A65536").End(xlUp).Row + 1
This solved it.
I encountered this error earlier today but could not use any solution above, I did however eventually managed to solve it myself.
My situation was that I had a list contained in column A. For each cell with a value I stored the value in a variable, created a new sheet and named the sheet according to the value stored in the variable.
A bit later in the code I tried to select the newly created sheet by using the code:
Sheets(ValueVariable).Select
I encountered the "Subscript out of range" error and I couldn't figure out why. I've used similar code before with success.
I did however solve it by casting the variable as a string. Declaring the variable as a string did not seem to work for me.
So, if anyone else encounter this error and want something to try, perhaps this will work for you:
Sheets(Cstr(ValueVariable)).Select