I've been struggling with this for a few days.
I have the below code which copies and pastes value when a certain If condition is met (the workbook has live data feeding into multiple sheets every second).
The code is currently located in a module, as the IF condition can apply to all sheets in the workbook.
The problem I have is the code only runs on the activesheet. I need it to run on all worksheets in the workbook. I've tried multiple loops with no success. Ideally I need the code to run across all sheets in the background (i.e. without activating them). Any help will be appreciated.
Dim TimeToRun
Sub auto_open()
Call SchedulePrices
End Sub
Sub SchedulePrices()
TimeToRun = Now + TimeValue("00:00:15")
Application.OnTime TimeToRun, "CopyPrice"
End Sub
Sub CopyPrice()
Calculate
If Range("AM7") = "1" Then
Range("AM10:AM69").Value = Range("K9:K68").Value
Range("AL10:AL69").Value = Range("B9:AM68").Value
Range("AM8:AM9").Value = Range("C2:C3").Value
End If
'run the timer sub
Call SchedulePrices
End Sub
Sub auto_close()
On Error Resume Next
Application.OnTime TimeToRun, "CopyPrice", , False
End Sub
Sub CopyPrice()
Dim sht as Worksheet
For Each sht in Worksheets
If sht.Range("AM7") = "1" Then
sht.Calculate
sht.Range("AM10:AM69").Value = sht.Range("K9:K68").Value
sht.Range("AL10:AL69").Value = sht.Range("B9:AM68").Value
sht.Range("AM8:AM9").Value = sht.Range("C2:C3").Value
End If
Next
'run the timer sub
Call SchedulePrices
End Sub
Related
I already coded my Excel workbook to print out all of my selective sheets that I need all at once. However, there are times where I will only need it to print specific sheets instead of all of them. Is there a way that before I print I can have my code ask me what range of sheets I want to print so I am not getting all 45 when I just need 7? Thank you in advance.
Chris
Sub PrintWorksheets()
Application.ScreenUpdating = False
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Feedback Data" Then
If ws.Visible = xlSheetVisible Then
ws.PrintOut
End If
End If
Next ws
Application.ScreenUpdating = True
MsgBox "All charts have been printed Mark"
End Sub
Here's an example of a UserForm where we populate a ListBox with the names of all sheets in the file:
Code behind the UserForm:
Dim i As Long
Private Sub UserForm_Initialize()
For i = 1 To ActiveWorkbook.Sheets.Count
ListBox1.AddItem ActiveWorkbook.Sheets(i).Name
Next i
End Sub
Private Sub btnPrint_Click()
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then
ActiveWorkbook.Worksheets(ListBox1.List(i)).PrintOut
End If
Next i
End Sub
Private Sub btnCancel_Click()
Unload Me
End Sub
Naturally, there are other facets to this, such as changing the ListBox's MultiSelect property to 1 (to allow multiple sheets to be selected), and in my example I rename my buttons out of practice. But this is how you would solve your problem, in theory.
You could try to create more subroutines, each having different predefined set of sheets to select. Examples:
Public Sub selectSheets_1()
Dim arrayOfNames As Variant
arrayOfNames = Array(ws1.Name, ws2.Name, ws4.Name)
ThisWorkbook.Sheets(arrayOfNames).Select
End Sub
Public Sub selectSheets_2()
Dim arrayOfNames As Variant
arrayOfNames = Array(ws8.Name, ws15.Name, ws25.Name, ws35.Name, ws45.Name)
ThisWorkbook.Sheets(arrayOfNames).Select
End Sub
And so on...
Where ws# is the codename of sheet.
I am having a little issue which is kind of strange.
So I have a macro Workbook (lets call it "Main" for simplification) with all its code that runs almost perfectly except for this little problem. "Main" is usually always open as it is our balances for the day.
When I or another user opens any other workbook at the same time as this one is open everything is fine, but when we close the workbook that doesn't have the code, "Main" runs it's before close code.
So this is my before Close code I have on "Main":
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim Tsweep As Integer
Dim sTime As Date
If ThisWorkbook.Sheets("Coordenador").Range("O2") <> "" Then
For Tsweep = 2 To Range("Coordenador!O1048000").End(xlUp).Row
Application.OnTime EarliestTime:=Range("Coordenador!O" & Tsweep).Value,
Procedure:="CloseC", Schedule:=False
Next Tsweep
End If
CloseC
sTime = ThisWorkbook.Sheets("Coordenador").Range("P15") +
TimeValue("00:30:00")
Application.OnTime EarliestTime:=sTime, Procedure:="SaveWb", Schedule:=False
ThisWorkbook.Save
End Sub[/CODE]
This is the code on "CloseC":
Sub CloseC()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Coordenador")
With ws
.Unprotect Password:=pass
.Range("O:O").ClearContents
End With
For Each Worksheet In ThisWorkbook.Worksheets
Worksheet.Protect Password:=pass
Next
ThisWorkbook.Sheets("Coordenador").Visible = xlSheetVeryHidden
ThisWorkbook.Sheets("LookupList").Visible = xlSheetVeryHidden
End Sub
And the Code on SaveWb:
Sub SaveWb()
Dim vTime As Date
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Coordenador")
ThisWorkbook.Save
vTime = Now
With ws
.Unprotect Password:=pass
.Range("P15") = vTime
.Protect Password:=pass
End With
Application.OnTime vTime + TimeValue("00:30:00"), "SaveWb"
End Sub
To explain this code stops all the OnTime runs that the system might still have. It clears some cells, protects some sheets and it saves. The error than appears when the user closes "Main" and excel tries to run "SaveWb".
I was wondering if there is a way to avoid this since in theory excel runs each instance by itself and even though me and/or the users are closing these other workbooks with the close button top we are not closing "Main" and that workbook remains open. Other idea would be to check if the workbook is still open after 5 seconds and if it is to run "SaveWb" but I haven't found a way to code that.
Thank you for your help in advance!
I have found a work around for this. Thank you all for helping me reach the idea.
Basicly what I did was add a If clause at the start of the before close:
If ActiveWorkbook.Name Like "ReportingReport*" Then
(code)
Else SaveWb
End If
I have a spreadsheet that I implemented a timer in to automatically update a formula every 10 seconds. Everything was working great until I would open another spreadsheet. My assumption was that it was still trying to run Timer() on the wrong sheet. So, I tried switching to absolute calls. Here is my full code:
Dim TimerActive As Boolean
Sub StartTimer()
Start_Timer
End Sub
Private Sub Start_Timer()
TimerActive = True
Application.OnTime Now() + TimeValue("00:00:10"), "timetrack.xlsm!Tracker.Timer"
End Sub
Sub Stop_Timer()
TimerActive = False
End Sub
Sub Timer()
Dim tracker As Worksheet
Set tracker = Workbooks("timetrack.xlsm").Sheets("Tracker")
tracker.Range("O1").Value = "Timer Stopped"
'On Error Resume Next
If TimerActive Then
tracker.Range("O2").Value = Time
Application.OnTime Now() + TimeValue("00:00:10"), "timetrack.xlsm!Tracker.Timer"
tracker.Range("N:N").Calculate
End If
tracker.Range("O1").Value = ""
End Sub
Specifically, I'm getting an error on the Application.OnTime line:
Cannot run the macro ''S:\OneDrive...!docs\timetrack.xlsm'!Tracker.Timer'. The macro may not be available in this workbook or all macros may be disabled.
The path that shows up in the error is correct. What is wrong? What's weird is it seems to run it in the StartTimer() sub without issue.
To refer to a procedure in a worksheet, you need to use the WorkSheet.CodeName and not the WorkSheet.Name :
Application.OnTime Now() + TimeValue("00:00:10"), ThisWorkbook.Name & "!" & Me.CodeName & ".Timer"
You'll need to activate the desired workbook prior to making changes to the cells within.
Before accessing the contents within the workbook, try adding:
Workbooks("timetrack.xlsm").Activate
If the macro that runs is in "timetrack.xlsm" you could also use the following code to avoid referencing the workbook name:
ThisWorkbook.Activate
ThisWorkbook refers to the workbook in which the macro resides.
I want to run an Excel VBA code (all it will do is delete specific cells within the same row and I've turned on relative reference so that I can apply the Excel VBA code to all rows, if there's the appropriate "X") based on whether there is an X in a certain cell.
Here's what I've tried so far (the Excel VBA code is just called "Biology"):
If Range("C22").Value = "X" Then
Call macro_Biology
End If
I should add that I'm writing this under VBA section "GetATPLabel". Like I said, total noob, but I think I'm close, so any help is appreciated.
It sounds as if it is important that the Biology (or macro_Biology) macro needs to know which row it is supposed to work on. You can pass this information across to it with a parameter. Example:
Sub start_with_this()
Dim rw As Long, lr As Long
With ActiveSheet
lr = .Cells(Rows.Count, "C").End(xlUp).Row
For rw = 2 To lr
If UCase(.Cells(rw, "C").Value) = "X" Then
Call macro_Biology(rw)
End If
Next rw
End With
End Sub
Sub macro_Biology(r As Long)
' r is the row that was passed in.
' do something with r
End Sub
After initially starting the start_with_this macro, it goes through each cell in column C from row 2 to the last row with anything in it. If it finds an X or an x (case-sensitivity is removed by forcing the cell value to upper case before comparing) then it calls the second macro, macro_Biology and tells it what row to deal with.
Lets assume that Biology() is a sub in a standard module:
Sub Biology()
MsgBox "study biology!"
End Sub
To call this as you want, run:
Sub TestIt()
If Range("C22").Value = "X" Then
Call Biology
End If
End Sub
To call Biology() automatically if the user types an X in cell C22, Insert the following event macro in the worksheet code area:
Private Sub Worksheet_Change(ByVal Target As Range)
Set intrs = Intersect(Target, Range("C22"))
If Not intrs Is Nothing Then
If intrs.Value = "X" Then
Application.EnableEvents = False
Call Biology
Application.EnableEvents = True
End If
End If
End Sub
To call Biology() automatically if a formula gives an X in cell C22, Insert the following event macro in the worksheet code area:
Private Sub Worksheet_Calculate()
If Range("C22").Value = "X" Then
Application.EnableEvents = False
Call Biology
Application.EnableEvents = True
End If
End Sub
I would like to write a macro or adjust Excel properties, so that whenever I open a new excel workbook all values are autofited to the columns.
I tried using the following code, which works if I save the code for a specific workbook, however if I save the code in the PERSONAL workbook, the code produces an error. "Method 'Columns' of object '_Global' failed"
Sub auto_open()
Columns().AutoFit
End Sub
The way I do this is to create a simple add-in that handles Application events I want to intercept. The reason that it doesn't work in the auto_open() is because you are trying to work with the Columns object before it gets instantiated. Much better to use the SheetActivate event. This also avoids the possibility of opening a Workbook with 20 pages and having to wait for all of them to AutoFit. You only see the active sheet, right?
The concept is to grab a reference WithEvents to the application and set up handlers to whatever events you care about. To do this, you'll have to put the code into a class. I called mine "AppHolder".
Class code:
Option Explicit
Private WithEvents app As Application
Private Sub Class_Initialize()
Set app = Application
End Sub
Private Sub app_SheetActivate(ByVal Sh As Object)
Sh.Columns().AutoFit
End Sub
Private Sub app_WorkbookActivate(ByVal Wb As Workbook)
Wb.ActiveSheet.Columns().AutoFit
End Sub
Private Sub app_WorkbookNewSheet(ByVal Wb As Workbook, ByVal Sh As Object)
Sh.Columns().AutoFit
End Sub
Then, create an instance of your class in and set it in auto_open (or Workbook_Open as the case may be) in the ThisWorkbook module:
Option Explicit
Private hook As AppHolder
Private Sub Workbook_Open()
Set hook = New AppHolder
End Sub
Save it as an Excel add-in file (.xlam) in the default location - should be in Users[You]\AppData\Roaming\Microsoft\AddIns. Close Excel and re-open it, then go to Developer...Add-Ins and enable it. All there is to it.
EDIT: Almost forgot - that doesn't cover all situations in which you'll be presented with a Worksheet. You need WorkbookActivate and WorkbookNewSheet too...
You could use something like this: (untested)
Sub auto_open()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Application.DisplayAlerts = False
Dim wb As Workbook
Dim ws As Worksheet
For Each wb In Workbooks
For Each ws In wb.Worksheets
ws.Columns.AutoFit
Next ws
Next wb
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Its important to identify the Objects you are working on (in this case workbooks and worksheets) because it helps you to know which method you could apply to them (see)
This might work :
Sub auto_open()
For i = 1 To Application.Workbooks.Count
For j = 1 To Application.Workbooks(i).Sheets.Count
For k = 1 To Application.Workbooks(i).Sheets(j).Cells(1, Columns.Count).End(xlToLeft).Column
Application.Workbooks(i).Sheets(j).Columns(k).EntireColumn.AutoFit
Next k
Next j
Application.Workbooks(i).Save
Next i
End Sub