Not responding in tkinter screen - python

Iam building a project tkinter.
Here my Code
from tkinter import *
screen=Tk()
screen.geometry('500x300+400+200')
def play():
from playsound import playsound
playsound("music.mp3")
screen.title("Simple project")
btn=Button(screen,text='play',width=20,command=play).place(x=340,y=260)
screen.mainloop()
And when I click button "play" then tkinter screen is Not responding.
So how can I fix it.
Thank you

You can use threading module.
from tkinter import *
from threading import Thread
screen=Tk()
screen.geometry('500x300+400+200')
def play():
from playsound import playsound
playsound("music.mp3")
def start_play():
t=Thread(target=play)
t.daemon=True
t.start()
screen.title("Simple project")
btn=Button(screen,text='play',width=20,command=start_play).place(x=340,y=260)
screen.mainloop()

Related

Tkinter close protocol when tkinter is threaded

I have this small code that execute a function and in the meanwhile shows an indeterminate tkinter progressbar. When you let the program execute everything works fine while if you try to stop the process by closing the tkinter window you get the RuntimeError: main thread is not in main loop. I understand that the solution could be to bring the bar mainloop in the main thread or alternatively use queue but it is not clear to me how to do this. Here you can find the code with a simple mock function (addit) that executes. Thank you everyone in advance!
import threading
importing tkinter module
import tkinter
import tkinter.ttk as ttk
from tkinter import messagebox
from tkinter import Button
from tkinter import Label
import sys
import time
class tkwindow(threading.Thread):
def __init__(self):
threading.Thread.__init__(self, daemon=True)
def run(self):
self.wbar=tkinter.Tk()
self.wbar.attributes("-topmost", True)
self.wbar.title('Tool')
lb=Label(self.wbar,text='Check in progress')
lb.pack()
pbar = ttk.Progressbar(self.wbar,orient='horizontal', length=500, mode='indeterminate')
pbar.pack(pady=25)
pbar.start(50)
self.wbar.protocol("WM_DELETE_WINDOW", self.on_closing)
self.loopmain()
def loopmain(self):
self.wbar.mainloop()
def quitall(self):
self.wbar.quit()
sys.exit()
def on_closing(self):
if messagebox.askokcancel("Quit", "Do you want to quit?"):
self.wbar.quit()
sys.exit()
def main():
mygui=tkwindow()
mygui.start()
addit(2,3)
mygui.quitall()
def addit(a,b):
time.sleep(3)
print(a+b)
return
if __name__=='__main__':
main()
The structure of the code is only wrong. You should inherit tk.Tk and not threading.Thread. Instead of creating a function for the mainloop, just insert it at the bottom of the run() function (use self instead of self.wbar). Initialize the thread at the start of the run() function. In the main() function you have called start but in the class you defined it as run(). Here is your code if you added the above changes and fixed all errors:
import threading
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import messagebox
from tkinter import Button
from tkinter import Label
import sys
import time
class tkwindow(tk.Tk):
def __init__(self):
super().__init__()
def run(self):
threading.Thread.__init__(self, daemon=True)
self.attributes("-topmost", True)
self.title('Tool')
lb=Label(self, text='Check in progress')
lb.pack()
pbar = ttk.Progressbar(self, orient='horizontal', length=500, mode='indeterminate')
pbar.pack(pady=25)
pbar.start(50)
self.protocol("WM_DELETE_WINDOW", self.on_closing)
self.mainloop()
def quitall(self):
self.quit()
sys.exit()
def on_closing(self):
if messagebox.askokcancel("Quit", "Do you want to quit?"):
self.quitall()
def main():
mygui=tkwindow()
mygui.run()
addit(2,3)
mygui.quitall()
def addit(a,b):
time.sleep(3)
print(a+b)
return
if __name__=='__main__':
main()
There is no way to put the progress bar into the thread. Even if you could, it wouldn't be of any use since it would make the code very complex. So just use this as an alternative.
Updated Code
import threading
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import messagebox
from tkinter import Button
from tkinter import Label
import sys
import time
class tkwindow(tk.Tk):
def __init__(self):
super().__init__()
def run(self):
threading.Thread.__init__(self, daemon=True)
self.attributes("-topmost", True)
self.title('Tool')
lb=Label(self, text='Check in progress')
lb.pack()
pbar = ttk.Progressbar(self, orient='horizontal', length=500, mode='indeterminate')
pbar.pack(pady=25)
pbar.start(50)
self.protocol("WM_DELETE_WINDOW", self.on_closing)
def quitall(self):
self.quit()
sys.exit()
def on_closing(self):
if messagebox.askokcancel("Quit", "Do you want to quit?"):
self.quitall()
def main():
mygui=tkwindow()
mygui.run()
addit(2,3)
mygui.mainloop()
def addit(a,b):
print("ADDIT")
threading.Timer(3, lambda: print(a+b)).start()
if __name__=='__main__':
main()
Probably I have found a way to do just what I wanted using queue. Unfortunately the code kill the main thread abruptly with interrupt_main and not in a nice way as sys.exit() could do but is the only solution I have found for now. The updated code is the following:
import threading
import tkinter
import tkinter.ttk as ttk
from tkinter import messagebox
from tkinter import Button
from tkinter import Label
import sys
import time
from queue import Queue
import _thread
import os
class tkwindow(threading.Thread):
def __init__(self,dataq):
threading.Thread.__init__(self, daemon=True)
self.dataq=dataq
def run(self):
self.wbar=tkinter.Tk()
self.wbar.attributes("-topmost", True)
self.wbar.title('Tool')
lb=Label(self.wbar,text='Check in progress')
lb.pack()
pbar = ttk.Progressbar(self.wbar,orient='horizontal', length=500, mode='indeterminate')
pbar.pack(pady=25)
pbar.start(50)
self.dataq.put(0)
self.loopmain()
def loopmain(self):
self.wbar.protocol("WM_DELETE_WINDOW", self.on_closing)
self.wbar.after(100,self.checkq)
self.wbar.mainloop()
def checkq(self):
v=self.dataq.get()
if v:
if messagebox.askokcancel("Quit", "Do you want to quit?"):
self.wbar.quit()
os._exit(0) #or alternatively _thread.interrupt_main()
def quitall(self):
self.wbar.quit()
sys.exit()
def on_closing(self):
self.dataq.put(1)
self.checkq()
def main():
dataq=Queue()
mygui=tkwindow(dataq)
mygui.start()
addit(2,3)
mygui.quitall()
def addit(a,b):
time.sleep(3)
print(a+b)
return
if __name__=='__main__':
main()

I'm using tkinter GUI and winsound but stop function is not working

from tkinter import *
import winsound
from winsound import PlaySound, SND_FILENAME, SND_LOOP, SND_ASYNC
root = Tk()
root.configure(background='light green')
def playing():
winsound.PlaySound('alarm', winsound.SND_FILENAME)
def stop_sound():
PlaySound(None, SND_FILENAME)
Button(root,text="playing ",font=("Helvetica 15"),command=playing).pack(pady=20)
Button(root,text="Stop",font=("Helvetica 15"),command=stop_sound).pack(pady=20)
root.mainloop()
Fix Updated
In your playing function
You can replace winsoud.PlaySound and winsound.SND_FILENAME with PlaySound and SND_FILENAME.
The complete code will look like this
from tkinter import *
from winsound import PlaySound, SND_FILENAME, SND_LOOP, SND_ASYNC
root = Tk()
root.configure(background='light green')
def playing(): PlaySound('alarm', SND_FILENAME)
def stop_sound(): PlaySound(None, SND_FILENAME)
Button(root,text="playing ",font=("Helvetica 15"),command=playing).pack(pady=20)
Button(root,text="Stop",font=("Helvetica 15"),command=stop_sound).pack(pady=20)
root.mainloop()
Description
The idea is same. The program doesn't know what winsound is since we are not importing it. But the functions we are calling are imported. So no need to prefix them with winsound.
Fix
Include this line with other imports
import winsound
Description
From looking at the code you are not importing the 'winsound' module. You are including from it by not the module itself.
Note
When asking question on StackOverflow kindly share your exceptions/log messages so people can help you easily

tkinter window behaves weirdly and stops responding

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()

Is Playsound able to play two sounds at the same time?

When you press e it will play the sound, which is fine. But when you try to press it while the sound is active it waits until the sound is done to play it again. I need the sounds to be played at the same time.
import tkinter
from playsound import playsound
root = tkinter.Tk()
def key_pressed(event):
playsound('sound.wav')
root.bind("<Key>", key_pressed)
root.mainloop()
Try this:
import tkinter
from playsound import playsound
root = tkinter.Tk()
def key_pressed(event):
playsound('sound.wav', block=False)
root.bind("<Key>", key_pressed)
root.mainloop()

tk messagebox import confusion

I'm just beginning to learn tkinter at the moment, and when importing messagebox I found that I must not really understand import statements.
The thing that confuses me is that:
import tkinter as tk
def text_box():
if tk.messagebox.askokcancel("Quit", "Never Mind"):
root.destroy()
root = tk.Tk()
button = tk.Button(root, text="Press the button", command=text_box)
button.pack()
root.mainloop()
compiles fine, but pressing the button gives the error 'module' object has no attribute 'messagebox', while the code:
import tkinter as tk
from tkinter import messagebox
...
if messagebox.askokcancel("Quit", "Never Mind"):
...
...works without a hitch.
I get a similar error if I import with from tkinter import *.
The help for tkinter shows messagebox in the list of PACKAGE CONTENTS, but I just can't load it in the normal way.
So my question is, why...and what is it about importing that I don't understand?
Just thought I should mention—the code only works in Python 3, and in Python 2.x messagebox is called tkMessageBox and is not defined in tkinter.
tkinter.messagebox is a module, not a class.
As it isn't imported in tkinter.__init__.py, you explicitly have to import it before you can use it.
import tkinter
tkinter.messagebox # would raise an ImportError
from tkinter import messagebox
tkinter.messagebox # now it's available eiter as `messagebox` or `tkinter.messagebox`
try this
import sys
from tkinter import *
... and your code

Categories

Resources