excel VBA - Loop of an array - excel

I made this simple code, or at least tried. But I have one small problem.
When I type For I = 14 To 25 I don't really know what I'm doing. I have a sheet called "Master" and in the range K6:V6 I have every name of every sheet I want to go through. I would like to write something like this: For I = sheets("Master").range("K6:V6") But this does not work, anyone that can help to me to assign the "names" in this array to I?
The rest of the code works as it should, it could be optimized by not having "select" but I don't seem to be able to do it so I took the easy way out. Thank you for your help!
Dim I As Integer
For I = 14 To 25
If Sheets(I).Visible = False Then
'If sheet = Not visble
'-----------------------------------------------------------------------------------------------------
Sheets(I).Visible = True
AA = Sheets("Master").Range("K6").Value
Sheets(AA).Select
ActiveSheet.Unprotect
ActiveSheet.Range("C3:C120").Copy
Range("G3").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
ActiveSheet.Range("C6:C120").ClearContents
ActiveSheet.Range("L6:M117").ClearContents
ActiveSheet.Protect
Range("A1").Select
Sheets(I).Visible = False
'-----------------------------------------------------------------------------------------------------
Else:
'If sheet = visble
'-----------------------------------------------------------------------------------------------------
AA = Sheets("Master").Range("K6").Value
Sheets(AA).Select
ActiveSheet.Unprotect
ActiveSheet.Range("C3:C120").Copy
Range("G3").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
ActiveSheet.Range("C6:C120").ClearContents
ActiveSheet.Range("L6:M117").ClearContents
ActiveSheet.Protect
Range("A1").Select
'-----------------------------------------------------------------------------------------------------
End If
Next I

Each Worksheet in a file is held in the Worksheets collection. You can look at each worksheet in the collection in turn and act on it.
Sub Test()
Dim wrkSht As Worksheet
Dim shtMaster As Worksheet
Dim InList As Range
Dim VisibleSetting As Long
Set shtMaster = ThisWorkbook.Worksheets("Master") 'Reference to Master worksheet
'This will look at each worksheet in the worksheets collection and reference it with 'wrkSht'
For Each wrkSht In ThisWorkbook.Worksheets
'Look for the worksheet name in the K6:V6 range.
Set InList = shtMaster.Range("K6:V6").Find(wrkSht.Name, LookIn:=xlValues, LookAt:=xlWhole)
'If the name is found InList will not be nothing.
If Not InList Is Nothing Then
With wrkSht
VisibleSetting = .Visible 'Remember the visible setting.
.Visible = xlSheetVisible
.Unprotect
.Range("C3:C120").Copy
.Range("G3").PasteSpecial xlPasteValues
Union(.Range("C3:C120"), .Range("L6:M17")).ClearContents
.Visible = VisibleSetting 'Put the visible setting back.
.Protect
End With
End If
Next wrkSht
End Sub
Further reading:
ThisWorkbook
With...End With Statement
For Each...Next Statement

Related

Paste Special macro Excel

Sub Copy_Cell2()
'Declare Variables
Dim Wr As Worksheet
'Define the excel sheet
Set Wr = ThisWorkbook.Sheets("Sheet2")
'Code to stop screen updating and flickering ON
Application.ScreenUpdating = False
'Select Sheet1 to get the random value
Sheets("Sheet1").Select
Cells.Select
Range("F1").Select
Range("F1").Copy
'Selects Sheet2 to paste the random value in the next blank cell in column A
Sheets("Sheet2").Select
Range("A2").Select
nrlife = Wr.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Select
'Establish what row has been selected
With ActiveCell
vRow = .Row
End With
vRange = "A" & vRow & ""
Range(vRange).Select
'Code to paste value and format from Sheet1 to first empty row on sheet2
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks_:=False, Transpose:=False
'Code to stop screen updating and flickering OFF
Application.ScreenUpdating = True
End Sub
I am getting error in Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks_:=False, Transpose:=False
Error code is Run-time error '1004' Aplication-defined or
object-defined error
Can anyone help me what am i missing?
Your code reduces to:
Dim wb As Workbook
Set wb = ThisWorkbook
wb.Sheets("Sheet2").Cells(Rows.Count, "A").End(xlUp).Offset(1).Value = _
wb.Sheets("Sheet1").Range("F1").Value
You can assign values directly - no need for copy/paste in this case.

Why does this show errors when it was working

Code at the bottom
Hi, I just got this macro to repair. People tell me that it was working before.
This macro is supposed to copy only the visible filtered data (dynamic tables mainly) and create a new excel file with all the same worksheets but with only the visible data copied and paste in them (worksheets) with no dynamic table. This is meant to reduce the weight of the file but not to make an exact copy.
You are supposed to open this file with the one you want to transfer data and you run the macro in the files you want to copy.
First there were methods errors with 'Sheets(Pages).Select' (I switched from .Activate) and it worked.
After that 'NewBook.Sheets(1).Range("A1:BZ500").Select' were methods errors for range, so I split it in two lines:
'NewBook.Sheets(1).activate'
'Range("A1:BZ500").Select'
This resolved that error.
After that, there is a name attribution error (like the name is already used) to the line:
NewBook.Sheets(1).Name = OldBook.Sheets(Page).Name ( i tried a spy but ieverything was ok) so I decided to write it like NewBook.Sheets(1).Name = OldBook.Sheets(Page).Name + Cstr(Page)
It resolved the error but the macro is still not doing what it's meant to:
Set OldBook = ActiveWorkbook
Set NewBook = Workbooks.Add
NewBook.Worksheets(1).Name = "Vide"
OldBook.Activate
For Page = 1 To Sheets.Count - 1
OldBook.Activate
Sheets(Page).Activate
Sheets(Page).Copy Before:=NewBook.Sheets(1)
NewBook.Activate
NewBook.Sheets(1).Name = OldBook.Sheets(Page).Name
NewBook.Sheets(1).Range("A1:BZ500").Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Next
End Sub
Below is the one with my corrections:
Sub Fichier_Plat()
Code_optimizer (True)
Set OldBook = ActiveWorkbook
Set NewBook = Workbooks.Add
NewBook.Worksheets(1).Name = "Vide"
OldBook.Activate
For Page = 1 To Sheets.Count - 1
OldBook.Activate
Sheets(Page).Activate
Sheets(Page).Copy Before:=NewBook.Sheets(1)
NewBook.Activate
NewBook.Sheets(1).Name = OldBook.Sheets(Page).Name + CStr(Page)
NewBook.Sheets(1).Activate
Range("A1:BZ500").Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Next
Code_optimizer (False)
End Sub
I'd start by giving the original coder a hard slap for not defining the variables/not having 'Option Explicit' at the top of the module, for using Select and Activate and for hard-coding the range that's to be copied.
Maybe this code would be better?
Public Sub Fichier_Plat()
Dim OldBook As Workbook 'Declare your variables!
Set OldBook = ActiveWorkbook
Dim NewBook As Workbook
Set NewBook = Workbooks.Add(xlWBATWorksheet) 'Create new workbook with a single sheet.
NewBook.Worksheets(1).Name = "Vide"
Dim wrkSht As Worksheet
Dim newwrksht As Worksheet
For Each wrkSht In OldBook.Worksheets 'Look at each sheet in turn.
Set newwrksht = NewBook.Worksheets.Add
With newwrksht
.Name = wrkSht.Name 'Will cause error if one of them is called "Vide". Can use wrksht.Index to get number of sheet.
wrkSht.Range(wrkSht.Cells(1, 1), LastCell(wrkSht)).Copy
.Range("A1").PasteSpecial xlPasteValues
.Range("A1").PasteSpecial xlPasteFormats
End With
Next wrkSht
End Sub
Public Function LastCell(wrkSht As Worksheet) As Range
Dim LastCol As Long, LastRow As Long
On Error Resume Next
With wrkSht
LastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
LastRow = .Cells.Find("*", , , , xlByRows, xlPrevious).Row
End With
If LastCol = 0 Then LastCol = 1
If LastRow = 0 Then LastRow = 1
Set LastCell = wrkSht.Cells(LastRow, LastCol)
End Function

VBA Best way to match an ID number from a spreadsheet to another sheet and then update the information

I am doing an Excel Workbook project for a poker room. There is a Player Database within the program. Each player has an ID number.
For the sake of my question I'm going to refer to two Sheets.
When a player comes in for that day they are logged in with Name, ID, and Time (This sheet is Worksheets("Cashout")). Cashout Sheet
Then when the player buys poker chips they get added to another sheet (Worksheets("Tab")).Tab Sheet This sheet keeps track of the chips that are purchased. Some of these players get loans from the house so they end up with a Tab. On the "Tab" sheet there is a cmd button called Cashout.
When the player is done for the day the goal is to click the cashout button and submit any remaining tab and the players end time to the "Cashout" sheet. Since both of these sheets have the players ID number, I am thinking that is how I should find the record on the Cashout page, but let me know if there is an easier way.
I have it working with using do loops and ActiveCell select, but it is a lot of code, and select slows the process. I know there is a better way to do this possibly Find, Match or even a For Each loop. Please let me know to change my code.
I am attaching the code that works, but I don't want to use it.
Private Sub CmdBtnCashout1_Click()
Dim LastRow As Long
Dim Rng1 As Range
Dim Rng2 As Range
Dim Rng3 As Range
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim cnt As Integer
Set ws1 = Worksheets("Tab")
Set ws2 = Worksheets("Cashout")
Set Rng1 = Worksheets("Tab").Range("A5")
Set Rng2 = Worksheets("Tab").Range("C4")
Set Rng3 = Worksheets("Tab").Range("W5")
cnt = 1
Application.ScreenUpdating = False
Rng1.Select
Selection.Copy
ws2.Activate
ws2.Range("A4").Select
If ws2.Range("A4") = "" Then
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws1.Activate
Rng2.Select
Application.CutCopyMode = False
Selection.Copy
ws2.Activate
ActiveCell.Offset(0, 2).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws1.Activate
Rng3.Select
Application.CutCopyMode = False
Selection.Copy
ws2.Activate
ActiveCell.Offset(0, 3).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws2.Range("A1").Select
ws1.Activate
ws1.Range("A1").Select
Application.CutCopyMode = False
Range("A1").Select
Else
Do Until ActiveCell.value = ""
ActiveCell.Offset(1, 0).Select
cnt = cnt + 1
If cnt > 49 Then Exit Do
Loop
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws1.Activate
Rng2.Select
Application.CutCopyMode = False
Selection.Copy
ws2.Activate
ActiveCell.Offset(0, 2).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws1.Activate
Rng3.Select
Application.CutCopyMode = False
Selection.Copy
ws2.Activate
ActiveCell.Offset(0, 3).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
ws2.Range("A1").Select
ws1.Activate
ws1.Range("A1").Select
Application.CutCopyMode = False
Range("A1").Select
End If
Application.ScreenUpdating = True
End Sub
Tab sheet: with Cashout Button: the player name is in Cell A5, ID number is in A4, tab balance is in W5.
Cashout Sheet: player name is within the range of A4:A53 and Player ID number is in range of B4:B53 this is where i would need to match my reference then insert the tab balance from the Tab Sheet in range G4:G53 on the row with that player. I also want to just insert the time stamp in E4:E53.
The sub would be worksheet level sub on the Tab Sheet using the CashoutCommandBtn Click event
How should I do this?
I found a way to do this see the attached code which works perfectly except I have 20 subs for 20 buttons. I know there is a way for me to put the long code into a module and call it from a sub so I am going to try and work on that so that the 20 subs have at least minimal code instead of the long code.
\\
Private Sub CmdBtnCashout1_Click()
Dim Rng2 As Range
Dim TimeOut As Date
Dim wst As Worksheet
Dim wsco As Worksheet
Dim Rng1 As Range
Dim Balance As Range
Dim COPlayer As Range
Dim COPlayerRng As Range
Dim i As Integer
Dim j As Integer
Dim Urng1 As Range
Dim Urng2 As Range
Dim UnionRng As Range
Dim WinLoss As Range
Dim ChipReturn As Range
Set COPlayerRng = Worksheets("Cashout").Range("B4:B53")
Set wst = Worksheets("Tab")
Set wsco = Worksheets("Cashout")
i = 4
j = 5
Set Rng1 = Worksheets("Tab").Cells(i, 1)
Set Rng2 = Worksheets("Tab").Cells(1, 1)
Set Balance = Worksheets("Tab").Cells(j, 23)
Set WinLoss = Worksheets("Tab").Cells(j, 24)
Set COPlayer = COPlayerRng.Find(What:=Rng1.value,LookIn:=xlValues,LookAt:=xlWhole)
Set Urng1 = wst.Range(Cells(i, 1), Cells(j, 1))
Set Urng2 = wst.Range(Cells(i, 3), Cells(j, 22))
Set UnionRng = Union(Urng1, Urng2)
Set ChipReturn = wst.Range(Cells(i, 25), Cells(j, 25))
TimeOut = Time
Application.ScreenUpdating = False
Application.FindFormat.Clear
Application.ReplaceFormat.Clear
With COPlayer
.Offset(0, 7).value = Balance.value
.Offset(0, 3).value = TimeOut
.Offset(0, 6).value = WinLoss.value
End With
Rng2.Select
UnionRng.ClearContents
ChipReturn.ClearContents
wst.Range("A6:V43").Copy
wst.Range("A4").PasteSpecial (xlPasteValues)
Application.CutCopyMode = False
wst.Range("A1").Select
Application.FindFormat.Clear
Application.ReplaceFormat.Clear
Application.ScreenUpdating = True
End Sub
\\
By using a few variables and the "find" function and "with" statement provided me with a solution that works. I am still new to VBA so if there is any way to streamline this code or to use a standard module and calling a sub from there to eliminate the code for 20 buttons let me know. The variables "i" and "j" are used to count rows in the Cells Property. The code above is for one of the buttons on the worksheet. when the command button is pressed the it looks for the matching value for the ID number. After that is complete it takes the data from cell "A4" and "A5 and "C4" and "V5" and moves that information to another worksheet. the variables "i" = 4 and "j" = 5. The next button code is identical except since the row changes "i" = 6 and "J" = 7 and so on.

Loop that references different sheet names each iteration

I have the following loop to create multiple tabs in Excel 2016 based on a list of PO#'s. ( see code below)
Sub CreateSheetsFromAList()
Dim MyRange As Range
Dim dic As Object, c As Range
Dim k As Variant, tmp As String
Set dic = CreateObject("scripting.dictionary")
Set MyRange = Sheets("Instructions").Range("h6")
Set MyRange = Range(MyRange, MyRange.End(xlDown))
Sheets("Template").Visible = True
For Each c In MyRange
tmp = Trim(c.Value)
If Len(tmp) > 0 Then dic(tmp) = dic(tmp) + 1
Next c
For Each k In dic.keys
If Not WorksheetExists(k) Then
Sheets("Template").Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = k
End If
Next k
End Sub
Public Function WorksheetExists(ByVal WorksheetName As String) As Boolean
On Error Resume Next
WorksheetExists = (Sheets(WorksheetName).Name <> "")
On Error GoTo 0
End Function
I also need to populate each newly created tab with info from another workbook (EDI PO Consolidated - 2018.xlsx)
(see code below)
Sub BandB2()
' BandB2 Macro
' Keyboard Shortcut: Ctrl+b
'
Application.Goto Reference:="R20C10"
Selection.Copy
Windows("EDI PO Consolidated - 2018.xlsx").Activate
ActiveSheet.Range("$A$1:$X$2628").AutoFilter Field:=2, Criteria1:= _
"34535453"
Application.Goto Reference:="R1C9"
Range("I2058").Select
Application.CutCopyMode = False
Selection.Copy
Windows("Book and Bill form - template.xlsm").Activate
Range("J26").Select
ActiveSheet.Paste
Windows("EDI PO Consolidated - 2018.xlsx").Activate
ActiveWindow.SmallScroll ToRight:=4
Application.Goto Reference:="R1C17"
Range("Q2058").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Windows("Book and Bill form - template.xlsm").Activate
ActiveWindow.SmallScroll Down:=6
Range("C33").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Windows("EDI PO Consolidated - 2018.xlsx").Activate
Application.Goto Reference:="R1C14"
Range("N2058").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Windows("Book and Bill form - template.xlsm").Activate
Range("D33").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Windows("EDI PO Consolidated - 2018.xlsx").Activate
Application.Goto Reference:="R1C18"
Range("R2058:T2058").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
Windows("Book and Bill form - template.xlsm").Activate
Range("E33").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
I have 2 questions:
1) i cannot make the sheet reference change for each tab; it always picks the
1st po# "34535453"
2) Can you help me combine these into 1 macro.
thank you in advance for your help
Here's a cleaner way to create those tabs.
Name cell H6 on the Instructions tab "PO_Start" or some other appropriate name. That way if you can insert rows or columns on the tab without possibly having to change the reference to H6 in your code.
Sub Create_Sheets()
Dim PO_list, PO As Range
Set PO_list = Range(Sheets("Instructions").Range("PO_Start"), Sheets("Instructions").Range("PO_Start").End(xlDown))
Sheets("Template").Visible = True
For Each PO In PO_list
If Not WorksheetExists(PO) Then
Sheets("Template").Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = PO
End If
Next PO
End Sub
1) To loop through your tabs, if you know that your PO tabs will always start on tab 3, you can loop through the sheets like this (including variable declarations):
Sub B_and_B()
Dim ws As Worksheet
Dim i As Integer
For i = 3 To Sheets.Count
Set ws = Sheets(i)
'... rest of code here
Next i
End Sub
Otherwise if down the road you anticipate adding other sheets besides "Instructions" and "Template" to your Book and Bill file, you could loop through all sheets, error checking to see if you can convert the sheet name to a "long" variable type with Clng(). Probably more than what's needed for your current project.
Another tip:
Avoid using hard-coded cell addresses ("N2058") in your code. If you filter on purchase orders in the Consolidated book and then pull in certain data elements, you'll need to find the row the Purchase Order is in (2058 in this case).
2) To combine these into one macro, you can create a Main subroutine, calling each step separately:
Sub Main()
Call Create_Sheets
Call B_and_B
End Sub

Cant write to cell

I am trying to get data from every other sheet in the workbook and paste it into a master sheet (Sheet1), but when I run my code nothing happens, Can someone tell me why this is?
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ActiveWorkbook
wb.Sheets("Sheet1").Cells(1, 1).Text = "Started"
i = 1
'cells is row,col
For Each objWorksheet In wb.Worksheets
'ws.Cells(1, i).Value = objWorksheet.Name
'objWorksheet.Activate
'ws = wb.ActiveSheet
doJStuff i, objWorksheet
i = i + 1
Next
wb.Sheets("Sheet1").Cells(1, 1).Text = "DONE"
End Sub
Sub doJStuff(row, ws)
ws.Select
Range("A2").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet1").Select
ActiveSheet.Cells(row, 1).Select
ActiveSheet.Paste
'end paste name
'copy post history and transpose into row 2 on sheet1
ws.Select
Range("H2:H30").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet1").Select
ActiveSheet.Cells(row, 2).Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
'end post history
End Sub
You've got a number of problems with your code. First of all, avoid using Select wherever possible. Second, you are not properly assigning variables. You should put Option Explicit on the top of the module and then make sure you've assigned things correctly.
As for the actualy code, when you are copying/pasting the H2:H30 range into your first sheet you are going to only end up getting the first value in the range for every sheet except the last because you are pasting 28 rows but only incrementing the destination row by one. I didn't fix that but it's worth pointing out. I also left in your comments though they don't make much sense. Without knowing what you are trying to do, I've only cleaned up some of your code but it probably still won't work exactly right.
Sub YourSub()
Dim wb As Workbook
Dim wksht As Worksheet
Dim i As Integer
Set wb = ActiveWorkbook
wb.Sheets("Sheet1").Cells(1, 1).Text = "Started"
i = 1
'cells is row,col
For Each wksht In Worksheets
'ws.Cells(1, i).Value = objWorksheet.Name
'objWorksheet.Activate
'ws = wb.ActiveSheet
doJStuff i, wksht
i = i + 1
Next
wb.Sheets("Sheet1").Cells(1, 1).Text = "DONE"
End Sub
Sub doJStuff(row As Integer, ws As Worksheet)
ws.Range("A2").Copy
Sheets("Sheet1").Cells(row, 1).PasteSpecial
'end paste name
'copy post history and transpose into row 2 on sheet1
ws.Range("H2:H30").Copy
Sheets("Sheet1").Cells(row, 2).PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
'end post history
End Sub

Resources