Professional PB Utilities
PowerGraphs Toolkit - Build 2D graphs not supported by PowerBuilder, including multi axes graphs, proportional time scale graphs, overlapped graphs, graph legends with any size, font and palcement, custom graph colors and labels and much more... PowerDrops Toolkit - Make datawindow drop-down boxes from virtually any object, don't be limited to drop-down datawindows and list-boxes only. PowerDrops Toolkit is the only tool that provides guaranteed, precise positioning of the drop-down objects, regardless of a datawindow style, number of rows, levels of parent objects, etc. PowerUndo Toolkit - Word-processor style multi-level undo/redo in any datawindow! Window-To-Bitmap - Save graphs, datawindows and other objects programmatically in standard BMP files, then print, email, fax them as graphics.
PB Tips, Scripts and Utilities
|
|
Secrets of ListView, PictureListBox, DropDownPictureListBox, TreeView, and Application IconUndocumented PowerBuilder: The following constants of enumerated data type may be used as Picture Names in any ListView, PictureListBox, DropDownPictureListBox, TreeView as well as Icon Name in the Application object properties: Question! For instance, some constants mentioned above can be used in a custom MessageBox window instead of bitmaps. Moreover, they can be changed dynamically from the script. Note that the images are consistent with the Operation System and have different look under Windows 3.1 and Windows 95/Windows NT. They look exactly like the images in the system MessageBox. To implement a custom MessageBox:
|
|
If you think your application features perfect bulletproof security system then try it with the "KGB Spy".Using KGB Spy you can "click" disabled and hidden buttons and controls. Check for yourself. Here you can download KGB Spy. Use this program to test your security. To run KGB Spy you will need PowerBuilder 6 deployment kit. KGB Spy source code can be dowloaded here. |
|
DataWindow property sheet: General tab.Undocumented PowerBuilder: On-line help says: "DataWindow property sheet,
General tab, DataWindow Object Name - The name of the DataWindow object you want to embed
in the Window." |
|
DYNAMIC Function Call.On-line help says: "When you specify a dynamic call, the function or event does
not have to exist when you compile the code. You are saying to the compiler: trust me -
there will be a suitable function or event available at execution time." //////////////////////////////////////// global function boolean f_zoom_out( powerobject apo_target )DataWindow ldw_target CHOOSE CASE TypeOf( apo_target )CASE DataWindow! ldw_target = apo_target ldw_target.Modify('DataWindow.Zoom=90') CASE DataWindowChild! ldwc_target = apo_target ldwc_target.Modify('DataWindow.Zoom=90') CASE DataStore! lds_target = apo_target lds_target.Modify('DataWindow.Zoom=90') CASE ELSE // invalid argument type RETURN False END CHOOSE RETURN TrueIn PowerBuilder 5 and 6 you may use a more efficient and elegant code: ////////////////////////////////////////////////// global function boolean f_zoom_out( powerobject apo_target )RETURN (apo_target.DYNAMIC Modify('DataWindow.Zoom=90') = '') You may apply this technique for other objects and functions as well. However, in PowerBuilder 5 some very important functions such as Describe cannot be called dynamically due to the compiler limitations. |
|
Secrets of DataWindows - CPU and other global functions.Undocumented PowerBuilder:DataWindow Painter provides the incomplete list of functions that may be used in the DataWindow expressions. For instance, you can use the CPU( ) function in DataWindow Painter expressions even if it is not listed in the "Modify Expression: Functions list box." This function might be useful when dealing with fractions of a second in a DataWindow. Perhaps you want to have some animation in the DataWindow and build an expression using Bitmap( ) function. Such an expression can tell PowerBuilder how to change the bitmap without intervention from outside of the DataWindow. Therefore, you may want to code the following expression: Bitmap(CASE( mod( cpu(), 200 ) Now if you set the "Timer Interval" property for the DataWindow object to 50 milliseconds, PowerBuilder will loop through file 1 to 4 and simulate the animated picture. Note that you also need to create at least one expression that uses Today() function otherwise PowerBuilder will ignore "Timer Interval". If you do not want this expression appearing on the screen then set its visible property to 0. When evaluating DataWindow expressions, PowerBuilder performs up to three lookups for the functions called in the expression. First, it checks DataWindow Painter's specific functions. Second, it checks user-defined global functions. Finally, it checks global system functions. This is why you can call many system functions in the DataWindow expressions including the CPU ( ). Moreover, knowing this, you can create some kind of macro language in PowerBuilder, which does not have to be compiled yet and can be executed in run-time. For instance, the following command will display a MessageBox: string ls_command // ... some file operations to read a command from the
script file. Perhaps it is Keep in mind that any DataWindow expression must return one of the following data types:
Within an expression, a function can return other data types (such as boolean, date, or integer) but the final value of an expression is converted to one of the four data types above. Click here to download tiny sample application that utilizes CPU( ) function to simulate a screen saver. |
|
Secrets of DataWindows - Timer Event.Undocumented PowerBuilder:In the DataWindow control, declare the Timer event mapped to the PowerBuilder PBM_TIMER event. Your initial impression is that nothing new will happen. However, if you set the "Timer Interval" property (see Properties: General tab page) to any non-zero value in the attached DataWindow object, you will find out that PowerBuilder now fires the timer event for the DataWindow control. Note that PowerBuilder starts DataWindow timer only if the attached DataWindow has at least one expression that calls Today( ) or Now( ) functions. Also, note that the value for the "Timer Interval" must be specified in milliseconds rather than in seconds, as it is in the Timer() Powerscript function. Now code this new timer event and PowerBuilder will take care of it. This method allows having the timer event in the DataWindow without declaring and calling external functions, and this works both under 16-bit and 32-bit Windows. |
|
Overriding System Functions.Perhaps some time ago you have developed a nice, user-friendly PowerBuilder application. Today your boss is asking you to update this application and make it even more friendlier by programming it to beep before displaying a MessageBox, e.g using sounf effects for informing operators that a certain error occured. What to do? One solution is to change tons of existing scripts and inserting Beep(1)
before the MessageBox ( ) call. Another solution is to override the system MessageBox ( )
by creating user-defined global function with the same name. As an experienced programmer
you should ask: "But how can I call the system function from this one? If I call
MessageBox( ) from this function, PowerBuilder will recursively call this function again
and again and it will go to an endless loop until Stack overflow
error occurs." Following is the technique you can use to call the system function and
avoid the endless loop: global function integer
messagebox (readonly string
as_title, readonly string
as_message) You may need to overload this function for the all argument types you use. If you plan to override several system functions, consider declaring a global variable of the SystemFunctions type, which you can create on the Open event of your application object and destroy on its Close event. Warning: The described method for overriding system functions works fine in PowerBuilder 5 only. Unfortunately, it causes run-time errors in PowerBuilder 6 and does not event compile in later versions. |
|
Secrets of Menus - Animated Toolbar Icons.Undocumented PowerBuilder: To simplify GUI development PowerBuilder, provides two events for each menu item: Selected and Clicked. Remember that menu level events are not native to Windows and they are generated and fired by PowerBuilder. Indeed, Windows sends all messages to the window that owns the menu and then PowerBuilder in turn dispatches and forwards messages to the appropriate menu items. On-line help says: "Selected event occurs when the user highlights an item on the menu using the arrow keys or the mouse, without choosing it to be executed." However, this event also occurs when the user places the mouse pointer over a toolbar icon for a moment and PowerBuilder displays the icon's ToolbarTip (PowerBuilder uses the toolbar text attribute for the ToolbarTip). This feature allows us to code the Selected event so that when it is fired we can change the Toolbar Icon for the appropriate menu item then restore original picture when the icon loses focus. The trick is to distinguish whether the event is triggered when the user highlights the menu item or whether PowerBuilder triggers this event before the ToolbarTip appears. You will need to do the following:
In the parent window or in the common window ancestor, declare the new user event
WM_MENUSELECT mapping PBM_MENUSELECT; then code in this event: Following are codes for the functions menthoined above: public subroutine mf_unselect () if isValid(im_last_selected) then public subroutine mf_select (menu am_menuitem) // First, find out what caused Selected event: the menu item
selection or the toolbar item tip Note that in this example a menu item tag is used for temporarily storing the item's Picture Name. If your application is already using menu item tags, you will need to declare another menu level instance variable, which you will use instead.
|
|
Click here to download tiny sample PB 6 application that features animated Toolbar Icons. | |
Secrets of Environment ObjectUndocumented PowerBuilder: An environment Object in PowerBuilder 6 has the new undocumented property Language of enumerated type LanguageID. This makes it very useful for multi-language applications. For a list of available IDs launch PowerBuilder Object Browser, then select Enumerated tab; after that, find and highlight LanguageID type in the left pane then expand its properties in the right pane. |
|
DataWindow Row Selection ColorUndocumented PowerBuilder: As you know standard PowerBuilder function SelectRow(long Row, boolean State) can be used to highlight rows in a DataWindow. Before PowerBuilder highlights the row, it calls Windows API to retrieve system-defined color for an active selection. If you want to know which color will be used for selected rows, you can call the GetSysColor function from Windows API. Following is a the required declaration for this external function: .// The GetSysColor function retrieves the current color of the
specified display FUNCTION long GetSysColor(long color_element) LIBRARY "user32"For 16-bit environments, change the type of color_element argument to integer and library name to "user." Pass 13 as a color_element to get row selection color. By the way, some PowerBuilder functions like SelectRow ( ) successfully accept invalid row numbers. For instance, SelectRow( -1, TRUE) acts as SelectRow( 0, TRUE) and, therefore, successfully deselects all selected rows. |
|
Secrets of DataStore ImplementationPowerBuilder Internals: On-line help says: "A DataStore is a non-visual DataWindow control. DataStores act just like DataWindow controls except that many of the visual properties associated with DataWindow controls do not apply to DataStores. However, because you can print DataStores, PowerBuilder provides some events and functions for DataStores that pertain to the visual presentation of the data. " I wonder why everything else in the PowerBuilder documentation except this paragraph says that a DataStore is a non-visual object when it is really a hidden DataWindow control. Let's prove that a DataStore is a regular DataWindow control implemented as a top-level hidden popup window. Two external functions are needed for unhiding DataStores. FUNCTION boolean SetWindowPos( &long hwnd, /* handle of window */ long hWndInsertAfter, /* placement-order handle */ int x, /* horizontal position */ int y, /* vertical position */ int cx, /* width */ int cy, /* height */ uint uFlag /* window-positioning flags */ ) LIBRARY "user32" FUNCTION ulong FindWindowA(REF string class, REF string name) LIBRARY "user32"We will use SetWindowPos function to show and resize the DataStore window, which is hidden and initially has zero size. Because the PowerBuilder compiler mostly treats DataStore as a pure non-visual object, it protects us from getting the handle of DataStore directly. That is why we will use FindWindowA function to find a DataStore window. For simplicity, we will call this function only once. This function will return the handle of the first found DataStore. The Following script demonstrates how to unhide a DataStore. Note that different PowerBuilder versions use different names of window classes for windows created within PowerBuilder. In PowerBuilder 5 a DataStore as well as a DataWindow class is PBDW050, in PowerBuilder 6 it is PBDW60. ulong ll_handle ls_class = "PBDW050" // PBDW60 for PB6 // create test DataStore // Get DataStore handle IF ll_handle = 0 THEN // unhide and resize MessageBox("DataStore", "Now you can see non-visual datastore!", Exclamation!) DESTROY lds_test If you will examine PowerBuilder 5 DataStores, you can even make them editable. How is that, huh? You can also use Windows SPY programs to search DataStores. A SPY program is usually a standard part of any C++ compiler package. You can find one that is included in Watcom C++ Class Builder that comes with PowerBuilder Enterprise. You can easily convert a DataStore window to a regular DataWindow control by calling the SetParent function from Windows API . For details, please see Windows API documentation. There are several improvements made in PowerBuilder 6 DataStores compared to the previous version. One of them is disabling DataStore painting (or should I say DataWindow painting?), which greatly improves performance, especially when doing multiple data manipulations in a DataStore. I wonder why the DataWindow control is not inherited from the DataStore, which would be logical and would significantly improve the performance of thousands of PowerBuilder developers by eliminating unnecessary code duplication when programming DataWindow and DataStore services. |
|
Secrets of DataWindow - Minimizing DataWindow ControlUndocumented PowerBuilder: As you know a DataWindow control may have a title bar with minimize and maximize boxes and a control box (an icon in Windows 95) with the control menu. As opposed to normal windows, when the user minimizes a DataWindow control it completely disappears instead of displaying an icon that represents the minimized DataWindow. Well, not really. PowerBuilder traps the Resize event and hides the DataWindow. It also happens when the user closes DataWindow using its control menu. To unhide the DataWindow control, simply restore the control's visibility attribute. my_dw.visible = True |
|
Secrets of PowerBuilder Resource Files (PBR)Undocumented PowerBuilder: Unfortunately, the documentation provided with PowerBuilder does not list all the resources supported by PowerBuilder. There is no exact definition of the resource term. In most places we can see definitions like this one: "Resource File Name - Specify a PowerBuilder resource file for the dynamic library if it uses resources, such as bitmaps and icons, and you want the resources included in the dynamic library." As far as I know, a resource file may contain names of graphic files (BMP, RLE, WMF, CUR, ICO, etc.) and names of dynamically referenced objects (UserObject, Window, Menu and DataWindow). You do not need to include names of dynamically referenced objects if you are going to compile dynamic libraries (no matter PBDs or DLLs) and these objects are compiled into PBD/DLL. But you do need to include them if you compile just a single EXE. The format for specifying an object in the resource file is MYLIBRARY.PBL (MYOBJECT). For example: REPORTS.PBL (W_CASH_BALANCE). The name of the resource is not case sensitive. |
|
PowerBuilder Dates and Y2000 ComplianceMany corporations are currently certifying products as Y2K compliant. In PowerBuilder, when saving DataWindow data in text files, we often deal with short date formats that include a 2-digit year. However, there is a way to change the format so that the date is saved using a 4-digit year. PowerBuilder looks in the system registry for the format for Date. Changing the format for Date requires changing the Registry setting for the sShortDate value under HKEY_CURRENT_USER\Control Panel\International. There you can find short Time format as well. To make PowerBuilder use a 4-digit year, you just need to change sShortDate value to whatever you want then save DataWindow contents and restore the old format. You can use standard PowerBuilder registry functions to perform this task programmatically. |
|
Secrets of Menus - Toolbar Icon Tip and TextUndocumented PowerBuilder: On-line help provides the following definition for the ToolbarItemText property of the menu item: "ToolbarItemText - Specifies the text that displays in the toolbar item when the display text option is on for toolbars." As you know, PowerBuilder also uses this property for the toolbar icon tips. How many times have you wanted to make the text long for the tip and short for the icon? Here is an extremely simple but undocumented way to do that: In the Toolbar Text property, specify different text, separated by comma, for the icon and the tip. For example: "Excel,Save report in MS Excel format. |
|
Secrets of Table Painter - Open Table DialogUndocumented PowerBuilder: To quickly locate the desired table in the Select Table dialog box just start typing its name and PowerBuilder will scroll the list box to the nearest match. This undocumented feature is very useful when your list of database tables is really long. |
|
Secrets of Menus - Dynamically Adding New Menu ItemsUndocumented PowerBuilder: The menu Item[] property is not fixed array as many of you think. Nothing can stop you from adding the new elements to this array. The trick is to force PowerBuilder to redraw updated menu properly. The following example demonstrate how to do this.
|
|
Most Simple Method To Count TreeView ItemsUse the following code to quickly count items in the TreeView control: To find out how many items can be fully visible in the TreeView control visible area
use the following script: |
|
Secrets of PowerBuilder ExecutablesDo you know that any program you create in PowerBuilder is property of Sybase, Inc. No kidding, it is not yours as you might think. Here is the proof:
If you fill strong that your work belongs to you, not to Sybase, Inc. use Resource Editor from any C++ package to correct EXE header. Unfortunately you have to do this each time you have a new executable compiled. By the way, you probably know that in any other programming system (take VisualBasic for instance) users can customize their EXE headers (usually via project properties) so that the correct information gets compiled into EXE. |
|
Secrets of GetChild( )Undocumented PowerBuilder: On-line help provides the following definition for
the GetChild ( ) function: According to the definition above, a call to GetChild ( ) for the nested report that is part of a tabular DataWindow fails and the function returns -1. So there is no way you can get a reference to the nested DataWindow that is part of a non-composite DataWindow. Well, not really. Just remember that all DataWindow presentation styles are equal, except "Grid". Therefore, the work-around for this GetChild ( ) issue is the following:
|
|
DataWindow Repair UtilityThis utility fixes invalid column IDs in the datawindow definition. |
|
Response Window With MenuUndocumented PowerBuilder: You can have a menu in a
response window? |
|
MDI Frame Without Menu and ToolbarUndocumented PowerBuilder: You can have a MDI frame without a menu and without a toolbar? Create a menu with only one item, which is invisible and disabled and use that menu for the MDI frame. |
|
Secrets of Dynamic DataWindowsUndocumented PowerBuilder: As you know you can use SyntaxFromSQL function to generate DataWindow source code based on a SQL SELECT statement.Then you can pass the source code returned by SyntaxFromSQL directly to the Create function to create new datawindow dynamically. On-line helps says that for SyntaxFromSQL argument you can use only a string whose value is a valid SQL SELECT statement. However, in PowerBuilder 6.0 and above you can also use EXEC <procedure name> <parameters>, where you substitute <procedure name> with the actual stored procedure name and <parameters> with the actual parameter values instead of parameter names. For example, you can use NULL as a value for each required parameter. After you have the new datawindow created, you can use the Modify function to correct parameter names in the datawindow SQL. |
|
Custom Toolbars - This is Really SimpleCan you have a toolbar in a response window? Or may be
you want a second or third toolbar on your MDI sheet window? |
|
Export DataWindow to Excel including computed columns, headers, footers, groups, text labels, etc...As you probably know, SaveAs function can save datawindow contents in MS Excel format, but ... Yes, unfortunately, it saves raw data only, forget about computed columns, formats, group headers and footers. Not many people have a solution for this problem. However, the solution is quite simple:
This method works quite well with grid-style reports and other style datawindows, but it is as good as good PowerBuilder datawindow conversion to HTML. Check out sample code here. |
|
Asynchronous Processing in PowerBuilder (submitted by Michael Mwamunga)This article contains information that is useful in creating PB applications where asynchronous functions need to be called. An example may be when you need to call a heavy database stored procedure and don't want your application to remain locked while the procedure executes.Click here to download ZIP file containing the article and the example code that you can use in your applications. |
|
Another Toolbar TipUndocumented PowerBuilder: The most simple and efficient way to
have both MDI frame and MDI sheets share the same toolbar and avoid multiple toolbars is
to give them the same name. You can do this in the application open event: |
|
Exchange information between PB applications (submitted by Jose Manuel Navarro)This trick is in case you need trigger a event from a application to another. |
|
SQL Exceptions handling (submitted by Jose Manuel Navarro)This excellent tip demonstrates how you can catch and handle SQL errors. |
|
isValid ?window my_window So far so good...and now, let's see how it works for dwo object in the datawindow events. Let's consider a situation when we have a script for datawindow clicked event and pehaps we clicked inside the datawindow, but not on any object. isValid(dwo) --> as you don't expect, it returns True Surprise? bug? or may be it is a feature? Note: old good GetObjectAtPointer() always works correctly as well as GetClickedColumn() and GetRow() are still much more reliable than these event arguments. |
|
Windows API library (submitted by Santiago Ciappesoni)This library contains ready for "copy and paste" declarations of most Window API functions, structures and constants. You will find there everything, from declarations of functions for working with standard Windows controls to WinSock interface. Do yourself a favor and download this library. If you don't need it today, you will need it tomorrow. |
|
Accesing TopSpeed Databases (submitted by Michael Mwamunga)Although perhaps the two were never meant meet, accessing Topspeed (.TPS) database tables from Powerbuilder via the ODBC driver from Soft Velocity is possible. Here is how... |
|
Note: This page is maintained by Dmitriy Evinshteyn
|
|
Press Ctrl+D to bookmark this page. I will add more tips soon.Have a cool tip? Why don't share with other? Email your tip and I will add it to this page along with a link to your site. |