I have this problem in Python. Yesterday, I copied the Countdown Calendar code in Coding Projects with Python and added the 'events.txt'. I checked all the problem to make sure it work. But when I ran it, the text isn't show up. Here is how my documents are set up:
Here's the code:
from tkinter import Tk, Canvas
from datetime import date, datetime
def get_events():
list_events = []
with open('events.txt') as file:
for line in file:
line = line.rstrip('\n')
current_event = line.split('.')
event_date = datetime.strptime(current_event[1], '%d/%m/%y').date()
current_event[1] = event_date
list_events.append(current_event)
return list_events
def days_between_dates(date1, date2):
time_between = str(date1 - date2)
number_of_days = time_between.split(' ')
return number_of_days[0]
root = Tk()
c = Canvas(root, width=800, height=800, bg='black')
c.pack()
c.create_text(100, 50, anchor='w', fill='orange', \
font='Arial 28 bold underline', text='My Countdown Calendar')
events = get_events()
today = date.today()
vertical_space = 100
for event in events:
event_name = event[0]
days_until = days_between_dates(event[1], today)
display = 'It is %s days until %s' % (days_until, event_name)
c.create_text(100, vertical_space, anchor='w', fill='lightblue', \
font='Arial 28 bold', text=display)
I think there are a couple things.
current_event = line.split('.') - I believe this should be a comma, not a period.
Like somebody else has mentioned, if using PyCharm, you need to add root.mainloop() to the end of your file.
Make sure your text file doesn't have any additional lines at the end and there are no spaces between the events and the event dates - just a comma.
I found that this fixed my issues when working on this exercise.
you need root.mainloop() at the end of your code for it to run
Related
This question already has an answer here:
Clock with date and time in tkinter hangs
(1 answer)
Closed 8 months ago.
Digital clock is running based on system time. But after 10 seconds it stops.
Before this you can even see that the last 'tick' is 2 seconds instead of 1 second. That means it slows down somehow.
Why does it happen?
from tkinter import *
from tkinter import ttk
from time import strftime
import datetime
root = Tk()
root.title('Clock')
tabs = ttk.Notebook(root)
tabs.pack()
clock_tab = ttk.Frame(tabs)
timer_tab = ttk.Frame(tabs)
stopwatch_tab = ttk.Frame(tabs)
alarm_tab = ttk.Frame(tabs)
international_time_tab = ttk.Frame(tabs)
tabs.add(clock_tab, text='Clock')
tabs.add(timer_tab, text='Timer')
tabs.add(stopwatch_tab, text='Stopwatch')
tabs.add(alarm_tab, text='Alarm')
tabs.add(international_time_tab, text='International time')
def time():
time_str = datetime.datetime.now().strftime("%H:%M:%S")
date_str = datetime.datetime.now().strftime("%d.%m.%Y")
time_label.config(text = time_str)
time_label.after(1000, time)
date_label.config(text = date_str)
date_label.after(1000, time)
time_label = Label(root,font = ('calibri', 20))
time_label.pack()
date_label = Label(root,font = ('calibri', 15))
date_label.pack()
exit_btn = ttk.Button(
root,
text = 'Exit',
command = lambda: root.quit()
)
exit_btn.pack(fill = 'x')
def exit_func(event):
root.quit()
root.bind('<Return>', exit_func)
time()
mainloop()
Add this root.mainloop. Btw, when I typed time period, I didn't get any intellisense. There is no intellisense. But I can see intellisense in my example.
import sys
from tkinter import *
import time
def timing():
current_time = time.strftime("%H : %M : %S")
clock.config(text=current_time)
clock.after(200,timing)
root=Tk()
root.geometry("600x300")
clock=Label(root,font=("times",60,"bold"),bg="blue")
clock.grid(row=2,column=2,pady=25,padx=100)
timing()
root.mainloop()
I'm kind of new to stackoverflow so I'm not exactly sure if I'm violating any rules right now but I imagine I'm living close to the edge. Regardless, here is my problem.
I'm trying to create a tkinter countdown timer. Everything was going smoothly and I had an app that should be working but the problem is the app begins lagging crazily once I move to a new function.
This is the code:
import time
import tkinter as tk
root = tk.Tk()
root.geometry("453x170")
def setTimer():
hourEntry = tk.Entry(root, width = 10)
hourEntry.grid(row = 1, column = 1, padx = 20, pady = 30)
col1 = tk.Label(root, text = ':')
col1.grid(row = 1, column = 2)
minuteEntry = tk.Entry(root, width =10)
minuteEntry.grid(row = 1, column = 3, padx = 20, pady = 30)
col2 = tk.Label(root, text = ':')
col2.grid(row = 1, column = 4)
secEntry = tk.Entry(root, width = 10)
secEntry.grid(row = 1, column = 5, padx = 20, pady = 30)
def timer():
try:
hours = int(hourEntry.get())
except ValueError:
hours = 0
try:
minutes = int(minuteEntry.get())
except ValueError:
minutes = 0
try:
seconds = int(secEntry.get())
except ValueError:
seconds = 0
for widget in root.winfo_children():
widget.destroy()
totalsecs = seconds + minutes*60 + hours*60*60
for i in range(totalsecs + 1):
print(hours, ':', minutes, ':', seconds)
if seconds == 0 and minutes > 0:
minutes = minutes - 1
seconds = 60
elif seconds == -1 and minutes == 0 and hours > 0:
hours = hours - 1
seconds = 60
seconds = seconds - 1
result = hours, ':', minutes, ':', seconds
for widget in root.winfo_children():
widget.destroy()
if seconds == 0 and minutes == 0 and hours == 0:
time.sleep(1)
label = tk.Label(root, text = result)
label.grid()
print(hours, ':', minutes, ':', seconds)
return None
label = tk.Label(root, text = result)
label.grid()
time.sleep(1)
button = tk.Button(root, text = 'Start', command = timer)
button.grid(row = 2, column = 3, pady = 30)
setTimer()
root.mainloop()
The setTimer function runs fine and allows you enter the amount of seconds minutes and hours. However, when you click the button to go to the new function, the app lags until the timer is done then it shows the result which of course is "0:0:0". I suspected that constantly clearing all the widgets on the screen causes this but even after removing the widget.destroy() code, it lagged the same just that this time, it would end up on a screen showing every number it went through.
I spent hours removing everything one by one to check its effect on the lag but everything yielded the same lag. However, when I removed the time.sleep(1), there was no lag.
Printing the results into the console doesn't lag. It only lags when the labels are on the tkinter app. All print statements in the code are just me showing that it doesn't lag that way.
Because of this, I'm thinking there is some sort of incompatibility between the time module and tkinter since another project I worked on also lagged a lot when using tkinter and time to the point where it was unusable. So I'm completely stumped.
I'm thinking it could be a case of processing power since I'm programming on a Macbook Air but I don't think the time module should be having such an effect.
Here's how to do something like you want without using the time.sleep() function which interferes with tkinter's mainloop() and doesn't use separate threads which can get tricky because tkinter isn't thread-safe.
Instead it uses the universal widget method after() to schedule periodic calls to a function that counts down the time.
Note also that I've made a number of changes to your code so it follows the PEP 8 - Style Guide for Python Code guidelines and so it's more readable and maintainable.
import tkinter as tk
from tkinter.constants import *
from tkinter.messagebox import showerror, showinfo
def start_timer():
try:
hours = int(hourEntry.get())
except ValueError:
hours = 0
try:
minutes = int(minuteEntry.get())
except ValueError:
minutes = 0
try:
seconds = int(secEntry.get())
except ValueError:
seconds = 0
totalsecs = hours*3600 + minutes*60 + seconds
if totalsecs == 0:
showerror(title='Error', message=f'Please enter some amount of time.')
return
for widget in root.winfo_children():
widget.destroy()
clockLabel = tk.Label(root, text=f'{hours:02}:{minutes:02}:{seconds:02}')
clockLabel.place(relx=0.5, rely=0.5, anchor=CENTER)
countdown(clockLabel, totalsecs) # Start count down process.
def countdown(clockLabel, totalsecs):
if totalsecs == 0:
clockLabel.bell()
clockLabel.config(text='Finished')
return
hours, minutes = divmod(totalsecs, 3600)
minutes, seconds = divmod(minutes, 60)
clockLabel.config(text=f'{hours:02}:{minutes:02}:{seconds:02}')
root.after(1000, countdown, clockLabel, totalsecs-1) # Repeat in 1000 ms.
root = tk.Tk()
root.geometry("453x170")
hourEntry = tk.Entry(root, width=10, justify=RIGHT)
hourEntry.grid(row=1, column=1, padx=20, pady=30)
col1 = tk.Label(root, text=':')
col1.grid(row=1, column=2)
minuteEntry = tk.Entry(root, width =10, justify=RIGHT)
minuteEntry.grid(row=1, column=3, padx=20, pady=30)
col2 = tk.Label(root, text=':')
col2.grid(row=1, column=4)
secEntry = tk.Entry(root, width=10, justify=RIGHT)
secEntry.grid(row=1, column=5, padx=20, pady=30)
startButton = tk.Button(root, text='Start', command=start_timer)
startButton.grid(row=2, column=3, pady=30)
root.mainloop()
I was coding a project called "My Countdown Calendar". I was almost done and so I gave what I had so far a test run. I ended up getting this error.
Here is my code.
from tkinter import Tk, Canvas
from datetime import date, datetime
def gete():
liste = []
with open('events.txt') as file:
for line in file:
line = line.rstrip('\n')
currente = line.split(',')
eventd = datetime.strptime(currente[1], '%d/%m/%y').date()
currente[1] = eventd
liste.append(currente)
return liste
def daysbd(date1, date2):
timeb = str(date1-date2)
numberofd = timeb.split(' ')
return numberofd[0]
root = Tk()
c = Canvas(root, width=800, height=800, bg='black')
c.pack()
c.create_text(100, 50, anchor='w', fill='orange', font = 'Arial 28 bold underline', text = 'My Countdown Calendar')
events = gete()
today = date.today()
for event in events:
eventn = event[0]
daysu = daysbd(event[1], today)
display = 'It is %s days until %s ' % (daysu, eventn)
c.create_text(100, 100, anchor='w', fill='lightblue',\
font = 'Arial 28 bold ', text = display)
When parsing a text file, you'll almost always want to skip empty lines. Here's an idomatic pattern for this:
for line in file:
line = line.strip()
if not line:
continue
# process line
If your file format depends on whitespace on the non-empty lines, you can join lines 2 and 3 to if not line.strip().
The program I just wrote is my playground for finding out how Tkinter works.
My question is how do I display my variable "timelabel" as a Label.
I allready made a label called timerefresher yet it doesnt show up.
I am aware that the DigitalClock class isn't written efficiently. I am new to this ;).
def Clockupdate(time):
timelabel = time
timerefresher = Label(root, textvariable=timelabel)
timerefresher.pack()
#print(timelabel) To test if variable made it this far.
class DigitalClock:
def secondrefesher(self):
newtime = ""
while 1 == 1:
oldtime = datetime.datetime.now()
a = str(oldtime.hour)
b = str(oldtime.minute)
c = str(oldtime.second)
curtime = (a+":"+b+':'+c)
if curtime != newtime:
newtime = curtime
#print("made it here")
Clockupdate(newtime)
else:
time.sleep(0.20)
DC = DigitalClock()
root = Tk()
mainlabel = Label(root, text="Hey this is working!")
Pressme = Button(root, text="Press me!", command=Presstoshowtextandpic,
bg='red', fg='white')
Clock = Button(root, text="Clock?", command=DC.secondrefesher, bg='blue',
fg='white')
Photo = PhotoImage(file="test.png")
ShowPhoto = Label(root, image=Photo)
mainlabel.pack()
Pressme.pack()
Clock.pack()
root.mainloop()
Ok so Here is what I would do with your code to accomplish what you are trying to do.
First lets make sure we have the correct imports.
from tkinter import *
import datetime
import time
I created this doNothing() function as a place holder for any commands I am not currently testing.
def doNothing():
pass
Now the way you had your Clockupdate(time): function would cause the label to be added every time you click the clock button. so this is probably not what you want as it just keeps adding new labels instead of replacing the existing one. Take a look at this function. All I do in this is .config() the text to be the time argument from the function. Note you do not need to redefine the time to timelabel or anything of the sort, just use time as your varable.
def Clockupdate(time):
timerefresher.config(text = time)
I don't know if you wanted to use a class for a specific reason but I think you should just use a function here. Also try to keep your quotes consistent. I know they are interchangeable but its good practice to keep them consistent.
def secondrefesher():
newtime = ""
oldtime = datetime.datetime.now()
a = str(oldtime.hour)
b = str(oldtime.minute)
c = str(oldtime.second)
curtime = (a + ":" + b + ":" + c)
if curtime != newtime:
newtime = curtime
Clockupdate(newtime)
Note I always place commands at the end of any config of a button. It helps when managing code so you can just check the end of each line as you scroll through your code. I also changed the command for Pressme to doNothing so I could test the code. You didn't provide the code for Presstoshowtextandpic and would not be able to test the code with out that part. Remember when asking a question here to use MCVE.
root = Tk()
mainlabel = Label(root, text="Hey this is working!")
Pressme = Button(root, text = "Press me!", bg = "red", fg = "white", command = doNothing)
Clock = Button(root, text = "Clock?", bg = "blue", fg = "white", command = secondrefesher)
Photo = PhotoImage(file = "test.png")
ShowPhoto = Label(root, image = Photo)
Here I created the time label just once and then you can call the update function all you want to change the text to current time.
timerefresher = Label(root, text = "")
timerefresher.pack()
mainlabel.pack()
Pressme.pack()
Clock.pack()
root.mainloop()
Here is what I think the completed code should look like for you.
from tkinter import *
import datetime
import time
def Clockupdate(time):
timerefresher.config(text = time)
def secondrefesher():
newtime = ""
oldtime = datetime.datetime.now()
a = str(oldtime.hour)
b = str(oldtime.minute)
c = str(oldtime.second)
curtime = (a + ":" + b + ":" + c)
if curtime != newtime:
newtime = curtime
Clockupdate(newtime)
root = Tk()
mainlabel = Label(root, text = "Hey this is working!")
Pressme = Button(root, text = "Press me!", bg = "red", fg = "white", command = Presstoshowtextandpic)
Clock = Button(root, text = "Clock?", bg = "blue", fg = "white", command = secondrefesher)
Photo = PhotoImage(file = "test.png")
ShowPhoto = Label(root, image = Photo)
timerefresher = Label(root, text = "")
timerefresher.pack()
mainlabel.pack()
Pressme.pack()
Clock.pack()
root.mainloop()
Edit:
In case you are trying to create a clock that is always active and does not require you to click the button you can use .after().
Take a look at this example.
from tkinter import *
import datetime
import time
root = Tk()
mainlabel = Label(root, text = "Hey this is working!")
Photo = PhotoImage(file = "test.png")
timerefresher = Label(root, text = "")
timerefresher.pack()
status_time = ""
def tick():
global status_time
time2 = time.strftime("%H:%M:%S")
if time2 != status_time:
status_time = time2
timerefresher.config(text = time2)
timerefresher.after(200, tick)
tick()
mainlabel.pack()
root.mainloop()
You should have written an MCVE so that one can test your code, especially that things are missing (such as Presstoshowtextandpic()).
When reading the rest of your code, I think you need to read about variable classes and modify Clockupdate() as follows:
def Clockupdate(time):
timelabel = StringVar() # modified
timelabel.set(time) # added
timerefresher = Label(root, textvariable=timelabel.get()) #modified
timerefresher.pack()
P.S. You should write clock_update() instead of Clockupdate()
This question already has answers here:
Making python/tkinter label widget update?
(5 answers)
Closed 7 years ago.
I have a python script which I have written for a Raspberry Pi project, the script reads a value from a micrometer every second, and stores this value as a TkInter StringVar (http://effbot.org/tkinterbook/variable.htm)
What I want to happen is that that string is displayed on the UI as a label, and updated on the UI when the value changes.
I chose to use a Tkinter stringvar instead of a standard string because I thought that Tkinter would then automatically update on the UI, but it doesn't seem to work.
Currently the script displays nothing for the label, and does not update when show sets virtual_reading.
From other threads I have read, the Tkinter method update_idletasks() should force the window to update, but I haven't been able to get this to work.
Can anyone give any guidance on where I'm going wrong?
This is my first go at Python so sorry if this is simple.
import datetime
import csv
from tkinter import *
from tkinter import messagebox
import time
import pigpio
import os
os.system("sudo pigpiod")
root = Tk()
winx = 480
winy = 320
CLOCK=21
DATA=20
g_level=0
g_reading=0
g_bits=0
pi = pigpio.pi()
virtual_reading = StringVar()
def go():
global cb1
global cb2
cb1 = pi.callback(DATA, pigpio.EITHER_EDGE, cbf)
cb2 = pi.callback(CLOCK, pigpio.EITHER_EDGE, cbf)
root.after(1000 ,go)
def show(bits, value):
inch = value & (1<<23)
minus = value & (1<<20)
value = value & 0xfffff
if inch:
reading = value / 2000.0
units = "in"
else:
reading = value / 100.0
units = "mm"
if minus:
sign = "-"
else:
sign = ""
global virtual_reading
virtual_reading = StringVar()
virtual_reading.set("{} {:.3f} {}".format(sign, reading, units))
print(virtual_reading.get())
cb2.cancel()
cb1.cancel()
def measure(event=None):
todays_date = datetime.date.today()
try:
get_tool_no = int(tool_no_entry.get())
if get_tool_no <= 0:
messagebox.showerror("Try Again","Please Enter A Number")
else:
with open("thickness records.csv", "a") as thicknessdb:
thicknessdbWriter = csv.writer(thicknessdb, dialect='excel', lineterminator='\r')
thicknessdbWriter.writerow([get_tool_no] + [todays_date] + [virtual_reading.get()])
thicknessdb.close()
except:
messagebox.showerror("Try Again","Please Enter A Number")
tool_no_entry.delete(0, END)
def cbf(g, l, t):
global g_level, g_reading, g_bits
if g == DATA:
if l == 0:
g_level = 1
else:
g_level = 0
elif g == CLOCK:
if l == pigpio.TIMEOUT:
if g_bits > 10:
show(g_bits, g_reading)
g_reading=0
g_bits=0
elif l == 0:
g_reading = g_reading | (g_level<<g_bits)
g_bits += 1
go()
record_button = Button(root,width = 30,
height = 8,
text='Measure',
fg='black',
bg="light grey", command = measure)
tool_no_entry = Entry(root)
reading_display = Label(root, font=("Helvetica", 22), text = virtual_reading.get())
reading_display.place(x = 50, y =80)
root.resizable(width=FALSE, height=FALSE)
root.geometry('%dx%d' % (winx,winy))
root.title("Micrometer Reader V1.0")
record_button.place(x = 340, y = 100, anchor = CENTER)
tool_no_entry.place(x = 120, y = 250, anchor=CENTER)
tool_no_entry.focus_set()
root.bind("<Return>", measure)
root.mainloop()
cb2.cancel()
cb1.cancel()
pi.stop()
You are misunderstanding how StringVars work. For one, you're recreating the StringVar every second, and only the original one is tied to the label. The one you create isn't associated with any widgets so it will never be visible.
The second problem is that you're associating the variable with the label incorrectly. You're doing this:
reading_display = Label(..., text = virtual_reading.get())
... when you should be doing it like this to get the auto-update feature:
reading_display = Label(..., textvariable = virtual_reading)
That being said, you don't need to use a StringVar at all. You can use it, but it's just an extra object you have to manage. You can directly set the displayed string with the configure method anytime you want
text = "{} {:.3f} {}".format(sign, reading, units)
reading_display.configure(text=text)
Note: you do not need to call update or update_idletasks