Home » Tutorials » How to Build a Weather App using Tkinter in Python

How to Build a Weather App using Tkinter in Python

In today’s tutorial, we are going to write a code that builds a weather app using a GUI Framework. Specifically the tkinter library, and an API method. This app will allow users to search for weather information by entering the name of any city.

Let’s get started!

Table of Contents

Necessary Libraries

Make sure to install these libraries via the terminal or your command prompt for the code to function properly.

$ pip install tk
$ pip install geopy
$ pip install timezonefinder
$ pip install requests
$ pip install pytz

Learn also: How to Build a Weather App with Flask in Python

Imports

from tkinter import *
from geopy.geocoders import Nominatim
from tkinter import messagebox
from timezonefinder import TimezoneFinder
from datetime import datetime
import requests
import pytz

We start by importing:

  • First, the tkinter library, which allows us to create a graphical user interface (GUI).
  • Second, Nominatim from geopy, used for geocoding and retrieving location information.
  • Third, messagebox from tkinter to display dialogs as message boxes.
  • Our fourth import is TimezoneFinder library, which, as the name suggests, retrieves the timezone based on geographical coordinates.
  • Fifth, we import the datetime library to utilize time functions.
  • Sixth, requests library to communicate with the OpenWeatherMap server.
  • Lastly, pytz library which provides accurate access to time-related information.

Get Weather Function

Next, we create a function that gets the city name and then retrieves the city’s geographical coordinates. If it’s unable to find the coordinates, an error message appears. Otherwise, it determines the timezone of the location and obtains the current local time in the specified timezone.

Using the API key, it extracts important information (such as temperature, wind speed, etc.) of the searched city. If any error occurs during this operation, an error message pops up.

def get_weather():
   try:
       city = textfield.get()
       geolocator = Nominatim(user_agent="weather_app")
       location = geolocator.geocode(city)


       if not location:
           raise ValueError("City Not Found")


       timezone_finder = TimezoneFinder()
       result = timezone_finder.timezone_at(lng=location.longitude, lat=location.latitude)


       home_timezone = pytz.timezone(result)
       local_time = datetime.now(home_timezone)
       current_time = local_time.strftime("%I:%M %p")
       clock.config(text=current_time)
       name.config(text=f"CURRENT WEATHER in {city}, {location.address.split(',')[-1].strip()}")


       # Weather API
       api_key = "Enter YOUR_OPENWEATHERMAP_API_KEY"
       api = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}"


       json_data = requests.get(api).json()
       weather_info = json_data.get('weather', [{}])[0]
       main_info = json_data.get('main', {})
       wind_info = json_data.get('wind', {})
       sys_info = json_data.get('sys', {})


       condition = weather_info.get('main', '')
       description = weather_info.get('description', '')
       temp = int(main_info.get('temp', 0) - 273.15)
       pressure = main_info.get('pressure', 0)
       humidity = main_info.get('humidity', 0)
       wind_speed = wind_info.get('speed', 0)
       country = sys_info.get('country', '')
       sunrise_time = datetime.utcfromtimestamp(sys_info.get('sunrise', 0)).strftime('%H:%M:%S')
       sunset_time = datetime.utcfromtimestamp(sys_info.get('sunset', 0)).strftime('%H:%M:%S')


       temperature_label.config(text=f"{temp} °C")
       condition_label.config(text=f"{condition} | Temperature is {temp} °C")


       wind_label.config(text=f"Wind: {wind_speed} m/s")
       humidity_label.config(text=f"Humidity: {humidity}%")
       description_label.config(text=f"{description.capitalize()}")
       pressure_label.config(text=f"Pressure: {pressure} hPa")
       country_label.config(text=f"Country: {country}")
       sunrise_label.config(text=f"Sunrise: {sunrise_time}")
       sunset_label.config(text=f"Sunset: {sunset_time}")


   except Exception as e:
       messagebox.showerror("Weather App", str(e))

Creating the Main Window

Now, we create the main window, give it a title, define its geometry then disable its resizing.

# Creating the main window
root = Tk()
root.title("Weather App - The Pycodes")
root.geometry("900x600")
root.resizable(False, False)

Creating Search Box and Button

After that we create a search box where the user can input the city name, then we make a “Search” button that once clicked triggers the get_weather function.

# Creating search box
textfield = Entry(root, justify="center", width=17, font=("poppins", 25, "bold"), bg="#404040", border=0, fg="white")
textfield.place(x=50, y=40)
textfield.focus()

search_button = Button(text="Search", font=("Arial", 12, 'bold'), command=get_weather)
search_button.place(x=400, y=34)

Creating Labels

Following that, we create labels that display the names of the important information retrieved by the API such as wind speed, pressure,…. etc, as well as the Labels that will display them by being Updated from the get_weather function.

# Creating labels
label1 = Label(root, text="WIND", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label1.place(x=120, y=400)


label2 = Label(root, text="HUMIDITY", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label2.place(x=250, y=400)


label3 = Label(root, text="DESCRIPTION", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label3.place(x=430, y=400)


label4 = Label(root, text="PRESSURE", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label4.place(x=650, y=400)


label5 = Label(root, text="COUNTRY", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label5.place(x=120, y=500)


label6 = Label(root, text="SUNRISE", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label6.place(x=250, y=500)


label7 = Label(root, text="SUNSET", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label7.place(x=430, y=500)


temperature_label = Label(font=("arial", 70, "bold"), fg="#ee666d")
temperature_label.place(x=400, y=150)
condition_label = Label(font=("arial", 15, 'bold'))
condition_label.place(x=400, y=250)


wind_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
wind_label.place(x=120, y=430)


humidity_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
humidity_label.place(x=280, y=430)


description_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
description_label.place(x=450, y=430)


pressure_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
pressure_label.place(x=650, y=430)


country_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
country_label.place(x=120, y=530)


sunrise_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
sunrise_label.place(x=250, y=530)


sunset_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
sunset_label.place(x=430, y=530)

Creating Time Labels

# Time
name = Label(root, font=("arial", 15, 'bold'))
name.place(x=30, y=100)
clock = Label(root, font=("Helvetica", 20,))
clock.place(x=30, y=130)

Here, we created labels that will display the location and current time.

Main Loop

root.mainloop()

To wrap things up, the script kicks off the Tkinter main event loop with root.mainloop(). This loop is like the heart of the GUI application, constantly listening for what the user does and keeping the app up and running.

Open Weather Map API Key

This is basically a digital key that allows our program to access specific weather information such as temperature, humidity, …., etc. To obtain the API key you need to follow these steps : 

  • First access this site https://openweathermap.org
  • Second, you need to click sign up and if you don’t have an account then create one.
  • Third, after you have successfully created an account, confirmed it, and signed in. Click API Keys.
  • Fourth and last generate an API key.

 Example

Once you hit run after following the code this is the result that you should be getting.

Full Code

from tkinter import *
from geopy.geocoders import Nominatim
from tkinter import messagebox
from timezonefinder import TimezoneFinder
from datetime import datetime
import requests
import pytz


def get_weather():
   try:
       city = textfield.get()
       geolocator = Nominatim(user_agent="weather_app")
       location = geolocator.geocode(city)


       if not location:
           raise ValueError("City Not Found")


       timezone_finder = TimezoneFinder()
       result = timezone_finder.timezone_at(lng=location.longitude, lat=location.latitude)


       home_timezone = pytz.timezone(result)
       local_time = datetime.now(home_timezone)
       current_time = local_time.strftime("%I:%M %p")
       clock.config(text=current_time)
       name.config(text=f"CURRENT WEATHER in {city}, {location.address.split(',')[-1].strip()}")


       # Weather API
       api_key = "Enter YOUR_OPENWEATHERMAP_API_KEY"
       api = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}"


       json_data = requests.get(api).json()
       weather_info = json_data.get('weather', [{}])[0]
       main_info = json_data.get('main', {})
       wind_info = json_data.get('wind', {})
       sys_info = json_data.get('sys', {})


       condition = weather_info.get('main', '')
       description = weather_info.get('description', '')
       temp = int(main_info.get('temp', 0) - 273.15)
       pressure = main_info.get('pressure', 0)
       humidity = main_info.get('humidity', 0)
       wind_speed = wind_info.get('speed', 0)
       country = sys_info.get('country', '')
       sunrise_time = datetime.utcfromtimestamp(sys_info.get('sunrise', 0)).strftime('%H:%M:%S')
       sunset_time = datetime.utcfromtimestamp(sys_info.get('sunset', 0)).strftime('%H:%M:%S')


       temperature_label.config(text=f"{temp} °C")
       condition_label.config(text=f"{condition} | Temperature is {temp} °C")


       wind_label.config(text=f"Wind: {wind_speed} m/s")
       humidity_label.config(text=f"Humidity: {humidity}%")
       description_label.config(text=f"{description.capitalize()}")
       pressure_label.config(text=f"Pressure: {pressure} hPa")
       country_label.config(text=f"Country: {country}")
       sunrise_label.config(text=f"Sunrise: {sunrise_time}")
       sunset_label.config(text=f"Sunset: {sunset_time}")


   except Exception as e:
       messagebox.showerror("Weather App", str(e))




# Creating the main window
root = Tk()
root.title("Weather App - The Pycodes")
root.geometry("900x600")
root.resizable(False, False)


# Creating search box
textfield = Entry(root, justify="center", width=17, font=("poppins", 25, "bold"), bg="#404040", border=0, fg="white")
textfield.place(x=50, y=40)
textfield.focus()


search_button = Button(text="Search", font=("Arial", 12, 'bold'), command=get_weather)
search_button.place(x=400, y=34)


# Creating labels
label1 = Label(root, text="WIND", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label1.place(x=120, y=400)


label2 = Label(root, text="HUMIDITY", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label2.place(x=250, y=400)


label3 = Label(root, text="DESCRIPTION", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label3.place(x=430, y=400)


label4 = Label(root, text="PRESSURE", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label4.place(x=650, y=400)


label5 = Label(root, text="COUNTRY", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label5.place(x=120, y=500)


label6 = Label(root, text="SUNRISE", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label6.place(x=250, y=500)


label7 = Label(root, text="SUNSET", font=("Helvetica", 15, 'bold'), fg="white", bg="#1ab5ef")
label7.place(x=430, y=500)


temperature_label = Label(font=("arial", 70, "bold"), fg="#ee666d")
temperature_label.place(x=400, y=150)
condition_label = Label(font=("arial", 15, 'bold'))
condition_label.place(x=400, y=250)


wind_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
wind_label.place(x=120, y=430)


humidity_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
humidity_label.place(x=280, y=430)


description_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
description_label.place(x=450, y=430)


pressure_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
pressure_label.place(x=650, y=430)


country_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
country_label.place(x=120, y=530)


sunrise_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
sunrise_label.place(x=250, y=530)


sunset_label = Label(text="...", font=("arial", 15, 'bold'), bg="#1ab5ef")
sunset_label.place(x=430, y=530)


# Time
name = Label(root, font=("arial", 15, 'bold'))
name.place(x=30, y=100)
clock = Label(root, font=("Helvetica", 20,))
clock.place(x=30, y=130)


root.mainloop()

Happy Coding!

Scroll to Top