Section: Tips

Tips  |  Programs  |  Download  |  Archive



Working with external programs

You can run an external program in PowerBuilder by calling functions Windows API CreateProcess (Ex) or ShellExecute (Ex) (the second function may not only run executable files, but also run applications associated with documents). You can, of course, use the standard PowerBuilder
Run ( "Program name" , windowstate) ,
but the most you can manage with this approach is the size of the window at the start of the program. Much more practical use the above functions (ShellExecuteEx implementation is in library
WinAPI ).
Using the ShellExecuteEx function to run the program, you get it header (handle). Further, using it as a parameter for the functions TerminateProcess or GetExitProcessCode you can terminate the program or to check if the program is still running (there are a number of other functions for work with external programs, but you should read about this in the documentation Microsoft), in addition, you can send messages to the created application.

How to get the rendered field in DDDW

MessageBox ( "LookUpDisplay" , string (dw_1. describe ( "evaluate ('" + &
"LookUpDisplay (field_name) ', 1)" )))

How to dynamically change the menu

Example of generating a menu level:
menu mi, m
m = create menu
for li_item = 1 to UpperBound (as_items []) / 2 // array with menu names and their tags
// menu items are a single-item menu created in painter,
// with a clicked script that determines what to do by tag

mi = create m_dyn_menu_item
m.item [li_item] = mi.item [ 1 ] .item [ 1 ] // like this :))
m.item [li_item] .text = as_items [li_item * 2 - 1 ]
m.item [li_item] .tag = as_items [li_item * 2 ]
next
// replace submenu number n with a new one
// if n = UpperBound (m_mdi.item []) + 1 then the menu item is added to the end.

m_mdi.item [n] = m
m_mdi.item [n] .Hide ()
m_mdi.item [n] .Show ()
From: "Anatoly Moskovsky"
avm@trais.com.ua

Printing to the printer bypassing DataWindow

PowerBuilder has a group of functions for printing objects on a printer, bypassing DataWindow:
PrintLine (...)
PrintBitMap (...)
PrintOval (...)
PrintRect (...)
PrintRoundRect (...)
PrintText (...)
PrintDefineFont (...)
PrintSetFont (...)

Getting / changing the height of the Detail field in DataWindow

Did you know that the height of the Detail field in the DataWindow can be changed independently for each line by calling the
function dw_control.SetDetailHeight (startrow, endrow, height)
and get the height of each line in the following way (here the height of the second lines): dw_control. Describe ( "evaluate ('RowHeight ()', 2)" )

Changing H Split Scrolling Position in DataWindow

Did you know that the position of the vertical dividing bar in DataWindow (H Split Scrolling) can be changed:
dw_control.Object.DataWindow.HorizontalScrollSplit

How to get filter and sort criteria in DataWindow

The current filter criterion for DataWindow can be obtained by calling the function:
dw_control. Describe ( "DataWindow.Table.Filter" )
and sorting:
dw_control. Describe ( "DataWindow.Table.Sort" )

How to break a page after a certain line

We set up a field in which we will store the page number. We make a group for this field, mark in the group the property New Page On Group Break (Rows / Create Group / Definition), then fill in this field for each line - on which page it should be. In principle, you can not page numbers, but simply if desired make a page break after a certain line increase the value of this field.

How to "nicely" delete lines.

long i
for i = dw_1.RowCount () to 1 step - 1
// Processing the i-th line, here it can be deleted, the loop will still be
// execute dw_1.RowCount () times (at the start of the cycle).
next

How to "reset" the boundary of a variable size array.

If you have declared an array, let's say long mas [], and have already done the assignment mas [5] = 1, then all mas elements with indices from 1 to 4 will be equal to 0. If after that, it will be necessary to use the mas array one more time, but it will be necessary to write a smaller number of elements there, then "reset" the border of the mess can be done with the following code:
long mas [], clr []
mas [ 5 ] = 1
MessageBox ( "Upper bound mas []" , UpperBound (mas []))
mas [] = clr []
MessageBox ( "Upper bound mas []" , UpperBound (mas []))

How can you speed up work with arrays of variable size.

If it is known in advance that it is necessary to put N elements in the array, then starting assign from N element (or at least by assigning to the Nth element before the start of the operation assignment "dummy" value) can significantly increase the rate of assignment. This is due to the fact that PowerBuilder each time the type is assigned mas [UpperBound (mas []) + 1] = 1 allocates a chunk of memory for an array.
Even if the exact number of elements is unknown, and the logic of the program allows, then periodically you can use something like mas [UpperBound (mas []) * 1.25 + 1] = 0. Actually, this should be taken care of Sybase, as well as much more ...

How can I install / get the list of libraries used by the program.

This can be done using the SetLibraryList (...) function. Naturally, this function must be called before accessing objects. from the libraries you are going to add with SetLibraryList (...).
Addition.
In order to get a list of libraries used by the program, you can use the GetLibraryList (...) function, but this is only suitable for PowerBulider version 7.0+. In earlier versions, you can use the following code:
string LibList = ProfileString ( "pb.ini" , "Application" ,
"$ d: \ pbuilder \ pb6 \ appgal \ CashTrak \ cashtrak.pbl (CashTrack)" )
The value of the ProfileString (...) function will be calculated for the LibList variable at compile time. It remains only to parse the LibList string for selection libraries.
Addon From: "Andrew Zorin"
azorin@online.ru

Dynamically creating objects in a window.

To dynamically create objects at runtime in PowerBuilder the function OpenUserObject (...) is used. To destroy an existing object created by this function, you must call the CloseUserObject (...) function. This function can only open objects created in the User Object painter.

Dynamically reorder groups in a report.

I know of at least four approaches for solving this problem:
1. Dynamic generation of requests from the client with the necessary conditions.
This method is very laborious, and in addition to everything, it "ties" a certain the kind of agreement (for example, on the structure of the base), but the end result can be quite good, in addition, you can not only be limited to changing the order of groups in the report.
2. Changing the syntax of DataWindow.
Works reasonably fast, but as you know, DataWindow syntax is not documented, which gives rise to additional difficulties and possible problems with portability of the program to other versions of PowerBuilder. Moreover, this the method requires an additional DataWindow or DataStore to store the results while the syntax of the main DataWindow changes. The advantage of this method is the fact that you can create more groups than provided in Design Time.
3. Setting up surrogate fields for grouping.
The idea is quite simple - to add additional fields (let's call them ID1, ID2, ..., IDn), equal to the number of report groups and create groups precisely along these fields and further, fill them with increasing values ​​from the same the sequence in which to group. A few tips for implementation. First, dynamically scramble the string and set the sort to the order in which you want to group, something like:
dw_1.SetSort ( "field_3 A field_1 A field_2 A" )
dw_1.Sort ()
After that, it will be enough to run through all lines dw_1 (or once all field_1..field_n, or run n times, but in each pass only one field_i - to taste) increasing some internal counters changes of fields field_1..field_n with each encountered change of fields and enter their values ​​into ID1..IDn, respectively. Then put sorting by fields ID1..IDn. The entire implementation takes, at most, 40-50 lines.
4. Groups can be defined by computed fields. So way, one can simply define the group by the calculated field and then change its expression.
The fourth method From: "Andrew Zorin"
azorin@online.ru

Errors when setting sort order in DataWindow.

Quite often you have to see how beginners, and not only programmers erroneously set the sort order in the DataWindow (DataStore) to the next, very common, situation. There is a directory with two fields - record code (ID) and name (NAME) and our task is to sort by field NAME. But you cannot simply set sorting by the NAME field, since in the case of the presence of records with the same NAME value but different IDs, we get an unpredictable result. Sorting by ID saves us from this, but a person on such a list finding anything is very difficult. Naturally, it is necessary to sort by NAME, and then by ID. Another thing is that this situation is rather strange, and if the logic of the task implies that NAME must be unique, then you can leave sorting only by NAME, and control the uniqueness at the moment making a record (for example, using unique constraints).

Printing and viewing HTML using Windows.

HTML viewing is achieved by calling the ShellExecuteEx function with with the following values ​​of the SHELLEXECUTEINFO structure attributes: SEI.lpfile = "C: \ MYPATH \ myfile.htm"
To do this, you need to install some kind of HTML file viewer.
And print:
SEI.lpfile = "rundll32.exe"
SEI.lpparameters = "MSHTML.DLL, PrintHTML C: \ MYPATH \ myfile.htm "
this invokes Internet Explorer's print dialog. Naturally, it must first be installed on the machine. Windows function implementation The SchellExecuteEx API is available in the
WinAPI library.

How to get DWObject for columns DataWindow.

For PB 6:
DWObject dwo dwo = dw_1.object.get_attribute ( "column_name" , True )
For PB 7, 8 and 9:
dwo = dw_1.object .__ get_attribute ( "column_name" , True )
From: "Anatoly Moskovsky"
avm@trais.com.ua

How to get column and text values ​​in DataWindow of Crosstab type.

Suppose that the column on which the report is expanded is called colname, and the text is textname. Then, to refer to the corresponding columns you need to use the following names:
Column # Data Text
1colname textname
2colname_1 textname_1_t
3colname_2 textname_2_t
4colname_3 textname_3_t
5colname_4 textname_4_t
...... ...
Note: in order to be able to access objects in this way DataWindow you must run the command:
dw_1.Modify ( "DataWindow.Crosstab.StaticMode = Yes" )
How to access nested reports.

The values ​​in the nested report can be accessed through the "dot notation. "However, this is a very bad way - you can only access data, and then the question remains as to whether the number of rows in the nested report value is 0 - then an error will occur when trying to access the report data. PowerBuilder does not provide an interface for accessing nested reports, however, it can be fooled by changing the report type to composite and using the GetChild (...) function. Example:
string s
long ll_rc, i
DataWindowChild dwch

s = dw_1. Describe ( "DataWindow.Processing" )
dw_1.Modify ( "DataWindow.Processing = 5" )
ll_rc = dw_1.RowCount ()

for i = 1 to ll_rc
dw_1.GetChild ( "ds_nested_items" , dwch)
MessageBox ( "" , dwch.RowCount ())
dw_1.RowsMove ( 1 , 1 , Primary! , dw_1, ll_rc + 1 , Primary! )
next

dw_1.Modify ( "DataWindow.Processing =" + s)