How to use tick() in a class [Python 3.x] - python-3.x

So basically I am doing a school project and it involves classes and tkinter, I want to put my tick() function into the class so that I can have a clock in my program, however I can't seem to get it to work when I add it to a class?
Any help/advice would be appreciated.
import urllib.request
from tkinter import *
from tkinter import ttk
import time
class MainWindow(object):
def __init__(self):
self.root = Tk()
self.root.state("zoomed") #to make it full screen
self.root.title("Vehicle Window Fitting - Management System")
self.root.configure(bg="grey80")
self.frame_1 = Frame(self.root, width=1350, height=50)
self.frame_1.pack(side=TOP, fill=X, expand=1, anchor=N)
self.title_lbl = Label(self.frame_1, font=('arial', 12, 'bold'), text="Vehicle Window Fitting - Management System", bd=5, anchor=W)
self.title_lbl.pack(side=LEFT) #puts title on left side
self.clockFrame = Frame(self.frame_1, width=100, height=50, bd=4, relief="ridge")
self.clockFrame.pack(side=RIGHT)#puts clock frame on right
self.clockLabel = Label(self.clockFrame, font=('arial', 12, 'bold'), bd=5, anchor=E)
self.clockLabel.pack() #puts the number in the clock frame
def tick(self, curtime=''): #acts as a clock, changing the label when the time goes up
newtime = time.strftime('%H:%M:%S')
if newtime != curtime:
curtime = newtime
self.clockLabel.config(text=curtime)
self.clockLabel.after(200, tick, curtime)
(more code here but irrelevant)
then:
window = MainWindow()
clock = window.tick()
Everything is in place correctly but the clock won't change it is stationary. I have managed to get it working outside of a class but how do I implement it into a class?

fixed by changing
self.clockLabel.after(200, tick, curtime)
to
self.clockLabel.after(200, self.tick, curtime)
took me a long time to figure that one out haha

Related

Python tkinter create multiple variables

I started to code with tkinter and class methods. I try to code a to-do-list where I can create multiple entries by pressing a button below the entry. And a button next to the entry should change the color of the entry if pressed. The problem now is, that when I create multiple entries, the buttons only change the latest entry. So my question is how do I specify the entry when created?
Sry for obvious mistakes, Im new to coding :p
import tkinter as tk
from tkinter.constants import ANCHOR, CENTER, X
from tkinter import messagebox
class App():
def __init__(self):
self.window = tk.Tk()
self.window.title("To-Do-List")
self.window.geometry("700x700")
self.x_but, self.y_but = 0.05, 0.2
self.x_ent, self.y_ent = 0.05, 0.2
self.x_but2 = 0.3
self.check_var = True
self.start_frame()
self.grid1()
self.window.mainloop()
def start_frame(self):
self.label1 = tk.Label(text="To Do List", font=("", 30))
self.label1.place(relx=0.5, rely=0.05, anchor=CENTER)
def grid1(self):
self.button1 = tk.Button(text="Create", command= self.create_field)
self.button1.place(relx = self.x_but, rely= self.y_but)
def create_field(self):
self.y_but += 0.05
self.button1.place(relx= self.x_but, rely= self.y_but)
self.entry1 = tk.Entry()
self.entry1.place(relx= self.x_ent, rely= self.y_ent)
self.button_check = tk.Button(text="✅", height= 1,command=self.check)
self.button_check.place(relx= self.x_but2, rely=self.y_ent)
self.y_ent += 0.05
def check(self):
if self.check_var:
self.entry1.configure(bg="Green")
self.check_var = False
else:
self.entry1.configure(bg="White")
self.check_var = True
app = App()
You are changing the bg of self.entry1 which keeps overwriting itself each time an entry is created, so when button is clicked, it is always the last entry. The easiest solution is to define a parameter for check and then pass the required entry as an argument to it.
So the method would be:
def check(self,ent):
if self.check_var:
ent.configure(bg="Green")
self.check_var = False
else:
ent.configure(bg="White")
self.check_var = True
...and your button would be:
self.button_check = tk.Button(text="✅", height= 1,command=lambda x=self.entry1: self.check(x))
Also I hope you have a good reason to use place because using grid can make your life much easier, in this case.
For more explanation, read: Tkinter assign button command in loop with lambda

Clock's clicking does not work in simoultaneous with countdown timer

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.

Picture disappear after change in Tkinter

I have this problem: I created this program with Python3 and Tkinter, that show the picture of a place (like mountain or sea) and the program speak what is the place shown in the picture. The problem is when the picture change, it only appears for a few moments, just the time the program say what place is, and the disappear and remain only the label where it is written what represent the picture.
This is the code:
from tkinter import *
from PIL import Image,ImageTk
import pyttsx3
root = Tk()
root.title("Try change image")
root.geometry("1000x600")
root.resizable(height=FALSE,width=FALSE)
Leftframe = Frame(root)
Leftframe.pack(side = LEFT)
Rightframe = Frame(root)
Rightframe.pack(side=RIGHT)
engine = pyttsx3.init()
voices = engine.getProperty('voices')
rate = engine.getProperty('rate')
engine.setProperty('rate', rate -20)
for voice in voices:
engine.setProperty('voice',voice.id)
def start():
global back_label,label
back = ImageTk.PhotoImage(file=directory mountain picture)
back_label = Label(Leftframe,image = back)
back_label.pack()
label=Label(Rightframe,text="Mountain")
label.pack()
root.update()
engine.say("Mountain")
engine.runAndWait()
def change():
back_label.destroy()
label.destroy()
back = ImageTk.PhotoImage(file=directory sea picture)
back_label1 = Label(Leftframe,image = back)
back_label1.pack()
label1 = Label(Rightframe,text="Sea")
label1.pack()
root.update()
engine.say("Sea")
engine.runAndWait()
start()
change()
root.mainloop()
I hope you understand what I want to do, every help will be appreciated

Scheduling order of events with tkinter OOP

I am using tkinter in python 3.6 to display a blue square in the middle of a window. At each click the blue square should disappear and reappear after 2 seconds on a different random location. When running the following code, the blue square (referred as stimulus) does not disappear. Everything else seem to work properly.
This is the code:
import tkinter as TK
import random as RAN
class THR:
def __init__(self, root):
self.root = root
self.root.config(background='black')
self.screenYpixels = 600
self.screenXpixels = 1024
self.ITI = 2000
self.background = TK.Canvas(root, width=1024, height=600, bg='black',
bd=0, highlightthickness=0, relief='ridge')
self.background.pack()
self.newtrial()
def newtrial(self):
self.xpos = RAN.randrange(200, 1000)
self.ypos = RAN.randrange(100, 500)
self.stimulus = TK.Canvas(root,width=100,height=100,bg='blue', bd=0,
highlightthickness=0, relief='ridge')
self.stimulus.place(x=self.xpos, y=self.ypos, anchor="c")
self.stimulus.bind("<Button-1>", self.response)
self.exitbutton()
def response(self, event):
self.stimulus.place_forget()
self.intertrialinterval()
def intertrialinterval(self, *args):
self.root.after(self.ITI,self.newtrial())
def exitbutton(self):
self.exitButton = TK.Button(self.root, bg="green")
self.exitButton.place(relx=0.99, rely=0.01, anchor="c")
self.exitButton.bind("<Button-1>", self.exitprogram)
def exitprogram(self, root):
self.root.quit()
root = TK.Tk()
THR(root)
root.mainloop()
Here a list of things I tried but that did not work
Using time.sleep instead of root.after
Changing the way a newtrial() is called
Putting the sleep or after in different places
The last couple of hours searching the web for similar problems / solutions did not really help. I would like to fix this and at the same time understand what am I doing wrong.
As it turns out the list of links on the right of this webpage provided me with the solution just 3 minutes after posting the question.
This is the original thread Python Tkinter after event OOPS implementation
and here I write the solution:
dropping the parenthesis in the function called with the after method. So this self.root.after(self.ITI,self.newtrial()) is self.root.after(self.ITI,self.newtrial)
Unfortunately I still do not understand how that fixed the problem..

TTKCalendar selection return Python

I have this ttk calendar and my program is meant to update a field when a date in the calendar widget is pressed.
Here are the start_date and end_date fields:
start_date = StringVar()
start_date = ttk.Entry(f2, width=15, textvariable=start_date)
start_date.grid(column=2, row=1, sticky=E)
ttk.Label(f2, text="Start date:", width=10).grid(column=1, row=1, sticky=E)
end_date = StringVar()
end_date = ttk.Entry(f2, width=15, textvariable=end_date)
end_date.grid(column=2, row=2, sticky=E)
ttk.Label(f2, text="End date:", width=10).grid(column=1, row=2, sticky=E)
Here's the function that the button triggers:
def callbackCal():
root2=Toplevel(f2)
ttkcal = ttkcalendar.Calendar(root2,firstweekday=calendar.SUNDAY)
ttkcal.pack(expand=1, fill='both')
root2.update()
root2.minsize(root2.winfo_reqwidth(), root2.winfo_reqheight())
Here's the button code:
b=ttk.Button(f2, width=4, text="Cal", command=callbackCal).grid(column=3,row=1, sticky=W)
Thanks to NorthCat's help, I was able to get this far. And I know the ttk calendar has the methods _pressed() , _show_selection() and selection(). But I have no idea how I can use them in order to show the selected date when it is clicked. And also, to close the calendar widget once that is done.
Thanks a lot! and sorry for these newbie questions.
I don't pretend to understand the code, but I found an answer to another question that suggested a few changes, the answer was from kalgasnik
Python tkinter with ttk calendar
Then I made this change :-
def __init__(self, master=None, selection_callback=None, **kw):
and added this in the init function
self.selection_callback = selection_callback
In the _pressed function I added
if self.selection_callback:
self.selection_callback(self.selection)
Basically adding a callback to get the values when a date is clicked.
My sample callback program was :-
import calendar
import tkinter as TK
import tkinter.font
from tkinter import ttk
from ttk_calendar import Calendar
import sys
class Test():
def __init__(self, root):
self.root = root
self.root.title('Ttk Calendar')
frame = ttk.Frame(self.root)
frame.pack()
quit_button = ttk.Button(frame, text="Calendar", command=self.use_calendar)
quit_button.pack()
self.calendarroot = None
def use_calendar(self):
if not self.calendarroot:
self.calendarroot=TK.Toplevel(self.root)
ttkcal = Calendar(master=self.calendarroot, selection_callback=self.get_selection, firstweekday=calendar.SUNDAY)
ttkcal.pack(expand=1, fill='both')
self.calendarroot.update()
self.calendarroot.minsize(self.calendarroot.winfo_reqwidth(), self.calendarroot.winfo_reqheight())
else:
self.calendarroot.deiconify() # Restore hidden calendar
def get_selection(self, selection):
print (selection)
self.calendarroot.withdraw() # Hide calendar - if that is what is required
if __name__ == '__main__':
root = tkinter.Tk()
x = Test(root)
root.mainloop()
I tried to destroy the TopLevel frame but got an error, hence I used withdraw and deiconify, not best, but at least I got something to work.
A bit of a muddled answer I realize, but you might be agle to figure out a better solution.

Resources