Reputation: 1
My first coding project, and I am trying to create an app to use as a dashboard on an old laptop.
Can I use tkinters grid to create boxes like in the picture?
I have stumbled for two days and I cannot come up with a good result at all nor have I managed to create a good box yet.
Here is my code:
import requests
from tkinter import *
from PIL import ImageTk, Image
def weather():
city=city_listbox.get()
url="https://api.openweathermap.org/data/2.5/weather?q={}&appid=*myappid*&units=metric".format(city)
res=requests.get(url)
output=res.json()
weather_status=output['weather'][0]['description']
temperature=output['main']['temp']
feelslike=output['main']['feels_like']
humidity=output['main']['humidity']
wind_speed=output['wind']['speed']
weather_status_label.configure(text="Weather status : "+ weather_status)
if weather_status=="few clouds":
partial_cloud_label=Label(image=partial_cloud)
partial_cloud_label.grid(row=3, column=4)
temperature_label.configure(text="Temperature : "+ str(temperature) +"°C")
feelslike_label.configure(text="Feels like : "+ str(feelslike) +"°C")
humidity_label.configure(text="Humidity : "+ str(humidity) +"%")
wind_speed_label.configure(text="Wind speed : "+ str(wind_speed) +"m/s")
window=Tk()
window.geometry("1920x1080")
window.iconbitmap('localfile')
window.title('Show dis weather')
partial_cloud=ImageTk.PhotoImage(Image.open("local file"))
day_clear=ImageTk.PhotoImage(Image.open("localfile"))
cloudy=ImageTk.PhotoImage(Image.open("localfile"))
city_name_list=["City1", "City2"]
city_listbox=StringVar(window)
city_listbox.set("select the city")
option=OptionMenu(window,city_listbox,*city_name_list)
option.grid(row=2,column=6,padx=150,pady=10)
b1=Button(window,text="Select",width=15,command=weather)
b1.grid(row=5,column=6,padx=150)
weather_status_label=Label(window, font=("didot",15,"bold"))
weather_status_label.grid(row=10,column=6)
temperature_label=Label(window,font=("didot",15,"bold"))
temperature_label.grid(row=16,column=6)
feelslike_label=Label(window,font=("didot",15,"bold"))
feelslike_label.grid(row=22,column=6)
humidity_label=Label(window,font=("didot",15,"bold"))
humidity_label.grid(row=28,column=6)
wind_speed_label=Label(window,font=("didot",15,"bold"))
wind_speed_label.grid(row=34,column=6)
window.mainloop()
Seeking advice towards Tkinter gui. I was thinking that you could possibly create boxes and set all the "widgets" or data inside them.
For e.x, creating a box and put it to the left and have the weather status and information inside there. A box NW for the buttons to choose city. Box N to show big text for which city it is showing information for.
Is this possible in Tkinter?
If I have left insufficient information or if this is a too loose thread to being helped through, please write and tell me about it, I am very new in this, so I appreciate all help.
With Regards!
Upvotes: 0
Views: 310
Reputation: 1
Thank you Newb, and you others, for different answers.
I have used Newb's code and made some changes, like making it a 12 grid big and changing the order of where the frames should be.
I have also tried to implement the "weather" code from the original code, and there is where I got stuck.
Can you put a function inside another function?
I still cannot understand what init is for, but that I can learn on the side.
Here is the updated code:
import tkinter as tk
#from tkinter import *
from PIL import ImageTk, Image
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
#Window config
tk.Tk.wm_title(self, "WeatherApp")
self.geometry("1920x1080")
self.iconbitmap('localfile')
#This part I have added
self.partial_cloud=ImageTk.PhotoImage(Image.open("localfile"))
self.day_clear=ImageTk.PhotoImage(Image.open("localfile"))
self.cloudy=ImageTk.PhotoImage(Image.open("localfile"))
#This part I have added
def weather():
self.city=city_listbox.get()
self.url="https://api.openweathermap.org/data/2.5/weather?q={}&appid=*myappid*&units=metric".format(city)
self.res=requests.get(url)
self.output=res.json()
self.weather_status=output['weather'][0]['description']
self.temperature=output['main']['temp']
self.feelslike=output['main']['feels_like']
self.humidity=output['main']['humidity']
self.wind_speed=output['wind']['speed']
self.weather_status_label.configure(text="Weather status : "+ weather_status)
if weather_status=="few clouds":
partial_cloud_label=Label(image=partial_cloud)
partial_cloud_label.grid(row=3, column=4)
temperature_label.configure(text="Temperature : "+ str(temperature) +"°C")
feelslike_label.configure(text="Feels like : "+ str(feelslike) +"°C")
humidity_label.configure(text="Humidity : "+ str(humidity) +"%")
wind_speed_label.configure(text="Wind speed : "+ str(wind_speed) +"m/s")
#Main Layout
self.mainframe = tk.Frame(self)
self.mainframe.pack(fill="both", expand = True)
self.mainframe.grid_rowconfigure(0, weight=1)
self.mainframe.grid_rowconfigure(1, weight=1)
self.mainframe.grid_rowconfigure(2, weight=1)
self.mainframe.grid_columnconfigure(0, weight=1)
self.mainframe.grid_columnconfigure(1, weight=1)
self.mainframe.grid_columnconfigure(2, weight=1)
self.mainframe.grid_columnconfigure(3, weight=1)
#Top Left Container
self.tl = tk.Frame(self.mainframe)
#placing in the main frame
self.tl.grid(row = 0, column = 0)
#configure layout for top view
self.tl.grid_rowconfigure(0, weight=1)
self.tl.grid_columnconfigure(0, weight=1)
#This part I have added
#content of top view
self.city_name_list=["city1", "city2"]
self.city_listbox=StringVar(self.tl)
self.city_listbox.set("select the city")
self.option=OptionMenu(self.tl,city_listbox,*city_name_list)
self.option.grid(row=0,column=0,padx=150,pady=10)
self.b1=Button(self.tl, text="Select",width=15,command=weather)
self.b1.grid(row=0,column=0,padx=150)
#self.tllabel = tk.Label(self.tl, text = "Button ", font=("Sentinel", 20, "bold"))
#self.tllabel.grid(row = 0, column = 0)
#Top Middle Container (tm)
self.tm = tk.Frame(self.mainframe)
#placing in the main frame
self.tm.grid(row = 0, column = 1) #Leaving comment for my self columnspan = 4
#configure layout for top view
self.tm.grid_rowconfigure(0, weight=1)
self.tm.grid_columnconfigure(0, weight=1)
#content of top view
self.tmlabel = tk.Label(self.tm, text = "City: ", font=("Sentinel", 36, "bold"))
self.tmlabel.grid(row = 0, column = 0)
#Left Container
self.left = tk.Frame(self.mainframe)
#placing in the main frame
self.left.grid(row = 1, column = 0)
#configure layout for top view
self.left.grid_rowconfigure(0, weight=1)
self.left.grid_columnconfigure(0, weight=1)
#content of top view
self.leftlabel = tk.Label(self.left, text = "Weather ", font=("Sentinel", 20, "bold"))
self.leftlabel.grid(row = 0, column = 0)
#day1
self.day1 = tk.Frame(self.mainframe) # Tried to make a border, leaving comment for my self width=3, height=100, highlightbackground="black", highlightthickness=1) #bd=100)#relief=tk.RIDGE)
#placing in the main frame
self.day1.grid(row = 2, column = 0)
#configure layout for top view
self.day1.grid_rowconfigure(0, weight=1)
self.day1.grid_columnconfigure(0, weight=1)
#content of day1 frame
self.label1 = tk.Label(self.day1, text="Saturday", font=("Sentinel", 26, "bold")).grid(row = 0, column = 0)
#day2
self.day2 = tk.Frame(self.mainframe)
#placing in the main frame
self.day2.grid(row = 2, column = 1)
#you don't have to configure if all cells should have equal size
#content of day1 frame
self.label2 = tk.Label(self.day2, text="Sunday", font=("Sentinel", 26, "bold")).grid(row = 0, column = 0)
#day3
self.day3 = tk.Frame(self.mainframe)
#placing in the main frame
self.day3.grid(row = 2, column = 2)
#content of day1 frame
self.label3 = tk.Label(self.day3, text="Monday", font=("Sentinel", 26, "bold")).grid(row = 0, column = 0)
#day4
self.day4 = tk.Frame(self.mainframe)
#placing in the main frame
self.day4.grid(row = 2, column = 3)
#content of day1 frame
self.label4 = tk.Label(self.day4, text="Tuesday", font=("Sentinel", 26, "bold")).grid(row = 0, column = 0)
app = Application()
app.mainloop()
You have already helped me a lot, but if you feel to help me how to implement this, feel free to do it.
Thanks and have a great day!
EDIT:
Hi there! Sorry for bumping an old thread, I am still working to make this application working!
When I am trying to run the following code, I get the NameError: "name 'city_listbox' is not defined code" at line 172
Anyone has any energy and clue what I can do to implement the Weather code inside the grid code supplied from Newb?
import requests
import tkinter as tk
#from tkinter import *
from PIL import ImageTk, Image
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
def weather():
def __init__(self, TopLFrame):
city=city_listbox.get()
url="https://api.openweathermap.org/data/2.5/weather?q={}&appid=ID&units=metric".format(city)
res=requests.get(url)
output=res.json()
weather_status=output['weather'][0]['description']
temperature=output['main']['temp']
feelslike=output['main']['feels_like']
humidity=output['main']['humidity']
wind_speed=output['wind']['speed']
weather_status_label.configure(text="Weather status : "+ weather_status)
if weather_status=="few clouds":
partial_cloud_label=tk.Label(image=partial_cloud)
partial_cloud_label.grid(row=3, column=4)
temperature_label.configure(text="Temperature : "+ str(temperature) +"°C")
feelslike_label.configure(text="Feels like : "+ str(feelslike) +"°C")
humidity_label.configure(text="Humidity : "+ str(humidity) +"%")
wind_speed_label.configure(text="Wind speed : "+ str(wind_speed) +"m/s")
#Window config
tk.Tk.wm_title(self, "WeatherApp")
self.geometry("1920x1080")
#self.iconbitmap('linktopicture')
#self.partial_cloud=ImageTk.PhotoImage(Image.open("linktopicture"))
#self.day_clear=ImageTk.PhotoImage(Image.open("linktopicture"))
#self.cloudy=ImageTk.PhotoImage(Image.open("linktopicture"))
#Main Layout
self.mainframe = tk.Frame(self)
self.mainframe.pack(fill="both", expand = True)
self.mainframe.grid_rowconfigure(0, weight=1)
self.mainframe.grid_rowconfigure(1, weight=1)
self.mainframe.grid_rowconfigure(2, weight=1)
self.mainframe.grid_columnconfigure(0, weight=1)
self.mainframe.grid_columnconfigure(1, weight=1)
self.mainframe.grid_columnconfigure(2, weight=1)
self.mainframe.grid_columnconfigure(3, weight=1)
#Top Left Container
self.tl = TopLFrame(self.mainframe, weather)
self.tl.grid(row = 0, column = 0)
#self.tl.grid_rowconfigure(0, weight=1)
#self.tl.grid_columnconfigure(0, weight=1)
#Top Middle Container (tm)
self.tm = TopMFrame(self.mainframe)
self.tm.grid(row = 0, column = 1)
#self.tm.grid_rowconfigure(0, weight=1)
#self.tm.grid_columnconfigure(0, weight=1)
#Left Container
self.left = MidFrame(self.mainframe)
self.left.grid(row = 1, column = 0)
#self.left.grid_rowconfigure(0, weight=1)
#self.left.grid_columnconfigure(0, weight=1)
#day1
self.day1 = BottomFrame(self.mainframe, "Monday")
self.day1.grid(row = 2, column = 0)
#self.day1.grid_rowconfigure(0, weight=1)
#self.day1.grid_columnconfigure(0, weight=1)
#day2
self.day2 = BottomFrame(self.mainframe, "saturday")
#placing in the main frame
self.day2.grid(row = 2, column = 1)
#day3
self.day3 = BottomFrame(self.mainframe, "test")
self.day3.grid(row = 2, column = 2)
#day4
self.day4 = BottomFrame(self.mainframe, "test2")
self.day4.grid(row = 2, column = 3)
class TopMFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
#add code for your widgets in top frame here
self.label = tk.Label(self, text="Top Mid Frame")
self.label.grid(row = 0, column = 0)
class TopLFrame(tk.Frame):
def __init__(self, parent, Application):
tk.Frame.__init__(self, parent)
self.city_name_list=["City1", "City2"]
self.city_listbox=tk.StringVar(self)
self.city_listbox.set("select the city")
self.option=tk.OptionMenu(self, city_listbox, *city_name_list)
self.option.grid(row=0,column=0,padx=150,pady=10)
self.b1=tk.Button(self, text="Select",width=15,command=weather)
self.b1.grid(row=0,column=0,padx=150)
class MidLFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.label = tk.Label(self, text="Left Frame")
self.label.grid(row = 0, column = 0)
self.weather_status_label=tk.Label(self, font=("didot",15,"bold"))
self.weather_status_label.grid(row=10,column=6)
self.temperature_label=tk.Label(self,font=("didot",15,"bold"))
self.temperature_label.grid(row=16,column=6)
self.feelslike_label=tk.Label(self,font=("didot",15,"bold"))
self.feelslike_label.grid(row=22,column=6)
self.humidity_label=tk.Label(self,font=("didot",15,"bold"))
self.humidity_label.grid(row=28,column=6)
self.wind_speed_label=tk.Label(self,font=("didot",15,"bold"))
self.wind_speed_label.grid(row=34,column=6)
class BottomFrame(tk.Frame):
def __init__(self, parent, day):
tk.Frame.__init__(self, parent)
# add code for bottom frame widgets here
# pass nessecary variables through to reuse the code
self.day = day
self.label1 = tk.Label(self, text = day, font=("Sentinel", 26, "bold"))
self.label1.grid(row = 0, column = 0)
app = Application()
app.mainloop()
With Regards, Joggster!
Upvotes: 0
Reputation: 212
I would use Frames in order to organize the view.
And instead of using random bigger numbers to try spacing things out(empty rows and columns stay at size zero until filled with content), you should take a look into the weight
option of grid.row(or column)configure
as well as the row(or column)span
option of grid
itself.
in order to achieve your view you might wanna start with something like this:
import tkinter as tk
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
#Window config
tk.Tk.wm_title(self, "WeatherApp")
self.geometry("1920x1080")
#Main Layout
self.mainframe = tk.Frame(self)
self.mainframe.pack(fill="both", expand = True)
self.mainframe.grid_rowconfigure(0, weight=1)
self.mainframe.grid_rowconfigure(1, weight=1)
self.mainframe.grid_columnconfigure(0, weight=1)
self.mainframe.grid_columnconfigure(1, weight=1)
self.mainframe.grid_columnconfigure(2, weight=1)
self.mainframe.grid_columnconfigure(3, weight=1)
#Top Container
self.top = tk.Frame(self.mainframe)
#placing in the main frame
self.top.grid(row = 0, column = 0, columnspan = 4)
#configure layout for top view
self.top.grid_rowconfigure(0, weight=1)
self.top.grid_columnconfigure(0, weight=1)
#content of top view
self.toplabel = tk.Label(self.top, text = "City: ")
self.toplabel.grid(row = 0, column = 0)
#day1
self.day1 = tk.Frame(self.mainframe)
#placing in the main frame
self.day1.grid(row = 1, column = 0)
#configure layout for top view
self.day1.grid_rowconfigure(0, weight=1)
self.day1.grid_columnconfigure(0, weight=1)
#content of day1 frame
self.label1 = tk.Label(self.day1, text="saturday")
self.label1.grid(row = 0, column = 0)
#day2
self.day2 = tk.Frame(self.mainframe)
#placing in the main frame
self.day2.grid(row = 1, column = 1)
#you don't have to configure if all cells should have equal size
#content of day1 frame
self.label2 = tk.Label(self.day2, text="sunday")
self.label2.grid(row = 0, column = 0)
#day3
self.day3 = tk.Frame(self.mainframe)
#placing in the main frame
self.day3.grid(row = 1, column = 2)
#content of day1 frame
self.label3 = tk.Label(self.day3, text="monday")
self.label3.grid(row = 0, column = 0)
#day4
self.day4 = tk.Frame(self.mainframe)
#placing in the main frame
self.day4.grid(row = 1, column = 3)
#content of day1 frame
self.label4 = tk.Label(self.day4, text="tuesday")
self.label4.grid(row = 0, column = 0)
app = Application()
app.mainloop()
EDIT:
The __init__
function is always getting called when a class is being used, see. You can use other functions from within each other, but you can't just toss it in there and expect it to run without beeing called, you might wanna take a look at inner Functions.
But that isn't what I would do in your case.
I would create 2 new other classes (1 for top frame, 1 for bottom frame) and inhereting from the tk.Frame
class for 2 reasons:
import tkinter as tk
class Application(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
#Window config
tk.Tk.wm_title(self, "WeatherApp")
self.geometry("1920x1080")
#Main Layout
self.mainframe = tk.Frame(self)
self.mainframe.pack(fill="both", expand = True)
self.mainframe.grid_rowconfigure(0, weight=1)
self.mainframe.grid_rowconfigure(1, weight=1)
self.mainframe.grid_columnconfigure(0, weight=1)
self.mainframe.grid_columnconfigure(1, weight=1)
self.mainframe.grid_columnconfigure(2, weight=1)
self.mainframe.grid_columnconfigure(3, weight=1)
#Top Container
#note the changed declaration, since we're now calling
#our own Frame class
self.top = TopFrame(self.mainframe)
#placing in the main frame
self.top.grid(row = 0, column = 0, columnspan = 4)
#day1
# note the passthrough of the day argument
self.day1 = DayFrame(self.mainframe, "saturday")
#placing in the main frame
self.day1.grid(row = 1, column = 0)
#day2
self.day2 = DayFrame(self.mainframe, "sunday")
#placing in the main frame
self.day2.grid(row = 1, column = 1)
#day3
self.day3 = DayFrame(self.mainframe, "monday")
#placing in the main frame
self.day3.grid(row = 1, column = 2)
#day4
self.day4 = DayFrame(self.mainframe, "tuesday")
#placing in the main frame
self.day4.grid(row = 1, column = 3)
class TopFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
#add code for your widgets in top frame here
label = tk.Label(self, text="Top Frame")
label.grid(row = 0, column = 0)
class DayFrame(tk.Frame):
def __init__(self, parent, day):
tk.Frame.__init__(self, parent)
# add code for bottom frame widgets here
# pass nessecary variables through to reuse the code
self.day = day
self.daylabel = tk.Label(self, text = day)
self.daylabel.grid(row = 0, column = 0)
app = Application()
app.mainloop()
Also please note what thelizzard said about my sloppiness when it comes to using .grid(row=0, column=0)
in the same row, because you will run into errors with this as soon as you want to change anything about the variable!
Upvotes: 1