#π Is this the proper way to run a ticking timer for stuff like Tkinter?
209 messages Β· Page 1 of 1 (latest)
@dark scroll
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.
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.
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)
really? That makes sense though after thinking about it
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
hmm
idk what that window is
ah its tkinter
So you can also pass that in but also, ideally, should be in a class
confused on this though, so is TimerBull1=False on the outside or inside of the function?
outside
So its hardcoded then?
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)
:white_check_mark: Your 3.12 eval job has completed with return code 0.
001 | True
002 | False
003 | False
004 | True
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
So instead of hardcoding the True or False inside the function, you just use not on the variable
a lot of this would be better managed with a class and attributes
so you don't have to worry about parameters or global
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)
there's no sense in returning if you're calling the function via after()
you can't access that result
makes sense
What do these "TimerBull" variables represent?
You mean like what does TimerBull mean?
yeah
It's just a name scheme I came up from my annoyance of doing it this way lol
TimerBull-
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
The same code logic is what makes this work
this can be way simplified with a single value and a list
if you ever want to cycle through values
like have it do +1?
!e
options = ['a', 'b', 'c']
current = 0
for i in range(10):
print(options[current])
current += 1
current %= len(options)
:white_check_mark: Your 3.12 eval job has completed with return code 0.
001 | a
002 | b
003 | c
004 | a
005 | b
006 | c
007 | a
008 | b
009 | c
010 | a
yes exactly
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
I did this just now
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)
could you give an example
btw I also made it rename the files before deleting them (just incase I wanted to recover it)
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
I always see people putting init and I don't understand it's purpose
do you understand the difference between class and instance?
I don't even know instances yet π
My understanding of Python and C++ is so broken and biased unfortunately
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?
yeah
!e
print(str)
print(int)
:white_check_mark: Your 3.12 eval job has completed with return code 0.
001 | <class 'str'>
002 | <class 'int'>
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
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
when it comes to custom classes, we create instances by calling the class, just like you would with a function
class Car:
pass
When I think of arguments I just think of one piece of code sending a message to another piece of code
when it comes to learning OOP, it usually reshapes the way you look at data
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()
:white_check_mark: Your 3.12 eval job has completed with return code 0.
A car is born!
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()
:white_check_mark: Your 3.12 eval job has completed with return code 0.
001 | A car is born!
002 | A car is born!
003 | A car is born!
!e
class Car:
def __init__(self):
print("A car is born!")
three_cars = [Car(), Car(), Car()]
:white_check_mark: Your 3.12 eval job has completed with return code 0.
001 | A car is born!
002 | A car is born!
003 | A car is born!
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?
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')]
:white_check_mark: Your 3.12 eval job has completed with return code 0.
001 | A red car is born!
002 | A black car is born!
003 | A pink car is born!
Do you follow what's happening here?
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
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
this is one way to use a class, just as a way to organize similar variables under a namespace
Ah well thats a relief to know
but it's not the primary use
Yeah
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
Geez talk about obfuscation
I assume you have an actual job in coding right
one of the goals is to take complex behaviour and slap a simple name on it
I did until I was let go recently π
Oh damn
but yes, I work(ed) in game dev
But hey point is you know a LOT of stuff
coding is more about what you can do and not necessarily just what you know
I'm trying to think and wrap my head around how I will use a class to make the timer more cleaner
I like to compare coding languages to spoken languages
I could spend time learning italian
and maybe that could open up some translation jobs
How many years have you been coding?
but it's still about what I could do with the language
but it's still about what I could do with the language
about 6
I'm self taught though, I didn't learn this in school
I went to school for animation π
Which explains why I have many gaping holes in my knowledge
Can you animate too?
I honestly don't think I touched classes for the first 6 months of python
yeah, I used to work as an animator before I switched into more technical work
I still deal a lot with animation, I'm just not the one directly animating anymore
Still awesome to know
I deal with setting up characters for animation
which can be quite tedious, and is why python is important
To automate it?
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
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
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
I honestly don't know what that means, haha. I don't know any c++
I'm "hacking" a game that died/shutdown and was designed for online play only, "hacking" it for good, basically getting the game to have private online servers to play on
what was the game?
It was made in Unreal Engine, so you have to inject it with a DLL
Rumbleverse
You've likely never heard of it, but maybe you have
ahh I played that a bit, haha
maybe for just a few rounds before uninstalling π
it was so-so. I saw potential though
I'm actually developing a fighting game with a small team
In the beginning or near end?
I think it was pretty early into the release
Ah, it's improved a lot since then
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
yeah I'm pretty sure I would get knocked down and then like insta-die
If for some reason you want to revisit the game just let me know lol, it's open source
I think I'll pass for now
I had a project going on back then called ProjectKO, and I met a reverse engineer who literally got me where I am now
I'm learning unreal right now too
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
np!
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
If you're ever interested in how python supports game development, I always recommend this video
The thread will get buried pretty quickly, but unfortunately you would have to delete your own messages if you want them gone
I see, it's fine honestly (this may or may not come back to bite me but oh well)
Thank you either way!
Happy to help!
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.