so I burned a whole day yesterday getting side tracked on a different process for toggling images on and off based on a cell value. The funny thing is it all started from me writing a wee bit of VBA to update the Header and Footer Information automatically prior to printing or saving.
Situation
I have 12 worksheets currently in the workbook.
Sheet1(HEADER AND FOOTER) contains all the information to go into the various header/footer locations.
Sheets 2-7 are the pages that get printed as a group and have the header and footers on them.
Sheets 2-6 are portrait letter pages with multiple pages on each sheet (I cannot force 1 page wide on certain sheets due to their layout).
Sheet 7 is landscape letter page.
If I print /save as pdf prior to writing the code and changing each page separately everything worked nice, all paged printed in their respective page layouts/setups.
When I implemented the VBA code in the beforeprint or beforesave in ThisWorkbook things did not go well. Depending on which variation of the VBA code I tried, either sheet 7 would adopt the portrait orientation and scaling same as the other sheets OR all sheets would be landscape and have the scaling of sheet 7.
OBJECTIVE
Update sheets 2 through 7 with the appropriate header/footer information while maintaining their original assigned page settings. That way when I print, sheets 2-6 are all portrait and sheet 7 is landscape all on letter paper.
What I have tried
I recorded a macro to get the base structure. Originally it had all sheets in one area and modifying them. I figured that the pages were all being made the same because they were all selected at the same time, So instead of selecting all them at once, I thought I would try modifying one sheet at a time. This lead to only one worksheet being printed, so I had to add reselecting all the sheets as the last line of code. This is the VBA code I currently have:
Private Sub WorkbookBeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim ws As Worksheet
For Each ws In Worksheets
If ws.Name <> "HEADER AND FOOTER" And InStr(1, Left(ws.Name, 5), "Table", vbTextCompare) = 0 Then
Application.PrintCommunication = False
With ActiveSheet.PageSetup
.CenterHeader = Sheets(1).Range("B1").Value & Chr(10) & "Load Evaluation"
.RightHeader = _
"Calculated by: " & Sheets(1).Range("B3").Value & " Date: " & Sheets(1).Range("B4").Value & Chr(10) & "Checked By: " & Sheets(1).Range("B5").Value & " Date: " & Sheets(1).Range("B6").Value
.LeftFooter = "Project Number: " & Sheets(1).Range("B2").Value
.CenterFooter = "Page &P/&N"
.RightFooter = "Print Date: " & Sheets(1).Range("B7").Value
End With
End If
Next ws
Sheets(Array("General", "Loads", "Capacity", "Analysis", "POSTING", "SUMMARY")).Select
Sheets("General").Activate
End Sub
I was thinking maybe there is something wrong with the way I implemented the For Each as that is not a form I am familiar with. I was originally thinking about using a For x = 2 to ws.count - UDF_worksheet_count_names_starting_with_tables to loop through the sheets. I thought I would check in here first to see if there is a better approach to this problem.
So first off thanks to D.K. for the suggestion to change from activesheet.page setup to ws.pagesetup. This however did not solve the problem but did make a lot more sense. I then stumbled onto this thread: Excel headers/footers won't change via VBA unless blank. I was wondering what the line
Application.PrintCommunication = False
actually did. When I commented that line out the last sheet's layout no longer got updated/changed to match the other pages and things are working as intended.
This is what the final code looks like:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim ws As Worksheet
For Each ws In Worksheets
If ws.Name <> "HEADER AND FOOTER" And InStr(1, Left(ws.Name, 5), "Table", vbTextCompare) = 0 Then
With ws.PageSetup
.CenterHeader = Sheets(1).Range("B1").Value & Chr(10) & "Load Evaluation"
.RightHeader = _
"Calculated by: " & Sheets(1).Range("B3").Value & " Date: " & Sheets(1).Range("B4").Value & Chr(10) & "Checked By: " & Sheets(1).Range("B5").Value & " Date: " & Sheets(1).Range("B6").Value
.LeftFooter = "Project Number: " & Sheets(1).Range("B2").Value
.CenterFooter = "Page &P/&N"
.RightFooter = "Print Date: " & Sheets(1).Range("B7").Value
End With
End If
Next ws
End Sub
Related
I've been working on a VBA macro that automatically creates watermark on a master slide for multiple named people and then automatically saves it to separate PDFs. All of this works well now. However, some presentations I may need to watermark, have multiple themes applied to different slides. (eg. first half is using theme 1 and the second half is using theme 2) Each theme has a separate master slide. When I use ActivePresentation.SlideMaster, this only affects the top master slide in the Slide Master view. How would I go about accessing master slides for the other themes?
Edit: Here is the code I have. The xlVariables come from an Excel file. The watermark line refers to the text box that is put furthest back. I searched for a way to access multiple master slides but I couldn't find anything on it.
xlName = Range("A" & CStr(count))
xlCompany = Range("B" & CStr(count))
xlDate = Range("C" & CStr(count))
xlMail = Range("D" & CStr(count))
'Create the watermark
ActivePresentation.SlideMaster.Shapes(1).TextFrame.TextRange.text = "Confidential - Do Not Share" & vbNewLine & "Issued to " _
& xlName & vbNewLine & "on " & xlDate & vbNewLine & xlCompany & " - Internal Use Only"
Here's some sample code that will do something (that you define) to each master (oDes.SlideMaster in the code) and layout (oLay) in a presentation.
Modify DoSomethingWithShapeContainer to do whatever it is you need to do to each master/layout.
Sub AllMastersAndLayouts()
Dim oLay As CustomLayout
Dim oDes As Design
With ActivePresentation
For Each oDes In .Designs
Call DoSomethingWithShapeContainer(oDes.SlideMaster)
For Each oLay In oDes.SlideMaster.CustomLayouts
Call DoSomethingWithShapeContainer(oLay)
Next
Next
End With
End Sub
Sub DoSomethingWithShapeContainer(oShapeContainer As Object)
With oShapeContainer.Shapes.AddTextbox(msoTextOrientationHorizontal, 20, 20, 200, 50)
.TextFrame.TextRange.Text = "I did something here"
End With
End Sub
I am trying to use Excel-VBA to set the PageSetup information for my worksheet, but it is giving me the following error:
Run-time error ‘1004’:
Unable to set the LeftFooter property of the PageSetup class
The relevant example code follows:
Set WS = ActiveWorkbook.ActiveSheet
WS.DisplayPageBreaks = False
With WS.PageSetup
.PrintArea = "$A$1:$L$32"
.Orientation = xlLandscape
.CenterHeader = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" & Chr(10) & _
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
.CenterFooter = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" & Chr(10) & _
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
.RightFooter = "XXXXXXXXXXXXXXXXXXXXXXX" & Chr(10) & _
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
.LeftFooter = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" & Chr(10) & _
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" & Chr(10) & _
"XXXXXXXXXXXXXXXXXXXXXXXXXX"
.CenterHorizontally = True
.Zoom = False
End With
Strangely, if I comment out any one of the three .xxxFooter lines, the code works fine. If I rearrange them into any possible different order, they all work with the exception of the last one which will throw the same 1004 error but for the new .xxxFooter.
This user seems to have a highly related problem, but did not ever resolve it: Error when setting Worksheet.PageSetup.XxxFooter. As a comment to the questions there, yes, I do have a printer installed.
Edit:
Another discovery: if I remove some of the characters, then it will work again. Adding in additional characters manually eventually caused this error box to pop up:
The text string you entered is too long. Reduce the number of characters used.
I can temporarily work around by abbreviating a lot of things in the footer, but is there any other way to solve this problem, and can anyone explain why there is a character limit in the footers? That seems arcane in Excel 2016...
I have a worksheet(adHoc) where cell b28 contains
"&9 2014 YTD Financial Data for PP" & Chr(10) & " &D &T" & Chr(10) & " Version 1.0" & Chr(10) & " &F"
When I use the above to update the footer of another worksheet in a different workbook. I don't get the embedded formatting - it displays exactly what is contained in the cell b28.For example excel should see &9 and make the font 9 points.
I am also getting a datatype mismatch error with the page orientation. The contents of cell b36 is xlLandscape.
I posted a copy of this question last week on another board but did not get any answers. I hope someone here has answer.
http://www.mrexcel.com/forum/excel-questions/919033-updating-pagesetup-using-cells-master-worksheet-orientation-formatting-footer-excel-visual-basic-applications.html
This is the code I am using.
Sub page_setup()
Dim reportWB As Excel.Workbook
Dim sheet As Excel.Worksheet
'open report workbook - name of workbook is in cell b4
Set reportWB = Workbooks.Open(Workbooks("macros.xlsm").Sheets("adHoc").Range("b4").Value)
Dim leftFooter
leftFooter = Workbooks("macros.xlsm").Sheets("adHoc").Range("b28").Value
For Each sheet In reportWB.Sheets
With sheet
.PageSetup.leftFooter = leftFooter
.PageSetup.Orientation = Workbooks("macros.xlsm").Sheets("adHoc").Range("b36").Value
End With
Next
End Sub
Reading in your footer definitions like that they are treated as literal string, not code. You need to resolve the code to valid footer strings somehow.
For the LeftFooter string, you can use Evaluate to resolve it, but it will need to be written as if it's a Excel Formula, not VBA, so use
"&9 2014 YTD Financial Data for PP" & Char(10) & " &D &T" & Char(10) & " Version 1.0" & Char(10) & " &F"
Note the I use Char rather than Chr, the Excel formula equivalent.
For Orientation you are using a named constant, which won't work. Either put the value on your Excel sheet (2 in this case) or write your own code to resolve the name to its value
Working version (with corrected source data on sheet as descibed above)
Sub page_setup()
Dim reportWB As Excel.Workbook
Dim sheet As Excel.Worksheet
Dim wsSource As Worksheet
'open report workbook - name of workbook is in cell b4
Set wsSource = Workbooks("macros.xlsm").Sheets("adHoc")
Set reportWB = Workbooks.Open(wsSource.Range("b4").Value)
Dim leftFooter
leftFooter = wsSource.Range("b28").Value
For Each sheet In reportWB.Sheets
With sheet
.PageSetup.leftFooter = Evaluate(leftFooter)
.PageSetup.Orientation = wsSource.Range("b36").Value
End With
Next
End Sub
To handle the constants you could add a UDF that resolves the string names to values and call that from your settings sheet
Eg
Function GetConst(s As String) As Variant
Select Case s
Case "xlLandscape"
GetConst = xlLandscape
Case "xlPortrait"
GetConst = xlPortrait
' etc
End Select
End Function
Put in cell B36 GetConst("xlLandscape") (as a string, not formula), and change your Orientation line of code to
.PageSetup.Orientation = Evaluate(wsSource.Range("b36").Value)
Add any other named constants you want to the Select Case statement.
AFAIK, there is no (straightforward) way to do what you're trying to do. When you put code in a cell, and then call that cell's value in place of actual code, what VBA is trying to run is not:
.PageSetup.Orientation = xlLandscape
but rather:
.PageSetup.Orientation = "xlLandscape"
which will produce the errors and behavior you're seeing.
As rule of thumb, if your VBA code needs a string (ie, something in ""), or a number, you can do that calculation on the sheet and have the code pull in the value.
For everything else (there's Mastercard) put it in the code. For example:
leftfooter = cell1.value & Chr(10) & cell2.value & Chr(10) & cell3.value
(As a side note, I'm not familiar with the formatting it seems you're trying to do in that string... Those are generally set up through things like
With sheet.PageSetup.leftFooter.
.Font.Size = 9
'etc...
)
I'm trying to retrieve the sheet reference location from a hyperlink that's in a cell
The following doesn't seem to work as test doesn't return anything, even though G8 points to Sheet: KO in Cell A19
test = Range("G8").Hyperlinks(3).Address
Now if I run the following:
For Each hl In Sheets("LIST").Hyperlinks
MsgBox "Range " & hl.Range.Address & " addr " & _
hl.Address & " text " & hl.TextToDisplay
Next hl
It cycles through and finds the correct address but I can't seem to work out how to detect the sheet it's pointing. Also the loop is a bit of a mess because it errors out once it has found the first and only hyperlink in this situation. And it's not always specific for G8. I guess I could just throw an if statement in and exit the for loop early.
Regardless of that, I can't find anywhere in stackoverflow, google, microsofts "hyperlinks" docs a way to get the sheet name.
See below sample illustration:
SubAddress is what you want:
Sub Test()
Dim hl As Hyperlink, r As Range
Set hl = ActiveSheet.Hyperlinks(1)
Set r = Application.Evaluate(hl.SubAddress)
Debug.Print "Sheet: '" & r.Parent.Name & "'", "Range:" & r.Address()
End Sub
I am duplicating with minor date changes, slideshows created by another user, who constantly forgets to embed audio, but links it instead.
Is there some simple way to determine whether audio is embedded or linked, and what the source file path is, if it is linked? If I could run a macro to just determine this it would help enormously.
Not sure how to approach this, but individually opening dozens of files to determine audio is there defeats everything else that is scripted in this case.
This is the way I would do it:
Sub DetermineAudioLinks()
Dim p As Presentation: Set p = ActivePresentation
Dim s As Slide
Dim sh As Shape
For Each s In p.Slides
For Each sh In s.Shapes
If sh.Type = msoMedia Then
If sh.MediaType = ppMediaTypeSound Then
Debug.Print "Slide " & s.SlideNumber & ":" ; sh.Name
If sh.MediaFormat.IsLinked Then
Debug.Print vbTab & "Is Linked: True"
Debug.Print vbTab & sh.LinkFormat.SourceFullName
End If
End If
End If
Next
Next
End Sub
Note the the MediaFormat property above is PowerPoint 2010 only - it won't work with earlier versions of PowerPoint.