1. Jim Reese
  2. PowerBuilder
  3. Thursday, 18 April 2024 16:49 PM UTC

Assume you have 6 different methods acting on a datawindow or multiple datawindows on a userobject, and these methods can be called in multiple combinations, singly or in combination.
They involve sorting/filtering or some other visual change that you don't want the user to see until all of the processing is complete.
Each method therefore has a setredraw false/true at the beginning and ending of the method.
Now suppose Method1 wraps all of the other methods as seen below, your goal is to prevent any flickering/intermediate processing from being seen.

Method1 SetRedraw(False)
  Method2 SetRedraw(False)
    Method3 SetRedraw(False)
      Method4 SetRedraw(False)
      Method4 SetRedraw(True)	//1,2,3 still want it false
    Method3 SetRedraw(True)	//1,2 still want it false
  Method2 SetRedraw(True)	//1 still wants it false
  Method5 SetRedraw(False)
    Method6 SetRedraw(False)
    Method6 SetRedraw(True)	//1,5 still want it false
  Method5 SetRedraw(True)	//1 still wants it false
Method1 SetRedraw(True)		//OK to show now

The following approach appears to resolve the problem, by removing the SetRedraw(True) at the end of each method,
and replacing it with a POST SetRedraw(True) at each SetRedraw(False)

Method1 SetRedraw(False); POST Setredraw(True)
  Method2 SetRedraw(False); POST Setredraw(True)
    Method3SetRedraw(False); POST Setredraw(True)
      Method4 SetRedraw(False); POST Setredraw(True)
//    Method4 SetRedraw(True)
//  Method3 SetRedraw(True)
//Method2 SetRedraw(True)
  Method5 SetRedraw(False); POST Setredraw(True)
    Method6 SetRedraw(False); POST Setredraw(True)
//  Method6 SetRedraw(True)
//Method5 SetRedraw(True)
//Method1 SetRedraw(True)
All POSTs execute here

You could also add a boolean instance variable to keep track of the False/True state, and instead of calling SetRedraw directly,
Call of_SetRedraw that will evaluate the instance variable and only execute the SetRedraw when the passed in state is different than the current state. The first false will execute, then all of the nested falses get ignored, and the first posted true gets executed, with the remaining posted trues being ignored. The boolean gets flipped when the Setredraw actually executes inside of_SetRedraw. (This is what we are currently doing, and where we previously had many SetRedraws executing, we now only have 2, 1 false and 1 true.)

This seems to be working well for us so far where we have implemented it, we are applying the setredraw to a tab page userobject that has multiple datawindows and a second set of smaller tabs with their own datawindows on them. All of the flickering we were seeing is gone.

Has anyone else ever tried this approach, or see any potential problems with it?

John Fauss Accepted Answer Pending Moderation
  1. Tuesday, 23 April 2024 01:43 AM UTC
  2. PowerBuilder
  3. # 1

I had essentially the same idea as Marc, but at the time I was unable to devote any time to developing and testing an implementation. It took a couple of iterations, but I've come up with a possible, suggested solution based on Marc's concept. A small example program called BalancedSetRedraw is attached.

The example contains a DataWindow user object inherited from the DataWindow standard visual class. An override of the base/ancestor SetRedraw function extends the base functionality to implement the "balanced redraw" concept, and an instance boolean and public access function enables/disables the new functionality in order that normal SetRedraw behavior performs as expected.

In the override function, the scope resolution (::) operator is used to execute the actual SetRedraw function in the DragObject ancestor when it is appropriate. I am not suggesting this is an optimal solution, only a possible one.

Best regards, John

Attachments (1)
Comment
  1. Jim Reese
  2. Tuesday, 23 April 2024 14:34 PM UTC
Thanks John. Maybe I wasn't clear, but I'm not really looking for alternative solutions, as much as I am looking for comments, pro or con, on the solution I have proposed, and now implemented in part of our existing application. It doesn't depend on making sure you have the right correspondence of false and true calls, except that you know you will have that because every time you set false, you also immediately post your matching true right then and there. It avoids the problem of an exit or early return before the true is called, while at the same time prevents an inner set of false/true prematurely making something redraw before the outer method wants a true to be set. No stack counter needed.
  1. Helpful
  1. John Fauss
  2. Tuesday, 23 April 2024 15:30 PM UTC
Hi, Jim! No, you were quite clear. The issue with SetRedraw that you've raised is interesting and intriguing. It got me to wondering if it was possible to enhance the base SetRedraw function that wouldn't require the refactoring of any legacy code. It was something I had been wanting to delve into for some time and this seemed like the perfect opportunity. Many (most?) PB developers are not familiar with the scope resolution operator, so this was a quick and easy way to demonstrate what it is and how it can be used. I'm super glad the POST'ing technique you've described is an effective solution for you, and I'm very appreciative that you took the time to share it with the Community. I certainly learned from it. Thank you for sharing!
  1. Helpful 1
There are no comments made yet.
Marc Wietscher Accepted Answer Pending Moderation
  1. Friday, 19 April 2024 12:15 PM UTC
  2. PowerBuilder
  3. # 2

Hi Jim,

we implemented something similar some years ago. Depending of the boolean argument our method wf_SetRedraw(boolean) increases or decreases an instance variable which counts the calls of that method. SetRedraw(TRUE) on all relevant controls is only executed when the counter is 1 (first call), SetRedraw(FALSE) is only executed if the counter is 0 (last call).

This way we don't need to post the method and the callstack cannot be interrupted by other posted calls in between.

 

Best regards,

Marc

Comment
  1. Jim Reese
  2. Friday, 19 April 2024 13:20 PM UTC
Hi Marc, This was the first approach I was taking, but wasn't certain that all of the False's had a corresponding True call, as this is a very mature application, and wasn't certain of all of the logic paths, thought we might have some RETURNs in some of the methods that bypass the True. I was going to get around that by adding a loop at what I knew to be the most outermost pair for what I was addressing for the final true, to handle any missed Trues. But then my manager suggested the POST approach, and we decided to go that route.
  1. Helpful
  1. Marc Wietscher
  2. Friday, 19 April 2024 16:09 PM UTC
Hi Jim,

good point. Our legacy code contains a lot of GOTOs for error handling. I tried to refactor that by using TRY...CATCH...FINALLY...

Now SetRedraw(FALSE) is the first thing to do and SetRedraw(TRUE) needs to be added to the FINALLY block.



btw you could even use TRY...FINALLY... without any CATCH block, at least I read that somewhen somewhere. To me TRY is the perfect approach for error handling and cleaning up afterwards in any case (success or failure) without maintaining duplicate code.



As Chris might say: Food for thought ;-)
  1. Helpful 1
There are no comments made yet.
Miguel Leeuwe Accepted Answer Pending Moderation
  1. Thursday, 18 April 2024 21:49 PM UTC
  2. PowerBuilder
  3. # 3

Yes.

What we do is call our own redraw function, which adds all of the calls to a datastore. Whenever a "redraw true" is called from any object, we first look at the level of nesting of the object that calls it and block the call if an outer/surrounding object still wants it to be false.

It's not ideal but it sure does stop a lot of flickering :)

Not sure if I explained myself very well.

Comment
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.