I have developed a code that allows me do set an alarm clock which can play sound effect:
import time
import tkinter as tk
import playsound
window = tk.Tk()
window.title('Alarm clock')
#where the problem lies
def submit():
hr=int(txtHr.get('1.0',tk.END))
minute=int(txtMin.get('1.0',tk.END))
sec=int(txtSec.get('1.0',tk.END))
while True:
time2=time.localtime()
nowHr=time2.tm_hour
nowMin=time2.tm_min
nowSec=time2.tm_sec
if nowHr==hr:
if nowMin ==minute:
if nowSec==sec:
playsound.playsound('D:/Python/Project/Alarm.mp3')
break
window.columnconfigure([0,2],minsize=70)
lbHr=tk.Label(text='Hour',font='italic')
lbHr.grid(row=0,column=0)
lbMin=tk.Label(text='Min',font='italic')
lbMin.grid(row=0,column=1)
lbSec=tk.Label(text='Sec',font='italic')
lbSec.grid(row=0,column=2)
txtHr=tk.Text(fg='white',bg='blue',width='2',height='1')
txtHr.grid(row=1,column=0,pady=5)
txtMin=tk.Text(fg='white',bg='blue',width='2',height='1')
txtMin.grid(row=1,column=1)
txtSec=tk.Text(fg='white',bg='blue',width='2',height='1')
txtSec.grid(row=1,column=2)
lbHow=tk.Label(text='The clock first show you the current time, \nnow type in the time of the alarm.')
lbHow.grid(row=2,columnspan=3)
butStart=tk.Button(text='Set alarm clock',command=submit)
butStart.grid(row=3,columnspan=3,pady=5)
t=time.localtime()
txtHr.insert('1.0',str(t.tm_hour))
txtMin.insert('1.0',str(t.tm_min))
txtSec.insert('1.0',str(t.tm_sec))
window.mainloop()
When I set the alarm clock and the window goes for more than 5 seconds, it stops responding:
Surprisingly, it still works and the alarm still rings. Of course, having a non responding window is not ideal, so how can I fix this? Should I use datetime module, is there even any difference?
You can use threading module and start the while loop on new thread:
import time,threading
import tkinter as tk
import playsound
window=tk.Tk()
window.title('Alarm clock')
#where the problem lies
def submit():
hr=int(txtHr.get('1.0',tk.END))
minute=int(txtMin.get('1.0',tk.END))
sec=int(txtSec.get('1.0',tk.END))
while True:
time2=time.localtime()
nowHr=time2.tm_hour
nowMin=time2.tm_min
nowSec=time2.tm_sec
if nowHr==hr:
if nowMin ==minute:
if nowSec==sec:
playsound.playsound('D:/Python/Project/Alarm.mp3')
break
window.columnconfigure([0,2],minsize=70)
lbHr=tk.Label(text='Hour',font='italic')
lbHr.grid(row=0,column=0)
lbMin=tk.Label(text='Min',font='italic')
lbMin.grid(row=0,column=1)
lbSec=tk.Label(text='Sec',font='italic')
lbSec.grid(row=0,column=2)
txtHr=tk.Text(fg='white',bg='blue',width='2',height='1')
txtHr.grid(row=1,column=0,pady=5)
txtMin=tk.Text(fg='white',bg='blue',width='2',height='1')
txtMin.grid(row=1,column=1)
txtSec=tk.Text(fg='white',bg='blue',width='2',height='1')
txtSec.grid(row=1,column=2)
lbHow=tk.Label(text='The clock first show you the current time, \nnow type in the time of the alarm.')
lbHow.grid(row=2,columnspan=3)
butStart=tk.Button(text='Set alarm clock',command=lambda: [threading.Thread(target=submit).start()])
butStart.grid(row=3,columnspan=3,pady=5)
t=time.localtime()
txtHr.insert('1.0',str(t.tm_hour))
txtMin.insert('1.0',str(t.tm_min))
txtSec.insert('1.0',str(t.tm_sec))
window.mainloop()
Related
Why does in the code below button1 hang until the time.sleep(10) has completed.
I can only assume tKinter is waiting for the click event to finish before updating it's paint function.
I want on button1 click the state to change to DISABLED as in the code straight away, not when mainformbutton1press() has finished.
I have put time.sleep(10) to mimic rest of code functions - but the actual programme will be many minutes instead.
EDIT! - sleep is just there to show how tkinter hangs. My real programme has lots more code and no sleep function - and it takes a long time to process data with the hung GUI as mentioned. No more sleep suggestions please :)
import tkinter as tk
from tkinter import ttk
from tkinter.constants import DISABLED, NORMAL
import time
# ==================================================
class App:
def __init__(self, tk, my_w):
self.button1 = tk.Button(my_w, text="START", width=34, command = self.mainformbutton1press)
self.button1.grid(columnspan=3, row=6, column=1,padx=10,pady=20, ipadx=20, ipady=20)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def mainformbutton1press(self):
self.button1.config(text="PLEASE WAIT...")
self.button1['state'] = DISABLED
# DO REST OF PROCESSING
# TO MIMIC THIS:
time.sleep(10)
print("doing...")
# ==================================================
if __name__ == "__main__":
my_w = tk.Tk()
my_w.geometry("430x380")
my_w.resizable(False, False)
app = App(tk, my_w)
my_w.mainloop() # Keep the window open
Tk.mainloop is a sort of while loop. time.sleep() stops the loop for a particular period of time. That makes the window unresponsive. You might use .after function:
class App:
def __init__(self, tk, my_w):
self.my_w=my_w
....
def continue_next(self):
print("Doing")
....
def mainformbutton1press(self):
self.button1.config(text="PLEASE WAIT...")
self.button1['state'] = DISABLED
# DO REST OF PROCESSING
# TO MIMIC THIS:
self.my_w.after(10000,self.continue_next)
The only change you need to make to your code is to insert an update to your button.
The 10 second delay might need to be shortened (10 seconds is a long time to wait)
self.button1.config(text="PLEASE WAIT...")
self.button1['state'] = DISABLED
# INSERT UPDATE HERE
self.button1.update()
# DO REST OF PROCESSING
# TO MIMIC THIS:
time.sleep(1)
print("doing...")
I am creating a timer for my quiz app and I decided to try it out first in a separate program,
however when I run the following code and press the 'start timer' button the app simply stops responding
and I am forced to close it through the task manager
from tkinter import *
import time
root=Tk()
root.geometry('{}x{}'.format(300,200))
lb=Label(root,text='')
lb.pack()
def func(h,m,s):
lb.config(text=str(h)+':'+str(m)+':'+str(s))
time.sleep(1)
s+=1
func(h,m,s)
if s==59:
m=1
s=0
bt=Button(root,text='start timer',command=lambda:func(0,0,0))
bt.pack()
root.mainloop()
You need to use root.after instead of time.sleep. Here's another answer about making a timer. This is what it looks like applied to your code:
from tkinter import *
import time
root=Tk()
root.geometry('{}x{}'.format(300,200))
lb=Label(root,text='')
lb.pack()
def func(h,m,s):
lb.config(text=str(h)+':'+str(m)+':'+str(s))
s+=1
if s==59:
m=1
s=0
root.after(1000, lambda: func(h,m,s))
bt=Button(root,text='start timer',command=lambda:func(0,0,0))
bt.pack()
root.mainloop()
I am trying to write a program where i have removed the main window close options and providing a exit button to the user to close the program.
After pressing i need to do some processing in the background which would be time consuming, i don't want user to close the program while that is going on accidentally. Is there a way to remove all buttons from the messagebox which is presented ?
import tkinter as tk
from win32api import GetSystemMetrics
from tkinter import messagebox
def on_closing():
pass
def exit():
messagebox.showinfo("Wait", "Please wait for background process to complete")
root.destroy()
root = tk.Tk()
root.resizable(width=False, height=False)
root.protocol("WM_DELETE_WINDOW", on_closing)
width = GetSystemMetrics(0)
height = GetSystemMetrics(1)
root.geometry('{}x{}'.format(width,height))
exitButton = tk.Button(root,text="Exit",width=15,command=exit)
exitButton.grid(row=0,column=1,padx=6,pady=6)
root.overrideredirect(True)
root.mainloop()
In the Background : There are some files generated on user's machine and i would like to archive them using python library. The files can go maybe sometime at 1GB so i think it would take more amount of time, if the laptop on which it is run is having very less computing power. And this would be the case for my base hence i want them just to wait until that popup is closed. This i can define in user manual.
I am not sure what work you want to do, but for this example I'm doing a work of printing something and then sleeping and then printing it. So this takes about 20 seconds. And in those 20 seconds you wont be able to exit the GUI.
import tkinter as tk
from win32api import GetSystemMetrics
from tkinter import messagebox
import time
import threading
def on_closing():
if started == False: #if work is not going on, then quit
root.destroy()
else: # else show the message.
messagebox.showinfo("Wait", "Please wait for background process to complete")
def work():
global started
started = True #mentioning that the work started
print('Hey')
time.sleep(5)
print('There')
time.sleep(5)
print('Whats Up')
time.sleep(5)
print('Cool?')
time.sleep(5)
started = False #mentioning that the work stopped
started = False #initially work is not started
root = tk.Tk()
root.resizable(width=False, height=False)
root.protocol("WM_DELETE_WINDOW", on_closing)
width = GetSystemMetrics(0)
height = GetSystemMetrics(1)
root.geometry('{}x{}'.format(width,height))
exitButton = tk.Button(root,text="Exit",width=15,command=on_closing)
exitButton.grid(row=0,column=1,padx=6,pady=6)
Button = tk.Button(root,text="Work",width=15,command=threading.Thread(target=work).start)
Button.grid(row=1,column=1,padx=6,pady=6)
# root.overrideredirect(True)
root.mainloop()
Here, started acts like a flag. You have to set it to True before starting your work and set it to False after it ends.
You can ignore the fact that I created a new button and used threading, it was just to simulate to you an example of work done. Threading helps the GUI to not freeze. Though I'm not sure if this will work with root.overrideredirect(True), but I think you can get rid of it.
I'm working on a tkinter GUI in Python to produce error messages in a new window. When running the code as shown below, the error noise plays, then it pauses for several seconds before opening the window. If I comment out the line with winsound, it opens it just fine.
import tkinter as tk
import winsound
class Error_Window:
def __init__(self, txt):
self.root = tk.Tk()
self.root.title("Error")
self.lbl = tk.Label(self.root, text=txt)
self.lbl.pack()
winsound.PlaySound("SystemExit", winsound.SND_ALIAS)
self.root.mainloop()
I suspect that it may be due to the error noise playing in full before reaching the mainloop command. One solution to this could be running the sound in a separate thread, but I've heard multithreading with tkinter should be avoided. Any tips on getting it to open smoothly at the same time as the noise is played?
Try this, the reason why it does that is the whole program is should we say in ONE THREAD/ MAIN THREAD so it would do first or execute first the sound then pop up the window. I think there's no problem with working with threads in tkinter just like what #jasonharper said
import tkinter as tk
import winsound
import threading
class Error_Window:
def __init__(self, txt):
self.root = tk.Tk()
self.root.title("Error")
self.lbl = tk.Label(self.root, text=txt)
th = threading.Thread(target=self.__play_sound,args=[])
th.start()
self.lbl.pack()
self.root.mainloop()
def __play_sound(self):
winsound.PlaySound("SystemExit", winsound.SND_ALIAS)
Error_Window("Hi")
I am writing a python script to display images, play music, and show a video on a raspberry pi when inputs are triggered. While i was working on this project I decided I wanted to add a webcam into the script. I played around with different webcam streamers until I found MPlayer which seemed to have the fastest frame rate and used the least resources. problem was, the MPlayer gui was hidden behind the tkinter windows that I was using to display the images. I tried several different things to bring the MPlayer window to the front and to make the tkinter windows go away but nothing seemed to work. Here's my code:
import sys
import os
import time
import subprocess
import RPi.GPIO as GPIO
if sys.version_info[0] == 2:
import Tkinter
tkinter = Tkinter
else:
import tkinter
from PIL import Image, ImageTk
import board
import neopixel
x=1
GPIO.setmode(GPIO.BCM)
pixels = neopixel.NeoPixel(board.D10, 38)
pixels.fill((0, 0, 0))
GPIO.setwarnings(False)
GPIO.setup(17,GPIO.OUT)
GPIO.setup(18,GPIO.OUT)
GPIO.setup(27,GPIO.OUT)
GPIO.setup(22,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
GPIO.setup(25,GPIO.OUT)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.output(17,GPIO.LOW)
GPIO.output(18,GPIO.LOW)
GPIO.output(27,GPIO.LOW)
GPIO.output(22,GPIO.LOW)
GPIO.output(24,GPIO.LOW)
GPIO.output(25,GPIO.LOW)
def showPIL(pilImage, exVar = 0):
try:
root.withdraw()
root.destroy()
root.update()
except:
pass
root = tkinter.Toplevel()
if x == 1:
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
else:
w, h = 100, 100
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
#root.focus_set()
root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
canvas = tkinter.Canvas(root,width=w,height=h)
canvas.pack()
canvas.configure(background='black')
imgWidth, imgHeight = pilImage.size
if imgWidth > w or imgHeight > h:
ratio = min(w/imgWidth, h/imgHeight)
imgWidth = int(imgWidth*ratio)
imgHeight = int(imgHeight*ratio)
pilImage = pilImage.resize((imgWidth,imgHeight), Image.ANTIALIAS)
image = ImageTk.PhotoImage(pilImage)
imagesprite = canvas.create_image(w/2,h/2,image=image)
root.update()
showPIL(Image.open("Data/blank.png"))
while not GPIO.input(4):
pass
music = subprocess.Popen(['cvlc', '/home/pi/Desktop/Data/music.mp3'])
showPIL(Image.open("Data/trophy.png"))
time.sleep(1)
GPIO.output(22,GPIO.HIGH)
time.sleep(0.5)
GPIO.output(27,GPIO.HIGH)
time.sleep(0.5)
GPIO.output(18,GPIO.HIGH)
time.sleep(0.5)
GPIO.output(17,GPIO.HIGH)
time.sleep(1)
showPIL(Image.open("Data/poison.png"))
pixels.fill((0, 255, 0))
os.system("pkill tk")
x=0
showPIL(Image.open("Data/blank.png"))
x=1
camera = subprocess.Popen(['mplayer', '-fs', 'tv://'])
os.system("wmctrl -a MPlayer")
time.sleep(8)
camera.kill()
os.system("omxplayer -b '/home/pi/Desktop/Data/movie.mp4'")
showPIL(Image.open("Data/gun.png"))
GPIO.output(24,GPIO.HIGH)
GPIO.output(25,GPIO.HIGH)
while not GPIO.input(23):
pass
pixels.fill((0, 0, 0))
showPIL(Image.open("Data/dumbell.png"))
time.sleep(1)
showPIL(Image.open("Data/pipe.png"))
time.sleep(1)
showPIL(Image.open("Data/noose.png"))
time.sleep(1)
music.kill()
showPIL(Image.open("Data/blank.png"))
end = subprocess.Popen(['cvlc', '/home/pi/Desktop/Data/end.wav'])
time.sleep(8)
end.kill()
Ok so there are a few key problems here.
One massive problem is your try/except statement.
Your try except is always going to do pass. There is never going to be a time where you can destroy() something and then call update() on it. This will always result in an error and therefor the except statement of pass will run.
Next root = tkinter.Toplevel() is a problem. Because you never define the tkinter instance or what root should be you create a toplevel window instead and this will result in an instance of tkinter being opened but without a variable name to work with. That said root here is only defined locally to the function and thus any time the function is called again there is not record of root for the function to try to destroy because it has not been created yet as far as the function knows. You will need to define your root as a global variable for something like this.
Even if this works for you there should be 2 problems. One is an extra blank window showing up and 2 is that window not closing on its own when you close the toplevel window.
Next you are trying to use sleep while also running a tkinter instance. These things are not compatible without the use of threading so you need to either work threading into this or preferable learn how to use after(). After() is how tkinter manages timed events.
Instead of using Toplevel() here you needto be using Tk(). Instead of destroying and rebuilding your GUI each update you should just update your window instead. Going on the scope of what you are attempting to do you should probably play around a bit more with tkinter and learn how the event manager works before trying the raspberry pi project. Once you have a sold grasp on the Tkinter GUI and its event based process you will be able to do the more complicated stuff easier.