PDA

View Full Version : Solved: Is there a way to have code trigger an event when trying to save or print?



andrewvanmar
07-24-2007, 02:28 AM
Short version:
I want to generate an error message when certain fields are not filled in when the user tries to save or print the document.

Slightly longer version:
Still working on the same workbook with the pdf code (http://vbaexpress.com/forum/showthread.php?p=103492#post103492 )

What I want to do, is make sure that certain fields are always filled (correctly) in before the user can print/save the document.

I want it to check only a few cells, three dates and a version number (1.2 etc)

If the cells are not filled in (correctly) by leaving them empty, or entering text, or only 1 number instead of 2 (for the version number), and they hit save/print (or try to pdf) the a popup error should appear saying that the dates or the version number has not been filled in correctly.

Is this a possibility?

rory
07-24-2007, 02:39 AM
You can use the Workbook_BeforeSave and Workbook_BeforePrint events for this. Code need to go into the ThisWorkbook module of your workbook.
HTH
Rory

andrewvanmar
07-24-2007, 03:16 AM
Thanks rory!

will this conflict with an automated pdf print script or will it interrupt it?

daniel_d_n_r
07-24-2007, 03:19 AM
You can use the Workbook_BeforeSave and Workbook_BeforePrint events for this. Code need to go into the ThisWorkbook module of your workbook.
HTH
Rory

just a quick hijack here..
these functions are only available in office 2007 ?

cheers

rory
07-24-2007, 03:24 AM
Looking at that script, the BeforePrint will be triggered when you hit the PrintOut lines in the code. But if you are running that code to print to PDF, you can do the checks at the beginning of that code anyway. That means that you either don't put the check into the BeforePrint event, or you can use Application.EnableEvents = False in the PDF code, do the printing, then set it back to True.
Regards,
Rory

rory
07-24-2007, 03:26 AM
Daniel_d_n_r,
No, those events have been around as long as I can recall. Since Excel 97 anyway.
Regards,
Rory

andrewvanmar
07-24-2007, 04:17 AM
I got the before save to work:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Sheets("signatures and pricing").[g2] = "" Then
Cancel = True
MsgBox "Can't save. No entry for Requested Date"
Else
Cancel = False
End If
End Sub

The same didn't work for printing ( it gave "Compile error: Procedure declaration does not match description of event or procedure having the same name.")
(this was tried for normal printing, not pdf. I changed the beforesave to before print in the above code)

I assume I have to set up two sets of code, one for the pdf script and one for regular printing.

I have no clue though what you mean me to add to the pdf code to check actually.



I found something elsewhere:

Private Sub Workbook_BeforePrint(Cancel As Boolean)
If Sheets("signatures and pricing").[g2] = "" Then
MsgBox "Cannot print until required cells have been completed!"
Cancel = True
End If
End Sub

This seems to work on both normal printing and the pdf code but.........

I have o clue how to add more than one cell to check ( for instance cell c2 from the sheet "information)

rory
07-24-2007, 04:40 AM
The BeforePrint event must look like this:
Private Sub Workbook_BeforePrint(Cancel As Boolean)
End Sub

In the VBEditor, if you choose Workbook from the left dropdown at the top of the main code window, the right dropdown contains a list of events; picking one will create a stub procedure with the right format.
All you would do with your print to PDF routine is add the check near the beginning like this:
If Sheets("signatures and pricing").[g2] = "" Then
MsgBox "You need to fill in cell G2!"
Exit Sub
End If

HTH
Rory

andrewvanmar
07-24-2007, 04:51 AM
I got a little further: I edited my last post while you wrote yours.
what do I do to make it check multiple required cells?

rory
07-24-2007, 05:01 AM
The simplest way is to use multiple If statements. If you are going to do this from different events and from the PDF routine, it would be better to put the checking code into a separate function which you can call from each of the routines; then if you have to edit the code, you will only need to do so in one location:
Function IsComplete() As Boolean
IsComplete = False
If Sheets("signatures and pricing").[g2] = "" Then Exit Function
If Sheets("signatures and pricing").[g3] = "" Then Exit Function
If Sheets("signatures and pricing").[g4] = "" Then Exit Function
If Sheets("signatures and pricing").[g5] = "" Then Exit Function
If Sheets("signatures and pricing").[g6] = "" Then Exit Function
' If we got here, then all cells are filled, so OK
IsComplete = True
End Function


then in your other routines you can use:
If IsComplete = False then
MsgBox "Values are missing!"
Exit Sub
End If

You could also change the function to return the addresses of the incomplete cells and check If Len(IsComplete) > 0

HTH
Rory

andrewvanmar
07-24-2007, 06:39 AM
Getting closer and closer, I can feel it :)

ok for the "before save" function i wrote:
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If IsComplete = False Then
Cancel = True
MsgBox "Cannot save, the CRM number and the appropriates dates are not filled in"
Else
Cancel = False
End If
End Sub

separate function looks like this.

It cancels the save regardless of having data in those specific fields now, what did I do wrong? :)

rory
07-24-2007, 06:47 AM
What does the IsComplete function look like?

andrewvanmar
07-24-2007, 06:56 AM
HAH!!!! I fell into my own trap! there was one field not filled in ( ok granted, stupid)

recap, the script works like a charm!!!!!

thanks rory!

rory
07-24-2007, 07:03 AM
Glad to help! :)
You might want to rewrite the IsComplete function to return the addresses of the cells that haven't been populated so you can use it in the messagebox, but that's cosmetic.
Rory

andrewvanmar
07-24-2007, 07:36 AM
hmm, that's a neat trick. I assume I need to add to the messagebox line?

rory
07-24-2007, 07:45 AM
Change the function to something like this:
Function IncompleteCells() As String
Dim strCells As String
Dim astrCells(), varItem
astrCells = Array("G2", "G3", "G4", "G5", "G6")
For Each varItem In astrCells
If Sheets("signatures and pricing").Range(varItem) = "" Then strCells = strCells & "," & varItem
Next varItem
If Len(strCells) > 0 Then IncompleteCells = Mid$(strCells, 2)
End Function


then use:


Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim strCells as String
strCells = IncompleteCells
If len(strCells) > 0 Then
Cancel = True
MsgBox "Cannot save, these cells are not filled in: " & strCells
Else
Cancel = False
End If
End Sub


Regards,
Rory

andrewvanmar
07-24-2007, 07:52 AM
NICE!!!

Thanks rory! That completes my project (for now, untill I decide to upgrade it).

really cool!

andrewvanmar
07-25-2007, 01:17 AM
is the same possible to trap an email event?

Charlize
07-25-2007, 01:27 AM
I'm not sure why you want to do everything with a before_event. If some cells aren't properly filled in, don't execute the code. No need for those events.

andrewvanmar
07-25-2007, 01:42 AM
At least for the printing, it disables the print prview code, and also the print command in the menu. the same goes for saving.

The last thing to make sure the doc isn't circulated without those fields filled in is disabling the "send as" menu command.

( the users of this doc need to be rather strictly guided to doing it the right way ;-) )

Charlize
07-25-2007, 03:27 AM
You can use the routine that disables the send button on workbook open when certain cells aren't filled in. If there is a value in all the cells that you need use the enable routine. Tested this under excel 2003.Option Explicit
'Link to numbers of id
'http://support.microsoft.com/kb/213552#top
Sub disable_menu_items()
Dim Ctrl As Office.CommandBarControl
For Each Ctrl In Application.CommandBars.FindControls(ID:=30095)
'mail menu under file - send
Ctrl.Enabled = False
Next Ctrl
For Each Ctrl In Application.CommandBars.FindControls(ID:=3738)
'mail button on toolbar
Ctrl.Enabled = False
Next Ctrl
End Sub
Sub enable_menu_items()
Dim Ctrl As Office.CommandBarControl
For Each Ctrl In Application.CommandBars.FindControls(ID:=30095)
Ctrl.Enabled = True
Next Ctrl
For Each Ctrl In Application.CommandBars.FindControls(ID:=3738)
Ctrl.Enabled = True
Next Ctrl
End Sub

andrewvanmar
07-25-2007, 04:35 AM
Hmm that looks like the trick :)
I think i'll even make this an always on situation, I don't want anyone mailing from within the doc.
Shall I copy this to "this workbook"?

Charlize
07-25-2007, 05:14 AM
The disable routine goes in the workbook_open event. The enable routine goes in the workbook_before close event.

andrewvanmar
07-25-2007, 05:30 AM
Thanks!!

(i'm so loving this!)

andrewvanmar
07-25-2007, 05:39 AM
compile error: procedure declaration does not match description of event or procedure having the same name
Private Sub Workbook_open()
Sub disable_menu_items()
Dim Ctrl As Office.CommandBarControl
For Each Ctrl In Application.CommandBars.FindControls(ID:=30095)
'mail menu under file - send
Ctrl.Enabled = False
Next Ctrl
For Each Ctrl In Application.CommandBars.FindControls(ID:=3738)
'mail button on toolbar
Ctrl.Enabled = False
Next Ctrl
End Sub
End Sub
Private Sub workbook_beforeclose()
Sub enable_menu_items()
Dim Ctrl As Office.CommandBarControl
For Each Ctrl In Application.CommandBars.FindControls(ID:=30095)
Ctrl.Enabled = True
Next Ctrl
For Each Ctrl In Application.CommandBars.FindControls(ID:=3738)
Ctrl.Enabled = True
Next Ctrl
End Sub
End Sub

I added and removed the sub enable menu items and it's end sub, but that made no diff.
missing something?

Charlize
07-25-2007, 05:44 AM
Put those routines in a normal module and use a call.Call disable_menu_itemsfor workbook_open.

andrewvanmar
07-25-2007, 06:08 AM
This is what module3 looks like now:

Private Sub Workbook_open()
Call disable_menu_items
End Sub
Private Sub Workbook_beforeclose()
Call enable_menu_items
End Sub


Sub disable_menu_items()
Dim Ctrl As Office.CommandBarControl
For Each Ctrl In Application.CommandBars.FindControls(ID:=30095)
'mail menu under file - send
Ctrl.Enabled = False
Next Ctrl
For Each Ctrl In Application.CommandBars.FindControls(ID:=3738)
'mail button on toolbar
Ctrl.Enabled = False
Next Ctrl
End Sub

Sub enable_menu_items()
Dim Ctrl As Office.CommandBarControl
For Each Ctrl In Application.CommandBars.FindControls(ID:=30095)
Ctrl.Enabled = True
Next Ctrl
For Each Ctrl In Application.CommandBars.FindControls(ID:=3738)
Ctrl.Enabled = True
Next Ctrl
End Sub


it doesn't seem to interfere with the emailing commands at all.

edit: I saved closed and reopened the doc, but nothing changed.

Charlize
07-25-2007, 06:26 AM
???

andrewvanmar
07-25-2007, 06:32 AM
I tested the call with a worksheet change event
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Range("c5"), Target) Is Nothing Then
Call disable_menu_items
End If
End Sub
and it works but apparantly i can't have two worksheet_change events on the same sheet, it gives an ambiguous name error. (so I can't use that as a workaround)

back to the on open and before close events...

andrewvanmar
07-25-2007, 06:35 AM
?? don't get it. I reverted to a previos save and now it works.

regardless, thanks charlize!!

andrewvanmar
07-25-2007, 06:37 AM
[yuck, now it has permanently disabled the controls, back to the backend....]

no that was the residual disable from the test i did. the global oen even still doesn't take effect

Charlize
07-25-2007, 06:43 AM
Use my file. Open it and see that the send button is disabled. Close that file and just start a new file. You'll see that the send button is enabled. Meaning that for my file the send button is disabled when you open it and enabled again when you close the workbook.

andrewvanmar
07-25-2007, 07:46 AM
I copied everything and now it works. Still don't know what I did wrong....
is the option specific an integral part?

rory
07-25-2007, 07:51 AM
Just a couple of housekeeping things:
1. You can only have one of each event for the object it belongs to - so only one worksheet_change event per worksheet. You can however, have multiple routines called from that event.
2. If you are going to disable controls in the workbook_open event and re-enable in the workbook_beforeclose, you really ought to disable/enable them in the workbook's activate and deactivate events so that if the user switches to a different workbook, the controls are available.
FWIW
Rory

andrewvanmar
07-25-2007, 09:38 AM
1. yeah I figured that out the hard way, but found code somewhere else to show me how to set it up. :)

2 You're right, it would be the polite thing to do.
can I add "copies"of the current routines, with the activate and deactivate events in their first lines?