Forum Archive

Close Timer in ui Custom Class using @ui.in_background

Phuket2

I wanted an auto_close function (async) in a custom ui.View class. I wanted to keep it as simple as possible without using date time and keeping the interface responsive . It's not meant to be exact, but close.
date time is used, just to to test the approx accuracy.
Below is a test of what is in my real class. I think the variance could easily be put down to other factors. Just post in case someone has some comments. This is not my forte, but I was happy with my solution. But opened to being to told I lost the plot.

import ui
import datetime, time

class Test (ui.View):
    def __init__(self, duration = 1.0):
        self.frame = (0,0,300,300)
        self.background_color = 'white'
        btn = ui.Button(title = 'start')
        btn.width = 100
        btn.border_width = .5
        # hmmmmmmm, center does not work ( as you would expect it too )
        # eg. btn.center = self.center
        btn.center = (self.center[0], self.center[1] - (44/2))
        btn.action = self.auto_close_timer
        self.add_subview(btn)
        self.auto_close_duration = float(duration)

    @ui.in_background
    def auto_close_timer(self, sender):
        # try to stay responsive regardless of the time
        # set.  its not meant to be exact, but its very close
        # for this close enough
        sender.enabled = False
        n = self.auto_close_duration
        st = datetime.datetime.now()
        while True:
            n -= self.auto_close_duration / 10.
            if n < 0.0 : break
            time.sleep(self.auto_close_duration / 10.)
        #print datetime.datetime.now() - st
        self.name = str(datetime.datetime.now() - st)
        sender.enabled = True


if __name__ == '__main__':
    t = Test(1.5)
    t.present('sheet')
JonB

@Phuket2 Why not just use ui.delay rather than a sleep loop? If this is supposed to be an inactivity timer, you could just use ui.cancel_delay whenever activity is detected.

Also, if there is the possibility of any other ui.in_background happening at the same time, you need to use ui.delay or a threading.thread, ( or see my run_async decorator that I have posted before) as no other ui.in_background calls will start until this one has completed.

Phuket2

@JonB , I want to cry sometimes. BUT yes, you are 100% correct. Thank you. But that's why I post. It would be horrible to have my code when such an elegant solution is there starring me in the face. But it's my learning curve, I guess.
Maybe that crazy crap I come up with will come in handy one day 😁

Phuket2

@JonB , revised version of the test code. is a lot of extra just for testing. But so clean now for the timer part. Also a lot more accurate timings . Thanks again

import ui
import datetime, time

class Test (ui.View):
    def __init__(self, duration = 1.0):
        self.frame = (0,0,300,300)
        self.background_color = 'white'
        btn = ui.Button(title = 'start')
        btn.width = 100
        btn.border_width = .5
        # hmmmmmmm, center does not work ( as you would expect it too )
        # eg. btn.center = self.center
        btn.center = (self.center[0], self.center[1] - (44/2))
        btn.action = self.JonB_way
        self.fire_obj = btn
        self.add_subview(btn)
        self.auto_close_duration = float(duration)
        self.start = None

    def JonB_way(self, sender):
        self.fire_obj.enabled = False
        self.start = datetime.datetime.now()
        ui.delay(self.fire_delay, self.auto_close_duration)

    def fire_delay(self):
        self.name = str(datetime.datetime.now() - self.start)
        self.fire_obj.enabled = True