Sorting Macro not functioning properly - vba

I've written a macro to cut and paste rows from one sheet ("New Providers - FPPE") into multiple sheets based on a column (H). When I first used it, it was working well, but when I have added additional data to the sorting sheet ("New Providers - FPPE") it is not fully functioning. The macro continues to cut the rows from "New Providers - FPPE" but the rows fail to populate onto the sheets. I have no idea where the rows are going. Does anyone have any insight as to what could be happening? I'm very new to writing macros so any help is appreciated!
Option Explicit
Sub Fr33M4cro()
Dim sh33tName As String
Dim custNameColumn As String
Dim i As Long
Dim stRow As Long
Dim customer As String
Dim ws As Worksheet
Dim sheetExist As Boolean
Dim sh As Worksheet
sh33tName = "New Providers - FPPE"
custNameColumn = "H"
stRow = 7
Set sh = Sheets(sh33tName)
For i = sh.Range(custNameColumn & sh.Rows.Count).End(xlUp).Row To stRow Step -1
customer = sh.Range(custNameColumn & i).Value
For Each ws In ThisWorkbook.Sheets
If StrComp(ws.Name, customer, vbTextCompare) = 0 Then
sheetExist = True
Exit For
End If
Next
If sheetExist Then
CopyRow i, sh, ws, custNameColumn
Else
InsertSheet customer
Set ws = Sheets(Worksheets.Count)
CopyRow i, sh, ws, custNameColumn
End If
Reset sheetExist
Next i
End Sub
Private Sub CopyRow(i As Long, ByRef sh As Worksheet, ByRef ws As Worksheet, custNameColumn As String)
Dim wsRow As Long
wsRow = ws.Range(custNameColumn & ws.Rows.Count).End(xlUp).Row + 1
ws.Rows(wsRow).EntireRow.Value = sh.Rows(i).EntireRow.Value
sh.Rows(i).EntireRow.Delete
End Sub
Private Sub Reset(ByRef x As Boolean)
x = False
End Sub
Private Sub InsertSheet(shName As String)
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = shName
End Sub

I suggest you change your InsertSheet sub to a function that returns a reference to the inserted worksheet:
Function InsertSheet(shName As String) As Worksheet
Set InsertSheet = Worksheets.Add(After:=Worksheets(Worksheets.Count))
InsertSheet.Name = shName
End Function
then change this part of the code:
InsertSheet customer
Set ws = Sheets(Worksheets.Count)
CopyRow i, sh, ws, custNameColumn
to this:
Set ws = InsertSheet(customer)
CopyRow i, sh, ws, custNameColumn

Related

Activate a closed workbook, perform lRow VBA

I've been through heaps of forums and still can't understand where I'm going wrong. One of my first VBA code attempts.
Private Sub Refresh_Click()
Dim ws As Long
Dim lRow As Variant
Dim wb As Workbook
Dim Arr() As Variant
Dim DHSWMP As String
Dim Dams As String
Dim PotR As String
DHSWMP = "E:\Copy of PWC DHSWMP WorkSheets.xlsm"
'Dams = "x"
'PotR = "x"
Application.ScreenUpdating = False
Set wb = Workbooks.Open(DHSWMP, True, False)
wb.Activate
ws = Worksheets.Count
Do While ws > 0
wb.Sheets(ws).Activate
lRow = Cells(Rows.Count, 2).End(xlUp).Row
MsgBox (lRow)
The code makes it through, however it is performing the lRow on the 'mastersheet' from which the macro is run and not the opened workbook. One bit that does confuse me it that the code does perform the worksheets.count on the opened workbook.
Cheers
Your code runs as expected for me. This is a perfect example of why you should fully qualify your references.
To test what is going on:
Don't turn off ScreenUpdating
Improve your MsgBox
Use F8 to step through the code
Use the Immediate Window for additional test
MsgBox Cells(Rows.Count, 2).End(xlUp).Address & vbNewLine & Cells(Rows.Count, 2).End(xlUp).Parent.Name & vbNewLine & Cells(Rows.Count, 2).End(xlUp).Parent.Parent.Name
Cells.Parent.Name: Returns the name of the Worksheet
Cells.Parent.Name: Returns the name of the Workbook
You should avoid the use of Do and While loops while iterating; if you know both the start and the end. For and For Each loops wi
Here are two different ways of writing your code. Notice that the use of With statements and the qualified references. For example both the Cells and the Rows are qualified to the Worksheet in: .Cells(.Rows.Count, 2).End(xlUp).Row. This is very important to avoid any confusion on the what is the actual target of the code.
Private Sub Refresh_Click()
Application.ScreenUpdating = False
Dim ws As Worksheet, wbDHSWMP As Workbook
Dim lRow As Variant
Dim Arr() As Variant
Dim DHSWMP As String, Dams As String, PotR As String
DHSWMP = "C:\Copy of PWC DHSWMP WorkSheets.xlsm"
Set wbDHSWMP = Workbooks.Open(DHSWMP, True, False)
For Each ws In wbDHSWMP.Worksheets
With ws
lRow = .Cells(.Rows.Count, 2).End(xlUp).Row
MsgBox (lRow)
End With
Next
Application.ScreenUpdating = True
End Sub
Private Sub Refresh_Click()
Application.ScreenUpdating = False
Dim wbDHSWMP As Workbook
Dim lRow As Variant, n As Long
Dim Arr() As Variant
Dim DHSWMP As String, Dams As String, PotR As String
DHSWMP = "C:\Copy of PWC DHSWMP WorkSheets.xlsm"
Set wbDHSWMP = Workbooks.Open(DHSWMP, True, False)
For n = wbDHSWMP.Worksheets.Count To 1 Step -1
With wbDHSWMP.Worksheets(n)
lRow = .Cells(.Rows.Count, 2).End(xlUp).Row
MsgBox (lRow)
End With
Next
Application.ScreenUpdating = True
End Sub

Copy VBA code from one sheet to all other sheets in workbook

I have code in my workbook that i need to copy to all sheets within the workbook, so when i update the code on one sheet, i dont need to copy/paste manually to all other sheets
The code is on a mastersheet called "Contents"
Alternatively, if i can get help to apply the code to all sheets from "ThisWorkbook" (I did try this option, however i could not get it to work)
This is the code i need applied to all sheets:
Private Sub CommandButton1_Click()
If ComboBox3.Value <> "" Then
Worksheets(ComboBox3.Value).Activate
ElseIf ComboBox3.Value = "" And ComboBox2.Value <> "" Then
Worksheets(ComboBox2.Value).Activate
Else:
Worksheets(ComboBox1.Value).Activate
End If
End Sub
Private Sub ComboBox2_Change()
Dim rngMenu2 As Range
Dim rngList As Range
Dim strSelected As String
Dim LastRow As Long
' check that a Menu1 has been selected
If ComboBox2.ListIndex <> -1 Then
ComboBox3.Clear
strSelected = ComboBox2.Value
LastRow = Worksheets("Contents").Range("F" & Rows.Count).End(xlUp).Row
Set rngList = Worksheets("Contents").Range("F1:F" & LastRow)
For Each rngMenu2 In rngList
If rngMenu2.Value = strSelected Then
ComboBox3.AddItem rngMenu2.Offset(, 1)
End If
Next rngMenu2
End If
End Sub
Private Sub ComboBox1_Change()
Dim rngMenu1 As Range
Dim rngList As Range
Dim strSelected As String
Dim LastRow As Long
' check that a Menu1 has been selected
If ComboBox1.ListIndex <> -1 Then
ComboBox2.Clear
ComboBox3.Clear
strSelected = ComboBox1.Value
LastRow = Worksheets("Contents").Range("D" & Rows.Count).End(xlUp).Row
Set rngList = Worksheets("Contents").Range("D1:D" & LastRow)
For Each rngMenu1 In rngList
If rngMenu1.Value = strSelected Then
ComboBox2.AddItem rngMenu1.Offset(, 1)
End If
Next rngMenu1
End If
End Sub
This is the code i have to copy code to another sheet, but it only copies to 1 sheet, how can i change this to all sheets? I would also need this to delete any existing code before copying the new code to the sheets...
I have a list of sheet names in a range
Private Sub CommandButton2_Click()
Dim CodeCopy As VBIDE.CodeModule
Dim CodePaste As VBIDE.CodeModule
Dim numLines As Integer
Dim rngList As Range
Dim LastRow As Long
LastRow = Worksheets("Contents").Range("H" & Rows.Count).End(xlUp).Row
Set rngList = Worksheets("Contents").Range("H1:H" & LastRow)
Set CodeCopy = ActiveWorkbook.VBProject.VBComponents("Sheet1").CodeModule
Set CodePaste = ActiveWorkbook.VBProject.VBComponents("Sheet40").CodeModule
End Sub
Any assistance with this would be awesome (Note: im a newbie with coding! :)
Thanks in advance!

Subscript out of range - runtime error 9

can you please advise why the below code does not select the visible sheets, but ends in a runtime error. This is driving me crazy. Thanks for any help.
Sub SelectSheets1()
Dim mySheet As Object
Dim mysheetarray As String
For Each mySheet In Sheets
With mySheet
If .Visible = True And mysheetarray = "" Then
mysheetarray = "Array(""" & mySheet.Name
ElseIf .Visible = True Then
mysheetarray = mysheetarray & """, """ & mySheet.Name
Else
End If
End With
Next mySheet
mysheetarray = mysheetarray & """)"
Sheets(mysheetarray).Select
End Sub
Long story short - you are giving a string (mysheetarray) when it is expecting array. VBA likes to get what it expects.
Long story long - this is the way to select all visible sheets:
Option Explicit
Sub SelectAllVisibleSheets()
Dim varArray() As Variant
Dim lngCounter As Long
For lngCounter = 1 To Sheets.Count
If Sheets(lngCounter).Visible Then
ReDim Preserve varArray(lngCounter - 1)
varArray(lngCounter - 1) = lngCounter
End If
Next lngCounter
Sheets(varArray).Select
End Sub
You should define Dim mySheet As Object as Worksheet.
Also, you can use an array of Sheet.Names that are visible.
Code
Sub SelectSheets1()
Dim mySheet As Worksheet
Dim mysheetarray() As String
Dim i As Long
ReDim mysheetarray(Sheets.Count) '< init array to all existing worksheets, will optimize later
i = 0
For Each mySheet In Sheets
If mySheet.Visible = xlSheetVisible Then
mysheetarray(i) = mySheet.Name
i = i + 1
End If
Next mySheet
ReDim Preserve mysheetarray(0 To i - 1) '<-- optimize array size
Sheets(mysheetarray).Select
End Sub
I have tried to explain the Sheets a little, HTH.
Note: Sheets property is defined on Workbook and on Application objects, both works and returns the Sheets-Collection.
Option Explicit
Sub SheetsDemo()
' All sheets
Dim allSheets As Sheets
Set allSheets = ActiveWorkbook.Sheets
' Filtered sheets by sheet name
Dim firstTwoSheets As Sheets
Set firstTwoSheets = allSheets.Item(Array("Sheet1", "Sheet2"))
' or simply: allSheets(Array("Sheet1", "Sheet2"))
' Array("Sheet1", "Sheet2") is function which returns Variant with strings
' So you simply need an array of sheet names which are visible
Dim visibleSheetNames As String
Dim sh As Variant ' Sheet class doesn't exist so we can use Object or Variant
For Each sh In allSheets
If sh.Visible Then _
visibleSheetNames = visibleSheetNames & sh.Name & ","
Next sh
If Strings.Len(visibleSheetNames) > 0 Then
' We have some visible sheets so filter them out
visibleSheetNames = Strings.Left(visibleSheetNames, Strings.Len(visibleSheetNames) - 1)
Dim visibleSheets As Sheets
Set visibleSheets = allSheets.Item(Strings.Split(visibleSheetNames, ","))
visibleSheets.Select
End If
End Sub

Looping through different sheets

I would appreciate your help with the macro I am trying to create.
I have an xls file with a bunch of worksheets, some of which named "1", "2", "3", and so forth. I would like to create a macro that loops only through those 'number-named' worksheets, hence NOT according to the index as in the code below. (Sheet "1" is not the first sheet in the workbook). Before the loop I need to define both the cell range and sheets.
Below is my (wrong) attempt.
Sub Refresh ()
Dim i As Integer
Dim rng As Range
Set rng = Range("A10:TZ180")
For i = 1 To 30
Sheets(i).Activate
rng.Select
rng.ClearContents
Application.Run macro:="xxx"
Next i
End Sub
dim w as worksheet
for each w in activeworkbook.worksheets
if isnumeric(w.name) then
w.range("A10:TZ180").clearcontents
xxx()
end if
next
If the macro "xxx()" requires a selected range you just need to add a select statement. (Borrowing from GSerg)
Dim w As Worksheet
For Each w In ActiveWorkbook.Worksheets
If IsNumeric(w.Name) Then
w.Range("A10:TZ180").ClearContents
w.Range("A10:TZ180").Select
Application.Run macro:="xxx"
End If
Next
To clear up your misunderstanding about assigning a range see the following:
Sub Refresh()
Dim ws As Worksheet
Dim rng As Range
Dim i As Integer
For Each ws In ActiveWorkbook.Worksheets
If IsNumeric(ws.Name) Then
'you must activate the worksheet before selecting a range on it
ws.Activate
'note the qualifier: ws.range()
Set rng = ws.Range("A10:TZ180")
'since the range is on the active sheet, we can select it
rng.Select
rng.ClearContents
Application.Run macro:="xxx"
End If
Next
End Sub
Sub test2()
Dim ws As Worksheet
Dim rg As Range
Dim arrSheets As Variant
arrSheets = Array("Sheet1", "Sheet2", "Sheet3")
Dim x As Long
For x = LBound(arrSheets) To UBound(arrSheets)
Set ws = Worksheets(arrSheets(x))
ws.Activate
'...
Next
End Sub
Sub test3()
Dim ws As Worksheet
Dim x As Long
For x = 1 To 20
Set ws = Worksheets(CStr(x))
ws.Activate
'...
Next
End Sub
try this
Sub main()
Dim shtNames As Variant, shtName As Variant
shtNames = Array(1, 2, 3, 4) '<== put your actual sheets "number name"
For Each shtName In shtNames
With Worksheets(CStr(shtName))
.Range("A10:TZ180").ClearContents
.Range("A10:TZ180").Select
Application.Run macro:="MacroToRun"
End With
Next shtName
End Sub
Sub MacroToRun()
MsgBox "hello from cells '" & Selection.Address & "' in sheet '" & ActiveCell.Parent.Name & "'"
End Sub

Select all "visible" worksheets (to print to pdf)

I'm using the following in an existing app and this works fine as is to print particular worksheets to a pdf:
Sheets(Array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")).Select
I'm trying to print an array of just my "visible" worksheets.
I've searched for a solution but can't put my finger on it.
A short approach that uses the False argument to add to an existing selection:
Sub Test()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Sheets
If ws.Visible Then ws.Select False
Next
End Sub
try this
Option Explicit
Sub main()
ThisWorkbook.Sheets(GetVisibleWorksheetsNames(ThisWorkbook)).Select
End Sub
Function GetVisibleWorksheetsNames(wb As Workbook) As String()
Dim ws As Worksheet
Dim wsNames() As String
Dim iV As Long
With wb
ReDim wsNames(1 To .Worksheets.Count)
For Each ws In .Worksheets
If ws.Visible Then
iV = iV + 1
wsNames(iV) = ws.name
End If
Next ws
ReDim Preserve wsNames(1 To iV)
End With
GetVisibleWorksheetsNames = wsNames
End Function
Try this code, it should do what you are looking for.
Sub SelectSheets()
Dim myArray() As Variant
Dim i As Integer
Dim j As Integer
j = 0
For i = 1 To Sheets.Count
If Sheets(i).Visible = True Then
ReDim Preserve myArray(j)
myArray(j) = i
j = j + 1
End If
Next i
Sheets(myArray).Select
End Sub