-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ui): updates + dynamically sized window #16
Changes from 3 commits
5ecb774
30e4f0f
a51ea38
ef949f0
acd812b
1543cf5
ad145eb
9d175d0
5c999bb
d9644d7
5615a12
5c45f57
426ad4c
795f5ab
dfdb7ff
06ee8cf
aa10a9a
f8d36d7
07a7651
2d7ddad
c263ca0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,96 +1,155 @@ | ||||||||||||||
from __future__ import annotations | ||||||||||||||
|
||||||||||||||
from platform import system | ||||||||||||||
from tkinter import Menu, Tk, messagebox | ||||||||||||||
from tkinter.ttk import Button, Entry, Frame, Label | ||||||||||||||
from tkinter import Event, Menu, Tk, Toplevel, messagebox | ||||||||||||||
from tkinter.ttk import Button, Entry, Frame, Label, Progressbar, Style | ||||||||||||||
|
||||||||||||||
from pyowm import OWM | ||||||||||||||
from pyowm.commons.exceptions import APIRequestError | ||||||||||||||
from pyowm.commons.exceptions import NotFoundError as OWMNotFoundError | ||||||||||||||
from requests import Response | ||||||||||||||
from requests import get as requests_get | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
class ProgressBar(Toplevel): | ||||||||||||||
def __init__(self, parent: App, *args, **kwargs): | ||||||||||||||
# Set up window | ||||||||||||||
super().__init__(parent, *args, **kwargs) | ||||||||||||||
self.title("Loading...") | ||||||||||||||
self.resizable(False, False) | ||||||||||||||
|
||||||||||||||
# Set up widgets | ||||||||||||||
self.main_frame = Frame(self) | ||||||||||||||
self.main_frame.grid() | ||||||||||||||
|
||||||||||||||
main_label = Label(self.main_frame, text="Loading...", font="Helvetica 15 bold") | ||||||||||||||
main_label.grid(padx=10, pady=10) | ||||||||||||||
|
||||||||||||||
self.progressbar = Progressbar( | ||||||||||||||
self.main_frame, | ||||||||||||||
orient="horizontal", | ||||||||||||||
length=200, | ||||||||||||||
mode="indeterminate", | ||||||||||||||
maximum=4, | ||||||||||||||
) | ||||||||||||||
self.progressbar.grid(padx=10, pady=10) | ||||||||||||||
|
||||||||||||||
self.resize_app() | ||||||||||||||
|
||||||||||||||
def resize_app(self) -> App: | ||||||||||||||
"""Use tkinter to detect the minimum size of the app, get the center of the screen, and place the app there.""" | ||||||||||||||
|
||||||||||||||
# TODO: Make a global function for this to remove boilerplate code | ||||||||||||||
# Update widgets so minimum size is accurate | ||||||||||||||
self.update_idletasks() | ||||||||||||||
|
||||||||||||||
# Get minimum size | ||||||||||||||
minimum_width: int = self.winfo_reqwidth() | ||||||||||||||
minimum_height: int = self.winfo_reqheight() | ||||||||||||||
|
||||||||||||||
# Get center of screen based on minimum size | ||||||||||||||
x_coords = int(self.winfo_screenwidth() / 2 - minimum_width / 2) | ||||||||||||||
y_coords = int(self.wm_maxsize()[1] / 2 - minimum_height / 2) | ||||||||||||||
|
||||||||||||||
# Place app and make the minimum size the actual minimum size (non-infringable) | ||||||||||||||
self.geometry(f"{minimum_width}x{minimum_height}+{x_coords}+{y_coords}") | ||||||||||||||
self.wm_minsize(minimum_width, minimum_height) | ||||||||||||||
return self | ||||||||||||||
|
||||||||||||||
def set_progress(self, progress: int): | ||||||||||||||
self.progressbar.step(progress) | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
class App(Tk): | ||||||||||||||
def __init__(self): | ||||||||||||||
super().__init__() | ||||||||||||||
self.withdraw() | ||||||||||||||
|
||||||||||||||
# Set up Menubar | ||||||||||||||
if system() == "Darwin": | ||||||||||||||
self.menubar = Menu(self) | ||||||||||||||
|
||||||||||||||
# Apple menus have special names and special commands | ||||||||||||||
self.app_menu = Menu(self.menubar, tearoff=0, name="apple") | ||||||||||||||
self.menubar.add_cascade(label="App", menu=self.app_menu) | ||||||||||||||
else: | ||||||||||||||
self.menubar = Menu(self) | ||||||||||||||
self.app_menu = Menu(self.menubar, tearoff=0) | ||||||||||||||
self.menubar.add_cascade(label="App", menu=self.app_menu) | ||||||||||||||
self.menubar.add_command(label="About Weather", command=self.about) | ||||||||||||||
self.app_menu.add_command(label="About Weather", command=self.about) | ||||||||||||||
self.config(menu=self.menubar) | ||||||||||||||
|
||||||||||||||
# Set up style | ||||||||||||||
Style().theme_use("clam") | ||||||||||||||
|
||||||||||||||
# Set up window | ||||||||||||||
self.title("Weather") | ||||||||||||||
self.resizable(False, False) | ||||||||||||||
self.configure(bg="white") | ||||||||||||||
|
||||||||||||||
# Set up widgets | ||||||||||||||
self.main_frame = Frame(self, padding=10) | ||||||||||||||
self.main_frame = Frame(self) | ||||||||||||||
self.main_frame.pack() | ||||||||||||||
|
||||||||||||||
heading = Label(self.main_frame, text="Weather", font="Helvetica 13") | ||||||||||||||
heading = Label(self.main_frame, text="Weather", font="Helvetica 25 bold") | ||||||||||||||
heading.grid(row=0, column=0, columnspan=2, padx=10, pady=10) | ||||||||||||||
|
||||||||||||||
self.cityname = Label(self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.cityname = Label(self.main_frame, text="City: None", font=("Helvetica 15")) | ||||||||||||||
self.cityname.grid(row=1, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
self.searchbar = Entry(self.main_frame, width=42) | ||||||||||||||
self.searchbar.grid(row=2, column=0, columnspan=2, padx=10, pady=10) | ||||||||||||||
self.bind("<Return>", self.OWMCITY) | ||||||||||||||
|
||||||||||||||
self.info_frame = Frame(self.main_frame, relief="sunken") | ||||||||||||||
self.info_frame.grid(row=3, column=0, columnspan=2, padx=10, pady=10) | ||||||||||||||
|
||||||||||||||
self.label_status = Label( | ||||||||||||||
self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_status.grid(row=3, column=0, columnspan=2) | ||||||||||||||
self.label_weather = Label(self.info_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_weather.grid(row=0, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
self.label_temp = Label( | ||||||||||||||
self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_temp.grid(row=4, column=0, columnspan=2) | ||||||||||||||
self.label_temp = Label(self.info_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_temp.grid(row=1, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
self.label_temp_max = Label( | ||||||||||||||
self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_temp_max.grid(row=5, column=0, columnspan=2) | ||||||||||||||
self.label_temp_max = Label(self.info_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_temp_max.grid(row=2, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
self.label_temp_min = Label( | ||||||||||||||
self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_temp_min.grid(row=6, column=0, columnspan=2) | ||||||||||||||
self.label_temp_min = Label(self.info_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_temp_min.grid(row=3, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
self.label_feels_like = Label( | ||||||||||||||
self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_feels_like.grid(row=7, column=0, columnspan=2) | ||||||||||||||
self.label_feels_like = Label(self.info_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_feels_like.grid(row=4, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
self.label_humidity = Label( | ||||||||||||||
self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_humidity.grid(row=8, column=0, columnspan=2) | ||||||||||||||
self.label_humidity = Label(self.info_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_humidity.grid(row=5, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
self.label_pressure = Label( | ||||||||||||||
self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_pressure.grid(row=9, column=0, columnspan=2) | ||||||||||||||
self.label_pressure = Label(self.info_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_pressure.grid(row=6, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
self.label_visibility = Label( | ||||||||||||||
self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_visibility.grid(row=10, column=0, columnspan=2) | ||||||||||||||
self.label_visibility = Label(self.info_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_visibility.grid(row=7, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
self.label_windspeed = Label( | ||||||||||||||
self.main_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_windspeed.grid(row=11, column=0, columnspan=2) | ||||||||||||||
Button(self.main_frame, text="Search for City", command=self.OWMCITY).grid( | ||||||||||||||
row=12, column=0, padx=10, pady=10 | ||||||||||||||
self.label_windspeed = Label(self.info_frame, text="", font=("Helvetica 13")) | ||||||||||||||
self.label_windspeed.grid(row=8, column=0, columnspan=2) | ||||||||||||||
|
||||||||||||||
# Set up buttons | ||||||||||||||
self.start_button = Button( | ||||||||||||||
self.main_frame, text="Search for City", command=self.OWMCITY | ||||||||||||||
) | ||||||||||||||
self.start_button.grid(row=12, column=0, padx=10, pady=10) | ||||||||||||||
Button(self.main_frame, text="Exit", command=self.exit_app).grid( | ||||||||||||||
row=12, column=1, padx=10, pady=10 | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
# Set variables | ||||||||||||||
self.searching: bool = False | ||||||||||||||
|
||||||||||||||
# Resize and deiconify | ||||||||||||||
self.resize_app() | ||||||||||||||
self.deiconify() | ||||||||||||||
|
||||||||||||||
def about(self) -> App: | ||||||||||||||
"""Display a messagebox with information about the app.""" | ||||||||||||||
|
||||||||||||||
messagebox.showinfo( | ||||||||||||||
"About Weather", | ||||||||||||||
"Weather is a simple weather app that uses the OpenWeatherMap API to get the weather for a given city.", | ||||||||||||||
|
@@ -100,6 +159,7 @@ def about(self) -> App: | |||||||||||||
|
||||||||||||||
def resize_app(self) -> App: | ||||||||||||||
"""Use tkinter to detect the minimum size of the app, get the center of the screen, and place the app there.""" | ||||||||||||||
|
||||||||||||||
# Update widgets so minimum size is accurate | ||||||||||||||
self.update_idletasks() | ||||||||||||||
|
||||||||||||||
|
@@ -109,79 +169,139 @@ def resize_app(self) -> App: | |||||||||||||
|
||||||||||||||
# Get center of screen based on minimum size | ||||||||||||||
x_coords = int(self.winfo_screenwidth() / 2 - minimum_width / 2) | ||||||||||||||
y_coords = int(self.winfo_screenheight() / 2 - minimum_height / 2) - 20 | ||||||||||||||
# `-20` should deal with Dock on macOS and looks good on other OS's | ||||||||||||||
y_coords = int(self.wm_maxsize()[1] / 2 - minimum_height / 2) | ||||||||||||||
|
||||||||||||||
# Place app and make the minimum size the actual minimum size (non-infringable) | ||||||||||||||
self.geometry( | ||||||||||||||
f"{minimum_width}x{minimum_height}+{x_coords}+{y_coords}") | ||||||||||||||
self.geometry(f"{minimum_width}x{minimum_height}+{x_coords}+{y_coords}") | ||||||||||||||
self.wm_minsize(minimum_width, minimum_height) | ||||||||||||||
return self | ||||||||||||||
|
||||||||||||||
def exit_app(self) -> None: | ||||||||||||||
"""Exit the app.""" | ||||||||||||||
self.destroy() | ||||||||||||||
|
||||||||||||||
def OWMCITY(self) -> App: | ||||||||||||||
def OWMCITY(self, _: Event | None = None) -> None: | ||||||||||||||
"""Get the weather for a given city using the OpenWeatherMap API and display it in a label.""" | ||||||||||||||
|
||||||||||||||
# Check if already searching | ||||||||||||||
if self.searching: | ||||||||||||||
return | ||||||||||||||
self.searching = True | ||||||||||||||
|
||||||||||||||
# Start the Progress Bar, disable buttons and clear labels, and disable searchbar | ||||||||||||||
self.start_button.configure(state="disabled") | ||||||||||||||
self.searchbar.configure(state="disabled") | ||||||||||||||
self.update_labels() | ||||||||||||||
pb = ProgressBar(self) | ||||||||||||||
|
||||||||||||||
# Get API key | ||||||||||||||
api_key: str = "c439e1209216cc7e7c73a3a8d1d12bfd" | ||||||||||||||
owm = OWM(api_key) | ||||||||||||||
mgr = owm.weather_manager() | ||||||||||||||
# Get city name | ||||||||||||||
city: str = self.searchbar.get() | ||||||||||||||
observation = mgr.weather_at_place(city) | ||||||||||||||
self.searchbar.delete(0, "end") | ||||||||||||||
|
||||||||||||||
# Check if city is empty | ||||||||||||||
if not city: | ||||||||||||||
# TODO: Make a method to reduce code duplication (boilerplate) | ||||||||||||||
self.cityname.configure(text="City: Needs Name") | ||||||||||||||
self.update_labels() | ||||||||||||||
self.start_button.configure(state="normal") | ||||||||||||||
self.searchbar.configure(state="normal") | ||||||||||||||
pb.destroy() | ||||||||||||||
self.searching = False | ||||||||||||||
self.resize_app() # In case the name gets too long or it renders differently on other systems | ||||||||||||||
return | ||||||||||||||
|
||||||||||||||
pb.progressbar.step() | ||||||||||||||
|
||||||||||||||
# Check if city exists | ||||||||||||||
try: | ||||||||||||||
observation = mgr.weather_at_place(city) | ||||||||||||||
except OWMNotFoundError or APIRequestError: | ||||||||||||||
self.cityname.configure(text="City: Not Found") | ||||||||||||||
self.update_labels() | ||||||||||||||
self.start_button.configure(state="normal") | ||||||||||||||
self.searchbar.configure(state="normal") | ||||||||||||||
pb.destroy() | ||||||||||||||
self.searching = False | ||||||||||||||
self.resize_app() # In case the name gets too long or it renders differently on other systems | ||||||||||||||
return | ||||||||||||||
|
||||||||||||||
pb.progressbar.step() | ||||||||||||||
|
||||||||||||||
# Get weather data | ||||||||||||||
weather = observation.weather | ||||||||||||||
|
||||||||||||||
# Send request to OpenWeatherMap API | ||||||||||||||
response: Response = requests_get( | ||||||||||||||
f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}" | ||||||||||||||
) | ||||||||||||||
|
||||||||||||||
# Check if request was successful | ||||||||||||||
if response.status_code != 200: | ||||||||||||||
self.label_status.configure(text="City not found") | ||||||||||||||
self.cityname.configure(text="City: Connection Error") | ||||||||||||||
self.update_labels() | ||||||||||||||
self.start_button.configure(state="normal") | ||||||||||||||
self.searchbar.configure(state="normal") | ||||||||||||||
pb.destroy() | ||||||||||||||
self.searching = False | ||||||||||||||
self.resize_app() # In case the name gets too long or it renders differently on other systems | ||||||||||||||
return | ||||||||||||||
|
||||||||||||||
pb.progressbar.step() | ||||||||||||||
|
||||||||||||||
# Get response data, simplify and create variables for usage | ||||||||||||||
# TODO: Give all data in dual columns | ||||||||||||||
# | Weather: Clear | Temp: 20°C | | ||||||||||||||
# TODO: Allow users to change between imperial and metric (Fahrenheit and Celsius) | ||||||||||||||
data = response.json() | ||||||||||||||
main = data["main"] | ||||||||||||||
temperature = weather.temperature("celsius") | ||||||||||||||
wind = weather.wind(unit="meters_sec") | ||||||||||||||
# Get temperature in Celsius | ||||||||||||||
# temperature_kelvin: float = main["temp"] | ||||||||||||||
# temperature_celsius = temperature_kelvin - 273.15 | ||||||||||||||
temp = temperature.get("temp", None) | ||||||||||||||
temp_max = temperature.get("temp_max", None) | ||||||||||||||
temp_min = temperature.get("temp_min", None) | ||||||||||||||
feels_like = temperature.get("feels_like", None) | ||||||||||||||
status: str = weather.status | ||||||||||||||
detailed_status: str = weather.detailed_status | ||||||||||||||
# Other data needed from the API | ||||||||||||||
humidity = main["humidity"] | ||||||||||||||
pressure = main["pressure"] | ||||||||||||||
visibility = weather.visibility(unit="kilometers") | ||||||||||||||
windspeed: float = wind["speed"] | ||||||||||||||
# Put in label | ||||||||||||||
self.cityname.configure( | ||||||||||||||
text=data["name"] + ", " + data["sys"]["country"]) | ||||||||||||||
self.label_status.configure( | ||||||||||||||
text="Weather: " + status + ":- " + detailed_status) | ||||||||||||||
self.label_temp.configure(text="Temperature: " + f"{temp:.2f}°C") | ||||||||||||||
self.label_temp_max.configure( | ||||||||||||||
text="Maximum Temperature: " + f"{temp_max:.2f}°C" | ||||||||||||||
) | ||||||||||||||
self.label_temp_min.configure( | ||||||||||||||
text="Minimum Temperature: " + f"{temp_min:.2f}°C" | ||||||||||||||
) | ||||||||||||||
self.label_feels_like.configure( | ||||||||||||||
text="Feels like " + f"{feels_like:.2f}°C") | ||||||||||||||
self.label_humidity.configure(text="Humidity: " + f"{humidity:.2f}%") | ||||||||||||||
self.label_pressure.configure( | ||||||||||||||
text="Pressure: " + f"{pressure:.2f}" + " hPa") | ||||||||||||||
self.label_visibility.configure( | ||||||||||||||
text="Visibility: " + f"{visibility:.2f}" + " km" | ||||||||||||||
) | ||||||||||||||
self.label_windspeed.configure( | ||||||||||||||
text="Wind Speed: " + f"{windspeed:.2f}" + " meters per second" | ||||||||||||||
|
||||||||||||||
# Update labels | ||||||||||||||
self.update_labels( | ||||||||||||||
[ | ||||||||||||||
f"Weather: {weather.status} ~ {weather.detailed_status}", | ||||||||||||||
f"Current Temperature: {temperature.get('temp', None):.2f}°C", | ||||||||||||||
f"Maximum Temperature: {temperature.get('temp_max', None):.2f}°C", | ||||||||||||||
f"Minimum Temperature: {temperature.get('temp_min', None):.2f}°C", | ||||||||||||||
f"Feels like {temperature.get('feels_like', None):.2f}°C", | ||||||||||||||
f"Humidity: {main['humidity']:.2f}%", | ||||||||||||||
f"Pressure: {main['pressure']:.2f} hPa", | ||||||||||||||
f"Visibility: {weather.visibility(unit='kilometers'):.2f} km", | ||||||||||||||
f"Wind Speed: { weather.wind(unit='meters_sec')['speed']:.2f} meters per second", | ||||||||||||||
] | ||||||||||||||
) | ||||||||||||||
return self | ||||||||||||||
|
||||||||||||||
# Set the city name | ||||||||||||||
self.cityname.configure(text=f"City: {city}") | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
SUGGESTIONThis change is simple: it takes the name of the city from the API( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you please put it all in the f-string? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, isn't it already in a f-string? What are you referring to? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for a variable is what I mean. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, now I get it. I'll fix it, I need some time. It's already nearing midnight and I'm doing homework. The Life of A Teenage Coder? I will commit it, no problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you do that, I will not work on it though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can improve the layout if you make a better one window idea though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But then how can we integrate the settings into our main window? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It already is. It could use a better design, sure, but a whole window for two settings? That's a little over the top. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could repurpose the same window for settings too. Any ideas on this type? We could use a tabbed window. I'll explain. |
||||||||||||||
|
||||||||||||||
# Update the Progress Bar one last time | ||||||||||||||
print("Updating Progress Bar one last time") | ||||||||||||||
pb.progressbar.step() | ||||||||||||||
|
||||||||||||||
# Stop the Progress Bar, enable buttons and searchbar, and set searching to False | ||||||||||||||
self.start_button.configure(state="normal") | ||||||||||||||
self.searchbar.configure(state="normal") | ||||||||||||||
pb.destroy() | ||||||||||||||
self.searching = False | ||||||||||||||
self.resize_app() # In case the name gets too long or it renders differently on other systems | ||||||||||||||
|
||||||||||||||
def update_labels(self, data: list[str] = ["" for _ in range(9)]) -> None: | ||||||||||||||
"""Clear all weather labels.""" | ||||||||||||||
|
||||||||||||||
self.label_weather.configure(text=data[0]) | ||||||||||||||
self.label_temp.configure(text=data[1]) | ||||||||||||||
self.label_temp_max.configure(text=data[2]) | ||||||||||||||
self.label_temp_min.configure(text=data[3]) | ||||||||||||||
self.label_feels_like.configure(text=data[4]) | ||||||||||||||
self.label_humidity.configure(text=data[5]) | ||||||||||||||
self.label_pressure.configure(text=data[6]) | ||||||||||||||
self.label_visibility.configure(text=data[7]) | ||||||||||||||
self.label_windspeed.configure(text=data[8]) | ||||||||||||||
return None | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
if __name__ == "__main__": | ||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is good to notice this! I tried using the same
bind()
function, but it didn't work. Maybe because I had to usecommand= self.OWMCITY
. I'll test this after lunch.