Adding variable to be displayed in tkinter - python

I want to write an app that displays current Bitcoin price next to current time. I am new to python and tkinter and I don't know how to add the Bitcoin variable next to time.
import requests
btc = requests.get('https://api.coindesk.com/v1/bpi/currentprice.json')
btc_price = (btc.json()['bpi']['USD']['rate'])
from tkinter import *
from tkinter.ttk import *
from time import strftime
root = Tk()
root.title('Btc')
label = Label(root, font = ('arial', 40, 'bold'), background = 'white', foreground = 'black')
def time():
string = strftime('%H:%M:%S %p')
label.config(text = string)
label.after(1000, time)
label.pack(anchor = 'center')
time()
mainloop()
I can only get it to display time.

Hope this is what you wanted.
#imports
import requests
from tkinter import *
from tkinter.ttk import *
from time import strftime
#Canvas preparation
root = Tk()
root.title('Btc')
label = Label(root, font = ('arial', 40, 'bold'), background = 'white', foreground = 'black')
label2 = Label(root, font = ('arial', 40, 'bold'), background = 'white', foreground = 'black')
#Looper/Updater method
def time():
string = strftime('%H:%M:%S %p')
#value request
btc = requests.get('https://api.coindesk.com/v1/bpi/currentprice.json')
btc_price = (btc.json()['bpi']['USD']['rate']) # You might wanna keep the value updated, right?
#Assigning values to label for updating.
label.config(text = string)
label2.config(text=btc_price)
#recursive rendition loop
label.after(1000, time)
#Use the coordinate system as opposed to anchor system to place the values.
#Here I have taken LEFT side edge as reference, you might wanna change per aesthetic appeal.
label.pack(padx=5, pady=10, side=LEFT)
label2.pack(padx=5, pady=20, side=RIGHT)
#Recursive rendition call
time()
#Exhibit
mainloop()

Related

Tkinter window stops updating randomly for no reason

I created a timer but for some reason the timer randomly stops updating until I click the tkinter window then it starts to update again. This happens about every minute or two. Here is my code:
from tkinter import *
from threading import Thread
tk = Tk()
tk.attributes('-alpha',1)
tk ['bg']='#302F2F'
tk.title('')
tk.wm_attributes('-topmost', 1) # put the window to front
def timer():
while True:
sleep(0.009)
...
#cut out all the stuff of creating the time but here is how i did it
label['text'] = (ftime2)
label['fg'] = colorfortext
label2['text'] = (ftime)
label2['fg'] = colorfortext
label3['text'] = (numberofworlds)
label3['fg'] = 'blue'
label = Label(tk, '', font=('Arial', 30),bg='#302F2F')
label.grid(columnspan=2)
label2 = Label(tk, '', font=('Arial', 30),bg='#302F2F')
label2.grid(columnspan=2)
label3 = Label(tk, '', font=('Arial', 30),bg='#302F2F')
label3.grid(columnspan=2)
timer_thread = Thread(target=timer)
timer_thread.start()
tk.mainloop()

Issue with refreshing values in a Tkinter window

Here is the code:
import steammarket as sm
import time
from tkinter import *
from PIL import ImageTk, Image
#Search function which gets the request from the market
name = ('Operation Broken Fang Case')
item = sm.get_csgo_item(name, currency='GBP')
#GUI
window = Tk()
window.title("OSMA")
window.geometry("300x110")
Lbl = Label(window, text=name, font= ('Helvetica 9 underline'))
Lbl.grid(column=0, row=0)
#Image for case
image1 = Image.open("FangCase.png")
case1 = ImageTk.PhotoImage(image1)
label1 = Label(image=case1)
label1.image = case1
label1.place(x=20, y=20)
Lbl = Label(window, text='Average cost: '+item["median_price"])
Lbl.grid(column=1, row=3)
Lbl = Label(window, text='Lowest cost: '+item["lowest_price"])
Lbl.grid(column=1, row=4)
Lbl = Label(window, text='Listings: '+item["volume"])
Lbl.grid(column=1, row=5)
#Waits 10 mins, searches again and refreshes value
def refresh():
name = ('Operation Broken Fang Case')
item = sm.get_csgo_item(name, currency='GBP')
print(item)
window.after(300000, refresh)
refresh()
window.mainloop()
I'm trying to get the last 3 labels to refresh the values and display them. Although the values are refreshed, it doesn't display the new values instead of the old ones.
I've looked at a previous question on how to do refreshing, and used said code from the question as a basis
Any help is appreciated,

Tkinter Button to refresh data via API call

I'm complete noob in Tkinter library and function calling so I'm turning to you for some help:
I try to create a widget to check cryptocurrency prices and PNL.
So far, I've created CoinGecko API call inside a function to return me a dataframe and PNL result.
I've also created GUI with Tkinter.
My current script looks like this:
from pycoingecko import CoinGeckoAPI
import pandas as pd
import datetime
from tkinter import *
import time
def get_crypto_data():
data = []
cg = CoinGeckoAPI()
coins = cg.get_price(ids='bitcoin,ethereum,,neo,ripple', vs_currencies='usd', include_24hr_change='true')
df = pd.DataFrame.from_dict(coins, orient='index')
PNL = "something"
data.append(df)
data.append(PNL)
return data
def Click():
get_crypto_data()
def setup_GUI(mask,crypto_data, click):
mask.wm_title("Live Portfolio Data")
date_time = datetime.datetime.now().strftime("%A %d.%m.%Y %H:%M:%S")
l1 = Label(mask,bg='blue', text= "Live Crypto portfolio Data")
l1.grid(row=0, column=0)
l2 = Label(mask,bg='yellow', text= date_time)
l2.grid(row=1, column=0)
l3 = Label(mask,bg='yellow', text=crypto_data[0])
l3.grid(row=2, column=0)
l4 = Label(mask, bg='yellow', text=crypto_data[1])
l4.grid(row=3, column=0)
butt = Button(mask, padx=2, bd=2, fg="black", font=('arial', 20, 'bold'),
text="Button", bg="yellow", command=lambda: Click())
butt.grid(row=5, column=0)
mask.geometry("500x500")
mask.configure(bg='yellow')
return mask
def main():
while True:
mask = Tk()
crypto_data = get_crypto_data()
click = Click()
mask = setup_GUI(mask,crypto_data,click)
mask.update()
mask.mainloop()
if __name__ == '__main__':
main()
What I'm trying to do is to make Button API call and refresh dataframe and PNL and show it on my mask.
Do you have any ideas how to make this happen? I guess it's not that difficult, but I don't know where to look :)
thanks!
You should subclass tkinter.Tk. I edited your code accordingly:
from pycoingecko import CoinGeckoAPI
import pandas as pd
import datetime
from tkinter import *
import time
class Window(Tk):
def __init__(self):
Tk.__init__(self) # initiate the window
def setup_ui(self):
self.wm_title("Live Portfolio Data")
date_time = datetime.datetime.now().strftime("%A %d.%m.%Y %H:%M:%S")
self.l1 = Label(self, bg="blue", text="Live Crypto portfolio Data")
self.l1.grid(row=0, column=0)
self.l2 = Label(self, bg="yellow", text=date_time)
self.l2.grid(row=1, column=0)
self.l3 = Label(self, bg="yellow", text="placeholder") # placeholder will be replaced with correct values
self.l3.grid(row=2, column=0)
self.l4 = Label(self, bg="yellow", text="placeholder")
self.l4.grid(row=3, column=0)
butt = Button(self, padx=2, bd=2, fg="black", font=("arial", 20, "bold"),
text="Button", bg="yellow", command=self.update_data) # when the user clicks the button, fetch the data again and update the labels
butt.grid(row=5, column=0)
self.geometry("500x500")
self.configure(bg="yellow")
self.update_data() # call update_data once to display correct values on the labels
def update_data(self, *args): # *args makes accept this function any number of arguments, args will be a list with all arguments
self.data = [] # make data a member of this class
cg = CoinGeckoAPI()
coins = cg.get_price(ids="bitcoin,ethereum,neo,ripple", vs_currencies="usd", include_24hr_change="true")
df = pd.DataFrame.from_dict(coins, orient="index")
PNL = "something"
self.data.append(df)
self.data.append(PNL)
date_time = datetime.datetime.now().strftime("%A %d.%m.%Y %H:%M:%S") # if you do not want
self.l2.config(text=date_time) # the time to be updated, remove these two lines
# update labels with values got above
self.l3.config(text=self.data[0])
self.l4.config(text=self.data[1])
def main():
mask = Window() # create window
mask.setup_ui() # create labels, buttons, etc.
mask.update() # make sure everything shows up correctly
mask.mainloop() # now show the window
if __name__ == "__main__":
main()
Please use either single quotes (') OR double quotes (") everywhere in your code. It is no problem for python to use both mixed, but it makes code more readable to NOT mix them.

Issues in time delay for RSS feed on full screen clock python

I have designed a full-screen clock for my Raspberry Pi 3 Model B which runs on Raspbian but can also run on Windows. The whole point of the clock is to show the date, time, and a RSS feed on r/news (Reddit).
The news feed should stay on the screen for 5 seconds then change to the next one, and this process should go on forever until I exit. If I use sleep(), the clock stops. I have tried using threading, but it only works on the first loop, and then tries to show the next one, but returns to the previous one.
The clock and date work fine, it's just that I can't get the feed to stay on screen for 5 seconds and move on to the next one.
Code:
import sys
if sys.version_info[0] == 2:
from Tkinter import *
else:
from tkinter import *
from time import *
import datetime
import feedparser
root = Tk()
d = feedparser.parse('https://www.reddit.com/r/news/.rss')
def exitt():
sleep(3)
root.destroy()
time1 = ''
extra_time1 = ''
clock = Label(root, font=('calibri light', 150), bg='black', fg='white')
clock.pack(fill=BOTH, expand=1)
extra_clock = Label(root, font=('calibri light', 45), bg='black', fg='white')
extra_clock.pack(fill=BOTH, expand=1)
label_rss = Label(root, font=('calibri', 14), bg='black', fg='white')
label_rss.pack(fill=BOTH)
end = Button(root, text="Exit", font=('bold', 20), fg="white",
bg='black', bd=0, borderwidth=0, highlightthickness=0,
highlightcolor='black', command=lambda:exitt(), height=0, width=0)
end.pack(fill=BOTH)
def rssfeeds():
for post in d.entries:
RSSFEED = post.title
label_rss.config(text=RSSFEED)
#sleep(5) <-- To prevent glitches but to keep my point
#rssfeeds()
def tick():
global time1
time2 = strftime("%H:%M:%S")
if time2 != time1:
time1 = time2
clock.config(text=time2)
clock.after(1, tick)
def ticki():
global extra_time1
extra_time2 = strftime("%A, %d %B %Y")
if extra_time2 != extra_time1:
extra_time1 = extra_time2
extra_clock.config(text=extra_time2)
extra_clock.after(1, ticki)
tick()
ticki()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set() # <-- move focus to this widget
root.mainloop()
I have added the first few lines to make it easier to run this code if you are using Python 3 because feedparser can run on Python up to v.3.4.
To do what you want you need an "iterator", which is a type of object that can spit out one element at a time. For you I would recommend itertools.cycle, since it also loops back to the beginning after it's done. Remember in event driven programming (GUIs) you can't use a normal loop, you have to have an event fire the next action. The event you will use is set with after.
#!/usr/bin/env python
import sys
if sys.version_info[0] == 2:
import Tkinter as tk
else:
import tkinter as tk
from time import sleep, strftime
import datetime
import feedparser
from itertools import cycle
root = tk.Tk()
d = feedparser.parse('https://www.reddit.com/r/news/.rss')
post_list = cycle(d.entries)
def exitt():
sleep(3)
root.destroy()
time1 = ''
extra_time1 = ''
clock = tk.Label(root, font=('calibri light', 150), bg='black', fg='white')
clock.pack(fill=tk.BOTH, expand=1)
extra_clock = tk.Label(root, font=('calibri light', 45), bg='black', fg='white')
extra_clock.pack(fill=tk.BOTH, expand=1)
label_rss = tk.Label(root, font=('calibri', 14), bg='black', fg='white')
label_rss.pack(fill=tk.BOTH)
end = tk.Button(root, text="Exit", font=('bold', 20), fg="white",
bg='black', bd=0, borderwidth=0, highlightthickness=0,
highlightcolor='black', command=lambda:exitt(), height=0, width=0)
end.pack(fill=tk.BOTH)
def rssfeeds():
post = next(post_list)
RSSFEED = post.title
label_rss.config(text=RSSFEED)
root.after(5000, rssfeeds) # call this method again in 5 seconds
rssfeeds()
def tick():
global time1
time2 = strftime("%H:%M:%S")
if time2 != time1:
time1 = time2
clock.config(text=time2)
clock.after(1000, tick)
def ticki():
global extra_time1
extra_time2 = strftime("%A, %d %B %Y")
if extra_time2 != extra_time1:
extra_time1 = extra_time2
extra_clock.config(text=extra_time2)
extra_clock.after(1000, ticki)
tick()
ticki()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set() # <-- move focus to this widget
root.mainloop()
Some more things to note:
use 4 spaces for indenting (read PEP8 for more style recommendations)
Do not use wildcard imports (from module import *), they lead to bugs and are also against PEP8.
Use a shebang always, but especially on linux systems.
move to classes and OOP as soon as you can to clean up the code.

Python display variable with tkinter inside a method

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

Categories