How to make tkinter delay a specific function without running another function? - python

I am aware of the .after method, but it requires a function to use.
I tried making a function that does nothing, but it just freezes the screen.
Is there a way to make it so it doens't modify the gui when doing .after? (I tried with a function that did, and it worked)
def doNothing():
return "nothing"
def init_timer(time=25):
global minutes
global onBreak
minutes = 0
onBreak = False
while True:
pomodoro()
def pomodoro():
global pomodoros
if pomodoros < 4:
setTimer(25)
while not(isTimerDone):
print("Timer In Progress")
setTimer(5)
while not(isTimerDone):
pomodoros += 1
else:
setTimer(30)
def timerDone():
global onBreak
global isTimerDone
isTimerDone = True
reminderTitle.config(text="The timer is done!")
onBreak = not(onBreak)
if onBreak:
reminderTitle.config(text="Go on break!")
else:
reminderTitle.config(text="Get to work!")
timer.config(text="Completed")
playsound(f'{os.getcwd()}/Audio/notification.mp3')
def setTimer(mins=25):
global isTimerDone
isTimerDone = False
timer.config(text="In Progress")
window.after(mins * 60 * 1000, timerDone)

This problem occurs when you use while function . So, in order to make your program work properly you have to use .after only , not inside a while function .Here is an example that you could base on to improve your program :
import tkinter as tk
root = tk.Tk()
clock = tk.Label(root)
k = 0
def timing(time):
'''time in minutes'''
global k
k = time
clock.configure(text = 'you still have : ' + str(time) + ' minutes')
def change_value():
global k
if k > 0:
k = k-1
clock.configure(text = 'you still have : ' + str(k)+' minutes')
root.after(60000,change_value)
else :
clock.configure(text = "it's over")
root.after(60000,change_value)
timing(5)
clock.pack()
root.mainloop()

Related

Close button for pyautogui / keyboard module python

I have a program that spams messages, but I need to make such a hot key that will stop the loop, how can I do this?
I trying do this with failsafe, while True wait key, add_hotkey, but it doesn't work
(Sorry for comments in Russian.)
import codecs
import sys
import time
from pathlib import Path
import colorama
import keyboard
from Tools.i18n.makelocalealias import pprint
from art import text2art
import yaml
import pyautogui as pag
pag.FAILSAFE = True
colorama.init()
# Клавиша для активации
hotkey = "9"
# Клавиша для открытия чата
open_hotkey = "shift+t"
# Включить кнопку открытия чата
enable_open_chat_hotkey = True
# Клавиша для отправки сообщения
send_msg_hotkey = "enter"
# Интервал между символами
character_interval = 0
# Интервал между сообщениями
interval = 0.15
close_hotkey = "H+J"
can_run = True
def initConfig():
global hotkey, open_hotkey, enable_open_chat_hotkey, send_msg_hotkey, character_interval, interval, close_hotkey
if Path("config.yml").is_file():
with codecs.open('config.yml', encoding="UTF-8") as f:
loadedConfig = yaml.safe_load(f)
hotkey = loadedConfig['hotkey']
open_hotkey = loadedConfig['open_hotkey']
enable_open_chat_hotkey = loadedConfig['enable_open_chat_hotkey']
send_msg_hotkey = loadedConfig['send_msg_hotkey']
character_interval = loadedConfig['character_interval']
interval = loadedConfig['interval']
close_hotkey = loadedConfig['close_hotkey']
print(
f"Клавиша активации: {hotkey}\n"
f"Клавиша открытия чата (если включено): {open_hotkey}\n"
f"Включить ли клавишу для открытия чата в играх?: " + ("Нет", "Да")[enable_open_chat_hotkey] + "\n"
f"Интервал между символами: {character_interval}\n"
f"Интервал между сообшениями (рекомендуем оставить 0.2, меньше Дота не тянет): {interval}\n"
f"Клавиша деактивации: {close_hotkey}\n"
)
def main():
print(text2art("1000-7 SCRIPT", "standart"))
print(
"Привет, твои текущие настройки программы: \n")
initConfig()
keyboard.add_hotkey(hotkey, lambda: print_1000_7())
keyboard.wait()
def invert_run():
global can_run
can_run = not can_run
print(can_run)
def print_1000_7():
print("What is 1000-7?")
if enable_open_chat_hotkey:
keyboard.press_and_release(open_hotkey)
keyboard.press_and_release('ctrl+a')
keyboard.press_and_release('backspace')
time.sleep(interval)
keyboard.write("What is 1000-7?", character_interval)
keyboard.press_and_release(send_msg_hotkey)
keyboard.press_and_release('ctrl+a')
keyboard.press_and_release('backspace')
keyboard.press_and_release('F9')
keyboard.write("What is 1000-7?")
keyboard.press_and_release(send_msg_hotkey)
if enable_open_chat_hotkey:
keyboard.press_and_release(open_hotkey)
for i in range(5):
if not can_run:
return
print(5 - i)
if enable_open_chat_hotkey:
keyboard.press_and_release(open_hotkey)
keyboard.press_and_release('ctrl+a')
keyboard.press_and_release('backspace')
time.sleep(interval)
keyboard.write(str(5-i), character_interval)
keyboard.press_and_release(send_msg_hotkey)
time.sleep(1)
x = 1000
while x > 0:
if not can_run:
return
var = x - 7
if enable_open_chat_hotkey:
keyboard.press_and_release(open_hotkey)
keyboard.press_and_release('ctrl+a')
keyboard.press_and_release('backspace')
time.sleep(interval)
keyboard.write(f"{x} - 7 = {var}", character_interval)
# print(f"{x} - 7 = {var}")
x = var
time.sleep(interval)
keyboard.press_and_release(send_msg_hotkey)
if __name__ == '__main__':
main()
while True:
keyboard.wait(close_hotkey)
invert_run()
I'm still new to python so I'm sure this is not the best answer, also as much as i could understand you want to create a ON\OFF hotkey and i wanted to do same in some program before, so i made sure that my whole program runs only if variable a==True
and i made a hotkey that changes the 'a', so can u do same ? i mean make whole code work only if 'a' variable is set to True
[ofcourse if there is a 'while True' loop inside one of those spam then im not sure that this will work...]
a=True
def b():
global a
while a :
sleep(0.10)
keyboard.press_and_release('F2')
for i in range(45):
sleep(0.1)
if keyboard.is_pressed('e') :#this is my fail-safe cuz in my program
#i didnt want to wait for the full 4.5 sec in case i wanted to stop
a=False
keyboard.press_and_release('f')
sleep(0.1)
b()
while not a:
if keyboard.is_pressed('e') :
a=True
sleep(0.5)
b()
or another version of it
a=True
def Endb():
global a
if a==False:
a=True
else:
a=False
keyboard.add_hotkey('e',lambda: Endb())
def b():
global a
while a :
sleep(0.10)
keyboard.press_and_release('F2')
for i in range(45):
sleep(0.1)
keyboard.press_and_release('f')
sleep(0.1)
b()
while True :
if keyboard.is_pressed('e'):
Endb()
b()
this one starts\stops when ever i press 'e' as a toggle for On\Off too, and it saves me the trouble of putting the if keyboard.is_pressed('e'): a=False in every step in case i have long code like you
I fixed this problem, i just use keyboard.add_hotkey(hotkey, lambda: on_off(), suppress=True)
and
def on_off():
global enabled
enabled = not enabled

How to print countdown timer and accept user input at the same time (python)?

Clarificaition
This is a repost of my previous question as I am extremely desperate to receive an answer to my problem. I am quite new and if this is against any of the rules, please inform me as I would remove this post if so.
I want to create a quiz-like program where the user would be able to see the countdown timer ticking down every second while they can input their answer at any time. According to my previous post regarding this question, I've tried using threading in my code. Here is a sample of my code.
from threading import Thread
import time
import sys
def func1():
t = 10
for t in range (t,1,-1):
sys.stdout.write('\r' + str(t))
sys.stdout.flush()
time.sleep(1)
if __name__ == '__main__':
Thread(target = func1).start()
answer = input("\tEnter: ")
It does function, but the problem is that the user input is forced to return back (\r) while the timer doesn't properly remove the '0' of the 10 which is not what I desire. Here is the output:
It would be a tremendous help if you could suggest a solution to this problem. Thank you in advance.
After some messing around, I came up with this.
If you would like me to edit this to make it work without the windows, let me know.
import time
import tkinter
from tkinter import messagebox
from tkinter import *
from tkinter import ttk
from threading import Thread
def clear():
print('\033[H\033[J', end='')
run = True
def timer():
tim = int(input("Type how long the countdown should last in seconds: "))
clear()
count = 0
while count < tim and run == True:
clear()
b1 = (tim-count)
c = (str(b1),"second(s) left")
win = Tk()
win = Tk()
win.attributes('-fullscreen', True)
if run == False:
win.destroy()
Label(win, text= c,
font=('Helvetica 20 bold')).pack(pady=20)
win.after(1000,lambda:win.destroy())
win.mainloop()
time.sleep(1)
count += 1
def take_input():
inpu = input()
#Your code
def time_input():
global run
while run == True:
t1 = Thread(target=timer)
t2 = Thread(target=take_input)
t1.start()
t2.start()
t2.join()
thread_running = False
run = False
time_input()
Hope this helps, and you're welcome. 乇卩丨匚卄乂尺
(To stop the window from being fullscreen, change the (window).attributes('-fullscreen', True) to (window).geometry(500x500) or whatever you wish.

How to create a Python timer to count down?

My code:
def timer():
while True:
try:
when_to_stop = 90
except KeyboardInterrupt:
break
except:
print("error, please star game again")
while when_to_stop > 0:
m, s = divmod(when_to_stop, 60)
h, m = divmod(m, 60)
time_left = str(h).zfill(2) + ":" + str(m).zfill(2) + ":" +
str(s).zfill(2) # got cut off, belongs to the line before this
print("time:", time_left + "\r", end="")
if time_left == 0:
print("TIME IS UP!")
time.sleep(1)
when_to_stop -= 1
This works perfectly fine, except that time.sleep means my whole program sleeps, so anything after that while stop for 90 seconds. Any way to fix that?(or make a new timer without time.sleep?)
I think that, alternatively, you could keep track of when the timer starts, and check the time by seeing if the time that's passed is longer than the timer is supposed to last. I'm not sure how much you know about classes and objects in Python, but here is the solution that came to mind:
import datetime
class Timer:
def __init__(self,**kwargs):
self.start = datetime.datetime.now()
self.length = datetime.timedelta(**kwargs)
self.end = self.start+self.length
def isDone(self):
return (self.end-datetime.datetime.now()).total_seconds()<=0
def timeLeft(self):
return self.end-datetime.datetime.now()
def timeElapsed(self):
return datetime.datetime.now()-self.start
Even if you don't quite understand the class itself, if you put it in your code it should work like a charm:
#This has the same options as:
#class datetime.timedelta(days, seconds, microseconds, milliseconds, minutes, hours, weeks)
t = Timer(days=2)
while(not t.isDone()):
#Do other game stuff here....
time_left = t.timeLeft()
print(f"time: {time_left}")
#And here....
print("Done now")

Is function inheritance possible like class inheritance in python? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
from tkinter import *
from tkinter import messagebox
import pygame
import time
pygame.init()
def alarm_time():
hrs = int(hrs_opt_ctrl.get())
min = int(min_opt_ctrl.get())
tme = tme_ctrl.get()
if hrs == int(time.strftime('%I')) and min == int(time.strftime('%M')) and tme == time.strftime('%p'):
# Time is up. Play the sound
alarm_ringtone = pygame.mixer.music.load('alarm_noise.mp3')
pygame.mixer.music.play()
# Don't call after again
else:
# Not time, sleep for 1 second
window.after(1000, alarm_time)
def snooze_time():
snoz_min=(2,5,10,20,30,35,40,45,50,55,59)
snooze=True
while snooze:
try:
min = min + int(snoz_min[minute])
window.after((min)*1000,alarm_time)
except:
messagebox.showerror("Error 404", "Cannot Snooze for given Time")
if minute<=len(snoz_min):
minute+=1
elif minute!=len(snoz_min):
minute=0
else:
pass
snooze=False
window=Tk()
window.title('Alarm')
window.config(background='black')
logo=PhotoImage(file='alarm.gif')
lab_1=Label(window,text='Alarm',bg='black',fg='white',font=('Times',25,'bold')).grid(column=100,row=0)
lab_2=Label(window,bg='black',image=logo).grid(column=300,row=0)
lab_3=Label(window,text='Hours',bg='black',fg='white',font=('Comic',10,'bold')).grid(column=50,row=130)
lab_4=Label(window,text='Minutes',bg='black',fg='white',font=('Comic',10,'bold')).grid(column=85,row=130)
opt_hrs=[]
opt_min=[]
opt_tme=('AM','PM')
minute=0
for i in range(1,13):
opt_hrs.append(i)
for j in range(0,60):
opt_min.append(j)
hrs_opt_ctrl=StringVar()
min_opt_ctrl=StringVar()
tme_ctrl=StringVar()
tme_ctrl.set(opt_tme[0])
hrs_lab=OptionMenu(window,hrs_opt_ctrl,*opt_hrs).grid(column=60,row=130,columnspan=15)
min_lab=OptionMenu(window,min_opt_ctrl,*opt_min).grid(column=86,row=130,columnspan=15)
tme_lab=OptionMenu(window,tme_ctrl,*opt_tme).grid(column=150,row=130)
but_1=Button(window,text='Set Alarm',font=('Comic',10,'bold'),command=alarm_time).grid(column=100,row=240)
but_2=Button(window,text='Snooze',font=('Comic',10,'bold'),command=snooze_time).grid(column=100,row=250)
window.mainloop()
The following code doesnt show any error when run but doesnt play the alarm.
The alarm file is in .mp3 extension and in the same folder as the project.
i probably think that something's wrong in the time module code
or the 'Set Alarm' button is not taking any input.The position of columns and rows are not accurate
As mentioned in the comments, you have it setup to only play the alarm iff the user clicks the button at the time the alarm is set to. Instead, you should check the time every second, and play the alarm at the given time:
def alarm_time():
hrs = int(hrs_opt_ctrl.get())
min = int(min_opt_ctrl.get())
tme = tme_ctrl.get()
if hrs == int(time.strftime('%I')) and min == int(time.strftime('%M')) and tme == time.strftime('%p'):
# Time is up. Play the sound
alarm_ringtone = pygame.mixer.music.load('alarm_noise.mp3')
pygame.mixer.music.play()
# Don't call after again
else:
# Not time, sleep for 1 second
window.after(1000, alarm_time)
Note, I convert everything to int because time.strftime('%I') and time.strftime('%M') return 0-pre-padded strings and your option box does not have 0-pre-padded values, so "1" != "01", etc.
Updated answer with multiple alarms and snooze. I just threw this together so there is plenty of room for improvement:
from tkinter import *
import pygame
import time
pygame.mixer.init()
window = Tk()
window.geometry('300x200')
window.title('Alarm')
#logo = PhotoImage(file='alarm.gif')
lab_1 = Label(window, text='Alarm Clock', font=('Times',20,'bold')).grid(column=200, row=0)
#lab_2=Label(window,image=logo).grid(column=300,row=0,columnspan=3)
lab_3 = Label(window, text='Hours', font=('Comic',10,'bold')).grid(column=50,row=10, columnspan=3)
lab_4 = Label(window, text='Minutes', font=('Comic',10,'bold')).grid(column=90,row=10, columnspan=3)
# Alarm class
class Alarm:
alarm_id = 1
def __init__(self, hours, minutes, ampm, sound_file):
self.sound_file = sound_file
# Convert hours, minutes, ampm to a timestamp
# Save time as a timestamp
t = time.localtime()
t = time.strptime(f"{t.tm_year}-{t.tm_mon}-{t.tm_mday} {hours} {minutes} {ampm}", "%Y-%m-%d %I %M %p")
self.alarm_time = time.mktime(t)
# Number of seconds to snooze
self.snooze_time = None
self.completed = False # Set to True after alarm has gone off
self.id = Alarm.alarm_id
Alarm.alarm_id += 1
# Every time this is called, it checks the time to see if the alarm should go off
def check_time(self, cur_time):
# Use alarm time or snooze time?
on_time = self.snooze_time if self.snooze_time else self.alarm_time
# Since might not be called when seconds is 0, check if it is with one minute of alarm time
time_diff = cur_time - on_time
if not self.completed and time_diff >= 0 and time_diff < 60:
self.completed = True
alarm_ringtone = pygame.mixer.music.load(self.sound_file)
pygame.mixer.music.play()
# Reset after 30 minutes - add 24 hours (daily timer)
elif self.completed and time_diff > 1800 and time_diff < 1860:
self.completed = False
self.snooze_time = None
self.alarm_time += 24 * 60 * 60
def snooze(self, minutes):
if self.completed and pygame.mixer.music.get_busy():
self.snooze_time = time.time() + (minutes * 60)
self.completed = False
pygame.mixer.music.stop()
# Convert to string for printing
def __str__(self):
id_str = f"[{self.id}]: "
if self.completed:
return id_str + ("Alarm in progress" if pygame.mixer.music.get_busy() else "Alarm completed")
elif self.snooze_time:
time_left = int(self.snooze_time - time.time())
minutes = time_left // 60
seconds = time_left % 60
if minutes:
return id_str + f"Snoozing for {minutes} minutes and {seconds} seconds"
else:
return id_str + f"Snoozing for {seconds} seconds"
else:
return id_str + f"Alarm set for {time.ctime(self.alarm_time)}"
# This list holds all alarms
all_alarms = []
# Tell all alarms to check the time
def check_alarms():
now = time.time()
for alarm in all_alarms:
print(f"Checking: {alarm}");
alarm.check_time(now)
# Call again after 1 second
window.after(1000, check_alarms)
# Creates a single object of the Alarm class
# Uses values from the option controls
def create_alarm():
hours = int(hrs_opt_ctrl.get())
minutes = int(min_opt_ctrl.get())
ampm = tme_ctrl.get()
alarm = Alarm(hours, minutes, ampm, "alarm.mp3")
all_alarms.append(alarm)
print(f"Adding: {alarm}");
# Snoozes all active alarms for 2 minutes
def snooze_current():
for alarm in all_alarms:
alarm.snooze(2)
but = Button(window, text='Set Alarm', font=('Comic',10,'bold'), command=create_alarm).grid(column=100,row=15)
snooze = Button(window, text='Snooze', font=('Comic',10,'bold'), command=snooze_current).grid(column=100,row=16)
opt_hrs = []
opt_min = []
opt_tme = ('AM','PM')
for i in range(1,13):
opt_hrs.append(i)
for j in range(0,60):
opt_min.append(j)
hrs_opt_ctrl = StringVar()
min_opt_ctrl = StringVar()
tme_ctrl = StringVar()
hrs_lab = OptionMenu(window, hrs_opt_ctrl, *opt_hrs).grid(column=70,row=10,columnspan=3)
min_lab = OptionMenu(window, min_opt_ctrl, *opt_min).grid(column=100,row=10,columnspan=3)
tme_lab = OptionMenu(window, tme_ctrl, *opt_tme).grid(column=120,row=10,columnspan=3)
# Fill with default values of current time
hrs_opt_ctrl.set(str(int(time.strftime('%I'))))
min_opt_ctrl.set(str(int(time.strftime('%M'))))
tme_ctrl.set(time.strftime('%p'))
check_alarms()
window.mainloop()
pygame.mixer.music.stop()

Python realtime timer

Could anybody advise me on converting the Java Timer class to Python? Currently I am converting a Java program to a Python script. However, Python does not have the Timer/TimerTask library (if it does have this, please enlighten me. Thanks!). I need to be able to reset the Timer. Java has Timer.cancel, but Python doesn't have this. Is there any replacement for it?
timer.cancel();
timer = new Timer("Printer");
MyTask t = new MyTask();
timer.schedule(t, 0, 1000);
Java script timer
class Timerclass extends TimerTask {
//times member represent calling times.
private int times = 0;
public void run() {
times++;
if (times <= 5) {
System.out.println(""+times);
} else {
this.cancel();
//Stop Timer.
System.out.println("Timer Finish");
}
}
}
Currently my code
import time
import threading
class Variable:
count = 0
people = 0
times = 0
def enter():
if int(Variable.count == 1):
print("Entered")
t = threading.Timer(5.0, countdown)
t.start()
else:
print("Entered +1")
t.clear() // Stuck Help
t = threading.Timer(5.0, countdown)
t.start()
def out():
if int(Variable.count > 0):
print("Exited")
elif int(Variable.count < 0):
print("Error")
def countdown():
print("TIMEUP")
while True:
sensor1 = input("Sensor 1: ")
sensor2 = input("Sensor 2: ")
Variable.count+=1
if int(sensor1) == int(sensor2):
Variable.count -= 1
print(Variable.count)
print("error")
elif int(sensor1) == 1:
Variable.people += 1
print(Variable.people)
enter()
elif int(sensor2) == 1:
Variable.people -= 1
print(Variable.people)
out()
else:
print("Error")
i have one problems that i'm stuck in i need to stop the current counting and start a new one whenever the method call
Basically what i want or im looking out for is when i recall this method it will reset or cancel any existing and recount again
Update latest
import time
import threading
class Variable:
count = 0
people = 0
times = 0
def countdown():
print("TIMEUP")
t = threading.Timer(5.0, countdown)
def enter():
if int(Variable.count == 1):
print("Entered")
t.start()
else:
print("Entered +1")
t.cancel()
t.join() # here you block the main thread until the timer is completely stopped
t.start()
def out():
if int(Variable.count > 0):
print("Exited")
elif int(Variable.count < 0):
print("Error")
while True:
sensor1 = input("Sensor 1: ")
sensor2 = input("Sensor 2: ")
Variable.count+=1
if int(sensor1) == int(sensor2):
Variable.count -= 1
print(Variable.count)
print("error")
elif int(sensor1) == 1:
Variable.people += 1
print(Variable.people)
enter()
elif int(sensor2) == 1:
Variable.people -= 1
print(Variable.people)
out()
else:
print("Error")
Anybody can spot my ,istake im getting this error but i t.clear() the process
in start raise RuntimeError("threads can only be started once")
RuntimeError: threads can only be started once
I would suggest using the time module for something like this:
from time import time, sleep
from datetime import datetime, timedelta
nowtime = time()
#Put your script here
x = 1
for k in range(1000):
x+=1
sleep(0.01)
sec = timedelta(seconds=int(time()-nowtime))
d = datetime(1,1,1)+sec
print("DAYS:HOURS:MIN:SEC")
print("%d:%d:%d:%d" % (d.day-1, d.hour, d.minute, d.second))
This assigns the time in seconds at the beginning to a variable, and after the main script has finished, it subtracts the previous time from the current time and formats it in days, hours, minutes, and seconds.
Here is it running:
bash-3.2$ python timing.py
DAYS:HOURS:MIN:SEC
0:0:0:10
bash-3.2$
You could also use the Threading module, which has a built-in cancel method:
>>> import threading
>>> def hello():
... print "This will print after a desired period of time"
...
>>> timer = threading.Timer(3.0, hello)
>>> timer.start() #After 3.0 seconds, "This will print after a desired period of time" will be printed
>>> This will print after a desired period of time
>>> timer.start()
>>> timer = threading.Timer(3.0, hello)
>>> timer.start()
>>> timer.cancel()
>>>
Python actually has a class for this, which includes a cancel method: threading.Timer. It seems to be close enough to the Java Timer class for your needs (The Java Timer also runs in background thread). Here's the example usage from the docs:
def hello():
print "hello, world"
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
Edit:
The problem with your updated code is that you're trying to use the same Timer object more than once. That may be possible in the Java implementation, but in Python you can't reuse a Thread object (Timer is a Thread subclass). You'll need to create a new Timer object after you join() it. Like this:
t = threading.Timer(5.0, countdown)
def enter():
global t # You need this to tell Python that you're going to change the global t variable. If you don't do this, using 't = ..' will just create a local t variable.
if int(Variable.count == 1):
print("Entered")
t.start()
else:
print("Entered +1")
t.cancel()
t.join() # here you block the main thread until the timer is completely stopped
t = threading.Timer(5.0, countdown)
t.start()

Categories