I am trying to add a button to an Excel workbook so that it shows up in every sheet. A great answer to my original question gave me a macro to create the buttons on each sheet:
Sub AddButtons()
Dim ws As Excel.Worksheet
Dim btn As Button
For Each ws In ThisWorkbook.Worksheets
Set btn = ws.Buttons.Add(X, Y, W, H)
[set btn properties]
Next ws
End Sub
I am now having trouble with setting the button properties so that the button prints the sheet when pressed. Again here is my print macro:
Dim WS_Count As Integer
Dim i As Integer
' Set WS_Count equal to the number of worksheets in the active workbook.
WS_Count = ActiveWorkbook.Worksheets.Count
'allows user to set printer they want to use
Application.Dialogs(xlDialogPrinterSetup).Show
' Begin the loop.
For i = 5 To WS_Count
Worksheets(i).Activate
With ActiveWorkbook.Worksheets(i).PageSetup
.PrintArea = "A1:O48"
.Orientation = xlLandscape
.Zoom = False
.FitToPagesTall = 1
.FitToPagesWide = 1
End With
ActiveWorkbook.Worksheets(i).PrintOut
There have been some good suggestions about how to go about incorporating this macro into the button properties (passing variables and creating a new print sub) however I am pretty new to VBA and have been unsuccessful in getting this to work. Ideally I would have a button macro that creates the button and every time it is pressed calls the print macro for each sheet.
One last thing, I am trying to change the button code so that it only adds buttons to sheet 5 onwards. It would be great if anyone knew how to do that as well?
Any advice is helpful and greatly appreciated!
Try this:
Sub AddButtons()
Dim ws As Excel.Worksheet
Dim btn As Button
For Each ws In ThisWorkbook.Worksheets
Set btn = ws.Buttons.Add(X, Y, W, H)
btn.OnAction = "MySub" ' MySub is executed when btn is clicked
' Substitute the name of your printing subroutine
btn.Caption = "Print"
'set additional btn properties as needed
Next ws
End Sub
X and Y determine the location, W and H determine the button size.
This will add a button (Form Control) and assign an existing macro to it.
Sub test()
Dim cb As Shape
Set cb = Sheet1.Shapes.AddFormControl(xlButtonControl, 10, 10, 100, 25)
cb.OnAction = "PrintMacro"
End Sub
Private Sub PrintMacro()
MsgBox "Test" ' for testing pursposes
' you actually put your print code here
End Sub
Now to add buttons from Sheet 5 onwards only, you can try:
Producing a list of all your sheet names (if there's only a few of them)
Dim shname
For Each shname In Array("Sheet 5", "Sheet 6", "Sheet 7")
test Sheets(shname) ' note that you'll have to use below test sub
Next
Do it the other way around. Make a list of what to exclude and test every sheet if it is on the list or not.
Dim sh As Worksheet
Dim xcludesheet: xcludesheet = Array("Sheet1", "Sheet2", "Sheet3", "Sheet4")
For Each sh In Worksheets
If IsError(Application.Match(sh.Name, xcludesheet, 0)) Then
test Sheets(sh.Name)
End If
Next
Your test sub to be used in above samples.
Sub test(ws As Worksheet)
Dim cb As Shape
Set cb = ws.Shapes.AddFormControl(xlButtonControl, 10, 10, 100, 25)
cb.OnAction = "PrintMacro"
End Sub
Related
I have looked through numerous posts on looping through UserForm Controls but cant seem to adjust the code i have found for my needs and need some help.
Scenario I am trying to figure out:
I have 44 text boxes on a userform whose names all start with "ch" example "chTextBox1"
When the userform activates I need to loop through all of the text boxes that start with "ch" and change the background color of those textboxes to a color based on the interior color of a cell
Below is the code that I have been messing around with and I either end up in an infinite loop or I get
Error 424
Private Sub UserForm_Activate()
Dim wb As Workbook
Dim wsRR As Worksheet
Dim bColor As Range
Dim c As Control
Dim y As String
Set wb = Application.ThisWorkbook
Set wsRR = wb.Sheets("RiskRating")
Set bColor = wsRR.Range("C3")
For Each c In JHKey.Controls
If TypeName(c) = "TextBox" Then
y = Left(c, 2)
End If
If y = "ch" Then
c.BackColor = bColor.Interior.Color
End If
Next c
End Sub
Try placing the If statement testing for "ch" within the If statement testing for "TextBox". Also, you should specify the Name property for the control when checking for its name, otherwise it defaults to its Value property. Also, as an aside, I would suggest replacing JHKey with the keyword Me, which refers to the userform itself regardless of its name.
Private Sub UserForm_Activate()
Dim wb As Workbook
Dim wsRR As Worksheet
Dim bColor As Range
Dim c As Control
Dim y As String
Set wb = Application.ThisWorkbook
Set wsRR = wb.Sheets("RiskRating")
Set bColor = wsRR.Range("C3")
For Each c In Me.Controls
If TypeName(c) = "TextBox" Then
y = Left(c.Name, 2)
If y = "ch" Then
c.BackColor = bColor.Interior.Color
End If
End If
Next c
End Sub
I have created a userform frmNavigation which has a ListBox1, which will list down all the worksheets present in my workbook and I can double click on any of worksheet listed in the listbox and go to that sheet.
Now as I have close to 50 worksheets so I double click from the list appearing in ListBox1 and go to that sheet but now I want a back button "CommandButton2" so that it can take me back to my previous active sheet.
I have created a code but its not working.
Private Sub CommandButton2_Click()
Application.ScreenUpdating = False
Dim i As Integer, Sht As String
'for loop
For i = 0 To ListBox1.ListCount - 1
'get the name of the selected sheet
If ListBox1.Selected(i) = True Then
Sht = ListBox1.List(i - 1)
End If
Next i
'select the sheet
Sheets(Sht).Select
'reset the userform
Unload Me
frmNavigation.Show
End Sub
Try the code below, I am not sure how to explain my logic of the code below, I tired my best to describe it in the code comments.
I've modified also the ListBox1_DblClick code event, to save the latest ActiveSheet before you Select the new sheet.
Code
Option Explicit
Dim LastSelectedSht As String ' Variable at module level, to store the name of the last selected sheet
'===================================================================
Private Sub CommandButton2_Click()
Dim TmpSht As String
TmpSht = ActiveSheet.Name ' <-- save the current active sheet
' select the previous sheet (stored in LastSelectedSht)
If LastSelectedSht = "" Then
MsgBox "Error, no sheet stored , is it your first time running ? "
Else
Sheets(LastSelectedSht).Select
End If
LastSelectedSht = TmpSht ' <-- use the temp variable to store the latest active sheet
' reset the userform
Unload Me
frmNavigation.Show
End Sub
'===================================================================
Private Sub ListBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
' modifed code for ListBox double-click event, store the sheet name before switching to the selected item
Dim i As Long
LastSelectedSht = ActiveSheet.Name ' <-- save the current active sheet before selecting a new one
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then
Worksheets(ListBox1.List(i)).Activate
End If
Next i
End Sub
'=================================================================
Private Sub UserForm_Activate()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Sheets
Me.ListBox1.AddItem ws.Name
Next ws
End Sub
I have a timer macro on multiple, identical worksheets. My users will time their task time and each worksheet represents a different task. I need to have a summary sheet with the macros that start and stop time that is linked to each worksheet so that my users don't have to toggle back and forth between sheets to start the timers for each task. Can you help. Here is the timer code I'm using. It works well on each worksheet, but I don't know how to code the buttons on a summary worksheet to activate this code on a specific worksheet. Here's the code:
Sub startStopTimer()
If Range("j4") = "Start" Then
Range("$b$8").Offset(Range("j6") + 1).Value = Now
Range("j4") = "Stop"
Else
Range("$b$8").Offset(Range("j6"), 1).Value = Now - Range("$b$8").Offset(Range("j6"))
Range("$j$4") = "Start"
End If
End Sub
I'm not sure you need to call your timer routine in each worksheet. You really only need one routine and knowledge of which worksheet to assign the times to.
One way would be with a kind of control panel of buttons on a UserForm. It might look something like this (just 3 worksheets as example):
Then you'd handle all of the click events within the UserForm code. In this example, I've created a collection of Worksheets and each item is accessed by a string key which is the button's name. Skeleton code would be:
Option Explicit
Private Const START_COLOUR As Long = &HFF00&
Private Const START_TEXT As String = "Start"
Private Const STOP_COLOUR As Long = &HFF&
Private Const STOP_TEXT As String = "Stop"
Private mSheets As Collection
Private Sub btnClock1_Click()
StartStopButton btnClock1
End Sub
Private Sub btnClock2_Click()
StartStopButton btnClock2
End Sub
Private Sub btnClock3_Click()
StartStopButton btnClock3
End Sub
Private Sub StartStopButton(btn As CommandButton, Optional initialise As Variant)
Dim ws As Worksheet
Dim v As Variant
Dim startTime As Date
Set ws = mSheets(btn.Name)
ws.Activate
If Not IsMissing(initialise) Then
'Initialise the button and sheet
SetProperties btn, CBool(initialise)
ws.Range("A1").Value = "Not yet actioned"
ws.Range("B1:D1").ClearContents
Else
If btn.BackColor = START_COLOUR Then
'Set clock running
SetProperties btn, True
ws.Range("A1").Value = "Running"
ws.Range("B1").Value = Now
ws.Range("C1:D1").ClearContents
Else
'Stop clock and calculate difference
SetProperties btn, False
ws.Range("A1").Value = "Stopped"
ws.Range("C1").Value = Now
v = ws.Range("B1").Value
If Not IsEmpty(v) And IsDate(v) Then
'For DateDiff, choose whichever unit you want, I've used seconds ("s")
ws.Range("D1").Value = DateDiff("s", v, Now)
End If
End If
End If
End Sub
Private Sub SetProperties(btn As CommandButton, running As Boolean)
With btn
If running Then
.Caption = STOP_TEXT
.BackColor = STOP_COLOUR
Else
.Caption = START_TEXT
.BackColor = START_COLOUR
End If
End With
End Sub
Private Sub UserForm_Initialize()
Dim ws As Worksheet
'Assign all worksheets to collection
Set mSheets = New Collection
Set ws = ThisWorkbook.Worksheets("Sheet1")
mSheets.Add ws, btnClock1.Name
Set ws = ThisWorkbook.Worksheets("Sheet2")
mSheets.Add ws, btnClock2.Name
Set ws = ThisWorkbook.Worksheets("Sheet3")
mSheets.Add ws, btnClock3.Name
'Set all buttons to start
StartStopButton btnClock1, False
StartStopButton btnClock2, False
StartStopButton btnClock3, False
End Sub
I'm trying to get a single macro that I can assign to my command buttons. I have multiple buttons that open different files so in each cell I include a different file path.
Currently my command buttons are looking for a specific cell reference and opening that value.
Is there any way I can get the macro to look for the value in the cell to which it is aligned?
I'm using two macros at the moment - one to create the buttons and then another to assign to the buttons. I am having to create a new macro for each button.
Macro to create button...
Sub Buttons()
Dim i As Long
Dim lRow2 As Integer
Dim shp As Object
Dim dblLeft As Double
Dim dblTop As Double
Dim dblWidth As Double
Dim dblHeight As Double
With Sheets("Print Schedule")
dblLeft = .Columns("A:A").Left 'All buttons have same Left position
dblWidth = .Columns("A:A").Width 'All buttons have same Width
For i = Range("E65536").End(xlUp).Offset(1, 0) To ActiveCell + 15
dblHeight = .Rows(i).Height 'Set Height to height of row
dblTop = .Rows(i).Top 'Set Top top of row
Set shp = .Buttons.Add(dblLeft, dblTop, dblWidth, dblHeight)
shp.Characters.Text = "Open Print Schedule"
Next i
End With
End Sub
Macros to open file...
Sub Mendip()
Dim myfile As String
myfile = Cells(6, 6).Value
Application.Workbooks.Open Filename:=myfile
End Sub
Please tell me there is a better way to do this!
When you create the form buttons as shown below then you can assign a common macro to them
And you can assign a macro like this
Sub Sample()
Dim shp As Shape
Set shp = ActiveSheet.Shapes(Application.Caller)
'MsgBox shp.TopLeftCell.Address
Select Case shp.TopLeftCell.Address
Case "$A$1"
'~~> Do Something
Case "$B$1"
'~~> Do Something
'
'~~> And So on
'
End Select
End Sub
EDIT:
One thing I forgot to mention. To assign the "Sample" macro to all buttons, Add the below line after you create the shape.
shp.OnAction = "Sample"
I currently run a macro to compare the most recent sheet of data to the report immediately prior and highlight changes. It works fine on its own. Now, however, we would like to be able to compare selected sheets from any time period. My idea was to pop up a simple userform with two textboxes that the user can use to specify which two reports he wants to compare. I am quite lost though with the idea of trying to declare public variables; what I've got atm is:
Option Explicit
Public shtNew As String, shtOld As String, _
TextBox1 As TextBox, TextBox2 As TextBox
Sub SComparison()
Const ID_COL As Integer = 31 'ID is in this column
Const NUM_COLS As Integer = 31 'how many columns are being compared?
Dim rwNew As Range, rwOld As Range, f As Range
Dim X As Integer, Id
shtNew = CSManager.TextBox1
shtOld = CSManager.TextBox2
'Row location of the first employee on "CurrentMaster" sheet
Set rwNew = shtNew.Rows(5)
Do While rwNew.Cells(ID_COL).Value <> ""
Id = rwNew.Cells(ID_COL).Value
Set f = shtOld.UsedRange.Columns(ID_COL).Find(Id, , xlValues, xlWhole)
If Not f Is Nothing Then
Set rwOld = f.EntireRow
For X = 1 To NUM_COLS
If rwNew.Cells(X).Value <> rwOld.Cells(X).Value Then
rwNew.Cells(X).Interior.Color = vbYellow
rwNew.Cells(33) = "UPDATE"
Else
rwNew.Cells(X).Interior.ColorIndex = xlNone
End If
Next X
End If
Set rwNew = rwNew.Offset(1, 0) 'next row to compare
Loop
Call SUpdates
End Sub
My Suggestion would be to use Comboboxes instead of TextBoxes. Create a userform with two command buttons and two comboboxes and populate the comboboxes in the UserForm_Initialize() event using this code.
Private Sub UserForm_Initialize()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Sheets
ComboBox1.AddItem ws.Name: ComboBox2.AddItem ws.Name
Next
End Sub
And then use this code in the OK button to do the comparison.
Private Sub CommandButton1_Click()
Dim shtNew As Worksheet, shtOld As Worksheet
If ComboBox1.ListIndex = -1 Then
MsgBox "Please select the first sheet"
Exit Sub
End If
If ComboBox2.ListIndex = -1 Then
MsgBox "Please select the Second sheet"
Exit Sub
End If
Set shtNew = Sheets(ComboBox1.Value)
Set shtOld = Sheets(ComboBox2.Value)
'~~> REST OF THE CODE HERE NOW TO WORK WITH THE ABOVE SHEETS
End Sub
Private Sub CommandButton2_Click()
Unload Me
End Sub
HTH
Sid
For an easy fix, couldn't you just colour (sorry, I'm English!) the worksheets that you want to refer to, then do something like:
Sub ListSheets()
'lists only non-coloured sheets in immediate window
'(could amend to add to combo boxes)
Dim w As Worksheet
'loop over worksheets in active workbook
For Each w In Worksheets
If w.Tab.Color Then
'if tab color is set, print
Debug.Print w.Name
End If
Next w
Let me know if this solves your problem.