1. Brad Mettee
  2. PowerBuilder
  3. Thursday, 31 October 2019 21:46 PM UTC

We have need to add some logging to all response windows in our system via a common ancestor. I just tried adding ue_constructor (event type pbm_constructor) with needed code on it, and it never fires. We can't use the open event because too many windows override the ancestor event for varying purposes (some eventually call the ancestor, some don't). We're dealing with about 150 response windows, so doing it one at a time would be somewhat tedious.

The constructor event is available on objects on the window. Why isn't it available on the window object itself? Or, at minimum, why doesn't adding the event allow it to fire like other built-in events?

 

John Fauss Accepted Answer Pending Moderation
  1. Friday, 1 November 2019 04:37 AM UTC
  2. PowerBuilder
  3. # 1

Hi, Brad -

I cannot answer the "why" part of your question, but here's a suggestion on how you might implement a pseudo-constructor event in an ancestor window where the Open event is not a workable solution:

In your base ancestor window, create an unmapped user event named ue_constructor or similar. Place in the base ancestor window a simple, hidden control, such as a static text control named st_constructor and set to text to something like "This static text control fires the window's ue_constructor event." as a clue for developers (it's hidden, so why not?). In st_constructor's Constructor event, code two lines:

This.Visible = False          // Just in case a developer makes it visible.
Parent.Event ue_constructor() // Fire window's "constructor" event.

As a little added insurance against st_constructor being seen, you could optionally also move it far to the right and/or down:

This.Move(25000,25000) // For example...

Now you can add code to the window's new "constructor" event as needed.

If you want that event to fire as soon as possible, you can Edit Source for the ancestor window and make the new, hidden static text control the first item in the window's Control array, but realize that references to any other controls in the ancestor window may not yet exist when the ue_constructor event executes. That's also a concern to keep in mind when the window's ue_constructor event fires.

HTH - Regards,
John

Comment
  1. Roland Smith
  2. Friday, 1 November 2019 14:40 PM UTC
I like the idea of using a hidden control's constructor event. If the ancestor window already has a control on it, the newly added one will be last in the control array so the last to be constructed. To make sure it fires first, you'll need to go into edit source and carefully re-order the controls.
  1. Helpful
  1. Ronnie Po
  2. Friday, 1 November 2019 16:48 PM UTC
Great idea, John. To avoid all visual concerns, you could also use a dummy nonvisual object in the window such as a message object (Insert > Object > Message) and use its constructor event to fire ue_constructor().
  1. Helpful
  1. Miguel Leeuwe
  2. Saturday, 2 November 2019 08:38 AM UTC
Wow Ronnie, after so many years, I´m still learning new stuff thanks to people like you. That´s a great tip too!
  1. Helpful
There are no comments made yet.
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Friday, 1 November 2019 03:09 AM UTC
  2. PowerBuilder
  3. # 2

I like Olan's solution of using the Activate event, but then ... of course that event might also be overridden. So to increment your chance of success, I'd do what he suggests in the activate AND in the open event of your common ancestor window.

Then again, how many windows would really have an override in the Open event? If it's not many, you can call the log code there explicitly. The only problem there is to identify them.

What I always do to find overriden events, is to use a little app I wrote in the 90's. It exports all code and allows me to do searches in the fully exported code. You could also use notepad++ (find in files) or GrepWin. With a powerbuilder search you would not find what I look for:

 

1)

I do a search on "event open;" and export that list to a text file. This list has all windows. 

2)

Then I do a search on "event open;call ..." (I don't remember if it's "call super::open", can't get into PB right now).  This list is the list of windows without an override of the open event.

3) copy and past both lists into excel, order by name and you can now easily see which windows have an override: it's the windows of list 1) which are missing in list 2).

 

There's tools like Visual Expert and maybe others like pb search or pbl peeper (not sure about these last 2) which might make this task easier.

 

Once identified, make sure any developers from now on call the login function or some event like  ue_init() or ue_override_open(), when doing an override of the open. (the ue_init would call the logging and would be called from the open event). The advantage of the ue_init is that you can add more stuff to it that you always want to execute.

 

Just to give you an idea,

regards

Comment
There are no comments made yet.
Olan Knight Accepted Answer Pending Moderation
  1. Thursday, 31 October 2019 22:44 PM UTC
  2. PowerBuilder
  3. # 3

One possible workaround:

1) On the prime ancestor window, in the PFC that would be W_MASTER or CORP_W_MASTER or PFC_W_MASTER depending on your scheme, add an instance variable "boolean      initial_open = TRUE"

2) Add your logging code to gnv_app.of_logit (string  as_log_msg)

3) In the activate event of the same window:
    IF (initial_open) THEN
       lw_window = this
       gnv_app.of_logit ("the window " + this.ClassName() + " just opened.")
       initial_open = FALSE
   END IF


Later -

Olan

Comment
There are no comments made yet.
Chris Pollach @Appeon Accepted Answer Pending Moderation
  1. Thursday, 31 October 2019 22:13 PM UTC
  2. PowerBuilder
  3. # 4

Hi Brad;

  That's because all visual & non-visual controls / objects already have the pbm_constructor message ID mapped to their built-in "constructor" event. Also, when the PBVM processes O/S messages it dismisses them from the message queue instead of "chaining" it.

   Note: DW Controls steal messages from the front of the O/S queue and then chain them into it's own message queue. So quite often, you can map various pbm_xxxx message ID's to a DC but your App doesn't see them.

Regards ... Chris

Comment
  1. Brad Mettee
  2. Thursday, 31 October 2019 22:32 PM UTC
I understand all of that, but the question still remains: Why isn't there a built in constructor event for window objects?



And given that you can map PBM_* events on objects, how are we to know which are mapped from OS->PB, which are mapped PB->PB, and which are never fired by PB or OS at all?
  1. Helpful
  1. Chris Pollach @Appeon
  2. Thursday, 31 October 2019 23:16 PM UTC
FWIW: I still use Spy++ to see what messages are sent to any part of a PB app and then I code the "other" event to track what actually comes to an object.
  1. Helpful
  1. Chris Pollach @Appeon
  2. Monday, 4 November 2019 15:56 PM UTC
If you analyze the MS-Windows message queue for an visual App, you'll see that Window classes do not receive a constructor from the O/S. The NVUO approach is a good workaround though. ;-)
  1. Helpful
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.