Clock's clicking does not work in simoultaneous with countdown timer - python-3.x

I am using tkinter and winsound.
I want the sound and the countdown timer to work simultaneously.
Right now, once the clicking sound is over the timer appears.
I have seen some countdown timers examples which use "after". Ex: self.after(1000, self.countdown). But I need both in simoultaneous.
import tkinter as tk
from tkinter import Tk
from nBackTools.NBackTools import *
from nBackTools.ZBack import *
#To play sounds
import winsound
from winsound import *
import numpy as np
class NBack:
def __init__(self, master):
##Title of the window
self.master = master
master.title("N-Back")
##It measures the screen size (width x height + x + y)
##The opened window will be based on the screen size
master.geometry("{0}x{1}-0+0".format(master.winfo_screenwidth(), master.winfo_screenheight()))
self.canvas = tk.Canvas(master, width=master.winfo_screenwidth(), height=master.winfo_screenheight(), \
borderwidth=0, highlightthickness=0, bg="grey")
self.canvasWidth = master.winfo_screenwidth()
self.canvasHeight = master.winfo_screenheight()
##If removed, a white screen appears
self.canvas.grid()
"""
BREAK TIMER
"""
self.play()
self.canvas.create_text(((self.canvasWidth/2), (self.canvasHeight/2)-130), text="LET'S TAKE A BREAK!", font=(None, 90))
self.display = tk.Label(master, textvariable="")
self.display.config(foreground="red", background = "grey", font=(None, 70), text= "00:00")
self.display.grid(row=0, column=0, columnspan=2)
def play(self):
return PlaySound('clock_ticking.wav', SND_FILENAME)
root = Tk()
my_gui = NBack(root)
root.mainloop()

Doing 2 things at once is called "asynchronous". To enable that mode in winsound you need the ASYNC flag:
def play(self):
PlaySound('clock_ticking.wav', SND_FILENAME | SND_ASYNC)
You will still need to use after to get the countdown to work.

Related

Is there a way to make tkinter windows work independantly Tkinter?

I have been looking to create a code that opens a second tkinter window to display stuffs live while a program is running on my main window. However, doing so, my main window gets frozen during 5s and then displays stuff on my second window when it is completed.
Is there a way to live display in the second window ?
My code below:
import tkinter as tk
from tkinter import ttk
import time
class PopUpLog(tk.Tk):
def __init__(self, parent):
tk.Tk.__init__(self)
self.y=5
tk.Button(self.master, text="Write in pop-up", command=self.write).pack(side="left")
# canvas
frameL = tk.Frame(self)
frameL.pack(side="left", fill="both")
self.canvasL = tk.Canvas(frameL, height=800, width=800)
self.canvasL.pack(fill="both", expand=True)
# scrollbar
vsb = ttk.Scrollbar(self, orient="v", command=self.canvasL.yview)
vsb.pack(side="left", fill="y")
self.canvasL.configure(yscrollcommand=vsb.set)
self.canvasL.bind("<Configure>", lambda e:self.canvasL.configure(scrollregion=self.canvasL.bbox("all")))
def write(self, text="hi im a pop-up"):
for i in range(5):
self.canvasL.create_text(5, self.y, anchor='nw', justify='left', text=text)
self.y += 25
time.sleep(1)
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
tk.Button(self, text="Open window", command=self.popup).pack(side="left")
def popup(self):
self.top = PopUpLog(self)
self.top.geometry("400x400")
self.top.title("pop-up")
self.top.mainloop()
if __name__ == "__main__":
root = App()
root.mainloop()
So far, the program runs for 5s and then displays everything in self.top. BUT I need a live display (made every time create_text is called) in self.top but I can't even get that.
I am sorry if this is redundant to another question asked but I couldn't find helpful enough information.
Thanks a lot !
time.sleep is the reason why your window is freezing. This is the case for virtually any GUI toolkit. If you want the updates to happen incrementally you can use the after method which will execute the callback you assign after a certain number of milliseconds.
Also there should only be one mainloop. There is no need to start one per window and doing so could cause problems.
Here is an example using the after method:
class PopUpLog(tk.Tk):
def __init__(self, parent):
tk.Tk.__init__(self)
self.y=5
self.c=5 # counter
tk.Button(self.master, text="Write in pop-up", command=self.write).pack(side="left")
# canvas
frameL = tk.Frame(self)
frameL.pack(side="left", fill="both")
self.canvasL = tk.Canvas(frameL, height=800, width=800)
self.canvasL.pack(fill="both", expand=True)
# scrollbar
vsb = ttk.Scrollbar(self, orient="v", command=self.canvasL.yview)
vsb.pack(side="left", fill="y")
self.canvasL.configure(yscrollcommand=vsb.set)
self.canvasL.bind("<Configure>", lambda e:self.canvasL.configure(scrollregion=self.canvasL.bbox("all")))
def write(self, text="hi im a pop-up"):
if self.c > 0:
self.canvasL.create_text(5, self.y, anchor='nw', justify='left', text=text)
self.y += 25
self.c -= 1 # reduce counter
self.after(1000, self.write) # call again in 1 second
else:
self.c = 5 # when counter is 0 reset counter
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
tk.Button(self, text="Open window", command=self.popup).pack(side="left")
def popup(self):
self.top = PopUpLog(self)
self.top.geometry("400x400")
self.top.title("pop-up")
if __name__ == "__main__":
root = App()
root.mainloop()

button to take frame screenshot

can someone help me take a screnshot of a specific frame?
been playing with these, but cant seem to specify just the frame
import pyautogui
#im1 = pyautogui.screenshot()
#im1.save('my_screenshot.png')
#im2 = pyautogui.screenshot('my_screenshot2.png')
from tkinter import *
import time
from PIL import ImageTk, Image
import pyautogui as pg
# Create an instance of tkinter frame or window
win = Tk()
# Set the size of the window
win.geometry("700x350")
frm2shoot = Frame(win)
frm2shoot.grid(column=0, row=0)
lbl = Label(frm2shoot, width=16, text="testing testing:", justify=LEFT, anchor="w").grid(row=0, column=0, sticky=W, pady=2)
# Define a function for taking screenshot
def screenshot():
random = int(time.time())
filename = "/Users/ricardosimoes/Desktop/"+ str(random) + ".jpg"
ss = pg.screenshot(filename)
ss.show()
frm2shoot.deiconify()
# Create a Button to take the screenshots
button = Button(win, text="Take Screenshot", font=('Aerial 11 bold'), background="#aa7bb1", foreground="white", command=screenshot)
button.grid(column=5, row=0)
win.mainloop()
Anyone have any idea how to do this??

how to display a timer in python

hey i am making a program which records desktop screen.
So what i want to do is when ever i click on my start button(tkinter Gui) in my gui window.
It should start a timer like 3.... ,2.... ,1.... in big font directly on my desktop screen and not on my tkinter window. and then my function should start.
How can i do that ..
import tkinter as tk
from tkinter import *
root = Tk()
root.title("our program")
start_cap =tk.button(text='start recording' command=start_capute)
start_cap.pack()
root.mainloop()
Not mentioning the functions and the entire code here as not necessary the code is working fine and i just want to add a new feature of the timer in it.
An minimal example:
import tkinter as tk
# from tkinter import *
def Start():
def Count(Number):
if Number == -1:
win.withdraw()
print("Start") # what you want to do
return False
NumberLabel["text"] = Number
win.after(1000,Count,Number-1)
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
win = tk.Toplevel()
win.geometry("+%d+%d"%((screen_width-win.winfo_width())/2,(screen_height-win.winfo_height())/2)) # make it in the center.
win.overrideredirect(1)
win.wm_attributes('-topmost',1) # top window
win.wm_attributes('-transparentcolor',win['bg']) # background transparent.
NumberLabel = tk.Label(win,font=("",40,"bold"),fg='white')
NumberLabel.pack()
win.after(0,lambda :Count(3))
win.mainloop()
root = tk.Tk()
root.title("our program")
start_cap = tk.Button(text='start recording',command=Start)
start_cap.pack()
root.mainloop()

Python code activated with checkbox/button

I want to call function doit when Checkbutton is ON and stop it when it's OFF.
I tried to do it with button and it kinda works, but when I have my CheckButton in ON and I click my button my window freeze and I can't turn it off again.
from tkinter import *
import PIL.ImageGrab
from PIL import ImageGrab
import time
import cv2
import numpy as np
import pyautogui
import random
def doit():
time.clock()
while label_text.get()=="ON":
rgb = PIL.ImageGrab.grab().load()[1857,307]
print(rgb)
print(time.clock())
else:
print('module is turned OFF')
window = Tk()
label_text = StringVar()
label = Label(window, textvariable=label_text)
label_text.set("OFF")
check=Checkbutton(window, text=label_text.get(), variable=label_text,
onvalue="ON", offvalue="OFF")
label.pack()
check.pack(side="left")
b = Button(window, text="OK", command=doit)
b.pack()
window.mainloop()
When you run long-runnign process - your while loop - then mainloop can't work and it can't get mouse/keyboard events from system, sends events to widgets, updates widgets, redraws window.
You can run doit once - without while - and then use after(time, doit) to run it after some time. This way mainloop will have time to do its job.
def doit():
time.clock()
if label_text.get() == "ON":
rgb = PIL.ImageGrab.grab().load()[1857,307]
print(rgb)
print(time.clock())
after(50, doit)
else:
print('module is turned OFF')
Or use window.update() in while to give mainloop time to update elements.
def doit():
time.clock()
while label_text.get() == "ON":
rgb = PIL.ImageGrab.grab().load()[1857,307]
print(rgb)
print(time.clock())
window.update()
else:
print('module is turned OFF')
If PIL.ImageGrab.grab() runs longer then you may have to run it in separated thread.

Convert Matplotlib embedding in tkinter code from defs to a class

I am trying to convert some code from the matplotlib documentation site that embeds a matplotlib graph into tkinter from a module containing defs into a module containing a class. This code is taken directly from matplotlib (https://matplotlib.org/gallery/user_interfaces/embedding_in_tk_sgskip.html) and works exactly as expected. However for my purposes I need this in the format of a class rather than a grouping of defs within a module. Here is the original matplotlib code:
import tkinter
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure
import numpy as np
root = tkinter.Tk()
root.wm_title("Embedding in Tk")
fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH,
expand=1)
toolbar = NavigationToolbar2Tk(canvas, root)
toolbar.update()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH,
expand=1)
def on_key_press(event):
print("you pressed {}".format(event.key))
key_press_handler(event, canvas, toolbar)
canvas.mpl_connect("key_press_event", on_key_press)
def _quit():
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL
tstate
button = tkinter.Button(master=root, text="Quit", command=_quit)
button.pack(side=tkinter.BOTTOM)
tkinter.mainloop()
# If you put root.destroy() here, it will cause an error if the window
# is closed with the window manager.
It is easy enough to convert the figure creation portion of this code into a class, but I am unable to figure out how to get the on_key_press and the toolbar sections to code properly.
This is my class code, which creates the plot but all my attempts at adding the toolbar and having key presses work have failed.
class matplotlibAsClass:
def __init__(self, master):
self.master = master
self.frame = Frame(self.master)
self.create_chart()
self.frame.pack(expand=YES, fill=BOTH)
def create_chart(self):
fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
canvas = FigureCanvasTkAgg(fig, self.master)
canvas.draw()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
if __name__ == '__main__':
root = Tk()
matplotlibAsClass(root)
root.mainloop()
Any help on how to convert the full matplotlib code, where the key presses and the toolbar works, into a fully functioning class would be greatly appreciated.
Here is code I have written that does not work:
The following code has been corrected and now works properly.
class matplotlibAsClass:
def __init__(self, master):
self.master = master
self.frame = Frame(self.master)
self.create_chart()
self.frame.pack(expand=YES, fill=BOTH)
def create_chart(self):
self.master.wm_title("Embedding in Tk")
fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
canvas = FigureCanvasTkAgg(fig, self.master)
canvas.draw()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
canvas.mpl_connect("key_press_event", self.on_key_press)
toolbar = NavigationToolbar2Tk(canvas, self.master)
toolbar.update()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
self.button = Button(self.master, text="Quit",command=self._quit)
self.button.pack(side=BOTTOM)
def on_key_press(event):
print("you pressed {}".format(event.key))
key_press_handler(event, canvas, toolbar)
def _quit(self):
self.master.quit() # stops mainloop
#self.master.destroy()
if __name__ == '__main__':
root = Tk()
matplotlibAsClass(root)
root.mainloop()
when I run this code I get the following error:
File
"/Users/Me/Mee/python_db_programs/simpletestgui_sc_two.py",
line 104, in create_stockchart
canvas.mpl_connect("key_press_event", on_key_press)
NameError: name 'on_key_press' is not defined
After changing the on_key_press to self.on_key_press I get the following error:
File "/Users/Me/Mee/python_db_programs/simpletestgui_sc_two.py", line
111, in create_stockchart
self.button = Button(self.master,
text="Quit",command=self._quit())
TypeError: _quit() takes 0 positional arguments but 1 was given
After correcting the def _quit() to def _quit(self) I get the following error:
File
"/Users/Me/Mee/python_db_programs/simpletestgui_sc_two.py",
line 111, in create_stockchart
self.button = Button(self.master, text="Quit",
command=self._quit())
_tkinter.TclError: can't invoke "button" command: application has been
destroyed
Based upon the previous error I commented out the self.master.destroy() portion of the def _quit and now the chart loads and the toolbar works but the quit button doesn't actually cause the widget to quit.
The final correction, which I didn't fully catch from a previous comment was to change command=self._quit() to command=self._quit and now everything works correctly.

Resources