Tkinter - For Loop too early - python

I have a code for a "Magic Mirror" where I want to display clock, title and news (in Japanese).
I have a whole code that works fine with a news code inside it - In Tkinter loop - news code takes whole messages with json, hide everything except of title, put them to the list and shows loop through it to show messages one by one. It works well in terminal, but I have a struggles to put it into Tkinter window loop - It loops through it and shows only the last news subject - I would like them all, one every 10 seconds, or so... Is there a way to do it please? I will be happy for every answer, thanks.
Here is THE Code
import tkinter as tk
from tkinter import *
startupscreen = tk.Tk()
startupscreen.title('Magic Mirror: Python Mod')
welcometext = tk.Label(startupscreen, font = ('caviar dreams', 40), bg='black', fg='white')
startupscreen.configure(background='black')
startupscreen.overrideredirect(True)
welcometext.config(text='Mirror: Vuoristo Mod')
welcometext.pack(side=LEFT, padx= 120, pady=80)
# Gets the requested values of the height and widht.
windowWidth = startupscreen.winfo_reqwidth()
windowHeight = startupscreen.winfo_reqheight()
# Gets both half the screen width/height and window width/height
positionRight = int(startupscreen.winfo_screenwidth()/3 - windowWidth/2)
positionDown = int(startupscreen.winfo_screenheight()/2 - windowHeight/2)
# Positions the window in the center of the page.
startupscreen.geometry("+{}+{}".format(positionRight, positionDown))
startupscreen.update()
import time
from newsapi import NewsApiClient
import os
import feedparser
import json
from time import sleep
decrypt = list()
global iteration
global timecount
global repull
global sleep
iteration = 0
timecount = 0
repull = 0
sleep = 0
while True:
def tick(time1=''):
time2 = time.strftime("%H")
if time2 != time1:
time1 = time2
clock_frame.config(text=time2)
clock_frame.after(200, tick)
def tickk(time3=''):
time4 = time.strftime(":%M:%S")
if time4 != time3:
time3 = time4
clock_frame2.config(text=time4)
clock_frame2.after(200, tickk)
#This function waits for a certain amount of 'tocks' and then initiates 'newsheader' -function
def tock():
global timecount
global repull
global sleep
global decrypt
newstitle.after(200, tock)
if timecount < 20:
timecount +=1
else:
timecount = 0
newsheader()
if repull < 200:
repull +=1
if sleep < 800:
sleep+=1
else:
sleep = 0
motiondetector()
#This function iterates over the news headlines. Iteration is the news number, 'itemlist' brings out only the title.
def newsheader():
url = 'https://news.google.com/rss?hl=ja&gl=JP&ceid=JP:ja'
d = feedparser.parse(url)
news = list()
for i, entry in enumerate(d.entries, 1):
p = entry.published_parsed
sortkey = "%04d%02d%02d%02d%02d%02d" % (p.tm_year, p.tm_mon, p.tm_mday, p.tm_hour, p.tm_min, p.tm_sec)
tmp = {
"title": entry.title,
#"link": entry.link,
"sortkey": sortkey
}
news.append(tmp)
news = sorted(news, key=lambda x: x['sortkey'])
myDict = {}
# HERE IS THE PROBLEM, I HAVE LIKE 30 news IN `frequency`, BUT IT SHOWS ONLY LAST ONE
for d in news:
c = d['title']
myDict[c] = myDict.get(c,0)+1
frequency = myDict.keys()
frequency = list(frequency)
for x in range(len(frequency)):
source.config(text=str(frequency[x]))
x += 1
root = tk.Tk()
root.title('Mirror')
lab = Label(root, text=" 日本", font = ('', 40), bg='black', fg='white')
lab.pack(anchor=SW, fill=X, padx=45)
masterclock = tk.Label(root)
masterclock.pack(anchor=NW, fill=X, padx=45)
masterclock.configure(background='black')
clock_frame = tk.Label(root, font = ('caviar dreams', 130), bg='black', fg='white')
clock_frame.pack(in_=masterclock, side=LEFT)
clock_frame2 = tk.Label(root, font = ('caviar dreams', 70), bg='black', fg='white')
clock_frame2.pack(in_=masterclock, side=LEFT, anchor = N, ipady=15)
newstitle = tk.Label(root, font = ('caviar dreams', 30), bg='black', fg='white')
newstitle.pack(side=BOTTOM, anchor=W, fill=X)
source = tk.Label(root, font = ('caviar dreams', 20), bg='black', fg='white')
source.pack(side=BOTTOM, anchor=W, fill=X)
newsheader()
tick()
tickk()
tock()
root.attributes("-fullscreen", True)
root.configure(background='black')
startupscreen.destroy()
root.mainloop()

This code use function display_next_item to get next element from list frequency and put in Label. And it use after() to do it again after 1 second. You can set 10 seconds but for test I use smaller value.
For tests I also had to removed fullscreen and newsapi (which I don't have installed)
import tkinter as tk
from tkinter import *
startupscreen = tk.Tk()
startupscreen.title('Magic Mirror: Python Mod')
welcometext = tk.Label(startupscreen, font = ('caviar dreams', 40), bg='black', fg='white')
startupscreen.configure(background='black')
startupscreen.overrideredirect(True)
welcometext.config(text='Mirror: Vuoristo Mod')
welcometext.pack(side=LEFT, padx= 120, pady=80)
# Gets the requested values of the height and widht.
windowWidth = startupscreen.winfo_reqwidth()
windowHeight = startupscreen.winfo_reqheight()
# Gets both half the screen width/height and window width/height
positionRight = int(startupscreen.winfo_screenwidth()/3 - windowWidth/2)
positionDown = int(startupscreen.winfo_screenheight()/2 - windowHeight/2)
# Positions the window in the center of the page.
startupscreen.geometry("+{}+{}".format(positionRight, positionDown))
startupscreen.update()
import time
#from newsapi import NewsApiClient
import os
import feedparser
import json
from time import sleep
decrypt = list()
global iteration
global timecount
global repull
global sleep
iteration = 0
timecount = 0
repull = 0
sleep = 0
while True:
def tick(time1=''):
time2 = time.strftime("%H")
if time2 != time1:
time1 = time2
clock_frame.config(text=time2)
clock_frame.after(200, tick)
def tickk(time3=''):
time4 = time.strftime(":%M:%S")
if time4 != time3:
time3 = time4
clock_frame2.config(text=time4)
clock_frame2.after(200, tickk)
#This function waits for a certain amount of 'tocks' and then initiates 'newsheader' -function
def tock():
global timecount
global repull
global sleep
global decrypt
newstitle.after(200, tock)
if timecount < 20:
timecount +=1
else:
timecount = 0
newsheader()
if repull < 200:
repull +=1
if sleep < 800:
sleep+=1
else:
sleep = 0
motiondetector()
#This function iterates over the news headlines. Iteration is the news number, 'itemlist' brings out only the title.
def newsheader():
url = 'https://news.google.com/rss?hl=ja&gl=JP&ceid=JP:ja'
d = feedparser.parse(url)
news = list()
for i, entry in enumerate(d.entries, 1):
p = entry.published_parsed
sortkey = "%04d%02d%02d%02d%02d%02d" % (p.tm_year, p.tm_mon, p.tm_mday, p.tm_hour, p.tm_min, p.tm_sec)
tmp = {
"title": entry.title,
#"link": entry.link,
"sortkey": sortkey
}
news.append(tmp)
news = sorted(news, key=lambda x: x['sortkey'])
myDict = {}
for d in news:
c = d['title']
myDict[c] = myDict.get(c,0)+1
global frequency
frequency = list(myDict.keys())
def display_next_item():
global frequency
global next_index
next_index += 1
if next_index >= len(frequency):
next_index = 0
source.config(text=str(frequency[next_index]))
root.after(1000, display_next_item)
frequency = [] # value at start
next_index = 0 # value at start
root = tk.Tk()
root.title('Mirror')
lab = Label(root, text=" 日本", font = ('', 40), bg='black', fg='white')
lab.pack(anchor=SW, fill=X, padx=45)
masterclock = tk.Label(root)
masterclock.pack(anchor=NW, fill=X, padx=45)
masterclock.configure(background='black')
clock_frame = tk.Label(root, font = ('caviar dreams', 130), bg='black', fg='white')
clock_frame.pack(in_=masterclock, side=LEFT)
clock_frame2 = tk.Label(root, font = ('caviar dreams', 70), bg='black', fg='white')
clock_frame2.pack(in_=masterclock, side=LEFT, anchor = N, ipady=15)
newstitle = tk.Label(root, font = ('caviar dreams', 30), bg='black', fg='white')
newstitle.pack(side=BOTTOM, anchor=W, fill=X)
source = tk.Label(root, font = ('caviar dreams', 20), bg='black', fg='white')
source.pack(side=BOTTOM, anchor=W, fill=X)
newsheader()
tick()
tickk()
tock()
display_next_item() # <- start displaying
#root.attributes("-fullscreen", True)
root.configure(background='black')
startupscreen.destroy()
root.mainloop()

You need to use threading. And you can create a Repeating class or a Background class to perform your news reading every 10 seconds like this.

Related

Python tKinter - Is there a way to get rid of existing label before making a new count-up?

I've found a countdown code and modified it so it counts up to a given number. It all works, but every time I push the button to run the functions, the existing label stays there and the new one gets put on top. (If I pack them, they get put underneath each other). It's because they get created inside the function, but I can't seem to find a way around it.
It might be a newbie question, but I'm just trying to learn :)
Code:
import time
from tkinter import *
import threading
betongtrykk = Tk()
betongtrykk.geometry("400x300")
canvas = Canvas(
betongtrykk,
bg = "#FFFFFF",
height = 300,
width = 400,
bd = 0,
highlightthickness = 0,
relief = "ridge"
)
canvas.place(x = 0, y = 0)
utnyttelseres = 65
def cd(timer_label_obj,ts):
while ts < utnyttelseres:
timer_label_obj.config(text=ts)
ts+=1
timer_label_obj.place(x=100, y=150)
time.sleep(0.01)
if ts == utnyttelseres:
timer_label_obj.config(text=utnyttelseres)
def countup(t):
timer = Label(betongtrykk)
th = threading.Thread(target=cd,args=[timer,t])
th.start()
submitCountdown = Button(betongtrykk, padx=5, pady=5, text="Submit", font=("Arial", 20), command= lambda:countup(0))
submitCountdown.place(x= 100, y=100)
betongtrykk.mainloop()
You can use the <widget>.destroy() method on the Label widget once the countdown is complete. This method will delete the widget and remove it from the screen.
Corrected Code:
import time
from tkinter import *
import threading
betongtrykk = Tk()
betongtrykk.geometry("400x300")
canvas = Canvas(
betongtrykk,
bg = "#FFFFFF",
height = 300,
width = 400,
bd = 0,
highlightthickness = 0,
relief = "ridge"
)
canvas.place(x = 0, y = 0)
utnyttelseres = 65
def cd(timer_label_obj,ts):
while ts < utnyttelseres:
timer_label_obj.config(text=ts)
ts+=1
timer_label_obj.place(x=100, y=150)
time.sleep(0.01)
if ts == utnyttelseres:
timer_label_obj.config(text=utnyttelseres)
timer_label_obj.destroy()
def countup(t):
timer = Label(betongtrykk)
th = threading.Thread(target=cd,args=[timer,t])
th.start()
submitCountdown = Button(betongtrykk, padx=5, pady=5, text="Submit", font=("Arial", 20), command = lambda:countup(0))
submitCountdown.place(x= 100, y=100)
betongtrykk.mainloop()
Alternate Solution:
If you want the countdown label to be removed JUST before the next countdown starts, you can make timer a global variable and use the .destroy() method on it before creating the new countdown label in countup.
def cd(timer_label_obj,ts):
while ts < utnyttelseres:
timer_label_obj.config(text=ts)
ts+=1
timer_label_obj.place(x=100, y=150)
time.sleep(0.01)
if ts == utnyttelseres:
timer_label_obj.config(text=utnyttelseres)
def countup(t):
global timer
try:
timer.destroy()
except NameError:
pass
timer = Label(betongtrykk)
th = threading.Thread(target=cd,args=[timer,t])
th.start()

To perform the timer task using python

I want reset the timer to 0 when it reaches to 8 and should sleep for 5 secs showing timer value as 0 and again restart from zero and repeat.
when linemode == 'dashed': But with my current code when it reaches 8 it displays 8, where i want to display 0 for 5 secs. I have posted full code snippet as well as piece of code where code has to perform expectation. Thanks in Advnc
code Snippet:-
if ton > ontym:
if linemode == 'dashed':
counter=0
lbl['text']='00'
sleep(offtym)
ton=-1
lbl.after(1000, count)
else:
lbl.after(1000, count)
else:
lbl.after(1000, count)
Full code Snippet:-
#!/usr/bin/env python
from Tkinter import Tk,Label,Button
import rospy
from time import sleep
from PIL import Image, ImageTk
ws = Tk()
#ws.geometry('400x450+1000+300')
ws.title('Stopwatch')
ws.attributes('-fullscreen', True)
ws.config(bg='#efb570')
#ws.resizable(0,0)
ontym=8
offtym=5
ton=-1
linemode = 'dashed'
counter = 0
running = False
def counter_label(lbl):
def count():
if running:
global counter,offtym,ontym,ton,linemode
if counter == 0:
display="00"
else:
display='0' +str(counter)
if counter > 9:
display = str(counter)
lbl['text']=display
counter += 1
ton += 1
if ton > ontym:
if linemode == 'dashed':
counter=0
lbl['text']='00'
sleep(offtym)
ton=-1
lbl.after(1000, count)
else:
lbl.after(1000, count)
else:
lbl.after(1000, count)
count()
def StartTimer(lbl):
global running
running=True
counter_label(lbl)
start_btn['state']='disabled'
stop_btn['state']='normal'
def StopTimer():
global running
start_btn['state']='normal'
stop_btn['state']='disabled'
running = False
pic=Image.open("/home/nooduupachuu/catkin_ws/src/gui_sample/scripts/abc.png")
tkImg=ImageTk.PhotoImage(pic)
lbl1=Label(ws, image=tkImg, bg='#efb570')
lbl1.image=tkImg
lbl1.place(x=405, y=50)
lbl = Label(ws, text="00", fg="black", bg='#efb570', font="Verdana 80 bold")
label_msg = Label(ws, text="seconds", fg="black", bg='#efb570', font="Verdana 30 bold")
lbl.place(x=585, y=315)
label_msg.place(x=570, y=445)
start_btn=Button(ws, text='START', width=9, bd=2, font=("Arial Bold", 12), command=lambda:StartTimer(lbl))
stop_btn = Button(ws, text='STOP', width=9, bd=2, font=("Arial Bold", 12), state='disabled', command=StopTimer)
start_btn.place(x=535, y=700)
stop_btn.place(x=675, y=700)
ws.mainloop()

“name is not defined” inside function

I want to create a countdown clock and I almost did but if I run this code down below and press the 'go' button, I get the error: NameError: name 'be' is not defined. Even if I try to put global be in there it doesn't seem to work
import tkinter as tk
def set1():
global be
if be1 is not '':
be = int(en.get())
def countdown():
global be
if be >= 0:
mins, secs = divmod(be, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
label['text'] = timer
root.after(1000, countdown)
be -= 1
root = tk.Tk()
label = tk.Label(root, text = '00:00', font = 'Helvetica 25')
label.pack()
en = tk.Entry(root)
en.pack()
be1 = en.get()
tk.Button(root, text = 'set', height = 3, width = 20, command = lambda: set1()).pack()
tk.Button(root, text = 'go', height = 3, width = 20, command = lambda: countdown()).pack()
root.mainloop()
Please give be a value on top of your code, for example
be = 0

Increasing integers at specific time with elapsed time

I'm trying to make a program that will work as an "infomercial" in a separate window.
What i have are two integers (x and y) that both increase at the same time, in this case every 5 seconds. With the increasing values i need a timer displayed at the same time, that can show the elapsed time of how long the program has been running. I want to be albe to start and pause the program
So far i have an infinite while loop running where the values are increased every 5 seconds with time.sleep(5). I have tried implementing a timer in the form of a time.time(), and get it to work with the increments. I have also added buttons but don't work. I'm using tkinter as gui obtion.
How am i supposed to make it work? with threading?
import time
from tkinter import *
import math
usage = 0
yearly = 0
cubik = 0
price = 0
root = Tk()
root.title("Usage of fluid")
root.geometry("300x400")
var = IntVar()
var1 = IntVar()
var2 = StringVar()
var3 = StringVar()
var4 = StringVar()
def update_timeText():
current= time.strftime("%H:%M:%S")
timeText.configure(text=current)
root.after(1000, update_timeText)
def start():
global state
state = True
def pause():
global state
state = False
def exist():
root.destroy()
frame = LabelFrame(root, text="Liter", font=30)
frame.pack(fill = "both", expand="yes")
l = Label(frame, textvariable=var, font=20)
l.pack(pady = 3)
frame2 = LabelFrame(root, text="price from use", font=30)
frame2.pack(fill = "both", expand= "yes")
l2 = Label(frame2, textvariable=var1, font=16)
l2.pack(side = LEFT)
l3 = Label(frame2, text="dollars", font=16)
l3.pack(side=LEFT)
frame3 = LabelFrame(root, text="yearly", font=30)
frame3.pack(fill = "both", expand="yes")
m3 = Label(frame3, textvariable=var2, font=16, wraplength=0)
m3.pack(side=TOP)
l4 = Label(frame3, text="Liter", font=16)
l4.pack(side=TOP)
l5 = Label(frame3, text="m3", font=16)
l5.pack(side=BOTTOM, fill="both")
m4 = Label(frame3, textvariable=var3, font=16, wraplength=0)
m4.pack(side=BOTTOM)
frame4 = LabelFrame(root, text='runtime', font=30)
frame4.pack(fill = "both", expand="yes")
timeText= Label(frame4, text="", font=16)
timeText.pack()
startButton = Button(frame4, text='Start', command=start)
startButton.pack()
pauseButton = Button(frame4, text='Pause', command=pause)
pauseButton.pack()
quitButton = Button(frame4, text='Quit', command=quit)
quitButton.pack()
while True:
var.set(usage)
usage += 300
var1.set(round(price,1))
price+= 10
var2.set(yearly)
var3.set(round(cubik,1))
yearly += 300
cubik += 0.1
time.sleep(5)
update_timeText()
root.update_idletasks()
##update_timeText()
##root.mainloop()

Combine two windows with tkinter

I have just started playing with tkinter today and I have two bit of code I have been playing with as examples however I am struggling to combine these can anyone advise. I would like to clock to display in the main window.
import tkinter
from tkinter import *
import sys
import time
root = Tk()
root.title('Logging')
Label(text='Time logging').pack(side=TOP,padx=100,pady=100)
entry = Entry(root, width=25)
entry.pack(side=TOP,padx=25,pady=25)
def onok():
x, y = entry.get().split('x')
for row in range(int(y)):
for col in range(int(x)):
print((col, row))
Button(root, text='Log Time', command=onok).pack(side=LEFT)
Button(root, text='CLOSE').pack(side= RIGHT)
def tick():
global time1
# get the current local time from the PC
time2 = time.strftime('%H:%M:%S')
# if time string has changed, update it
if time2 != time1:
time1 = time2
clock.config(text=time2)
# calls itself every 200 milliseconds
# to update the time display as needed
# could use >200 ms, but display gets jerky
clock.after(200, tick)
root = Tk()
time1 = ''
status = Label(root, text="v1.0", bd=1, relief=SUNKEN, anchor=W)
status.grid(row=10, column=10)
clock = Label(root, font=('times', 20, 'bold'), bg='green')
clock.grid(row=0, column=1)
tick()
root.mainloop()
You can use Frame to group clock widgets and use grid inside this frame. And frame you can put in main window. (And you don't need second Tk())
I put it at the top but you can choose other place.
import tkinter as tk
import time
# --- functions ---
def on_ok():
x, y = entry.get().split('x')
for row in range(int(y)):
for col in range(int(x)):
print((col, row))
def tick():
global time1
# get the current local time from the PC
time2 = time.strftime('%H:%M:%S')
# if time string has changed, update it
if time2 != time1:
time1 = time2
clock.config(text=time2)
# calls itself every 200 milliseconds
# to update the time display as needed
# could use >200 ms, but display gets jerky
clock.after(200, tick)
# --- main window ---
time1 = ''
root = tk.Tk()
root.title('Logging')
# add frame in main window (root)
other = tk.Frame(root)
other.pack()
# put widgets in frame (other)
status = tk.Label(other, text="v1.0", bd=1, relief=tk.SUNKEN, anchor=tk.W)
status.grid(row=10, column=10)
clock = tk.Label(other, font=('times', 20, 'bold'), bg='green')
clock.grid(row=0, column=1)
# put other widget directly in main widnow (root)
tk.Label(root, text='Time logging').pack(side=tk.TOP, padx=100, pady=100)
entry = tk.Entry(root, width=25)
entry.pack(side=tk.TOP, padx=25, pady=25)
tk.Button(root, text='Log Time', command=on_ok).pack(side=tk.LEFT)
tk.Button(root, text='CLOSE', command=root.destroy).pack(side= tk.RIGHT)
tick()
# --- start ---
root.mainloop()
You have two different root windows. Use one root = Tk() line at the top and you should have them on the same page.

Categories

Resources