Page 1 of 1

timerListener not firing

Posted: 24 Aug 2020 1:36
by kwkisiel
Hope someone can help me understand and get the timerListener event to fire. I’ve created a very simple project which has one form, ‘timerTest’. This form has just 2 buttons; 1) startTimer_ctl, and 2) stopTimer_ctl. In addition, there is a class, ‘timerControl’ that contains two clauses; 2) startTimer, and 2) stopTimer. The project contains the following code:

Code: Select all

class timerControl     open core   predicates     startTimer : (window).     stopTimer : ().   end class timerControl

Code: Select all

implement timerControl     open core   class facts     myTimer : vpiDomains::timerId := erroneous.   clauses     startTimer(Win) :-         myTimer := vpi::timerSet(Win:getVpiWindow(), 1000), % Need to get the handle for the window parameter         stdio::write("Timer set for 1 sec.\n").       stopTimer() :-         vpi::timerKill(myTimer),         stdio::write("Timer stopped.\n").   end implement timerControl (only the relevant clauses)

Code: Select all

predicates     onMouseDown : window::mouseDownListener. clauses     onMouseDown(Source, _Point, _ShiftControlAlt, _Button) :-         timerControl::startTimer(Source). % Call to start the timer for window Source   predicates     onStartTimerClick : button::clickResponder. % Start Button clicked clauses     onStartTimerClick(Source) = button::defaultAction :-         timerControl::startTimer(Source).  % Call to start the timer for button Source   predicates     onStopTimerClick : button::clickResponder. % Stop Button clicked clauses     onStopTimerClick(_Source) = button::defaultAction :-         timerControl::stopTimer.  %Call to stop the timer   predicates     onStartTimerTimer : window::timerListener. % Timer for Start Button event fired clauses     onStartTimerTimer(_Source, _Timer) :-         stdio::write("Timer event from Button\n").   predicates     onTimer : window::timerListener. % Timer for the Form event fired clauses     onTimer(_Source, _Timer) :-         stdio::write("Timer event from Form\n").
As can be seen, I have two ways to start the timer; 1) onMouseDown on the form, and 2) clicking the startTimer_ctl button. You can also see that the onTimer event has been defined for both the form and start button.

Result: When initiating the timer using either method the ‘Timer set…’ text is displayed in the Messages window. When clicking the stopTimer_ctl button, the ‘Timer stopped’ text is displayed in the Messages window. It also appears that all variables are being properly set (as viewed in the Debug mode).

The problem is that the timer event for both the form and button are not firing so the ‘Timer event…’ text is not being displayed.

I suspect that the problem may be with the vpi::timerSet call. Examples from web site show a ‘window’ parameter being passed to vpi::timerSet. When I did this, I get a compile time error since vpi::timerSet in looking for a ‘windowHandle’ as the parameter not a ‘window’. So I added ‘getVpiWindow’ to the parameter to get the handle of the window object being passed. Currently, I’m using the personal version of Visual Prolog 9 Build 906.

Any help or suggestions would be greatly appreciated. Thanks.

Re: timerListener not firing

Posted: 24 Aug 2020 12:13
by Thomas Linder Puls
The only thing in your code that say that you expect onStartTimerTimer to be called when the timer on the button fires is a comment in the code.

I.e. you start and stop a timer, and you have a listener, but you have not told what the listener should listen to.

So somewhere in your code you will need to attach the listener to the window that it has to listen to:

Code: Select all

predicates     addTimerListener : (timerListener Listener).     % @short Adds a <b>e_Timer</b> event listener #Listener for     % for the #Timer timer in the current window.<br>     % @end
Besides that you also have a problem with being able to start numerous timers, but only having one fact for the timers (myTimer). This means that you can start many timers, but only stop the last one that was started.

However, I think you should refrain from using vpi::timer... at all. Instead you should use the timer predicates which exist on window. In this case it could look like this:

Code: Select all

facts     buttonTimer : timerHandle := erroneous.   predicates     onStartButtonClick : button::clickResponder. clauses     onStartButtonClick(_Source) = button::defaultAction :-         if isErroneous(buttonTimer) then             buttonTimer := tickAction(1000, onButtonTimer)         else             stdio::write("Timer already running\n")         end if.   predicates     onStopButtonClick : button::clickResponder. clauses     onStopButtonClick(_Source) = button::defaultAction :-         if not(isErroneous(buttonTimer)) then             timerKill(buttonTimer),             buttonTimer := erroneous         else             stdio::write("No timer to stop\n")         end if.   predicates     onButtonTimer : (). clauses     onButtonTimer() :-         stdio::write("Timer event from Button\n").
See if you can figure out what the code does yourself. Otherwise ask then I will gladly explain it in details.

(In this code the timer is actually on the form rather than the button, but I don't see any reason to have it on the button).

Re: timerListener not firing

Posted: 24 Aug 2020 15:44
by kwkisiel
Thomas, thanks for your reply. It worked and got me pointed in the right direction. It appears that my misunderstanding was with the TimerListener event. I assumed that when a timer event occurred, the onTimer clause would be called. Much like the MouseDownListener event would cause the onMouseDown clause to be called. I know 'Why' questions usually are not helpful but...Why is the TimerListener behavior different than the other object events (i.e., MosueDownListener)? Changing from vpi::timerSet to window::tickAction which included a specific Action clause did the trick.

The addTimerListener is part of the code that is maintained automatically so no problem there.

Also, I knew that there was a problem with the number of timer handles that could be created but at this point I was not concerned with ensuring that only one-at-a-time would be created. My long term goal is to create a class from which 1000's of instances will be created and each will have its own timer. I read somewhere that I'll be limited to 10000 timers. Your code sample was helpful (and completely understandable) and I thank you for that.

Now on to the next set of challenges...will probably be back soon.