If you want to expand your diary items, it should be better to put the diary items in external file and read them in your backend library. Also you should put the bounding checking in the backend library as well. Then you main application will not need to be changed due to change of the diary items.
I have modified your backend (PhotoDiaryLib.py
) code using class as below:
from PIL import ImageTk, Image
import json
class PhotoDiary:
def __init__(self, width=500, height=500):
self.imageWidth = width
self.imageHeight = height
self.current = -1
self.diary = None
self.loadDiaries()
def loadDiaries(self):
with open('diaries.json') as f:
self.diaries = json.load(f)
def getDiaryList(self):
return self.diaries.keys()
def getDiaryImage(self, diary):
return self.diaries[diary]['image']
def setDiary(self, diary):
self.diary = diary
self.diaryDetails = self.diaries[diary]['items']
self.current = -1
def getImage(self, imageName):
originalImage = Image.open(imageName)
imageRatio = float(originalImage.size[0]) / float(originalImage.size[1])
if imageRatio > 1:
targetSize=(self.imageWidth, int(self.imageHeight/imageRatio))
else:
targetSize=(int(self.imageWidth*imageRatio), self.imageHeight)
resizedImage = originalImage.resize(targetSize, Image.ANTIALIAS)
return ImageTk.PhotoImage(resizedImage)
def get(self, index):
''' get the diary item at given index '''
if 0 <= index < len(self.diaryDetails):
self.current = index
details, imageName = self.diaryDetails[index]
return details, self.getImage(imageName)
return None, None
# navigation functions
next = lambda self: self.get(self.current+1)
previous = lambda self: self.get(self.current-1)
And diaries.json
contains something like below:
{
"Fish": {
"image": "images/fish.jpg",
"items": [
["Test1", "images/1.jpg"],
["Test2", "images/2.jpg"],
["Test3", "images/3.jpg"],
["Test4", "images/4.png"]
]
},
"Birds": {
"image": "images/birds.jpg",
"items": [
...
]
},
"Mammals": {
"image": "images/mammals.jpg",
"items": [
...
]
},
"Snakes": {
"image": "images/snakes.jpg",
"items": [
...
]
}
}
You can add more items into the JSON file.
Then modify your main application to cater the change of the backend library:
from tkinter import *
from PIL import ImageTk,Image
from PhotoDiaryLib import PhotoDiary
class PhotoDiaryApp:
def __init__(self):
self.mainWindow = Tk()
self.mainWindow.title("Diary")
self.pd = PhotoDiary(500, 500)
self.current = StringVar()
# diary list
diaryFrame = Frame(self.mainWindow, bg='blue')
for i, item in enumerate(self.pd.getDiaryList()):
imgtk = ImageTk.PhotoImage(file=self.pd.getDiaryImage(item))
btn = Radiobutton(diaryFrame, text=item, image=imgtk, compound=TOP, indicatoron=0, variable=self.current, value=item)
btn.config(command=lambda d=item:self.changeDiary(d))
btn.grid(row=0, column=i, sticky='ew', ipadx=10)
btn.image = imgtk
if i == 0: self.current.set(item)
diaryFrame.pack(fill=X)
# diary detail frame
detailFrame = Frame(self.mainWindow)
detailFrame.pack(fill=BOTH, expand=1)
self.photoFrame = Frame(detailFrame)
self.labelFrame = Frame(detailFrame)
self.controlFrame = Frame(detailFrame)
self.canvasImage = Canvas(self.photoFrame, width=500, height=500)
self.canvasImage.pack()
self.photo = self.canvasImage.create_image(250, 250, image=None)
self.photoDetails = StringVar()
self.photoLabel = Label(self.labelFrame, textvariable=self.photoDetails)
self.photoLabel.pack()
self.previousButton = Button(self.controlFrame, command=self.previousEntry, text="Previous", width=10)
self.previousButton.pack(side='left')
self.previousNext = Button(self.controlFrame, command=self.nextEntry, text="Next", width=10)
self.previousNext.pack(side='left')
self.photoFrame.pack()
self.labelFrame.pack()
self.controlFrame.pack(pady=10)
# show first diary
self.changeDiary(self.current.get())
self.mainWindow.mainloop()
def changeDiary(self, diary):
#print(self.pd.diary, diary)
if self.pd.diary != diary:
print('Changed to diary:', diary)
self.pd.setDiary(diary)
self.nextEntry()
def updateDiary(self, details, image):
''' update photo details and image '''
if details and image:
self.photoDetails.set(details)
self.photoImage = image
self.canvasImage.itemconfig(self.photo, image=image)
def previousEntry(self):
self.updateDiary(*self.pd.previous())
def nextEntry(self):
self.updateDiary(*self.pd.next())
executeWindow = PhotoDiaryApp()