Powerbuilder – Anvil of Time https://anvil-of-time.com Nature Forges Everything on the Anvil of Time Fri, 02 Apr 2021 16:18:01 +0000 en-US hourly 1 PowerBuilder – Back Tab to Last Field in DataWindow https://anvil-of-time.com/powerbuilder/powerbuilder-back-tab-to-last-field-in-datawindow/ https://anvil-of-time.com/powerbuilder/powerbuilder-back-tab-to-last-field-in-datawindow/#respond Tue, 23 Mar 2021 23:11:00 +0000 https://anvil-of-time.com/?p=2188 An annoyance in a PB window with a datawindow control on it is if you back tab to the dw, your cursor is positioned to the first field and not the last field. The following technique can eliminate that and make your application a bit more user friendly.

In the Getfocus event of the datawindow:

long ll_col = 1
long ll_pos, ll_x, ll_y, ll_tab
long ll_curr_x, ll_curr_y
string ls_list, ls_piece, ls_column, ls_setting

// user back tabbed to get here
IF Keydown(keyshift!) AND Keydown(keytab!) THEN
	// objects on datawindow
	ls_list = THIS.object.datawindow.objects + '~t'
	DO WHILE ls_list <> ''
		ll_pos = POS(ls_list, '~t')
		IF ll_pos > 0 THEN
			ls_piece = MID(ls_list, 1, ll_pos - 1)
			ls_list = TRIM(MID(ls_list, ll_pos + 1))
			IF TRIM(ls_piece) <> '' THEN
				ls_setting = THIS.Describe(ls_piece + '.Type')
				IF UPPER(ls_setting) = 'COLUMN' THEN // only look at columns
					ls_setting = THIS.Describe(ls_piece + '.Visible')
					//check for visible only	
					IF ls_setting = "1"	THEN			
						ls_setting = THIS.Describe(ls_piece + '.X')
						ll_x = long(ls_setting)
						ls_setting = THIS.Describe(ls_piece + '.Y')
						ll_y = long(ls_setting)
						ls_setting = THIS.Describe(ls_piece + '.TabSequence')
						ll_tab = long(ls_setting) //check tab sequence
						IF ll_tab > 0 AND ((ll_y = ll_curr_y AND ll_x > ll_curr_x) OR (ll_y > ll_curr_y)) THEN
							ll_curr_x = ll_x
							ll_curr_y = ll_y
							ls_column = ls_piece
						END IF
					END IF
				END IF
			END IF
		END IF
	LOOP
	IF TRIM(ls_column) <> '' THEN
		THIS.setrow(long(THIS.Object.DataWindow.LastRowOnPage))
		THIS.setcolumn(ls_column)
	END IF
END IF

On any given datawindow (if you put this in an ancestor) you need to make sure that any columns you place ‘out of view’ are either invisible or have a tab sequence of zero.

]]>
https://anvil-of-time.com/powerbuilder/powerbuilder-back-tab-to-last-field-in-datawindow/feed/ 0
PowerBuilder – Getting the Display Value from a Drop Down DataWindow https://anvil-of-time.com/powerbuilder/powerbuilder-getting-the-display-value-from-a-drop-down-datawindow/ https://anvil-of-time.com/powerbuilder/powerbuilder-getting-the-display-value-from-a-drop-down-datawindow/#respond Thu, 18 Mar 2021 20:51:00 +0000 https://anvil-of-time.com/?p=2182 This is very basic functionality but easily forgotten. Say you have a datawindow built from the ‘part’ table and a column for partType is a DDDW. You want the description of the partType code (which is displayed in the row showing the parts). To do this you use the evaluate method with the describe method on the datawindow.

string ls_desc
ls_desc = dw_parts.describe("evaluate('lookupdisplay(partTypeID)'," + string(ll_row))

Where ‘ll_row’ is the row number in dw_parts datawindow from which you want the description.

]]>
https://anvil-of-time.com/powerbuilder/powerbuilder-getting-the-display-value-from-a-drop-down-datawindow/feed/ 0
PowerBuilder – SQL Native Client Transaction Persistance https://anvil-of-time.com/powerbuilder/powerbuilder-sql-native-client-transaction-persistance/ Tue, 17 Dec 2013 15:08:42 +0000 http://anvil-of-time.com/wordpress/?p=1641 There can be an issue with transactions not being disconnected from SQL Server when using the SQL Native Driver (SQLNCLIxx driver). In my case when the application was closed, the transactions were held open for up to four minutes. This may not be an issue with a small number of connections but with a large user base it can be problematic.

To correct this you need to add an Extended Property to the Database Profile Setup. The entry is “OLE DB Services=-4”.

This changes your connection string to something like:

SQLCA.DBParm = “Provider=’SQLNCLI10′,Database=’myDB’,ProviderString=’OLE DB Services=-4′

]]>
PowerBuilder – Refactoring Code to Reduce Database Calls https://anvil-of-time.com/powerbuilder/powerbuilder-refactoring-code-to-reduce-database-calls/ https://anvil-of-time.com/powerbuilder/powerbuilder-refactoring-code-to-reduce-database-calls/#respond Wed, 27 Nov 2013 21:11:37 +0000 http://anvil-of-time.com/wordpress/?p=1630 So I’m working on a fairly large enhancement to an application which is about twelve years old.  In a nutshell it involves allowing users to see data for multiple sites and multiple locations within each site.  Originally the app was created so the user could only view a single site at a time.  Which sites (and locations) are visible to any given user is based on security settings.

The existing windows normally had your typical ‘search’ datawindows which defaulted to the ‘default’ site assigned to the user and then they could select a location from a drop down datawindow.

Example ‘post open’ event on window code:

datawindowchild ldwc

long ll_rows

dw_search.getchild('loc_code', ldwc)
ldwc.settransobject(SQLCA)
ll_rows = ldwc.retrieve(gs_user_id)
dw_search.object.loc_code[1] = gs_default_site

Example ‘itemchanged’ event on dw_search code

this.getChild("site_to", ldwc)
ldwc.setTransObject(SQLCA)
If ldwc.Retrieve(long(data)) = 0 then
  ldwc.insertrow(0)
End if

So each time the user changed the location value another retrieve was sent to the database.

I needed to add a site column to the search datawindow which would also be a dddw.  This meant that even more calls to the database would occur as the user changed the value in the new column.

My approach involved creating an nvo with two datastores, one for the sites and the other for the locations.  Each were populated when the window was opened (populated based on the user’s security settings).  Then when I needed to set up the drop down datawindow columns I used the following.

// all sites and locations for this user
ls_sites = invo_multisite.ids_site.object.datawindow.data
ls_locs = invo_multsite.ids_loc.object.datawindow.data

dw_search.getchild('site_code', ldwc)
ldwc.importstring(ls_sites)
dw_search.object.site_code[1] = is_site_code
ll_find = ldwc.Find('site_code = ' + string(is_site_code), 1, ldwc.RowCount() + 1)

dw_search.getchild('loc_code', ldwc)
ldwc.importstring(ls_locs)

ldwc.setfilter("site_code = '" + is_site_code + "' AND status = 'Active'"

ldwc.filter()  // only show locations associated with the chosen site

You need to remember to turn off Autoretrieve on the DDDW columns you are using for this.  You also need to have the datawindow object used in the nvo datastores the same as that used in the other datawindow dddw columns.  If you need to account for user access being changed during the sesssion, set up a timer in the nvo and periodically refresh the datastores.

]]>
https://anvil-of-time.com/powerbuilder/powerbuilder-refactoring-code-to-reduce-database-calls/feed/ 0
PowerBuilder – Failed to get the service list https://anvil-of-time.com/powerbuilder/powerbuilder-failed-to-get-the-service-list/ Thu, 04 Apr 2013 23:49:28 +0000 http://anvil-of-time.com/wordpress/?p=1604 Just so this is documented and maybe come up on a search sometime, here is an error message fail:
webservicefail

I got this attempting to set up a new .Net Web Service proxy in PB Classic.

]]>
PowerBuilder ‘Gotcha’ – Tooltips do not display https://anvil-of-time.com/powerbuilder/powerbuilder-gotcha-tooltips-do-not-display/ Mon, 01 Apr 2013 22:17:51 +0000 http://anvil-of-time.com/wordpress/?p=1598 I was working on setting up datawindow tooltips for a project and ran into an issue where sometimes they would not display for specific columns on the datawindow.

Here is what you have to do:

The tooltip Enabled property must be TRUE.

The tooltip text must not be an empty string or NULL.

The tooltip duration must be greater than zero.

tooltip

All of these are properties which can be set via expressions and/or modify statements.  Make sure they evaluate correctly as well.

]]>
Windows 7 ‘Gotcha’ – PowerBuilder Application Control Fonts Too Large https://anvil-of-time.com/powerbuilder/windows-7-gotcha-powerbuilder-application-control-fonts-too-large/ Thu, 21 Feb 2013 12:17:44 +0000 http://anvil-of-time.com/wordpress/?p=1553 So I finally got my computer upgraded to Windows 7 at work.  I was very happy to have it since XP was really starting to annoy me and I couldn’t really do some of the development tasks I needed to get done.

After a week or so I started looking through the applications I work on and found some issues with some of the fonts; they were too big in Windows 7.  Now, if you went through a Windows upgrade before this may come a no surprise; I remember some issues going from Win95 to Win 2000 to Win XP back in the day.  Here is an example of what I’m talking about.

win7_fonttoobig

 

Now these buttons had MS Sans Serif font sized at 9 point.

So I tasked myself with going through each window/visual object in the application libraries to check for this.  The last thing I want to have  happen is my apps to go to customers looking like crap.

Lo and behold you don’t need to do this.  The answer is a setting in Windows.

Right Click on the desktop:

Rt Click on Desktop

Choose ‘Personalize’

win7_screensettingdisplayChoose ‘Display’

win7_screensettingdefaultMake sure you are using the default setting.

 

Now things are fine:

win7_normalfont

Now this seemed to only be an issue with MS Sans Serif  so I’m not sure if there are other fonts to be concerned with or not.

]]>
PowerBuilder – Writing to the Windows Event Log https://anvil-of-time.com/powerbuilder/powerbuilder-writing-to-the-windows-event-log/ Wed, 13 Feb 2013 22:32:09 +0000 http://anvil-of-time.com/wordpress/?p=1538 Here are  two ways to write to the Event log in Windows and indicate the source of the message.

Reportevent External Function and Eventcreate command line command

You can use the command shell to do this too but this has the drawback of not being able to assign the source of the event.

First you need the following External Functions:

Function ulong RegisterEventSource ( &
	ulong lpUNCServerName, &
	string lpSourceName &
	) Library "advapi32.dll" Alias For "RegisterEventSourceW"

Function boolean ReportEvent ( &
	ulong hEventLog, &
	uint wType, &
	uint wCategory, &
	ulong dwEventID, &
	ulong lpUserSid, &
	uint wNumStrings, &
	ulong dwDataSize, &
	string lpStrings[], &
	ulong lpRawData &
	) Library "advapi32.dll" Alias For "ReportEventW"

Function boolean DeregisterEventSource ( &
	ref ulong hEventLog &
	) Library "advapi32.dll"

Then in PowerScript

integer li_messagelevel
string ls_errmsg[]
string ls_messagesource
ulong lul_eventsource
// the event message is here
ls_errmsg[1] = "Event Log Entry " + String(now(), 'hh:mm:ss') 
// setting the source of the message
ls_messagesource = this.classname()

lul_eventsource = RegisterEventSource(0, ls_messagesource)
IF IsNull(ls_eventsource) THEN ls_eventsource = -1
// set the level of the message
li_messagelevel = 4 // Information,  also 1 = Error, 2 = Warning

IF lul_eventsource > 0 THEN
	// write to the log
	ReportEvent(lul_eventsource, li_messagelevel, 0, 0, 0, &
        UpperBound(ls_errmsg), 0, ls_errmsg, 0)
	DeregisterEventSource(lul_eventsource)
END IF

Viewing the Log

pbeventlog

Per the MSDN documentation, if the source name cannot be found the event logging service uses the Application log. Although events will be reported , the events will not include descriptions because there are no message and category message files for looking up descriptions related to the event identifiers.

Thanks to Roland Smith for most of the code for this functionality.

You are also able to use the ‘EVENTCREATE’ command line command.

From the Microsoft Technet page (found Here):

Enables an administrator to create a custom event in a specified event log.
Syntax
eventcreate [/s Computer [/u Domain\User [/p Password]] {[/l {APPLICATION|SYSTEM}]|[/so SrcName]} /t {ERROR|WARNING|INFORMATION|SUCCESSAUDIT|FAILUREAUDIT} /id EventID /d Description
Top of page 
Parameters
/s   Computer   : Specifies the name or IP address of a remote computer (do not use backslashes). The default is the local computer.
/u   Domain \ User   : Runs the command with the account permissions of the user specified by User or Domain\User. The default is the permissions of the current logged on user on the computer issuing the command.
/p   Password   : Specifies the password of the user account that is specified in the /u parameter.
/l { APPLICATION | SYSTEM } : Specifies the name of the event log where the event will be created. The valid log names are APPLICATION and SYSTEM.
/so   SrcName   : Specifies the source to use for the event. A valid source can be any string and should represent the application or component that is generating the event.
/t { ERROR | WARNING | INFORMATION | SUCCESSAUDIT | FAILUREAUDIT } : Specifies the type of event to create. The valid types are ERROR, WARNING, INFORMATION, SUCCESSAUDIT, and FAILUREAUDIT.
/id   EventID   : Specifies the event ID for the event. A valid ID is any number from 1 to 65535.
/d   Description   : Specifies the description to use for the newly created event.
/? : Displays help at the command prompt.

In PowerScript:

// command line event log
integer li_rtn
string ls_msg, ls_eventmsg
ls_msg = 'Command Line Message'

 ls_EventMsg = 'EVENTCREATE /T ERROR /ID 100 /SO "My Application" /l APPLICATION /D "' +ls_msg + '" '
 li_Rtn = Run (ls_EventMsg,  Minimized!)

 IF li_Rtn <> 1 THEN
	messagebox('event log', 'error loging msg')
 END IF

And the message in the Event Log viewer

eventcreatemessage

To use this the user must be an administrator on the machine or you have to provide the id/password combination of one.

Thanks to Kyle Griffis for this tip.

]]>
PowerBuilder – Datawindow Usability Improvements https://anvil-of-time.com/powerbuilder/powerbuilder-datawindow-usability-improvements/ Thu, 27 Dec 2012 22:25:31 +0000 http://anvil-of-time.com/wordpress/?p=1523 I did a presentation at the 2012 PowerBuilder Developers Conference on improving the user experience in older PowerBuilder applications.  Later in December 2012 I presented an abstract of that on PowerBuilder TV.  The recorded session can be found here.

I have updated the presentation files along with exports of the PB objects so that folks using versions prior to 12.5 can take a look at the code and the functionality it provides.  The new file is available here.

The examples presented cover some basic datawindow functionality techniques which can improve the ‘usability’ of an application.  Most of these can be considered ‘second nature’ in that many ‘modern’ applications do these sorts of things already.  Taking advantage of the power of the datawindow, these types of improvements can be made quickly and with very low risk to an already established user base.  What I mean here is since the ‘improvement object (IO)’ is inherited from a datawindow, all you need to do is to establish a reference between any datawindow already in your application and the IO, wire some events on the existing datawindow to corresponding events on the IO, and you have access to the new functionality.

Once you have the IO in place, it’s easy to add even more functionality to it and have those improvements flow into as many datawindows in your applications as you like.

In this version of the IO I have included ‘Type ahead’ functionality.  My earlier blog post on this is here.

Treeview like tooltips.  Blog post is here.

‘Mouseover’ effects.  Similar blog post is here.

And a ‘Universal Searcher’ tool which can be used not only on datawindows but also multi line edit, rich text edit, and treeview controls.

]]>
Datawindow Usability Improvements Presentation https://anvil-of-time.com/powerbuilder/datawindow-usability-improvements-presentation/ Tue, 04 Dec 2012 12:49:44 +0000 http://anvil-of-time.com/wordpress/?p=1518 You can find the files from my PBTV presentation here.  I’ll do an in depth article later for those who could not attend the session.

This is an extract from the session I presented at the SAP PowerBuilder Developers Conference 2012.

]]>