#πŸ”’ Is this the proper way to run a ticking timer for stuff like Tkinter?

209 messages Β· Page 1 of 1 (latest)

dark scroll
#

I was super sleep deprived one day and kept picking at it until I could finally get this logic working, I have no idea if this is commonly used or if I just made a super makeshift method to something already being used that I don't know about.

fiery flameBOT
#

@dark scroll

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

dark scroll
#
TimerBull1 = False
TimerBull2 = True
TimerBull3 = True

def timeticker():
    global TimerBull1, TimerBull2, TimerBull3
    if not TimerBull1:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker1)
        TimerBull1 = True
        return
    if not TimerBull2:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker1)
        TimerBull2 = True
        return
    if not TimerBull3:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker1)
        TimerBull3 = True
        return      

def timeticker1():
    global TimerBull1, TimerBull2, TimerBull3
    if TimerBull1:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker)
        TimerBull2 = False
        return
    if TimerBull2:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker)
        TimerBull3 = False
        return
    if TimerBull3:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker)
        TimerBull1 = False
        return

And before anyone complains about global variables, they HAVE to be otherwise it is unable to access them within the if blocks.

bleak sleet
#

So you can do without the global if you pass them in as parameters.

e.g.

def timeticker(TimerBull1, TimerBull2, TimerBull3):
    if not TimerBull1:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker1)
        TimerBull1 = True
        return
    if not TimerBull2:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker1)
        TimerBull2 = True
        return
    if not TimerBull3:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker1)
        TimerBull3 = True
        return

timeticker(TimerBull1, TimerBull2, TimerBull3)
dark scroll
bleak sleet
#

Although, ideally, this can be further simplified (because it breaks the DRY principle)

def timeticker(TimerBull):
    if not TimerBull:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker)
        TimerBull = True
        return TimerBull

TimerBull1 = False
TimerBull1 = timeticker(TimerBull1)
#

And then repeat for TimerBull 2 and 3

#

But only reusing the same timeticker() function

#

less lines, easier to read and maintain

dark scroll
#

hmm

bleak sleet
#

idk what that window is

dark scroll
bleak sleet
#

ah its tkinter

dark scroll
#

yeah

bleak sleet
#

So you can also pass that in but also, ideally, should be in a class

dark scroll
dark scroll
#

So its hardcoded then?

bleak sleet
#

as per your example, yes

#

So if you wanna use the timeticker function on all 3 timerbulls

def timeticker(TimerBull):
    if not TimerBull:
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)
        window.after(500, timeticker)
        TimerBull = True
        return TimerBull

TimerBull1 = False
TimerBull2 = True
TimerBull3 = True
TimerBull1 = timeticker(TimerBull1)
TimerBull2 = timeticker(TimerBull2)
TimerBull3 = timeticker(TimerBull3)
#

Oh I realized that you set one function to set it to True and the other to False

#

You can have it inverse the value in the function

#

!e

timer1 = True
print(timer1)
timer1 = not timer1
print(timer1)
timer2 = False
print(timer2)
timer2 = not timer2
print(timer2)
fiery flameBOT
dark scroll
#
def timeticker(TimerBull1, TimerBull2, TimerBull3):
    if not TimerBull1:
        window.after(500, timeticker)
        ticking()
        TimerBull1 = True
        TimerBull2 = False
        return TimerBull2
    if not TimerBull2:
        window.after(500, timeticker)
        ticking()
        TimerBull2 = True
        TimerBull3 = False
        return TimerBull3
    if not TimerBull3:
        window.after(500, timeticker)
        ticking()
        TimerBull3 = True
        TimerBull1 = False
        return TimerBull1
bleak sleet
#

So instead of hardcoding the True or False inside the function, you just use not on the variable

dark scroll
#

dhuh

#

now im extremely confused

chrome juniper
#

a lot of this would be better managed with a class and attributes

#

so you don't have to worry about parameters or global

dark scroll
#

for now
I managed to chop it down a bit

def timeticker():
    global TimerBull1, TimerBull2, TimerBull3
    if not TimerBull1:
        TimerBull1 = True
        TimerBull2 = False
        window.after(500, timeticker)
        ticking()
        return TimerBull2
    if not TimerBull2:
        TimerBull2 = True
        TimerBull3 = False
        window.after(500, timeticker)
        ticking()
        return TimerBull3
    if not TimerBull3:
        TimerBull3 = True
        TimerBull1 = False
        window.after(500, timeticker)
        ticking()
        return TimerBull1

def ticking():
    timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
    window.title(timeline)
chrome juniper
#

there's no sense in returning if you're calling the function via after()

#

you can't access that result

dark scroll
#

makes sense

chrome juniper
#

What do these "TimerBull" variables represent?

dark scroll
chrome juniper
#

yeah

dark scroll
#

It's just a name scheme I came up from my annoyance of doing it this way lol

#

TimerBull-

chrome juniper
#

but how are these values used?

#

what are you using them to keep track of?

dark scroll
#

It's like a flow, I have no idea how to describe it

#

So in a way

#

0 1 1
1 0 1
1 1 0
And then it repeats

#

For some reason doing it this way just lets the timer work without the recursion limit

#

I did this same tactic making this button switcher mabob

dark scroll
chrome juniper
#

if you ever want to cycle through values

dark scroll
#

like have it do +1?

chrome juniper
#

!e

options = ['a', 'b', 'c']
current = 0

for i in range(10):
    print(options[current])
    current += 1
    current %= len(options)
fiery flameBOT
chrome juniper
dark scroll
#

It doesn't work like that for the timer though right

#

Because recursion limit

chrome juniper
#

not sure, I've never dealt with recusion limit with tkinter

#

I don't see how 3 timers calling the same function is any better though

dark scroll
#

I did this just now

dark scroll
# chrome juniper I don't see how 3 timers calling the same function is any better though
class timery():

    def timeticker(startup=False):
        global TimerBull1, TimerBull2, TimerBull3
        if startup:
            TimerBull1 = False
            TimerBull2 = True
            TimerBull3 = True
        
        if not TimerBull1:
            TimerBull1 = True
            TimerBull2 = False
            window.after(500, timery.timeticker)
            timery.ticking()
            return 
        if not TimerBull2:
            TimerBull2 = True
            TimerBull3 = False
            window.after(500, timery.timeticker)
            timery.ticking()
            return 
        if not TimerBull3:
            TimerBull3 = True
            TimerBull1 = False
            window.after(500, timery.timeticker)
            timery.ticking()
            return 

    def ticking():
        timeline = datetime.now().strftime("%m/%d/%Y "+" %H:%M:%S "+" %p")
        window.title(timeline)

#(outside of the class)
timery.timeticker(startup=True)
chrome juniper
#

that isn't quite how you would use a class

#

you need an instance and attributes

dark scroll
#

could you give an example

#

btw I also made it rename the files before deleting them (just incase I wanted to recover it)

chrome juniper
#
import tkinter as tk

class Timer:

    def __init__(self, root):
        self.root = root
        self.current_timer = 0
        self.timers = ['A', 'B', 'C']

    def tick(self):
        value = self.timers[self.current_timer] 
        self.current_timer += 1
        self.current_timer %= len(self.timers)
        print(value)
        self.root.after(1000, self.tick)



root = tk.Tk()
timer = Timer(root)



root.after(1000, timer.tick)

root.mainloop()

#

it's not a perfect implementation since I'd even likely be using another class for the tk.Tk, but it's good enough to demonstrate

#

try running it

dark scroll
#

I always see people putting init and I don't understand it's purpose

chrome juniper
#

do you understand the difference between class and instance?

dark scroll
#

I don't even know instances yet πŸ’€

#

My understanding of Python and C++ is so broken and biased unfortunately

chrome juniper
#

you've been working with instances this whole time without realizing it

#

classes are the instructions of a datatype

#

do you know int, str, etc?

dark scroll
#

yeah

chrome juniper
#

!e

print(str)
print(int)
fiery flameBOT
chrome juniper
#

those are classes

#

an instance is the data created of that datatype

#

so "hello" is an instance of str class

#

123 is an instance of int class

dark scroll
#

well that makes sense, for some reason my mind kinda just- doesn't put 2 and 2 together

#

Like

#

My mind goes, oh yeah those are the hardcoded key elements of coding, I don't really label them as classes or instances/etc

chrome juniper
#

when it comes to custom classes, we create instances by calling the class, just like you would with a function

#
class Car:
    pass
dark scroll
#

When I think of arguments I just think of one piece of code sending a message to another piece of code

chrome juniper
#

if I have this Car class, I can create a new instance with Car()

#

new_car = Car()

chrome juniper
#

so now for __init__, it's simply a method of the class that gets called automatically when an instance is created

#

!e

class Car:

    def __init__(self):
        print("A car is born!")


new_car = Car()
fiery flameBOT
chrome juniper
#

so whenever we do Car(), we run the code inside __init__

#

!e

class Car:

    def __init__(self):
        print("A car is born!")


Car()
Car()
Car()
fiery flameBOT
chrome juniper
#

!e

class Car:

    def __init__(self):
        print("A car is born!")


three_cars = [Car(), Car(), Car()]
fiery flameBOT
dark scroll
#

huh okay wow

#

so for my dumbed down brain explanation, and if I'm correct, it's essentially a way to group functions together and call them all at the same time?

chrome juniper
#

they don't have to all be called at the same time

#

a class is a collection of data and behaviours

#

right now my Car class is quite basic. It doesn't really have any data or behaviour (other than printing a message)

#

__init__ is also responsible for receiving any arguments you might want to pass into the instance

#

!e

class Car:

    def __init__(self, colour):
        print(f"A {colour} car is born!")


three_cars = [Car('red'), Car('black'), Car('pink')]
fiery flameBOT
chrome juniper
#

Do you follow what's happening here?

dark scroll
#

That's crazy how much I don't know

#

I follow

chrome juniper
#

this is really only scratching the surface

#

classes can have a bit of a steep learning curve

#

but the basics can be learned fairly quickly

#

the difficult thing about learning classes is more the why than the how

dark scroll
#

I made a class a long time ago but I will assume I did it completely wrong and I'll show you

#
class Pic_GUI():
    mainpic = PhotoImage(file=relative_to_assets("mainpic.png"))
    dllpic = PhotoImage(file=relative_to_assets("dllpic.png"))
    consoledllpic = PhotoImage(file=relative_to_assets("consoledll.png"))
    intervalspic = PhotoImage(file=relative_to_assets("intervals.png"))
    nullbox = PhotoImage(file=relative_to_assets("nullbox.png"))
    checkboxpic = PhotoImage(file=relative_to_assets("checkbox.png"))
    intervalentry = PhotoImage(file=relative_to_assets("intervalentry.png"))
    greenstatpic = PhotoImage(file=relative_to_assets("greenstat.png"))
    redstatpic = PhotoImage(file=relative_to_assets("redstat.png"))
    startlooppic = PhotoImage(file=relative_to_assets("startloop.png"))
    stoplooppic = PhotoImage(file=relative_to_assets("stoploop.png"))
    stoplooppic2 = PhotoImage(file=relative_to_assets("stoploop2.png"))

Yeah I made this back at the end of June

#

Just used it as a way to store all the photo variables

chrome juniper
#

this is one way to use a class, just as a way to organize similar variables under a namespace

dark scroll
#

Ah well thats a relief to know

chrome juniper
#

but it's not the primary use

dark scroll
#

Yeah

chrome juniper
#
class Sizing:

    fill = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
    fill_h = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
    fill_v = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.MinimumExpanding)
    smallest = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
    no_stretch = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
#

I have a similar class for my PySide GUI

dark scroll
#

Geez talk about obfuscation

chrome juniper
#

more like "abstraction"

#

which is one of the pillars of OOP

dark scroll
#

I assume you have an actual job in coding right

chrome juniper
#

one of the goals is to take complex behaviour and slap a simple name on it

chrome juniper
dark scroll
#

Oh damn

chrome juniper
#

but yes, I work(ed) in game dev

dark scroll
#

But hey point is you know a LOT of stuff

chrome juniper
#

coding is more about what you can do and not necessarily just what you know

dark scroll
#

I'm trying to think and wrap my head around how I will use a class to make the timer more cleaner

chrome juniper
#

I like to compare coding languages to spoken languages

#

I could spend time learning italian

#

and maybe that could open up some translation jobs

dark scroll
#

How many years have you been coding?

chrome juniper
#

but it's still about what I could do with the language

#

but it's still about what I could do with the language

chrome juniper
#

I'm self taught though, I didn't learn this in school

dark scroll
#

Ah

#

Yeah me too

chrome juniper
#

I went to school for animation πŸ™‚

dark scroll
#

Which explains why I have many gaping holes in my knowledge

dark scroll
chrome juniper
#

I honestly don't think I touched classes for the first 6 months of python

chrome juniper
#

I still deal a lot with animation, I'm just not the one directly animating anymore

dark scroll
#

Still awesome to know

chrome juniper
#

I deal with setting up characters for animation

#

which can be quite tedious, and is why python is important

dark scroll
#

To automate it?

chrome juniper
#

yes, as much as possible

#

to save time, but also to eliminate human error

dark scroll
#

I made this program today (which includes the timer that I just made a bit of time ago)
And the entire reason I made it was to move a singular file from one directory to another, rename it, etc

#

Just to save time aswell

chrome juniper
#

yeah, that's a big part of what I do as well

#

There's A LOT of files when it comes to making games

#

so keeping it all nice and orderly is super important

dark scroll
#

Specifically because I'm learning on being a reverse engineer at the exact same time and I've been learning a bit of C++
And since I'm a beginner I've just been experimenting a bunch of things with DLLs, and I have to keep recompiling and moving them

#

That's the entire reason I made this one program

#

And then I went into obsession for a couple hours trying to make it as optimized and "efficient" as possible

chrome juniper
#

I honestly don't know what that means, haha. I don't know any c++

dark scroll
chrome juniper
#

what was the game?

dark scroll
#

It was made in Unreal Engine, so you have to inject it with a DLL

dark scroll
#

You've likely never heard of it, but maybe you have

chrome juniper
#

ahh I played that a bit, haha

dark scroll
#

oh wow

#

crazy

chrome juniper
#

maybe for just a few rounds before uninstalling πŸ˜‰

dark scroll
#

you didn't like it?

#

dang, each to their own though

chrome juniper
#

it was so-so. I saw potential though

#

I'm actually developing a fighting game with a small team

dark scroll
#

In the beginning or near end?

chrome juniper
dark scroll
#

I didn't get to actually play in the earlier versions, but I've gotten access to those builds and messed around a bit

#

It was super janky

#

It's alot better in it's current (frozen) state

chrome juniper
#

yeah I'm pretty sure I would get knocked down and then like insta-die

dark scroll
#

If for some reason you want to revisit the game just let me know lol, it's open source

chrome juniper
#

I think I'll pass for now

dark scroll
#

I had a project going on back then called ProjectKO, and I met a reverse engineer who literally got me where I am now

chrome juniper
#

I'm learning unreal right now too

dark scroll
#

He was the one who actually made the server code

#

And then he quit after we got a shutdown "warning" from Iron Galaxy

#

So I'm working on learning all of the stuff so that I can finish it

#

And I've definitely made alot of progress so far

#

Either way I appreciate you taking the time to teach me some of the basics, I actually learned a bit from this

chrome juniper
#

np!

dark scroll
#

I might try to fix the timer later using classes and make the code clean

#

If you are able to + if you could please do me a favor, could you possibly clear / delete these messages or ?clear them or something?
the whole secret project being not so secret

chrome juniper
#

If you're ever interested in how python supports game development, I always recommend this video

dark scroll
#

Yeah definitely

#

I opened it and it's in my "to-do" browser tabs

chrome juniper
dark scroll
#

I see, it's fine honestly (this may or may not come back to bite me but oh well)

#

Thank you either way!

chrome juniper
#

Happy to help!

dark scroll
#

I'll see you in another help ticket in the future

#

Bye for now

#

!close

fiery flameBOT
#
Python help channel closed

This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.