I have tested code and done fix where needed,the code was also written in Python 2.
So i have also changed so it now work for Python 3.
Here how it look for me,i run Python 3.7 and Win-10.
from newsapi import NewsApiClient
from tkinter import *
from decimal import *
import webbrowser
import PIL.Image
import datetime
import requests
import time
import json
import sys
import dis
import os
directory = 'C:\\code\\img\\WeatherIcons\\' # Where you stored your collection of weather icons
time1 = '' # used in clock
news_api_key = 'your key' # News API key
weather_api_key = 'your key' # Dark Sky API key
width = 100 # Width of four day forecast icons in pixels
height = 100 # Height of four day forecast icons in pixels
degree_sign = u'\N{DEGREE SIGN}' # unicode degrees sign for temperature
# *****Headline Class***** #
class Headline:
# Headline Object consists of a button and an onClick() method
def __init__(self, headline, url, parent_frame):
self.Btn = Button(parent_frame, justify=LEFT, wraplength=250, text=headline, command=self.onClick,
highlightbackground='black', highlightcolor='black', highlightthickness=1)
self.url = url
def onClick(self):
webbrowser.open(self.url) # When pressed open url in web browser
# *****Following 4 day forecast Tkinter layout***** #
class DailyWeather:
days_of_the_week = ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun'] # list of abbreviated weekdays
today = datetime.datetime.today().weekday() # get integer value for current day of the week
# index is it's index of the list produced by getWeather, this identifies it's numerical distance from today's day of the week
# forecast_icons is a dictionary consisting of the icon key names parameter and the local path to the corresponding icon image file
def __init__(self, icon, temp, index, parent_frame, forecast_icons):
self.frame = Frame(parent_frame, highlightbackground='black', highlightcolor='black',
highlightthickness=1) # create frame inside parent_frame
# index determines day of the week and therefore placement relative to today's weather
if index == 0:
self.frame.grid(column=2, row=1, sticky=N + S + E + W)
if index == 1:
self.frame.grid(column=0, row=2, sticky=N + S + E + W)
if index == 2:
self.frame.grid(column=1, row=2, sticky=N + S + E + W)
if index == 3:
self.frame.grid(column=2, row=2, sticky=N + S + E + W)
# configure the 3 by 3 layout to scale when there is available space
for i in range(0, 3):
self.frame.rowconfigure(i, weight=1)
self.frame.columnconfigure(i, weight=1)
self.fp = forecast_icons.get(icon) # get file path of the icon
self.img = PhotoImage(
file=self.fp) # convert image into Tkinter PhotoImage object so it can be placed in a label
self.icon = Label(self.frame, image=self.img) # create icon label
self.temp = Label(self.frame, text=str(temp) + ' ' + degree_sign + 'C') # create temperature label
self.day_name = self.days_of_the_week[
(self.today + index + 1) % len(
self.days_of_the_week)] # use modulo to make list circular and retrieve relative day of the week
self.day = Label(self.frame, text=self.day_name) # create day of the week label
# place the objects labels in the proper spots
def place(self):
self.icon.grid(row=0, column=0, rowspan=3, columnspan=2, sticky=N + S + E + W)
self.day.grid(row=0, column=2, sticky=N + S + E + W)
self.temp.grid(row=2, column=2, sticky=N + S + E + W)
# *****Today's Weather Label Layout***** #
class TodaysWeather:
# icon_fp is the filepath to today's weather icon
def __init__(self, icon_fp, temp, summary, parent_frame):
self.todaysWeatherFrame = Frame(parent_frame, highlightbackground='black', highlightcolor='black',
highlightthickness=1) # create frame for today's weather
self.todaysWeatherFrame.grid(column=0, columnspan=2, row=0, rowspan=2, sticky=N + S + E + W)
# configure todaysWeatherFrame to scale
for i in range(0, 3):
self.todaysWeatherFrame.rowconfigure(i, weight=1)
self.todaysWeatherFrame.columnconfigure(i, weight=1)
# image process is the same as explained in DailyWeather
self.fp = icon_fp
self.img = PhotoImage(file=self.fp)
self.icon = Label(self.todaysWeatherFrame, image=self.img)
self.temp = Label(self.todaysWeatherFrame, text=str(temp) + ' ' + degree_sign + 'C',
justify=LEFT)
self.summary = Label(self.todaysWeatherFrame, text=summary)
self.today = Label(self.todaysWeatherFrame, text='Today', justify=LEFT)
def place(self):
self.icon.grid(row=0, column=0, rowspan=2, columnspan=3, sticky=N + S + E + W)
self.temp.grid(row=1, column=3, sticky=N + S + E + W)
self.summary.grid(row=2, column=0, columnspan=4, sticky=N + S + E + W)
self.today.grid(row=0, column=3, sticky=N + S + E + W)
class MainWindow:
def __init__(self, directory, news_api_key, weather_api_key, width, height):
# initialize MainWindow object variables
self.width = width # width of DailyWeather icons
self.height = height # height of DailyWeather icons
self.news_api_key = news_api_key
self.weather_api_key = weather_api_key
self.directory = directory # directory of base weather icons
self.buttonHeadlines = [] # list of headline buttons
self.forecast = [] # list containing the next four days weather
self.forecast_icons = {} # dictionary of standardized weather keys, and their corresponding DailyWeather sized icon paths
self.todays_icons = {} # dictionary of standardized weather keys, and their corresponding TodaysWeather sized icon paths
self.objects = {} # holds daily weather objects
self.state = False # state for full screen toggle
self.root = Tk() # base Tk() object
self.country = '' # country code used for news headlines
self.todays_weather_list = []
def body(self):
self.root.attributes('-fullscreen', True) # start in fullscreen mode
self.root.bind("<F11>", self.toggle_fullscreen) # bind F11 as button to toggle fullscreen
self.root.bind("<Escape>", self.end_fullscreen) # bind Escape as a way to exit fullscreen
self.root.columnconfigure(0, weight=1) # making root scalable in y
self.root.rowconfigure(0, weight=1) # and x
# ***Base Frame*** #
frame = Frame(self.root)
# allow frame to scale to the size of root
frame.rowconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
frame.grid(sticky=N + S + E + W) # sticky allows it to scale in all directions
# ***Create Left Frame for News Headlines*** #
leftFrame = Frame(frame, bg="red")
leftFrame.grid(row=0, column=0, sticky=N + S + E + W) # in the first row and column of frame
# ***Making the headlines scalable*** #
leftFrame.columnconfigure(0, weight=1)
# top ten headlines, be displayed in 10 rows
for i in range(0, 10):
leftFrame.rowconfigure(i, weight=1)
# ***Frame for clock and weather*** #
rightFrame = Frame(frame)
rightFrame.grid(column=1, row=0, sticky=N + S + E + W)
# allow frame to scale
rightFrame.columnconfigure(0, weight=1)
rightFrame.rowconfigure(0, weight=1)
# ***Frame for weather data*** #
weatherFrame = Frame(rightFrame)
weatherFrame.grid(column=0, row=0, sticky=N + S + E + W)
# make rows and columns of weather data scalable
for i in range(0, 3):
weatherFrame.rowconfigure(i, weight=1)
weatherFrame.columnconfigure(i, weight=1)
# *****Weather***** #
todays_forecast, four_day_forecast = self.getWeather()
# *** Four Day Forecast*** #
for i, day in enumerate(four_day_forecast):
item = DailyWeather(day[0], day[1], i, weatherFrame, self.forecast_icons) # day[0] = icon, day[1] = avgTemp
self.objects['item' + str(i)] = item # store in dictionary to avoid garbage collection on image
for item in self.objects:
self.objects[item].place() # place the DailyWeather Items
# ***Today's weather*** #
icon_fp = self.todays_icons.get(todays_forecast[0])
temp = todays_forecast[1]
summary = todays_forecast[2]
todays_weather = TodaysWeather(icon_fp, temp, summary, weatherFrame)
self.todays_weather_list.append(todays_weather) # store it in list so that garbage collection doesn't throw out the image
self.todays_weather_list[0].place() # place stored TodaysWeather object
# ***Headlines*** #
for title in self.getNews(self.country): # takes in country code for relevant news
headline = Headline(title[0], title[1], leftFrame) # create Headline object with each headline. title[0] = title or article, title[1] = url of article
self.buttonHeadlines.append(headline) # create list of headline objects
# ***Clock Placeholder*** #
Clock = Label(weatherFrame, font=('helvetica', 20, 'bold'), highlightbackground='black',
highlightcolor='black', highlightthickness=1)
# ***Packing in Headlines*** 3
for i, object in enumerate(self.buttonHeadlines):
object.Btn.grid(row=i, sticky=N + S + E + W)
# *****Clock Widget***** #
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)
# ***Placing Clock*** #
Clock.grid(column=2, row=0, sticky=N + S + E + W)
tick()
def toggle_fullscreen(self, event=None):
self.state = not self.state # Just toggling the boolean
self.root.attributes("-fullscreen", self.state)
def end_fullscreen(self, event=None):
self.state = False
self.root.attributes("-fullscreen", False)
def getNews(self, country):
newsapi = NewsApiClient(api_key=self.news_api_key)
newsHeadlines = []
top_headlines = newsapi.get_top_headlines(country=country)
response = top_headlines # this is already in json format, hype
top_ten_headlines = response['articles'][:10] # take top 10 headlines
for articles in top_ten_headlines:
newsHeadlines.append((articles['title'], articles['url'].encode('utf-8')))
return newsHeadlines # return list of tuples
def getWeather(self):
four_day_forecast = [] # list of tuples[(icon, avgTemp)]
# ***Use IP to get Lat/Long for local weather
r = requests.get('http://ip-api.com/json')
response = r.text
response = json.loads(response)
lat_long = str(response['lat']) + ', ' + str(response['lon'])
self.country = str(response['countryCode'])
self.country = self.country.lower()
# ***API request to get weather data
url = 'https://api.darksky.net/forecast/' + self.weather_api_key + '/' + lat_long
weather = requests.get(url, params={'exclude': 'minutely,alerts,flags', 'units': 'ca'})
weather = weather.json()
# ***Today's weather info*** #
todays_weather_raw = weather['hourly']['data'][0]
todays_summary = todays_weather_raw['summary'] # summary of today's weather
todays_icon = todays_weather_raw['icon'] # icon for today's weather
temp = Decimal(todays_weather_raw['temperature'])
temp = round(temp, 1)
todays_temp = temp # current temp
todays_weather = [todays_icon, todays_temp, todays_summary]
# ***Next 4 days weather*** #
for i in range(1, 5):
daily_weather = weather['daily']['data'][i]
x = Decimal((daily_weather['temperatureHigh'] + daily_weather['temperatureLow']) / 2)
avg_temp = round(x, 1)
four_day_forecast.append((daily_weather['icon'], avg_temp))
# now just have to reference icon title to a library of icons for representation in gui
return todays_weather, four_day_forecast
# *****Resize Icons***** #
def resize_icons(self):
# ***Create Subdirectories for resized icons*** #
subdir_forecast = self.directory + 'forecast' # directory for daily forecast sized icons
subdir_todays = self.directory + 'todays' # directory for today's weather sized icons
# if they don't already exist
if not os.path.exists(subdir_forecast):
os.makedirs(subdir_forecast)
if not os.path.exists(subdir_todays):
os.makedirs(subdir_todays)
# ***Iterate through icons directory resizing each image*** #
for file in os.listdir(directory):
if file.endswith('.jpeg') or file.endswith('.png'): # expand depending on what file types your icons are
original_path = directory + file
# open images so they can be resized
#fp = open(original_path)
img = PIL.Image.open(original_path)
resizedImage = img.resize((self.width, self.height), PIL.Image.ANTIALIAS)
resizedImage.save(subdir_forecast + '/' + file, "PNG") # save forecast sized icon
#fp.close()
resizedImage.close()
# repeat above for double the size today's icons
#fp = open(original_path)
img = PIL.Image.open(original_path)
resizedImage = img.resize((int(2 * width), int(2 * height)), PIL.Image.ANTIALIAS) # adjust the multiplying factor of height and width
resizedImage.save(subdir_todays + '/' + file, "PNG")
#fp.close()
resizedImage.close()
# fill dictionary for reference in filling label
name, extension = file.split(".")
self.forecast_icons[name] = str(subdir_forecast + '/' + file)
self.todays_icons[name] = str(subdir_todays + '/' + file)
if __name__ == '__main__':
window = MainWindow(directory, news_api_key, weather_api_key, width, height)
window.resize_icons()
window.body()
window.root.mainloop()