Amending a VBA so that it works between two workbooks as opposed to two worksheets - vba

Hi all and thanks in advance.
I currently have a VBA within my workbook to copy rows from "Demand Log" to "Change Log" when cells within column "O" have a specific value.
The VBA is working great, however I am now looking to split the two worksheets apart and have a separate workbook for each.
My question is - How can I change my VBA so that it copies and pastes between workbooks as opposed to between worksheets?
Please see my VBA code below:
Dim xRg As Range
Dim xCell As Range
Dim I As Long
Dim J As Long
Dim K As Long
I = Worksheets("Demand Log").UsedRange.Rows.Count
J = Worksheets("Change Log").Cells(Worksheets("Change Log").Rows.Count, "B").End(xlUp).Row
If J = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("Change Log").Range) = 0 Then J = 0
End If
Set xRg = Worksheets("Demand Log").Range("O5:O" & I)
Application.ScreenUpdating = False
For K = xRg.Count To 1 Step -1
If CStr(xRg(K).Value) = "Change Team" Then
J = J + 1
With Worksheets("Demand Log")
Intersect(.Rows(xRg(K).Row), .Range("A:Z")).Copy Destination:=Worksheets("Change Log").Range("A" & J)
Intersect(.Rows(xRg(K).Row), .Range("A:Z")).Delete xlShiftUp
End With
End If
Next
Application.ScreenUpdating = True

You should refer to your worksheets and workbooks at the same time. So, instead of:
I = Worksheets("Demand Log").UsedRange.Rows.Count
You should type:
I = Workbooks("Book1").Worksheets("Demand Log").UsedRange.Rows.Count
anywhere in your code. For simplicity, you may set object variable, like:
Dim wb1 as Workbook
Set wb1 = Application.Workbooks("Book1")
or, better, set your worksheets as variables, for example:
Dim wsDemand as Worksheet
Set wsDemand = Workbooks("Book1").Worksheets("Demand Log")
and then you can use wsDemand instead of Worksheets("Demand Log") anywhere in your code.
Book1 is of course default workbook's name, your file has probably other name.

If the workbook is open then you can refer to it like this:
Workbooks("mybook.xls")[.method]
If the workbook is closed you need to open it: Workbooks.Open("C:\path\mybook.xls")[.method]
You can assign them to variables:
set wb = Workbooks("mybook.xls")
set wb = Workbooks.Open("C:\path\mybook.xls")
set ws = wb.Sheets("MySheet")
You can also get to the worksheet and assign it to a variable: (useful if you're working with a single sheet)
set ws = Workbooks("mybook.xls").Sheets("MySheet")
set ws = Workbooks.Open("C:\path\mybook.xls").Sheets("MySheet")
Untested, but give it a try:
Sub mysub()
Dim xRg As Range
Dim xCell As Range
Dim I As Long
Dim J As Long
Dim K As Long
Dim wbDem As Workbook
Dim wbChg As Workbook
Dim wsDem As Worksheet
Dim wsChg As Worksheet
'Open/Get Workbook
If Application.Workbooks("Demand.xls") Is Nothing Then
Set wbDem = Application.Workbooks.Open("C:\path\Demand.xls")
Else
Set wbDem = Application.Workbooks("Demand.xls")
End If
'Open/Get Workbook
If Application.Workbooks("Change") Is Nothing Then
Set wbChg = Application.Workbooks.Open("C:\path\Change.xls")
Else
Set wbChg = Application.Workbooks("Change.xls")
End If
'Set Sheet Variables
Set wsDem = wbDem.Worksheets("Demand Log")
Set wsChg = wbChg.Worksheets("Change Log")
I = wsDem.UsedRange.Rows.Count
J = wsChg.Cells(wbChg.Rows.Count, "B").End(xlUp).Row
If J = 1 Then
If Application.WorksheetFunction.CountA(wbChg.Range) = 0 Then J = 0
End If
Set xRg = wsDem.Range("O5:O" & I)
Application.ScreenUpdating = False
For K = xRg.Count To 1 Step -1
If CStr(xRg(K).value) = "Change Team" Then
J = J + 1
With wsDem
Intersect(.Rows(xRg(K).Row), .Range("A:Z")).Copy Destination:=wsChg.Range("A" & J)
Intersect(.Rows(xRg(K).Row), .Range("A:Z")).Delete xlShiftUp
End With
End If
Next
Application.ScreenUpdating = True
End Sub

Related

UserForm.Show within a prior Initial User form causes blank grey un-closeable workbook to open

Below is the excerpt of code where the "error(more like an unwanted occurrence)" happens. My code is running in a userform (not userform1) after a command button click. The initial form shows on workbook open. The second userform - UserForm1 in the code below - is a check box that I want to present to the user upon my IF condition. When the program gets there, it opens the UserForm1, but also opens a blank grey excel workbook. The workbook cannot be closed until I close the Userformm1 interface.
Note: the second msgbox does not display until AFTER I close the userform.
I tried searching for this problem, but couldn't find the issue in regards to UserForm stuff. Thanks in advance for any help.
Private Sub CommandButton1_Click()
Dim wbName As String, wb As Workbook, ws As Worksheet
Dim sht As Worksheet
Dim myValue As Variant
Dim counter As Integer
Dim EstNumAttempt As Boolean
EstNumAttemp = False
counter = 0
Dim ThisNum As String
Dim EstNum As String
Dim CopyFromBook As Workbook
Dim CopyToWbk As Workbook
Dim ShToCopy As Worksheet
Set CopyToWbk = ThisWorkbook
Application.ScreenUpdating = False
ThisUserPath = Application.ActiveWorkbook.Path
userDataPath = ThisUserPath & "\SBNBidDataSet01112018.xlsx"
Dim StartDate As String
Dim EndDate As String
StartDate = TextBox1.Value
EndDate = TextBox2.Value
EstNum = TextBox3.Value
Set wb = Workbooks.Open(userDataPath)
Set CopyFromWbk = wb
WSCount = wb.Worksheets.Count
If EstNum <> "" Then
EstNumAttempt = True
For X = 1 To WSCount
Set ws = wb.Sheets(X)
ThisNum = ws.Cells(2, 2)
If ThisNum = EstNum Then
counter = counter + 1
Set ShToCopy = CopyFromWbk.Worksheets(X)
ShToCopy.Copy After:=CopyToWbk.Sheets(CopyToWbk.Sheets.Count)
End If
Next X
If counter = 0 Then
MsgBox " That's probably not a valid EST# in SmartBidNet"
End If
End If
If IsDate(StartDate) = True And IsDate(EndDate) = True And EstNumAttempt = False Then
MsgBox "h"
wb.Application.Visible = False
UserForm1.Show
wb.Application.Visible = True
MsgBox "h"
'BLANK GREY SHEET HERE
For X = 100 To 101
Set ws = wb.Sheets(X)
lastrow = ws.Cells(Rows.Count, 1).End(xlUp).Row
'future code
Next X
End If
wb.Close
Application.ScreenUpdating = False ' from before also!
End Sub
THIS IS NOT A SOLUTION, I tested a piece of your code and here is my feedback below.
I ran just this code in a workbook named testbook.xslm and I created a form (myForm that is just a grey layout, nothing on it):
Private Sub CommandButton1_Click()
Dim wb As Workbook
Dim anotherbook As Workbook
Dim anotherbook2 As Workbook
Dim anotherbook3 As Workbook
Set wb = Workbooks.Add
Set anotherbook = wb
Set anotherbook2 = wb
Set anotherbook3 = wb
MsgBox "h"
wb.Application.Visible = False
myForm.Show
wb.Application.Visible = True
MsgBox "h"
wb.Close
Application.ScreenUpdating = False ' from before also!
End Sub
From the user standpoint:
1) testbook opens
2) click the button -> book# opens on top of testbook
3) msgbox "h" pops up
4) x out of msgbox "h" -> Both workbooks disappear (testbook and book1)
5) my grey user form pops up (its empty)
6) x out of userform
7) testbook shows again on top of the new book created which is behind it
8) msgbox "h" #2 pops up
9) x out of msgbox
10) the book# behind testbook disappears
That's it. No grey box residue. How are you closing the userforms (the first one and the second one)? obviously I used the terminate with the x. I did not add any code. So how are you closing your form with no code?
Adding the same behavior occurs if I make multiple workbook references to wb.
So this code area is not your problem . . . .
Second test, still no problems, adding worksheets, running through the number of worksheets, copying them to the testbook.
Option Explicit
Private Sub CommandButton1_Click()
Dim wb As Workbook
Dim wb2 As Workbook
Dim ws As Worksheet
Dim anotherbook As Workbook
Dim anotherbook2 As Workbook
Dim anotherbook3 As Workbook
Dim X As Double
Dim lastrow As Double
Dim thisNum As String
Set wb = Workbooks.Add
Set anotherbook = wb
Set anotherbook2 = wb
Set anotherbook3 = wb
Set wb2 = ThisWorkbook
wb.Worksheets.Add
wb.Worksheets.Add
wb.Worksheets.Add
wb.Worksheets.Add
wb.Worksheets.Add
wb.Worksheets.Add
myForm2.Show
MsgBox "h"
wb.Application.Visible = False
myForm.Show
wb.Application.Visible = True
MsgBox "h"
For X = 1 To wb.Worksheets.Count
Set ws = wb.Sheets(X)
thisNum = ws.Cells(2, 2)
lastrow = ws.Cells(Rows.Count, 1).End(xlUp).Row
ws.Copy After:=wb2.Worksheets(wb2.Worksheets.Count)
'future code
Next X
wb.Close
Application.ScreenUpdating = False ' from before also!
End Sub
Perhaps you have a lot of data being acted upon. Clear the clipboard after the paste? With:
Application.CutCopyMode = False
Digging - WWC

How to use two workbooks and their worksheets altogether

I am using two workbooks at a time. The first workbook is the current workbook and the second will be opened while programming execution. I have made the global objects of the workbooks and worksheets. I'm having issues with using the worksheets simultaneously. The error is ERROR: object variable or with block variable, not set. I have mentioned the error in the comment in the second subroutine.
Dim WB As Workbook
Dim WB2 As Workbook
Dim WKS As Worksheet
Dim WKS2 As Worksheet
Sub Button1_Click()
Dim fd As Office.FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
Set WB = ThisWorkbook
WB.Activate
fd.AllowMultiSelect = False
fd.Title = "Provide a title here."
fd.InitialFileName = ThisWorkbook.Path
If fd.Show() = True Then
strFile = fd.SelectedItems(1)
Set WB2 = Workbooks.Open(strFile)
Set WSK2 = WB2.Sheets("Schweitzer Analysis")
CalculateGrades
Else
MsgBox ("No file selected")
End If
End Sub
Sub CalculateGrades()
' first clear the contents where grades results can appear
clearGradesContents
Dim index As Integer ' for current sheet
Dim index2 As Integer ' for student sheet
Dim countCorrect As Integer ' to count no of correct answers
index = 2
index = 8
countCorrect = 0
' this first error here
' ERROR: object variable or with block variable not set
Set WKS = WB.ActiveSheet
Do While index <= 21
' the SECOND error shows here
If WKS.Cells(index, 2) = WKS2.Cells(index2, 3) Then
Count = Count + 1
Else
WKS.Cells(index, 5) = WKS2.Cells(index2, 3)
End If
If WKS.Cells(index, 3) = WKS2.Cells(index2, 4) Then
Count = Count + 1
Else
WKS.Cells(index, 6) = WKS2.Cells(index2, 4)
End If
index2 = index2 + 1
index = index + 1
Loop
End Sub
Sub clearGradesContents()
Range("E2:F21").Select
Selection.ClearContents
Range("I2:I3").Select
Selection.ClearContents
End Sub
EDIT: sorry for the previous answer, I hadn't seen your global declarations on top and I was sure it was because you hadn't declare it.
I think the issue is the following:
[...]
Set WB = ThisWorkbook
WB.Activate '<-- WB is the active workbook now
[...]
Set WB2 = Workbooks.Open(strFile) '<-- WB2 is the active workbook now!
Set WSK2 = WB2.Sheets("Schweitzer Analysis")
CalculateGrades '<-- going to next macro
[...]
Set WKS = WB.ActiveSheet '<-- ERROR: WB2 is the active workbook. WB can't have an active sheet if it's not the active workbook
Then of course, being WKS not correctly set, you can't execute this:
If WKS.Cells(index, 2) = WKS2.Cells(index2, 3) Then
I have no way to test it now, but I think that should be the issue.
To solve it,
If you really need WKS to be the ActiveSheet
Dim activeSheetName As String
...
Sub Button1Click()
...
Set WB = ThisWorkbook
WB.Activate
activeSheetName = WB.ActiveSheet.Name
...
End Sub
Sub CalculateGrades()
...
Set WKS = WB.Sheets(activeSheetName)
...
If you already know the name of the sheet you need
Just write:
Set WKS = WB.Sheets("your sheet")
instead of
Set WKS = WB.ActiveSheet

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

VBA Copying from one workbook to another workbook

I am trying to copy information from one workbook to another existing workbook, but the wrong information is being added.
Sub Set_Open_ExistingWorkbook()
Dim UserRoleWkb As Workbook, ConfigWkb As Workbook, UserRoleWkst As Worksheet, ConfigWkst As Worksheet
Set UserRoleWkb = Workbooks.Open("C:\Users\cs\Desktop\Ar.xlsx")
**Set ConfigWkb = ActiveWorkbook**
Set UserRoleWkst = UserRoleWkb.Sheets("RS Users")
**Set ConfigWkst = ActiveWorkbook.ActiveSheet**
Dim i As Integer, j As Integer
j = 10 'user role
For i = 8 To 16 'config
If ConfigWkst.Cells(i, 2).Value <> "" Then
UserRoleWkst.Cells(j, 2).Value = ConfigWkst.Cells(i, 2).Value
j = j + 1
End If
Next i
End Sub
The part of the code with the ** around it is the issue. When I call the ActiveWorkbook and ActiveSheeet, it is grabbing the information from the UserRoleWkst (worksheet) rather than what I wanted: Configwkst.
I have tried this but will get errors on the ConfigWkst line and the code will not run:
Sub Set_Open_ExistingWorkbook()
Dim UserRoleWkb As Workbook, ConfigWkb As Workbook, UserRoleWkst As Worksheet, ConfigWkst As Worksheet
Set UserRoleWkb = Workbooks.Open("C:\Users\cs\Desktop\Ar.xlsx")
**Set ConfigWkb = ActiveWorkbook**
Set UserRoleWkst = UserRoleWkb.Sheets("RS Users")
**Set ConfigWkst = ConfigWkb.Sheets("Users")
Dim i As Integer, j As Integer
j = 10 'user role
For i = 8 To 16 'config
If ConfigWkst.Cells(i, 2).Value <> "" Then
UserRoleWkst.Cells(j, 2).Value = ConfigWkst.Cells(i, 2).Value
j = j + 1
End If
Next i
End Sub
Any help is appreciated. Thanks!
Once you open another workbook then that will become the ActiveWorkbook, so you need to get that reference before opening UserRoleWkb
Set ConfigWkb = ActiveWorkbook
Set ConfigWkst = ConfigWkb.ActiveSheet
Set UserRoleWkb = Workbooks.Open("C:\Users\cs\Desktop\Ar.xlsx")
Set UserRoleWkst = UserRoleWkb.Sheets("RS Users")

VBA macro that can update the worksheets based on a source worksheet cell range

So what I'm trying to do is to update a list of worksheets based on the cell range in my source worksheet (same workbook). I know I could probably do this by deleting all the worksheets and adding new ones, but I need to have it where it takes out one and adds another.
Here is what I have so far, my problem started with the macros not responding when run or when I try to combine both macros so that I can link it to a button, nothing happens.
Sub Delete_Insert()
Dim i As Integer
i = 2
Dim ws As Worksheet
Dim stocks As Variant
Dim c_stocks As Integer
c_stocks = 7
Dim match As Boolean
'This is to see if a worksheet matched with a stock name
Dim j As Integer
j = 1
'To count the internal cell FOR loop
Application.DisplayAlerts = False
'This turns off the alert for deleting sheets
For Each ws In Worksheets
c = ActiveWorkbook.Worksheets.Count
match = False
For Each stocks In ThisWorkbook.Sheets("Main").Range("A2:A8").Cells
If CStr(stocks) = ActiveWorkbook.Sheets(i).name Then
match = True
Exit For
End If
Next stocks
If match = False Then
ws.Delete
End If
i = i + 1
If i = c Then
Exit For
End If
Next ws
End Sub`
And then this is to insert
For Each stocks In ThisWorkbook.Sheets("Main").Range("A2:A8").Cells
i = 2
match = False
For Each ws In Worksheets
If (ws.name = stocks) Then
match = True
Exit For
End If
i = i + 1
Next ws
If match = False Then
ActiveWorkbook.Worksheets.Add
ActiveSheet.Move After:=ActiveWorkbook.Sheets(ActiveWorkbook.Sheets.Count)
ActiveSheet.name = CStr(stocks)
End If
j = j + 1
If (j = 7) Then
Exit For
End If
Next stocks
End Sub
Something like this (untested):
Sub Delete_Insert()
Dim i As Integer
Dim sht As Worksheet, wb As Workbook
Dim stocks As Range, c As Range, stck As String
Set wb = ActiveWorkbook
Set stocks = ThisWorkbook.Sheets("Main").Range("A2:A8")
'remove sheets not in list
For i = wb.Worksheets.Count To 1 Step -1
Set sht = wb.Worksheets(i)
If IsError(Application.match(sht.Name, stocks, 0)) Then
Application.DisplayAlerts = False
sht.Delete
Application.DisplayAlerts = False
End If
Next i
'add new sheets from list
For Each c In stocks.Cells
stck = c.Value
If Len(stck) > 0 Then
Set sht = Nothing
On Error Resume Next
Set sht = wb.Worksheets(stck)
On Error GoTo 0
If sht Is Nothing Then
With wb.Worksheets.Add(after:=wb.Sheets(wb.Sheets.Count))
.Name = stck
End With
End If
End If
Next c
End Sub