Printing from Excel VBA - vba

Trying to print the same excel sheet a number of times (e.g 100) with a cell incremented each time (e.g cell 4F).
I tried using
Workbook_BeforePrint
to increment the cell, but it requires interaction with the "select printer" dialog for each printed sheet.
Would it be possible to make something like:
a = getIntegerUserInput()
for i in 1..a
increment 4F with one
print the sheet suppressing the "select printer" dialog
end for
Cheers

Have you selected a default printer?
I used this:
Sub printinc()
For i = 0 To 3
Range("A1").Value = Range("A1").Value + 1
Sheets("Sheet1").PrintOut
Next
End Sub
It printed 4 copies incrementing the value in cell A1 each time without prompting me for settings or printer selection.

To print a sheet, you can use this kind of code (assuming you know on which printer you want to print) using PrintOut:
Sub PrintFile()
Dim curPrinter As String
curPrinter = Application.ActivePrinter
Application.ActivePrinter = "Myprinter"
ActiveWindow.SelectedSheets.PrintOut
Application.ActivePrinter = curPrinter
End Sub
Hence, you can create a loop to increase a cell and print your worksheet with the increment.
By the way, you could do it using Before_print and if you don't want to display the print dialog, you can set Cancel to False while calling the procedure Private Sub Workbook_BeforePrint( Cancel As Boolean) (ref on MSDN)
You can also read this SO thread to prevent displaying the printing dialog: How do you prevent printing dialog when using Excel PrintOut method.
[EDIT] see Seyren's answer for a working solution on what you want. Yet, take care about the performance if you really wanted to loop 100 times.

Private Sub Workbook_BeforePrint(Cancel As Boolean)
'//supress recursion into this event when we print
Application.EnableEvents = False
'//increment
If Not IsNumeric(ActiveSheet.Range("A1").Value) Then ActiveSheet.Range("A1").Value = 0
ActiveSheet.Range("A1").Value = ActiveSheet.Range("A1").Value + 1
'//do a default print
ActiveSheet.PrintOut
Application.EnableEvents = True
'//prevent the default print
Cancel = True
End Sub

Related

VBA_Processing a value as 29160012040000TZ

I created a couple of user forms which operate a data in separate report workbook. My script can successfully proceed a value in digit type. Unfortunately the circumstances have changed and now it has to work with a Serial Numbers as: 29160012040000TZ. With that new value script after starting the Sub, open a report, but it never enter into a 'with' statement. It doesn't look for a value or doing something else. Just open a report workbook and freeze.
Below you can see the code lines where issue is present and a little description:
Single_PHA is a text window in User Form where user can enter a a value, proceeding value is 29160012040000TZ
Private Sub Wydaj_button_Click()
Workbooks.Open Filename:="N:\ENGINEERING\1. ENGINEERS\Mateusz Skorupka\PHA_Cleaning_report_path\PHA_CLEANING_REPORT.xlsm", ReadOnly:=False
Dim REPORT As Workbook
Set REPORT = Application.Workbooks("PHA_CLEANING_REPORT.xlsm")
Set TABLE = REPORT.Worksheets("Main_table")
...
With TABLE.Range("A1")
If Single_PHA = True Then
If Not IsError(Application.Match(Single_PHA.Value, .Range("A:A"), 0)) Then
Single_PHA_row = TABLE.Range("A:A").Find(What:=Single_PHA.Value, LookIn:=xlValues).Row
.Offset(Single_PHA_row - 1, 4).Value = Date
REPORT.Close SaveChanges:=True
Single_PHA.Value = ""
Exit Sub
Else
MsgBox "Numer seryjny głowicy nie istnieje w bazie"
REPORT.Close SaveChanges:=False
Exit Sub
End If
End If
End With
In VBA I don't know how to open something like debugger or make the print instruction which would show me how the variables look on specific steps.
I am not sure if VBA read the value as 29160012040000TZ as string. I tried to declare at the beginning a variable as Single_PHA_STR as String and the proceed it as just text, but no wins there:
Dim Single_PHA_STR As String
...
With TABLE.Range("A1")
If Single_PHA = True Then
Single_PHA_STR = Str(Single_PHA.Value)
If Not IsError(Application.Match(Single_PHA_STR, .Range("A:A"), 0)) Then
Single_PHA_row = TABLE.Range("A:A").Find(What:=Single_PHA_STR, LookIn:=xlValues).Row
.Offset(Single_PHA_row - 1, 4).Value = Date
REPORT.Close SaveChanges:=True
Single_PHA.Value = ""
Exit Sub
Else
MsgBox "Numer seryjny głowicy nie istnieje w bazie"
REPORT.Close SaveChanges:=False
Exit Sub
End If
End If
End With
I noticed that if in VBA IDE I write a bold value 29160012040000TZ, I get an error
Expected line number or label or statement or end of statement
and the value is highlighted in red.
Could someone help me in that field and explain the nature of issues:
To reproduce a situation you can create a simply user form with one TextBox and one CommandButton. In the same worksheet as user form in a column A put a values: 29160012040000 and 29160012042027IR
Then make a sub which execute after double click on command button with code:
Private Sub CommandButton1_Click()
With Worksheets("Sheet1").Range("A1")
If Text_box1 = True Then
If Not IsError(Application.Match(Text_box1.Value, .Range("A:A"), 0)) Then
Text_box1_row = Worksheets("Sheet1").Range("A:A").Find(What:=Text_box1.Value, LookIn:=xlValues).Row
.Offset(Text_box1_row - 1, 4).Value = Date
Text_box1.Value = ""
Exit Sub
Else
MsgBox "PHA SN not exist in a database"
Exit Sub
End If
End If
End With
End Sub
Then try to input in a UserForm's TextBox a value = 29160012040000 and you will see that script successfully filled a forth column in row with current date. Then try to input a value 29160012042027IR and you will see that nothing happened. Script don't proceed that value at all.
So that is my issue and question indeed. How to process a value with letters at the end like: 29160012042027IR : )
I also tried to focus a script statement on one specific cell in which is a text value "29160012042027IR" that which I input into a UserForm TextBox. Looking with a debugger both of variables in if statement have the same text value, but still script miss that statement and go to else instructions : (
I mean abut: If Range("A3").Text = Text_box1.Text Then
When I change a statement for "If Range("A3").Value = Text_box1.Value Then" the same thing happen.
Private Sub CommandButton1_Click()
With Worksheets("Sheet1").Range("A:A")
If Text_box1 = True Then
If Range("A3").Text = Text_box1.Text Then
Text_box1_row = Worksheets("Arkusz1").Range("A:A").Find(What:=Text_box1.Value, LookIn:=xlWhole).Row
.Offset(Text_box1_row - 1, 4).Value = Date
Text_box1.Value = ""
Exit Sub
Else
MsgBox "PHA SN not exist in a database"
Exit Sub
End If
Else
MsgBox "Other loop"
End If
End With
End Sub
IMPORTANT NOTICE:
I found the main issue. I made wrong if condition, it should be:
If Single_PHA <> "" Then previously I have got: If Single_PHA = True Then, and there the results is a value not the boolean type.
Everything works. Thank everyone very much for help.
Topic is ready to be closed.
PS: thank you Tom for suggestion and tip with debugger: )

Why does Excel vba copy to clipboard inconsistently?

I have an excel macro that does two very simple things:
It displays the current date and time in a little window.
It copies the display as a text string for pasting into other apps as needed.
The cell that is displayed has the following formula in it:
=TEXT(NOW(),"yyyy.MM.dd hh:mm:ss")
Every 5 seconds, the macro refreshes the time and the clock ticks.
My problem is that when I copy the time from the cell, I don't consistently get the contents pasted to the clipboard. Sometimes the cell contents are posted to the clipboard. I can't figure out why it works sometimes and not others as there isn't a lot going on. It should just always work.
I know the data aren't on the clipboard because I can try pasting the clipboard into different programs like notepad and other text apps and nothing happens.
The entire code is in a single module.
Dim stopSwitch As Integer
Dim NextTick
Sub myupdate()
If ActiveCell.Address = "$B$1" Then
growWindow ' resize window beyond just clock display
stopTime '
Exit Sub ' stop updating
End If
Range("a1").Select
Calculate
DoEvents
If ActiveWorkbook.Name = "calendar clock.xlsb" Then shrinkWindow
NextTick = Now + TimeValue("00:00:05") ' give me 5 seconds to copy/paste
Application.OnTime NextTick, "myupdate"
ThisWorkbook.Save ' futile attempt to prevent save dialog
End Sub
Sub auto_open()
' to stop clock, tap right arrow to select cell b1 when workbook is active
Range("a1").Select
myupdate
End Sub
Sub growWindow()
Application.Width = 768
Application.Height = 621.75
ThisWorkbook.Save
End Sub
Sub shrinkWindow()
' strip decorations so window is as small as possible
Application.DisplayFormulaBar = False
ActiveWindow.DisplayGridlines = False
ActiveWindow.DisplayHeadings = False
' move window to second monitor and size to single cell display
Application.WindowState = xlNormal
Application.Top = 0
Application.Left = -720
Application.Width = 174
Application.Height = 127
ActiveWindow.WindowState = xlMaximized
End Sub
Sub stopTime() ' called when workbook is closed
On Error Resume Next
Application.OnTime NextTick, "myupdate", schedule:=False
Range("b1").Select
End Sub
Sub copyTime()
Range("a1").Copy ' copy time
Range("f5").PasteSpecial xlPasteValues ' strip formatting
Range("f5").Copy ' copy time as text
DoEvents ' hack to attempt to make copy work consistently
End Sub
The above code sizes the window and updates the clock every 5 seconds.
To copy the clock as text to the clipboard, I have the following code in the workbook
Private Sub Workbook_Activate()
Application.OnKey "^c", "module1.copyTime"
End Sub
Private Sub Workbook_Deactivate()
Application.OnKey "^c"
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
' turn off auto update
Module1.stopTime
' resize window so if I open another spreadsheet, it's a reasonable size
Application.WindowState = xlNormal
Application.Width = 768
Application.Height = 621.75
Application.OnKey "^c"
ThisWorkbook.Save ' try to prevent save dialog at close
End Sub
I modified the copyTime function to verify the ^C is seen by selecting the unformatted cell and I can see that the data consistently go to the cell so I know my problem isn't with the Range("a1").copy step in copytime or the pastespecial to cell f5.
That leaves the range("a5").copy command as the bad actor when the copy fails which is weird. It's as if copy works as long as the data are kept inside the spreadsheet but fails to update the external clipboard consistently.
That observation led me to try setting application.cutcopymode to xlcopy, true and false to see if that helped. The only effect I saw from trying all the settings is whether I saw f5 get highlighted with a marquee or not - none of the setting forced a copy to the external clipboard.
I tried waiting for a clock tick before copying to see if something was clearing the clipboard following the copy if it was time to update the clock. That appeared to help somewhat but, again not consistently.
So why does the copy fail to always update the clipboard? And why does it not work when it doesn't and does when it does? Even better, how can I modify this code so it always exports to the external clipboard?
Try using this method, it's always reliable for me
Dim TimeInClip As MSForms.DataObject
Set TimeInClip = New MSForms.DataObject
TimeInClip.SetText Range("A1").Value
TimeInClip.PutInClipboard
Try
Sub copyTime()
Range("a1").Copy ' copy time
Range("f5").PasteSpecial xlPasteValues ' strip formatting
Application.CutCopyMode = False ' Clear Excel clipboard
Range("f5").Copy ' copy time as text
DoEvents ' hack to attempt to make copy work consistently
End Sub
You said that you tried Application.CutCopyMode, but have you tried it that way?
It only forces the application to clear the clipboard before copying something else, which should then copy properly on the fresh clipboard.

How to fire on unhiding rows or columns

Some users hide columns/rows and forget to unhide them before saving a workbook. I want to catch that with unhide all columns/rows on the save event with
Sub ReInvisible()
ThisWorkbook.Worksheets(1).UsedRange.EntireRow.Hidden = False
ThisWorkbook.Worksheets(1).UsedRange.EntireColumn.Hidden = False
End Sub
this works fine but I would like to inform the user that all hidden columns/rows are now visible. Now I am looking for a way to trigger on unhiding a column/row so as soon as at least one column or row is made visible I want to fire a messagebox.
In VB.NET I would try to write my own event but in VBA I do not know how I can do a workaround. Does anyone have an idea?
Something like this should do it:
Sub ReInvisible()
Dim lVisColCount As Long
Dim lVisRowCount As Long
With ThisWorkbook.Worksheets(1).UsedRange
lVisColCount = .Rows(1).SpecialCells(xlCellTypeVisible).Count
lVisRowCount = .Columns(1).SpecialCells(xlCellTypeVisible).Count
.EntireRow.Hidden = False
.EntireColumn.Hidden = False
If .Rows(1).SpecialCells(xlCellTypeVisible).Count <> lVisColCount Then MsgBox "Columns unhidden"
If .Columns(1).SpecialCells(xlCellTypeVisible).Count <> lVisRowCount Then MsgBox "Rows unhidden"
End With
End Sub

Advancing two slides in powerpoint VBA

I am trying to advance slides based on a response. I want to go forward 2 slides if the user selects easy and one if they select hard. This is my current code. The Nextpage script isn't working AND I would prefer for it to be usable for multiple questions--I can't seem to get it to work with something like slide +1 or slide +2 (or ++).
Sub Start()
ActivePresentation.Slides(2).Shapes("selection_hard").Visible = False
ActivePresentation.Slides(2).Shapes("selection_easy").Visible = False
ActivePresentation.SlideShowWindow.View.Next
End Sub
Sub Shoe_Easy()
ShoeAnswer = "Easy"
ActivePresentation.Slides(2).Shapes("selection_hard").Visible = False
ActivePresentation.Slides(2).Shapes("selection_easy").Visible = True
'ActivePresentation.SlideShowWindow.View.GotoSlide (11)
End Sub
Sub Shoe_Hard()
ShoeAnswer = "Hard"
ActivePresentation.Slides(2).Shapes("selection_hard").Visible = True
ActivePresentation.Slides(2).Shapes("selection_easy").Visible = False
'ActivePresentation.SlideShowWindow.View.GotoSlide (12)
End Sub
Sub Nextpage()
If ActivePresentation.Slides(2).Shapes("selection_hard").Visisble = True Then
ActivePresentation.SlideShowWindow.View.GotoSlide (3)
ElseIf ActivePresenation.Slides(2).Shapes("selection_easy").Visible = True Then
ActivePresenation.SlideShowWindow.View.GotoSlide (4)
End If
End Sub
Assuming that "response" means clicking on one of two shapes (Easy or Hard), this will do it. You just need to make sure that the text in the shape and the code below match up and that you assign the HandleClick macro as a RunMacro action setting to each of the shapes (assign them to two of them then copy/paste the shapes elsewhere as needed).
There are a few extra hoops to jump through to get this working on a Mac; shout if you need it to work there too.
Sub HandleClick(oSh As Shape)
' Did they click the Easy or Hard button?
' oSh contains a reference to the shape they clicked
' Look a the text in oSh to decide where to go next:
Select Case UCase(oSh.TextFrame.TextRange.Text)
Case Is = "EASY"
SlideShowWindows(1).View.GotoSlide (oSh.Parent.SlideIndex + 2)
Case Is = "HARD"
SlideShowWindows(1).View.GotoSlide (oSh.Parent.SlideIndex + 1)
Case Else
' Do nothing
End Select
End Sub
This immediately advances the slide as soon as it's clicked. If you want the user to be able to choose an answer and then advance, you'd need a different approach.
Instead of advancing immediately as above, you'd set the value of a global variable to, say, "EASY" or "HARD", depending on the user's selection.
Then in a separate macro assigned to your forward button, you'd advance one or two slides depending on the value of the global variable.
I think something like this might help:
Nextpage()
Dim currentSlide as Slide
Set currentSlide = ActivePresentation.SlideshowWindow.View.Slide
If ActivePresentation.Slides(2).Shapes("selection_hard").Visisble = True Then
ActivePresentation.SlideShowWindow.View.GotoSlide currentSlide.SlideIndex + 1
ElseIf ActivePresenation.Slides(2).Shapes("selection_easy").Visible = True Then
ActivePresenation.SlideShowWindow.View.GotoSlide currentSlide.SlideIndex + 2
End If
End Sub

PrintOut prints groups of sheets instead of 1 group

We have this problem on many workbooks where we select a few sheets with VBA and print them using the following line and Excel will actually print multiple groups of pages instead of 1 group of multiple pages.
ActiveWindow.SelectedSheets.PrintOut
Here is an example of a Sub that has this behaviour:
Private Sub imprimer(iColTypeRapport As Integer)
Dim cell As range, rangeImpr As range, colonne As range
Dim debute As Boolean ' True seulement si on a déjà sélectionné une feuille
On Error GoTo erreur
application.ScreenUpdating = False
debute = False
Set rangeImpr = ActiveSheet.range("impression")
Set colonne = rangeImpr.Offset(0, iColTypeRapport).EntireColumn
For Each cell In rangeImpr
If LCase(Intersect(cell.EntireRow, colonne)) = "o" Then
If Not debute Then
Worksheets(cell.Value).Select
debute = True
Else
Worksheets(cell.Value).Select False
End If
End If
Next cell
ActiveWindow.SelectedSheets.PrintOut
Worksheets("TableauDeBord").Select
application.ScreenUpdating = True
Exit Sub
erreur:
Call GestionErreur(Err.Number, Err.Description, "modRequete", "ImportData")
End Sub
This is made even more obvious if we use Print2PDF or AdobePDF print as it will prompt multiple times (in this case, 3 times) for file names.
If I put a breakpoint before PrintOut the sheets are selected appropriately and I see nothing unusual / unexpected.
Any idea ?
I've seen this. It can have to do with things like different print resolutions. If you search on "print workbook produces multiple pdfs" you'll find some answers. With the PDF problem specifically, it can be resolved (in XL 2010 and, I'm guessing, 2007) by doing a "Save As" to PDF instead.