PowerBuilder ‘Gotcha’ – Grid Datawindows with Picture Controls

Posted on Wednesday, June 27th, 2012 at 6:14 pm in

So I’m working on a ‘dashboard’ style datawindow in an application which shows a grid of data along with some graphics so the user can easily see changes/important stuff. There are a number of reasons to use a grid datawindow for this, especially since they can easily be changed by the user to suit their particular tastes and preferences. Since the individual columns can be resized by the user, I can’t use the ‘display as bitmap’ option on a column to display my graphics since they can be resized which screws up the image on the datawindow. Fine, I’ll use picture objects placed on the individual columns and then use expressions to control the positioning of them automatically. Gee, isn’t PowerBuilder great?

Now in my particular situation I have a series of picture objects placed on a column with the value of the column itself determining which of them is visible. This is standard stuff achieved via an expression on the visual property of the picture objects . The next thing to do is to set the X position on the picture objects based on the column it is placed upon; I’d like the position of the picture to change dynamically as the column itself changes due to the user dragging the column to a different position or if they make it larger/smaller in width. So far, so good – I’m starting to count my chickens…

I fire up the app and ‘wha, wha, wha, wha, whaaaa…‘.

Here is the application when I launch it.

Looks fine, my visible expressions are correct.

I resize the Mood column to make it larger and…

Something’s not working as expected.

Okay, lets try re-arranging the columns by dragging Name after Mood.

Well this sucks, grrrr….

What happens if I make the Mood column smaller?

Okay boss, when is the deadline for this?

First let’s tackle the positioning issue. To make the expressions on the pictures work correctly, each has to be unique. So these expressions will not work:

long(describe("custmood.X")) + 100
long(describe("custmood.X")) + 100
long(describe("custmood.X")) + 100

These are the X position expression for my three picture objects on the datawindow column. To make them unique I change them to:

long(describe("custmood.X")) + 100 // p_1.X
long(describe("custmood.X")) + 100 + 0 // p_2.X
long(describe("custmood.X")) + 100 * 1 // p_3.X

Note also that ‘+ 100’ is different from ‘+100’ as far as this goes

Now when I run the app and I change the order of the columns in the grid I get:

Moving Name to after Mood.


One thing of note. If you are going to use a Modify to change the X position expressions at runtime rather than within the datawindow definition, each of the ‘New’ expressions must be different from those in the original. Thanks to my manager Robert Sisk for this tidbit.

The second issue is a bit trickier and is one I’ve encountered at various times in my PB career. You can look and look and look online for answers to this and find either nothing or many suggestions which don’t work too well. Often you are faced with preventing the user from resizing the column which eliminates one of the main reasons you choose the grid datawindow in the first place.

Since we are dealing with controls which we have created in the datawindow painter to be the size we want them to be when they appear to the user, all we have to do is capture their widths and then re-apply them once the user has resized the columns on the datawindow. However, we have to create a user event on the datawindow to do this since there is no standard event which is triggered when the user resizes a grid column.

First define an instance variable to hold the modify information on the picture objects for the datawindow.
Next capture the initial values of the widths of the picture objects once the window opens; a ‘post open’ style event is good for this. If your application dynamically changes these for some reason during run time, you will have to reset this after the change so the property is set to the correct value.
Define a user event on the datawindow in question which will perform the modify on the picture objects.
Define a user event mapped to pbm_dwnlbuttonup which will post the first user event. This event is triggered when a user releases the left mouse button on the datawindow (which happens when the are finished resizing the column).

//instance var and postopen event
type variables
string is_picture_widths
end variables

event we_postopen();// triggered from open of window
string ls_objects, ls_object, ls_type
long ll_col_pos, ll_col_start, ll_len
// load picture settings to instance variable
ls_objects = dw_1.Object.DataWindow.Objects
// go through tab separated list
ll_col_pos = pos(ls_objects, '~t')
ll_col_start = 1
ll_len = len(ls_objects)
DO WHILE ll_col_start < ll_len
	ls_object = mid(ls_objects, ll_col_start, ll_col_pos - ll_col_start)
	ls_type = dw_1.describe(ls_object + '.type')
	IF  ls_type = 'bitmap' then //only concerned about bitmaps (picture objects)
		is_picture_widths += ls_object + '.width = ' + dw_1.describe(ls_object + '.width') + '~r'
	END IF					
	ll_col_start = ll_col_pos + 1
	ll_col_pos = pos(ls_objects, '~t', ll_col_start)
	IF ll_col_pos = 0 then
		ll_col_pos = ll_len + 1
end event

event ue_lbuttonup;// call event to resize pictures if needed, mapped to PBM_DWNLBUTTONUP on datawindow
this.event post ue_checkmodified()
end event

event ue_checkmodified();// posted from ue_lbuttonup
string ls_mess

IF this.object.datawindow.syntax.modified = "yes" THEN
	ls_mess = modify(is_picture_widths) // re apply the picture widths
	IF Len(ls_mess) > 0 THEN
		// error condition
setredraw(true) //was set to false in calling event
end event

So now when run the application we get this.

Resize the column with the picture controls

Now make it smaller.

Ahhhh, all is good again.

I’ve attached a sample application (PB12.5.1) demonstrating how the resizing does not work and how it can be corrected. Exports of the objects are included as well if you need to create your own version. When running the example, first resize/reposition the columns after the window opens. This will show the problems with the picture objects. When you click on the ‘Modify Bitmap X Expressions’ button the changes in the X position expressions for the picture objects will be displayed in the multi line edit control.

The ‘Reset DWO’ button resets the datawindow object if you need to.

You might also be interested in