| Event PFC
Code PFCExt You add code
PBNative Public,
Name (arguments), return type
|
What is it? Arguments
Return Values |
When does it
execute? What does it do?
How should I either extend or add to
it? |

Close ( ) returns long |
Window Close Returns long:
not used |
Of course this Close event is the native PowerBuilder event that executes when
- The user exits the application and the frame is told to close, thereby
closing all open windows and sheets first
- The user double-clicking the control menu, the user clicking the X close
box
- The user selecting File/Close (which sends a message to the
pfc_close event,
which in turn issues the script Close(this)
- The user clicking a default or cancel button that eventually may do a Close( this ) or CloseWithReturn ( this, <return info> )
Note This Close event
is not executed if a HALT or HALT CLOSE is
done. That means that some services may not be properly destroyed. And while NT is better
at "cleaning up" after such things, care should be taken to avoid doing this as
it is not a good programming practice. |
In this Close event, PFC
- Stores the window size preferences and
- Destroys any existing window service objects, such as the Basic Window,
Resize and Preference service instances
|

CloseQuery ( ) returns long |
Window About to Close - Query if user wants to Save,
Close, etc. Returns long:
0 = Allow window to close
1 = Prevent window from closing |
Note 
 CloseQuery
is a KEY event in the PFC! |
And, of course this CloseQuery event is the native PowerBuilder event that executes when a window is told to close, just
before the Close event.
Heres what the PFCs CloseQuery script does:
- Checks the
ib_DisableCloseQuery flag.
If it is TRUE, the entire PFC CloseQuery logic will be bypassed. So in order to skip all of the CloseQuery script, simply set ib_DisableCloseQuery to TRUE elsewhere in your program.
- Triggers the empty
pfc_PreClose event.
If there are cases where you need to stop a window from closing,
place that code in the pfc_PreClose event. The pfc_PreClose event allows you to stop the window from closing without actually having to
override the CloseQuery
events script.
- Sets the
ib_CloseStatus flag to TRUE to indicate that a close is in progress. This is because in the
PFC, individual validation errors are suppressed if the window is closing. If the window
is not allowed to close during this event, it is automatically reset back to FALSE for
you.
So during the time that you are in the CloseQuery script, ib_CloseStatus is TRUE.
You may wish to know whether or not the window is in the process of closing in other
scripts to determine how you handle things like validation errors. Outside of this window,
you may check this flag if you need to know if the user is in the process of closing via
the windows of_GetCloseStatus(
) function.
- Checks all updateable DataWindows for changes or validation errors by
calling the
of_UpdateChecks(
) function.
- If no pending updates are found, the window is allowed to close.
- If a validation error occurs, the
user is asked if they would like to close anyway (and lose their
changes), or if they would like to cancel so that
they may correct their error (and then they may save).
- If unsaved changes are detected (and there are no validation errors), the user is asked if they would like to save their changes. If they choose to save, the
pfc_Save event is triggered. Furthermore, if
the save fails, the window is prevented from closing. If the save is successful, the
window is then allowed to close.
Note Summary of whats done in the PFC CloseQuery |
| Prior to PowerBuilder 5.0.03, there was a bug, not in the PFC, but in
PowerBuilder itself (low-level). This PB bug sometimes makes the No and
Cancel buttons on the Error Service Special Message Window (w_message) not
actually stop the window from closing. Scenario:
The user makes some changes (and does not save).
Then the user goes to close the window by using the "close box" or "control
menu" (versus menuoptions File/Close or File/Exit, or the toolbar Exit button ~ which
work!).
Next, the PFC w_message window opens, and
- The user is told that they have validation errors, and the user is asked
if they would like to close anyway. They say No, but the window closes anyway.
- The user is asked if they would like to save their changes. The user
presses Cancel, but the window closes anyway.
Users find this particularly annoying because the window just closes and
they lose their changes. And actually, they were trying to stop the window from closing so
that they may correct their input and then save.
The problem surfaces because the Error Service uses the PowerBuilder OpenWithParm( ) function, passing a PowerObject type parameter, in order to
open the w_message window.
And the bug in PB centers around that scenario. Somehow when PB does that, it interferes
with the CloseQuery events return code - even though the Return <rc> happens
much later. Go figure. I am pointing this out because there are other implications where
the OpenWithParm( ) may
interfere with other events return codes as well.
Note that the problem is fixed in PowerBuilder 5.0.03, as opposed
to PFC 5.0.03.
If you are not yet at PowerBuilder 5.0.03, and you are using the
Error Service PFC Message Window style, here are some temporary workarounds
- Users like the Error Services PFC Message Window, so the preferred
temporary workaround is to change the Error Service to not use OpenWithParm( ), but simply Open( ) instead (See code below under A
- D)
- One workaround is to use the Error Services Standard MessageBox
style, rather than the PFC Message Window style. But this does not allow the user to
add their comments and/or print error messages.
- Another workaround is to not use the Error Service at all. But this does
not give you any of the advantages of error logging and reporting.
- Oddly enough, this problem only happens when the user closes the window
by using the "close box" or "control menu" (versus menuoptions
File/Close or File/Exit, or the toolbar Exit button). So one "workaround"
(although lame) is to suggest that your users use the File/Close menuoption for a while -
Or ask your users to please make it a practice to always save first before closing
windows.
|
- Add comments to each object that you change (as
appropriate):
//////////////////////////////////////////////////////////////////////////////
//
// NOTE: Temporary fix until PowerBuilder 5.0.03
// NOTE: Ancestor is overridden!!
//
//////////////////////////////////////////////////////////////////////////////
- Add an instance variable to your Application Manager:
n_cst_errorattrib inv_errorpass
- Override & Copy n_cst_error's of_processmessage()
function to make this one small change to the existing code:
li_testrc = OpenWithParm(w_message,
inv_errorpass)
gnv_app.inv_errorpass =
this.inv_errorpass
li_testrc = Open(w_message)
- Override & Copy the ancestor script in
w_messages pfc_PreOpen event to make this one small change to the existing code:
//Get the PowerObjectParm.
inv_errorattrib = Message.powerobjectparm
//Populate
inv_errorattrib from gnv_app.inv_errorpass
this.inv_errorattrib = gnv_app.inv_errorpass
|
Note By the way, the Powersoft PFC newsgroup (news://forums.powersoft.com/powersoft.public.powerbuilder.pfc ) plus the pfcsig & pfc-users mail lists are invaluable resources for PFC
information sharing
such as finding out about these kinds of workarounds as problems
are found. Read all about them at the PFC Cheat Sheet (http://www.pfccheatsheet.com/). |
|

Move ( integer xpos, integer ypos ) returns long |
Window has moved - Store the window position and size Returns long:
not used |
This event is actually a PFC user-defined event which is
simply mapped to the native Windows pbm_move event. Since it is not strictly
a user-defined PFC event, it is not prefaced with pfc_. This event
executes when the user moves a window.
This Move
event will post an event to the Preference service to take note of the
windows current position and size if it is in its Normal state. This is so that the
service will know the normal size of the window (which should be saved when the window
closes) even when the window is closed as maximized/minimized. |

Open ( ) returns long |
Window is Opening Very first event
of window to execute by PowerBuilder
Triggers pfc_PreOpen at very top, so
note that pfc_PreOpen actually executes before PFCs script in this Open event
Window does not show until Open event completes (so as little as
possible should be done here)
Returns long:
not used |
Of course, this is the native PowerBuilder event that executes whenever
a window is opened.In this Open event, the PFC
- First thing, triggers the
pfc_PreOpen empty event - to execute any
script that needs to happen very first, such as turning on the Window Resize and
Preference services.
- Posts the
pfc_PostOpen empty event so that it will execute after this Open event completes
- Restores the window preference settings if the Window Preference service
is turned on. This is why it is important to turn on your Window Preference and Resize
service in the
pfc_PreOpen event if desired. Because first of all, this event needs to know if the
Preference service is turned on, and secondly, when the Preference service resizes your
window, you want your Resize service to kick in and resize and reposition any controls on
the window as well.
Note Summary of whats done in the PFCs Open |
- Triggers
pfc_PreOpen
(put your Preference and Resize initialization in this
event)
- Posts
pfc_PostOpen
(save anything that can wait until here so window
appears faster when opened. Put your database retrievals here)
- // If no window title, sets it to the Applications
title
- // Check User Preferences, and resizes/moves window/menu as
appropriate
|
Note It is best to add application-specific code to either the pfc_PreOpen or the pfc_PostOpen
event, rather than overriding or extending this actual Open event. And of course, if it can wait until the pfc_PostOpen event, that
is best so that the windows Open event completes quickly, allowing the window to appear to open just as quickly as
possible. |
|
 pfc_AcceptText
( powerobject apo_control [ ], boolean ab_focusonerror ) returns integer |
Perform AcceptTexts on all DataWindows on current
window Argument
apo_control [ ]:
an array of powerobjects containing the control array for the current window when PFC
triggers this event from of_UpdateChecks( )
Note: For optional uses, you may pass an array of
any objects which you would like to have this event perform AcceptTexts on any DWs
within those objects
Argument ab_focusonerror:
boolean to specify whether or not to set focus on a DataWindow column with errors
Returns integer:
1 = Success
-1 = Error |
This event is triggered by of_UpdateChecks( ) from the  CloseQuery or the pfc_save event.It issues a DataWindow AcceptText( ) function to
all DataWindow's on the current window.
Note: This event includes support for the Linkage Service
and for non-PFC DataWindows as well.
Note: This event features recursive
processing for tab controls and user objects. In other words, this event calls itself in
order to drill down through tab controls, tab pages and user objects, looking for
DataWindows within them.
Note:
This script can be "extended" to check for other objects (besides DataWindows)
as well. I say "extended" because
Note
If you do have a need to "extend" the script for this
event, you should first check the ancestors return code. And to do so (at least
pre-PB 6.0), you must override the ancestor script. You must check the ancestors
return code because there is already script in the PFCs ancestor code, and it may
fail.
Note:
In the PFC 6.0 Release, rather than
having to extend this event to recognize such controls as the ListView and TreeView,
you may take advantage of the new Self-Updating Object (SUO) architecture. To do so, you
may either switch to using the new SUO objects. Or you may add the SUO API to your current
objects. For more details, please see the section at the end of this appendix which covers
the PFC 6.0 Release.
| Prior to PFC 5.0.02, there was a bug in this event. The problem was
that AcceptText()s
were being performed on DataWindows in Tab pages which were not yet created. Here is the
code that needs to be fixed as shown: |
Case Else
// This is a NonLink PFC DW or a Non PFC DataWindow
// Perform AcceptText, check rc
la_rc = ldw_dw.AcceptText()
If la_rc < 0 Then
If ab_FocusOnError Then ldw_dw.SetFocus()
Return -1
End If
// 5.0.02 Do not perform AcceptText on Datawidows found on uncreated tab pages.
Case Else
// This is a NonLink PFC DW or a Non PFC DataWindow
// Do not perform AcceptText on Datawidows found on uncreated
// tab pages.
If ldw_dw.RowCount() + ldw_dw.FilteredCount() + &
ldw_dw.ModifiedCount() + ldw_dw.DeletedCount() > 0 Then
// Perform AcceptText, check rc
la_rc = ldw_dw.AcceptText()
If la_rc < 0 Then
If ab_FocusOnError Then ldw_dw.SetFocus()
Return -1
End If
End If
* Datawidows= PFC code Easter egg
found by Judy Cote <s> |
| Rather than overriding the ancestor and copying the code to make the
change
In this case, you could change the PFC code directly since it
is a known problem with a known, existing, official fix in a particular
version. This is not a bad idea in these kinds of cases. There are very few cases like
this where it is kosher to change the PFC directly. But, still, dont forget to
document it! |
|
 pfc_BeginTran
( ) returns integer |
Begin a Transaction Returns integer:
1 = Success
-1 = Error |
Note 
pfc_BeginTran is a
KEY event in the PFC! |
Note The pfc_BeginTrans& pfc_EndTrans events control your database transactions. Therefore, they are the KEY to the success of your
client/server application! |
PFC triggers this event from the
pfc_Save event in order to begin a
transaction.
Note:
You should add code here to begin a transaction.
Note The way that you will approach this depends
on the database which you are using, and how your company wishes to handle their
transactions. Consult your DataBase Administrator for details. This is very important.
Note Be careful to make sure that if code is in this event, that the corresponding
code is also in the matching pfc_EndTran
event. In all truth, code should be required in both of them. |
Ex: In your pfc_BeginTran event for your
particular window:// Begin a transaction
if SQLCA.of_begin( ) <> 0 then
SQLCA.of_DisplayError( "pfc_begintran event after" + "~r~n" + &
"of_begin in" + "~r~n" + &
"window titled ~r~n'" + this.Title + "'~r~n"+ &
"(WindowObject is " + this.ClassName() + &
")" )
Return -1 //error
end if
Return 1 //success
|
|
 pfc_Close
( ) |
Close a PFC Window |
The PFC menu calls this event whenever the File/Close
menu option is selected. Closes the window. The PFC script simply
contains Close(this).
Post or trigger this event in order to close a window. |
 pfc_ControlGotFocus
( dragobject adrg_control ) |
A Control just Got Focus Keeps
track of last active DataWindow
Argument adrg_control:
control (of type dragobject) which just got focus |
PFC triggers this event whenever any PFC visual control
gets focus. This event keeps track of the current control.
Specifically it keeps track of the last active DataWindow. (Needed by
several things, including the "Message Router"). If the control getting focus is
a DataWindow inherited from u_dw, this event sets the idw_Active instance variable.
If you have some special need, you could use this event to add
application-specific functionality to be performed when a visual control gets focus. |
 pfc_DBError ( ) returns integer 5.0.02
|
Display any stored DBError message Returns integer:
1 = Success
-1 = Error |
PFC triggers this event from the pfc_Save event in order
to display any saved DBError message. This event is only
triggered if there was an error, and it does so only after the transaction has ended
(after pfc_EndTran). |
 pfc_Descendant
( ) returns boolean |
Is this Window a PFC Descendant? Returns boolean:
TRUE = Window is a descendant of w_master
FALSE = Window is not a descendant of w_master |
PFC events and functions call this event to determine if
the window is inherited from w_master. This event simply has the script to Return True
Heres an
interesting, indepth look into this odd little trick here, compliments of Jon Credit
Whenever the PFC code uses this event, the PFC code does a TriggerEvent(
) as follows:
If adrg_control.TriggerEvent
("pfc_descendant") = 1 Then
The TriggerEvent( ) function will return either a 1 or -1
1 if the event exists AND has code in it;
-1 if the event does not exist OR the event exists but does not have any code.
So the PFC guys and gal had to put something in the event in order for TriggerEvent
to return 1. Interesting tidbit there for you.
Internal use only (so usually you would not need to call this) |
 pfc_EndTran
( integer ai_update_results ) returns integer |
End a Transaction Argument ai_update_results:
integer that contains the results of the last update
1 = Success
-1 = Error
NULL= Some argument NULL
Returns integer:
1 = Success
-1 = Error |
Note 
pfc_EndTran is a
KEY event in the PFC! |
Note The pfc_BeginTrans& pfc_EndTrans events control your database transactions. Therefore, they are the KEY to the success of your
client/server application! |
PFC triggers this event from the pfc_Save event in order to
end a transaction.
Note:
You should add code here to end a transaction.
Note The way that you will approach this depends
on the database which you are using, and how your company wishes to handle their
transactions. Consult your DataBase Administrator for details. This is very important.
Note: You would normally call n_trs of_end(
) function here, and then encapsulate of_commit( ) and of_rollback( ) calls within n_tr itself.
Note: The ai_update_results argument will indicate the success (when = 1) or failure of the previous Update
functions. You will need to pass this to your of_end(
) function so that it knows whether or not to ROLLBACK or COMMIT.
Note Be careful to make sure that if code is in this event, that the corresponding
code is also in the matching pfc_BeginTran
event. In all truth, code should be required in both of them. |
Ex: In your pfc_EndTran event for your
particular window:// End the transaction
if SQLCA.of_end( ai_update_results ) <> 0 then
SQLCA.of_DisplayError( "pfc_endtran event after" + "~r~n" + &
"of_end in" + "~r~n" + &
"window titled ~r~n'" + this.Title + "'~r~n"+ &
"(WindowObject is " + this.ClassName() + &
")" )
Return -1 //error
end if
Return 1 //success
|
|
 pfc_Help
( ) returns integer |
Show Help Returns integer:
1 = Success
-1 = Error |
The PFC menu calls this event whenever the Help/Help
Topics menu option is selected. You can also trigger it
directly (from a Help CommandButton, for example).
It calls the ShowHelp function by index, topic or keyword, based on the ia_HelpTypeID
instance variable.
Note: To specify the application's Help filename, call the
n_cst_AppManagers of_SetHelpfile( ) function. |
 pfc_MessageRouter
( string as_message ) returns integer |
Message Router Key Event Route a
message to the current window, current active control, or to the last active DataWindow
control
last resort to frame if MDI
Argument as_message:
string of event name to route
Returns integer:
1 = Success
0 = No objects contain the user event
-1 = Error |
Note 
pfc_MessageRouter is
a KEY event in the PFC! |
Note This event is known as the "Message Router" event. Its purpose
is to "route" the message passed in argument as_message to the appropriate object. |
PFC triggers this event most anytime that a menu option is
selected. At that time, the menu uses its of_SendMessage(
) function to trigger this event to communicate to windows.
Message = User Event
The "Message" that
the menu passes is actually the passed as_message argument containing a user event name that needs to be triggered on the window
or one of its controls.
Route = Trigger Event
By "Routing", we
mean that the menu needs to tell some window or window control to do something. So the
menu tries to trigger the given event on various window/window controls until some control
understands the message.
There is a particular defined order of objects to which the Message
Router attempts to send a message
First, it will attempt to trigger the event on the current window.
If not found there, then on the current control.
If not found there, then on the last active DataWindow control.
Finally, if still not found (and if this is an MDI frame), the event is triggered on the
frame.
Note "Message Router" tries to trigger the given event on these objects,
in this order
|
è
Current Window
è Current Active Control
è Last Active DataWindow
è MDI Frame
|
| until it finds an object that can process the message |
Note: All PFC visual controls, including the windows
and the u_dw, include
events that work with the Message Router.
Note: Although this window event usually bridges a menu
and a window/its controls, it could also be used to communicate between a window/its
control and any other kind of object. |
 pfc_MicroHelp
( string as_microhelp ) |
Display MicroHelp Argument as_microhelp:
string for MicroHelp text to display |
This event is called by u_dws
ItemFocusChanged( ) event. It
is extended in pfc_w_sheet
and pfc_w_frame to simply
display the string in as_microhelp
in the MicroHelp area of the frame.
Pfc_w_sheet simply routes to pfc_w_frame, which in turn simply
displays the MicroHelp text if the AppManagers Display MicroHelp attribute is TRUE. |
 pfc_New
( ) |
Add New Entity to Window (For
example File/New menu selected, so you would Add a New Employee by inserting a blank row
to be entered by user) |
The PFC menu calls this event whenever the File/New
menu option is selected. Note: If needed,
you should add code here to perform processing to add a new entity to the current window,
window control, or DataWindow.
Ex: In your pfc_New event for your
particular window:// Add a New Employee
dw_Employee.InsertRow(0)
or // Add a New Row to the Active DW
idw_Active.InsertRow(0)
|
|
 pfc_Open
( ) |
Open sheets from the frame Or open
a file from this Window
Open another Window from this Window
(For example File/Open from a selection list window
of all Employees, so you would maybe open a detail window for that selected Employee) |
Note 
pfc_Open is a KEY
event in the PFC! |
The PFC menu calls this event whenever the File/Open menu
option is selected.
Note This pfc_Open event is in a different category from the Open, pfc_PreOpen and pfc_PostOpen events
This pfc_Open event opens another
window from the current window. Whereas the other events are involved with the opening
of this current window. They are easy to get mixed up sometimes, so make a mental
note of the distinction. |
Note:
You will need to add code here to open your sheets from your frame.
Note:
If needed, you should add code
here to open another window or a file from the current window.
Open Another Window - Ex: In your
pfc_Open event for your particular selection window:SetPointer(Hourglass!)
long ll_row
string ls_student_id
ll_row = dw_student.GetRow()
if ll_row < 1 then
messagebox("Student Selection Error", "No student selected")
else
ls_student_id = dw_student.object.state_stu_id[ll_row]
message.inv_open_window.is_window_stringparm[1] = ls_student_id
message.inv_open_window.is_window_name = "w_stu_pmz210_maint_id_demo"
gnv_app.of_GetFrame().Event pfc_open()
end if
|
Open A File - PS** Ex: In your pfc_Open
event for your particular window:// Display Open dialog box when the user selects File/Open menu option
// Is_fullname and is_filename are instance variables:
Integer li_fileid
SetPointer (HourGlass!)
IF GetFileOpenName("Open", is_fullname, is_filename &
"txt", "Text Files (*.txt),*.txt) < 1 THEN
Return
END IF
// Open the new file and put results into the MLE
li_fileid = FileOpen(is_fullname, StreamMode!)
FileRead (li_fileid, mle_notepad.text)
FileClose (li_fileid)
|
| ** from hereonè "PS Ex:" denotes
an example from the Powersoft Manual |
|
 pfc_PageSetup
( ) returns integer |
Display a Page Setup Dialog Box Returns integer:
1 = Success
-1 = Error |
The PFC menu calls this event whenever the File/Page
Setup menu option is selected. Note: If needed, you should add code here to display the Page
Setup dialog box for a particular DataWindow. If there are multiple DataWindows to be
printed, you may also want to then sync their print properties accordingly.
Note The PFC has a couple of "PFC DLLs" that it accesses for print-related
external function calls [via pfc_n_cst_platformwin##
(16/32)]. For example, u_dws pfc_PageSetupDlg event needs these DLLs to open the
print dialog window. So make sure that you include these DLLs when deploying. These PFC
DLLs are PFCCOMM.DLL (16-bit) and PFCCOM32.DLL (32-bit). By the way, the
other PFC DLL to be aware of is PFCFLSRV.DLL, and it is used for file services [via pfc_n_cst_filesrvwin##].
Ex: In your pfc_PageSetup for your
particular window:Integer li_rc
s_pagesetupattrib lstr_pagesetup
// Open the Page Setup Dialog Box for the first DataWindow
li_rc = dw_1.event pfc_PageSetupDlg(lstr_pagesetup)
// Sync the paper source for the other two DataWindows
IF li_rc = 1 THEN
dw_2.object.datawindow.print.paper.source = &
lstr_pagesetup.i_papersource
dw_3.object.datawindow.print.paper.source = &
lstr_pagesetup.i_papersource
RETURN 1 //Success
ELSE
RETURN -1 //Error
END IF
|
|
 pfc_PostOpen
( ) |
Post-Open Processing |
Note 
pfc_PostOpen is a
KEY event in the PFC! |
PFC posts this event at the top of the windows
Open event, right after it
triggers the pfc_PreOpen event.
This event is posted, not triggered. Therefore, it is simply
queued, and will execute whenever it gets a chance. It would normally end up executing
just after a window opens (and displays). This is the classic use of a posted event in
PowerBuilder.
Note I was surprised to find that this event was not
posted at the end of the PFCs Open code. This is because if any process in the windows Open event allows a queued event to slip in
(such as a MessageBox or something), this event would execute "prematurely". So
just be aware.
- If for some reason you end up overriding the Open event, avoid anything
that could allow a posted event to execute (a MessageBox being a common culprit of this)
- In some cases, this event could end up executing before the window
actually opens and displays. This is because, in fact, if you are in PFC debug mode, there
are some MessageBoxes that may display in the PFC Open
event if PFC encounters an error.
|
Add code
here which you would like to execute just after a window opens. Processes which need to be
done when the window opens, but not necessarily right away are best placed here, rather
than in the pfc_PreOpen event, which holds up the display of the window to the user. Remember, perceived
quick response time is very important when dealing with human users who need to be kept
happy <s>
So save any of your:
- of_SetTransObject( )s (if
no tabs involved)
- database retrievals or
- long-running processes
for this event.
PS-modified Ex: In your
pfc_PostOpen event for your particular window:Long ll_return
dw_employee.of_SetTransObject(SQLCA)
ll_return = dw_employee.Retrieve( )
IF ll_return = -1 THEN
MessageBox("Retrieve", "Retrieval error")
ELSE
gnv_app.of_get_frame( ).SetMicroHelp( String(ll_return) + " rows retrieved")
END IF
|
|
 pfc_PostUpdate
( powerobject apo_control [ ] ) returns integer |
Post-Update Processing Reset
update flags on all DataWindows
Argument apo_control [ ]:
an array of powerobjects containing a control array for the current window which within
PFCs code usually holds all of the DataWindows which have pending updates
Note: For optional uses, you may pass an array of
any objects which you would like to have this event perform Post-update processing upon
Returns integer:
1 = Success
-1 = Error |
PFC triggers this event at the very bottom of the pfc_Save event if
all of the previous save process was successful. The logic in this event executes outside
of any database transaction.The PFC code that is already in this
even will reset all of the DataWindow update flags since all of the database updates were
successful and the DataWindows need to know that.
Note:
This script can be "extended" to check for other objects (besides DataWindows),
such as ListViews or TreeViews as well. I say "extended" because
Note
If you do have a need to "extend" the script for this
event, you should first check the ancestors return code. And to do so (at least
pre-PB 6.0), you must override the ancestor script. You must check the ancestors
return code because there is already script in the PFCs ancestor code, and it may
fail.
Note:
In the PFC 6.0 Release, rather than
having to extend this event to recognize such controls as the ListView and TreeView,
you may take advantage of the new Self-Updating Object (SUO) architecture. To do so, you
may either switch to using the new SUO objects. Or you may add the SUO API to your current
objects. For more details, please see the section at the end of this appendix which covers
the PFC 6.0 Release.
Note:
You can also extend this event to perform additional updates that do not need to be done
within the database transaction.
PS Ex: In your pfc_PostUpdate for
your particular window to add functionality to reset the update flags for the ListView:Integer li_return
Integer li_max, li_i
powerobject lpo_changed
u_lv llv_changed
// apo_control is an argument to pfc_PostUpdate.
// It contains the ipo_pendingupdates array.
li_max = UpperBound(apo_control)
FOR li_i = 1 to li_max
lpo_changed = apo_control(li_i)
IF lpo_changed.TypeOf () = Listview! THEN
llv_changed = ipo_changed
li_return = llv_changed.of_ResetUpdate()
IF li_return = -1 THEN
Return -1
END IF
llv_changed.ib_changed = FALSE
END IF
NEXT
Return 1
|
|
 pfc_PreClose
( ) returns integer |
Pre-Close Processing Returns integer:
1 = Success
-1 = Prevent window from closing |
PFC triggers this event from the top of the  CloseQuery event in order to give you a chance to do anything that you may need to do just
before the CloseQuery processing begins since the window will be closing, but there is
still a chance to stop if from doing so. Note: If needed, you should add code here that needs to be done
before the CloseQuery processing begins.
PS Ex: In your pfc_PreClose for
your particular window:// Write message to a log file to report that the window is closing
IF inv_filesrv.of_FileWrite (is_logfile, "Window: " + this.title &
+ " closing at " + String(Today()) &
+ String(Now()),TRUE) = 1 THEN
Return 1 //Success
ELSE
Return -1 //Prevent window from closing
END IF
|
|
 pfc_PreOpen
( ) |
Pre-Open Processing |
Note 
pfc_PreOpen is a
KEY event in the PFC! |
PFC triggers this event first thing at the top of the  Open event.
Note Remember that since this event is triggered at
the top of the Open event,
when this code executes, the window has not yet opened so it has not yet been displayed to
the user.Also, it is not good practice to put anything in here
that would try to close the window, because the window is not yet open. Save anything like
that for the pfc_PostOpen event.
Also save any database retrievals or long-running processes for the pfc_PostOpen
event as well. |
Note:
Add code here which you need to execute prior to the PFCs Open event or anything that cannot wait until
the pfc_PostOpen event. Common things to add here are:
Examples: In pfc_PreOpen event for
whichever level of your window that you deem appropriate (perhaps w_sheet level, perhaps
application window level, etc) :// Turn on the Window Resize Service
this.of_SetResize (TRUE)
this.inv_Resize.of_register (dw_1,"ScaletoRight&Bottom")
// Turn on the Window Preference Service
this.of_SetPreference (TRUE)
this.inv_preference.of_SetToolBars (TRUE)
this.inv_preference.of_SetWindow (TRUE)
// Turn on the Basic Window Service
// (in your w_response to center all response windows for example)
this.of_SetBase(TRUE)
this.inv_Base.of_Center()
// Register this window with the Security Service
IF IsValid (gnv_app.inv_security) THEN
gnv_app.inv_security.of_SetSecurity(this)
END IF
// Set your Help Type ID
ia_HelpTypeID = "Part#"
// To protect the user from being able to
// save data on "read only" windows,
// by responding "Yes" to a message that says
// that the data has changed would you like to save?
m_xxx_master lm_menu
lm_menu = this.menuid
IF lm_menu.m_file.m_save.Enabled THEN
ib_DisableCloseQuery =FALSE
ELSE
ib_DisableCloseQuery =TRUE
END IF
|
|
 pfc_PreUpdate
( ) returns integer |
Pre-Update Processing Returns integer:
1 = Success
-1 = Error, terminate save processing |
PFC triggers this event from the pfc_Save event after it
has been determined that there are changes and there are no validation errors, but before
the database transaction is actually started. Note: If needed, you should add code here to perform Pre-Update
processing that is needed before the updates take place, but does not need to be in the
actual database transaction. One great example (contributed by Bob Fields), is the case
where you would generate new primary keys for inserts, which must be outside of the
normal save transaction.
Note:
If you do add code with database updates in here, please realize that if you are running
with AUTOCOMMIT=FALSE, you
should be sure to include a COMMIT after any updates that you perform in here. Otherwise, the updates you do in
here will be included with the database transaction. This would defeat the purpose of
including those updates in here, versus simply extending the pfc_Update event.
PS Ex: In your pfc_PreUpdate for
your particular window:// Check for any unauthorized User IDs
String ls_user
ls_user = gnv_app.of_GetUserID( )
IF ls_user = "UnauthorizedPerson" THEN
Return -1 //Do not proceed with update - Terminate save
ELSE
Return 1 //Okay to proceed with update
END IF
|
|
 pfc_Print
( ) returns integer |
Print Window - first showing Print Dialog Box (or Print
content of one or more DataWindows on Window) Returns integer:
User defined, suggested:
1 = Success
-1 = Error |
The PFC menu calls this event whenever the File/Print
menu option is selected.
Note: The only difference between this event
and the pfc_PrintImmediate event is that this event should first open the print dialog box. |
Note:
If needed, you should add code
here to print windows or DataWindows, first displaying the Print dialog box.
Note:
If you leave this event (which pertains to the whole window) empty, the Message Router
will attempt to send the pfc_print message to the "last active DataWindow". And
then that DataWindow will print. So it is not necessary to add code here if that is all
that you would like for this event to do, especially if you only have one DataWindow on
your window
However, please note that if for some reason, there was no "last
active DataWindow", nothing will happen. Also, if you leave this event empty and
there are multiple DataWindows on the current window, you should point out to the user the
expected behavior (of how the "last active DataWindow" will print), as it is not
obvious to them. That way, they will know to click on the desired DataWindow before
printing.
Note:
In this event you might choose to:
- Leave the script emtpy and allow the "last active DataWindow"
to print
- Print multiple DataWindows
- Force only a particular DataWindow to always print
- Call the DataWindow Report Service's of_CreateComposite(
) function to create a composite report of all the window's
DataWindows
Note The PFC has a couple of "PFC DLLs" that it accesses for print-related
external function calls [via pfc_n_cst_platformwin##
(16/32)]. For example, u_dws pfc_PageSetupDlg event needs these DLLs to open the
print dialog window. So make sure that you include these DLLs when deploying. These PFC
DLLs are PFCCOMM.DLL (16-bit) and PFCCOM32.DLL (32-bit). By the way, the
other PFC DLL to be aware of is PFCFLSRV.DLL, and it is used for file services [via pfc_n_cst_filesrvwin##].
Ex: In your pfc_Print for your
particular window:// Force only the student DataWindow to print
Integer li_rc
s_pagesetupattrib lstr_pagesetup
// Open the Print Dialog Box
li_rc = dw_student.event pfc_PageSetupDlg(lstr_pagesetup)
IF li_rc = 1 THEN
// Print the Student DataWindow Only
IF dw_student.Print( ) = 1 THEN
RETURN 1 //Success
ELSE
RETURN -1 //Error
END IF
ELSE
RETURN -1 //Error
END IF
|
|
 pfc_PrintImmediate
( ) returns integer |
Print Information Immediately (without displaying Print
Dialog Box first) Returns integer:
User defined, suggested:
1 = Success
-1 = Error |
The PFC menu calls this event whenever the
"File/Print Immediate..." menu option is selected.
Note: The difference between this event and
the pfc_Print
event is that this event should not first open the print dialog box. It should just print
the report immediately. |
Note:
If needed, you should add code
here to print windows or DataWindows, without first displaying the Print
dialog box.
Note:
Please see extra notes in the pfc_Print
event directly above, since these two events are so similar.
Ex: In your pfc_PrintImmediate for
your particular window:// Print the Employee DataWindow
IF dw_employee.Event pfc_PrintImmediate( ) <> 1 THEN
RETURN -1
END IF
// Print the Employees Pay DataWindow
IF dw_employee_pay.Event pfc_PrintImmediate( ) <> 1 THEN
RETURN -1
END IF
RETURN 1
|
|
 pfc_Save
( ) returns integer |
Save any Pending Changes Returns integer:
1 = Success
0 = No pending changes
-1 = AcceptText error
-2 = UpdatesPending error
-3 = Validation error
-4 = Failed pfc_PreUpdate
-5 = Failed pfc_BeginTran
-6 = Failed pfc_Update
-7 = Failed pfc_EndTran
-8 = Failed pfc_PostUpdate
-9 = Failed pfc_DBError |
Note 
pfc_Save is a KEY event in the PFC! |
Note Please note that there has been a major overhaul of the Save Process of
the PFC 6.0 Release. |
The PFC menu calls this event whenever the File/Save menu
option is selected.
And the PFC  CloseQuery event calls this user event
automatically after finding pending updates and verifying that the user would like to save
before closing.
Note: You can call it from your application to save
changes, as needed also.
This pfc_Save event saves all changes for all DataWindows (plus any added controls) in the
window. It calls:
- Only If NOT
ib_CloseStatus
(since if it is closing this function has already been
called)
of_UpdateChecks( ) (exits save on error or if no updates to
do)
which in turn calls these three events
pfc_AcceptText
to do an AcceptText on all DataWindows.
If no AcceptText errors
pfc_UpdatesPending
to look for any DataWindows with pending changes
Builds an array of all of
the DataWindows which do in ipo_PendingUpdates[ ]
pfc_Validation
to check for any Validation errors in any of the DataWindows with pending updates
- (Continues if updates pending and no validation errors)
pfc_PreUpdate (exits save on error)
to perform anything special needed before updating
transaction begins
Starting DB Transaction
pfc_BeginTran (exits save on error)
|
- Set
ib_SaveStatus = TRUE (suppress
error msgs)
pfc_Update
which updates all DataWindows in ipo_PendingUpdates[ ]
- Set
ib_SaveStatus = FALSE
|
pfc_EndTran (always executes even
if error on pfc_Update)
Ended DB Transaction |
pfc_DBError (if error during
pfc_PreUpdate)
which displays any DBErrors from pfc_Update
pfc_PostUpdate (if no errors
throughout)
which resets all update flags on all DataWindows in ipo_PendingUpdates[
] if all updates completed successful
Note: Basically, if any of the events encounter errors,
the save process is aborted and the corresponding error return code is returned. There are
exceptions to this. For example, if pfc_Update were not successful, the
transaction still needs to be ended and a DBError message still needs to display.
Therefore, first pfc_EndTran and pfc_DBError are executed, and then it bails out. |
 pfc_SaveAs
( ) |
SaveAs all or part of a window, usually using the SaveAs
Dialog Box to choose a name of the file to be saved |
The PFC menu calls this event whenever the File/Save As
menu option is selected.
Note: The difference between this event and
the pfc_Save event is that this event usually saves data to a File rather than to the
database. |
Note:
If needed, you should add code
here to save all or part of a window (usually as a File format versus updating the
DataWindow).
Ex: In your pfc_SaveAs for your
particular window:IF IsValid (idw_active) THEN
idw_active.SaveAs()
END IF
|
PS Ex: In your pfc_SaveAs for your
particular window:// Display the Save As dialog box
String is_docname, is_named
Integer li_value
li_value = GetFileSaveName( "Save As", &
is_docname, is_named, "TXT", &
"Text Files (*.TXT),*.TXT," + &
" Doc Files (*.DOC), *.DOC")
|
|
 pfc_Update
( powerobject apo_control [ ] ) returns integer |
Update all DataWindows Argument apo_control [ ]:
an array of powerobjects containing a control array for the current window which within
PFC code usually holds all of the DataWindows which have pending updates
Note: For optional uses, you may pass an array of
any objects which you would like to have this event perform update processing upon
Returns integer:
1 = Success
-1 = Error |
PFC triggers this event in the middle of the pfc_Save event.This event actually updates all of the DataWindows with modified, updateable
DataWindows.
- Linkage service
Calls the n_cst_dwsrv_linkage of_Update( ) function
- All other PFC DataWindows
Calls the datawindows pfc_Update event
- Non-PFC DataWindows
Calls the PowerScript Update( ) function
Note For the duration of this event, the ib_SaveStatus flag
is turned on, and no messages or other modal windows should be displayed. This is because
we are in the middle of a database transaction, and we want to finish just as quickly as
possible - to avoid causing locks. So if any DataWindows DBError event should fire due to a database
error, the PFC will store the error message into is_DBErrorMsg for later display, after the
transaction has ended (after pfc_EndTrans). |
Note:
This script can be "extended" to check for other objects (besides DataWindows),
such as ListViews or TreeViews as well. I say "extended" because
Note
If you do have a need to "extend" the script for this
event, you should first check the ancestors return code. And to do so (at least
pre-PB 6.0), you must override the ancestor script. You must check the ancestors
return code because there is already script in the PFCs ancestor code, and it may
fail. Please see the sample below for how to do this.
Note:
In the PFC 6.0 Release, rather than
having to extend this event to recognize such controls as the ListView and TreeView,
you may take advantage of the new Self-Updating Object (SUO) architecture. To do so, you
may either switch to using the new SUO objects. Or you may add the SUO API to your current
objects. For more details, please see the section at the end of this appendix which covers
the PFC 6.0 Release.
Ex: In your pfc_Update event for
your particular window://////////////////////////////////////////////////////////////////////////////
//
// NOTE: Ancestor is overridden!!
//
//////////////////////////////////////////////////////////////////////////////
// Override ancestors code
// (so that we may check the ancestors return code)
// Check ancestors return code
// Note that with PowerBuilder 6.0 you can do this easier
// This is done so that if the PFCs ancestor already had a failure,
// we want do not want to continue with our updates
// and then possibly return a misleading return code
// that says that our update was successful
li_rc = Super::EVENT pfc_update()
IF li_rc <> 1 THEN return li_rc
|
|
 pfc_UpdatesPending
( powerobject apo_control [ ] ) returns integer |
Check if Updates are Pending (i.e.
Check if Changes were made that were not yet saved)
Populate the ipo_PendingUpdates[
] array
Argument apo_control [ ]:
an array of powerobjects containing the control array for the current window when PFC
triggers this event from of_UpdateChecks( )
This array is "read in", and
the ipo_PendingUpdates[ ] array is then "written out"
Note: For optional uses, you may pass an array of
any objects which you would like to have this event populate the ipo_PendingUpdates[
] array
Returns integer:
1 = Pending updates found
0 = No pending updates
-1 = AcceptText failed
-2 = Other validation failed
-3 = Validation error |
This event is triggered by of_UpdateChecks( ) from the  CloseQuery or the pfc_save event.It searches for DataWindows which have pending
changes (unsaved data), and it builds an array of all of the DataWindows found which
therefore need to be updated. These DataWindow objects are then stored in the ipo_PendingUpdates[ ] array.
In other words, it looks thru all of the DataWindows found in its
arguments control array apo_control [ ], and then it populates the instance variable ipo_PendingUpdates[ ] array with those that
have unsaved data.
When  CloseQuery calls this user event,
validation messages are suppressed.
Note: This event includes support for the Linkage Service
and for non-PFC DataWindows as well.
Note: This event features recursive
processing for tab controls and user objects. In other words, this event calls itself in
order to drill down through tab controls, tab pages and user objects, looking for
DataWindows within them.
Note: A tip from Bob Fields
In order to improve
performance, you may wish to populate the ipo_PendingUpdates[ ] array directly with all
updateable DataWindows, rather than having this function call itself recursively.
Note:
This script can be "extended" to check for other objects (besides DataWindows)
as well. I say "extended" because
Note
If you do have a need to "extend" the script for this
event, you should first check the ancestors return code. And to do so (at least
pre-PB 6.0), you must override the ancestor script. You must check the ancestors
return code because there is already script in the PFCs ancestor code, and it may
fail.
Note:
In the PFC 6.0 Release, rather than
having to extend this event to recognize such controls as the ListView and TreeView,
you may take advantage of the new Self-Updating Object (SUO) architecture. To do so, you
may either switch to using the new SUO objects. Or you may add the SUO API to your current
objects. For more details, please see the section at the end of this appendix which covers
the PFC 6.0 Release
Bug Alert! - Pre-PFC 5.0.03 - Tech Support Bug #: 40210 |
| Prior to PFC 5.0.03, there was a bug in this event. The
problem was that pfc_UpdatesPending gets triggered recursively and li_max doesn't get reset. So if you have nested
objects, then your update array may not be properly loaded, and not all of your objects
would get updated properly. Here is the code that needs to be fixed as shown: |
If lb_updatespending Then
li_max ++
ipo_pendingupdates[li_max] = ldw_dw
End If
// 5.0.03 Corrected variable information which allowed the new upperbound for
// ipo_pendingupdates to be off due to the recursive nature of the event.
If lb_updatespending Then
// Get the new upperbound for the pending changes.
li_newupper = UpperBound (ipo_pendingupdates) + 1
// Store the control with updates pending.
ipo_pendingupdates[li_newupper] = ldw_dw
End If
|
| Rather than overriding the ancestor and copying the code to make the
change
In this case, you could change the PFC code directly since it
is a known problem with a known, existing, official fix in a particular
version. This is not a bad idea in these kinds of cases. There are very few cases like
this where it is kosher to change the PFC directly. But, still, dont forget to
document it! |
|
 pfc_Validation
( powerobject apo_control [ ] ) returns integer |
Validate all DataWindows with Pending Updates Argument apo_control [ ]:
an array of powerobjects containing a control array for the current window which holds
all of the DataWindows which have pending updates when PFC triggers this event from
of_UpdateChecks( )
Note: For optional uses, you may pass an array of
any objects which you would like to have this event perform validation processing upon
Returns integer:
1 = Success, no validation errors
-1 = Error |
This event is triggered by of_UpdateChecks( ) from the  CloseQuery or the pfc_save event.Searches for validation errors in any DataWindow
which has pending updates.
- Linkage service
Calls the n_cst_dwsrv_linkage of_Validation(
) function
- All other PFC DataWindows
Calls the datawindows pfc_Validation event
|