I have been learning python for 1.5 month now I am learning in my free time between job and other life commitments so my progress may be slow. It may take time for me to reply but I am interested in opinions and reviews on my code in order to get better faster and identify any mistakes I have made.
I would appreciate ideas to improve the code or any thoughts you may have. I would also appreciate reviews focusing on:
- code readability
- code efficiency
Learning language program with few different subjects and languages included.
I have taken all my data from the internet, with translations through Google Translate so the data may be inaccurate. I am also not an artist, please excuse the graphics I've created.
Buttons.py
from tkinter import Button
class Button(Button):
def __init__(self,master, command=None):
super().__init__(master=master)
self['borderwidth'] = 0
self['bg'] = self.master['bg']
self['command'] = command
self['activebackground'] = self.master['bg']
class LanguageSettingsButton(Button):
def __init__(self,master, image, command):
super().__init__(master=master,command=command)
self['image'] = image
class MenuButton(Button):
def __init__(self,master, text, command,font):
super().__init__(master=master,command=command)
self['text'] = text
self['font'] = (font,25)
self['fg'] = '#040814'
Data.py
from PIL import ImageTk,Image
import pandas as pd
import numpy as np
import json
class Data():
def __del__(self):
json.data = {
'native_lang' : self.native_lang,
'active_language' : self.active_language
}
self.prase_data['native_lang'] = self.native_lang
self.prase_data[f'active_language_{self.native_lang}'] = self.active_language
self.settings_file.write(json.dumps(self.prase_data,indent=4))
def __init__(self):
self.supported_languages = ['en','fr','de','es','ja','it','he']
self.subjects = ['Top 100','Top 400','Top 1000','Animals','Food']
self.font = 'David'
self.font_2 = 'FuturistStencil'
self.colors = {
'main' : '#b469ff',
'white' : '#FAF9F6'
}
self.word_list = None
self.progress_list = None
self.logos = {}
self.dictionary = {}
self.borders = {}
self.generals = {}
self.settings_file = open('resources/pylang/settings.json',mode='r')
self.prase_data = json.load(self.settings_file)
self.native_lang = self.prase_data['native_lang']
self.active_language = self.prase_data[f'active_language_{self.native_lang}']
self.settings_file = open('resources/pylang/settings.json', mode='w')
self.load_images()
def load_images(self):
for lang in self.supported_languages:
self.logos[lang] = ImageTk.PhotoImage(file=f'resources/pylang/images/{lang}.png')
self.logos['main'] = ImageTk.PhotoImage(Image.open(fp='resources/pylang/images/main_logo.png'))
self.logos['main_small'] = ImageTk.PhotoImage(Image.open(fp='resources/pylang/images/main_logo.png').resize(size=(140,35)))
self.borders['border'] = ImageTk.PhotoImage(file='resources/pylang/images/border.png')
self.borders['big_up'] = ImageTk.PhotoImage(file='resources/pylang/images/big_border_upside.png')
self.borders['big_down'] = ImageTk.PhotoImage(file='resources/pylang/images/big_border_downside.png')
self.borders['selected'] = ImageTk.PhotoImage(file='resources/pylang/images/selected_border.png')
self.borders['non'] =ImageTk.PhotoImage(file='resources/pylang/images/non_selected_border.png')
self.borders['shade'] = ImageTk.PhotoImage(file='resources/pylang/images/border_shade.png')
self.borders['loadbar'] = ImageTk.PhotoImage(file='resources/pylang/images/loadbar_border.png')
self.generals['return'] = ImageTk.PhotoImage(file='resources/pylang/images/return.png')
self.generals['start'] = ImageTk.PhotoImage(Image.open(fp='resources/pylang/images/start.png').resize(size=(60,60)))
self.generals['start_s'] = ImageTk.PhotoImage(Image.open(fp='resources/pylang/images/start.png').resize(size=(49,40)))
self.generals['loadbar'] = Image.open(fp='resources/pylang/images/loadbar.png')
self.generals['check_button'] = ImageTk.PhotoImage(file='resources/pylang/images/check_button.png')
self.generals['cancel_button'] = ImageTk.PhotoImage(file='resources/pylang/images/cancel_button.png')
def load_menu(self,lang):
temp_csv = pd.read_csv('resources/pylang/menu.csv')
return temp_csv[lang]
def load_language(self,lang):
temp_csv = pd.read_csv('resources/pylang/languages.csv')
return temp_csv[lang]
def get_loadbar(self,percentage):
temp_loadbar = self.generals['loadbar'].crop((0,0,155*(percentage/100),15))
temp_loadbar = ImageTk.PhotoImage(temp_loadbar)
return temp_loadbar
def get_lists(self,subject,lang):
self.word_list = pd.read_csv(f'resources/pylang/words/{subject}.csv').copy()
self.progress_list = pd.read_csv(f'resources/pylang/progress/{subject}_{self.native_lang}_progress.csv').copy()
for n,word in enumerate(self.progress_list[lang]):
self.word_list[self.word_list[lang] == word] = np.nan
def update_progress(self,subject,learned_lang,word):
word_list = self.progress_list[learned_lang].dropna()
self.progress_list.loc[len(word_list),learned_lang] = word
self.progress_list.to_csv(path_or_buf=f'resources/pylang/progress/{subject}_{self.native_lang}_progress.csv',index=False)
self.word_list[self.word_list[learned_lang] == word] = np.nan
SubFrame.py
from tkinter import Frame,Canvas,Label
from Buttons import *
class SubFrame(Frame):
def __init__(self,master,data,headline):
super().__init__(master=master,width=master.width,height=master.height,bg=master['bg'])
self.width = master.width
self.height = master.height
self.pack_propagate(False)
self.pack()
self.data = data
self.header_frame = Frame(master=self,width=self.width,height=self.height*0.08,
bg=self.data.colors['white'])
self.header_frame.pack_propagate(False)
self.header_frame.pack()
self.return_button = LanguageSettingsButton(master=self.header_frame, image=self.data.generals['return'],
command=self.destroy)
self.return_button.pack(side='left', pady=5, padx=10)
self.logo = Canvas(master=self.header_frame, width=140, height=35, highlightthickness=0,
bg=self.header_frame['bg'])
self.logo.create_image(70, 35 / 2, image=self.data.logos['main_small'])
self.logo.pack(side='right', pady=5, padx=10)
self.header = Label(master=self.header_frame, text=headline, font=(self.data.font, 20),
bg=self.header_frame['bg'])
self.header.pack(pady=5)
self.main_frame = Frame(master=self, width=self.width, height=self.height - 50, bg=self['bg'])
self.main_frame.pack()
def clear_frames(self):
self.main_frame.destroy()
self.header_frame.destroy()
mainwindow.py
import pandas as pd
from tkinter import Tk,Frame,Canvas
from Data import Data
from Buttons import LanguageSettingsButton,MenuButton
from NewLearnFrame import NewLearnFrame
from ContinueLearnFrame import ContinueLearnFrame
MAIN_COLOR = '#b469ff'
MAIN_COLOR_LIGHT = '#cd9cff'
SECOND_COLOR = '#040814'
SECOND_COLOR_LIGHT = '#0c193e'
OFF_WHITE = '#FAF9F6'
class MainWindow(Tk):
def __init__(self, title, width, height):
#window settings
super().__init__()
self.title(title)
self.geometry('1x1+600+200')
self.minsize(width=width, height=height)
self.width = width
self.height = height
self['bg'] = MAIN_COLOR
#general settings
self.data = Data()
#settings_frame
self.settings_container = Frame(master=self,bg=self['bg'],borderwidth=0)
self.settings_container.place(x=self.width*0.94, y=self.height*0.01)
self.language_button = LanguageSettingsButton(master=self.settings_container,
image=self.data.logos[self.data.native_lang],
command=self.open_lang_menu)
self.language_button.grid(column=0,row=0)
#menu_frame
self.menu = self.data.load_menu(self.data.native_lang)
item_spaces = 25
self.menu_container = Frame(master=self,bg=OFF_WHITE)
self.menu_container.place(x=self.width/2, y=self.height/2,anchor='center')
self.logo = Canvas(self.menu_container,width=240,height=60,highlightthickness=0,bg=self.menu_container['bg'])
self.logo.create_image(0,0,image = self.data.logos['main'],anchor='nw')
self.logo.pack(pady=item_spaces/2,anchor='center')
self.learn_new_button = MenuButton(self.menu_container,text=self.menu[0],font=self.data.font,
command=lambda : NewLearnFrame(self,self.data))
self.learn_new_button.pack(pady=item_spaces)
self.continue_learn_button = MenuButton(self.menu_container, text=self.menu[1],font=self.data.font,
command=lambda: ContinueLearnFrame(master=self,data=self.data))
self.continue_learn_button.pack(pady=item_spaces)
self.exit_button = MenuButton(self.menu_container,font=self.data.font,text=self.menu[2],command=self.destroy)
self.exit_button.pack(pady=item_spaces)
def open_lang_menu(self):
if len(self.settings_container.children) <= 1:
row_parm = 0
for language in self.data.supported_languages:
if language != self.data.native_lang:
row_parm += 1
LanguageSettingsButton(master=self.settings_container, image=self.data.logos[language],
command=lambda lang=language: self.update_language(lang)).grid(column=0,row=row_parm)
else:
self.close_lang_menu()
def update_language(self,lang):
self.data.native_lang = lang
self.language_button.config(image=self.data.logos[lang])
self.menu = self.data.load_menu(self.data.native_lang)
self.learn_new_button['text'] = self.menu[0]
self.continue_learn_button['text'] = self.menu[1]
self.exit_button['text'] = self.menu[2]
self.close_lang_menu()
self.data.active_language = self.data.prase_data[f'active_language_{self.data.native_lang}']
for subject in self.data.subjects:
try:
open(f'resources/pylang/progress/{subject}_{self.data.native_lang}_progress.csv')
except:
df = pd.DataFrame(columns=self.data.supported_languages)
df.to_csv(f'resources/pylang/progress/{subject}_{self.data.native_lang}_progress.csv')
def close_lang_menu(self):
for child in self.settings_container.winfo_children()[1:]:
child.destroy()
if __name__ == '__main__':
MainWindow = MainWindow('Pylang',800,600)
MainWindow.mainloop()
NewLearnFrame.py
from tkinter import Canvas
from Buttons import LanguageSettingsButton
from SubFrame import SubFrame
class NewLearnFrame(SubFrame):
def __init__(self,master,data):
super().__init__(master=master, data=data, headline='Choose Language')
self.lang_cards = []
self.selected_card = None
self.language_list = self.data.load_language(self.data.native_lang)
self.main_frame.grid_propagate(False)
for x in range(0,int(len(self.data.supported_languages)/3)+1):
if x < 3:
self.main_frame.columnconfigure(index=x,pad=25)
self.main_frame.rowconfigure(index=x,pad=25)
row = 0
col = 0
for index,lang in enumerate(self.data.supported_languages):
card = Canvas(master=self.main_frame, width=240, height=160,bg=self.main_frame['bg'],highlightthickness=0)
card.create_image(120, 80, image=self.data.borders['non'],tag='border')
card.create_text(120,30,text=self.language_list[index],font=(self.data.font,25))
card.create_image(120, 80, image=self.data.logos[lang])
if lang == self.data.native_lang or lang in self.data.active_language:
card.create_image(120,80,image=self.data.borders['shade'],tag='shade')
card.grid(column=col,row=row)
card.bind("<Button-1>",lambda e,i=index:self.select_card(i))
col += 1
if col == 3:
col = 0
row += 1
self.lang_cards.append(card)
self.start_learn_button = LanguageSettingsButton(master=self.main_frame,image=self.data.generals['start'],
command=lambda : self.add_language(self.selected_card))
self.start_learn_button.grid(column=2,row=row,sticky='se',pady=10)
def add_language(self,language):
self.data.active_language.append(self.data.supported_languages[self.lang_cards.index(language)])
self.destroy()
def select_card(self,index):
if self.data.native_lang != self.data.supported_languages[index] and self.data.supported_languages[index] not in self.data.active_language:
if self.selected_card == None:
self.selected_card = self.lang_cards[index]
self.selected_card.itemconfig('border',image=self.data.borders['selected'])
return
self.selected_card.itemconfig('border',image=self.data.borders['non'])
self.selected_card = self.lang_cards[index]
self.selected_card.itemconfig('border', image=self.data.borders['selected'])
ContinueLearnFrame.py
import random
import numpy as np
from SubFrame import SubFrame
from Buttons import LanguageSettingsButton
from tkinter import Canvas
class ContinueLearnFrame(SubFrame):
def __init__(self,master,data,selected_lang=None):
super().__init__(master=master, data=data, headline='Choose Language')
self.main_frame.grid_propagate(False)
self.main_frame.pack_propagate(False)
self.cards = []
self.cards_loadbar = []
self.buttons = []
self.words = {}
self.selected_lang = selected_lang
if self.selected_lang == None:
self.load_languages()
def learn_language(self,lang):
self.selected_lang = lang
self.load_subjects()
def erase(self):
for card in self.cards:
card.destroy()
for button in self.buttons:
button.destroy()
self.cards = []
self.buttons = []
self.cards_loadbar = []
def load_languages(self):
self.erase()
self.header.config(text="Choose Language")
self.return_button.config(command=self.destroy)
for col in range(0, 3):
self.main_frame.columnconfigure(index=col, pad=25)
for row in range(0, int(len(self.data.active_language) / 3) + 1):
self.main_frame.rowconfigure(index=row, pad=25)
col = 0
row = 0
for index, lang in enumerate(self.data.active_language):
card = Canvas(master=self.main_frame, width=240, height=160, bg=self.main_frame['bg'], highlightthickness=0)
card.create_image(120, 80, image=self.data.borders['border'], tag='border')
card.create_text(120, 50, text=self.data.active_language[index], font=(self.data.font, 25))
card.create_image(120, 110, image=self.data.logos[lang])
card.grid(column=col, row=row)
card.bind("<Button-1>", lambda e, l=lang: self.learn_language(l))
if col < 2:
col += 1
else:
row += 1
col = 0
self.cards.append(card)
def load_subjects(self):
self.erase()
self.header.config(text="Choose Subject")
self.return_button.config(command=self.load_languages)
for col in range(0, 3):
self.main_frame.columnconfigure(index=col, pad=25)
for row in range(0, int(len(self.data.subjects) / 3) + 1):
self.main_frame.rowconfigure(index=row, pad=25)
col = 0
row = 0
for index, subj in enumerate(self.data.subjects):
self.data.get_lists(subject=subj,lang=self.selected_lang)
total = len(self.data.word_list[self.selected_lang])
progress = len(self.data.progress_list[self.selected_lang].dropna())
precent = round((progress/total)*100)
self.cards_loadbar.append(self.data.get_loadbar(precent))
card = Canvas(master=self.main_frame, width=240, height=160, bg=self.main_frame['bg'], highlightthickness=0)
if len(self.data.word_list[self.selected_lang].dropna()) != 0:
card.create_image(120, 80, image=self.data.borders['loadbar'], tag='border')
card.create_image(14, 135, image=self.cards_loadbar[-1], tag='loadbar',anchor='w')
card.create_text(205, 135, text=f'{precent}%', font=(self.data.font, 16))
card.create_text(120, 90, text=f'{progress}/'
f'{total}',
font=(self.data.font, 25))
card.bind("<Button-1>", lambda e, sub=self.data.subjects[index]: self.load_learn_program(sub))
else:
card.create_image(120, 80, image=self.data.borders['border'], tag='border')
card.create_text(120, 135, text=f'COMPLETED', font=(self.data.font, 16))
card.create_text(120, 90, text='100%',
font=(self.data.font, 25))
card.create_text(120, 40, text=self.data.subjects[index], font=(self.data.font, 30))
card.grid(column=col, row=row)
if col < 2:
col += 1
else:
row += 1
col = 0
self.cards.append(card)
def load_learn_program(self,subject):
self.data.get_lists(subject=subject,lang=self.selected_lang)
def load_cards(self):
card_upside = Canvas(master=self.main_frame, width=600, height=400, bg=self.main_frame['bg'],
highlightthickness=0)
card_upside.create_image(300, 200, image=self.data.borders['big_up'], tag='border')
card_upside.create_text(300, 100,
text=f'{self.data.load_language(lang=self.data.native_lang)[self.data.supported_languages.index(self.selected_lang)]}',
font=(self.data.font, 50),
tags='headline')
card_upside.create_text(300,250,text='',font=(self.data.font, 30),tags='word')
card_upside.bind("<Button-1>", lambda e: swap_cards(self, 0))
card_upside.pack(pady=40)
self.cards.append(card_upside)
card_downside = Canvas(master=self.main_frame, width=600, height=400, bg=self.main_frame['bg'],
highlightthickness=0)
card_downside.create_image(300, 200, image=self.data.borders['big_down'], tag='border')
card_downside.create_text(300, 100,
text=f'{self.data.load_language(lang=self.data.native_lang)[self.data.supported_languages.index(self.data.native_lang)]}',
font=(self.data.font, 50),
tags='headline')
card_downside.create_text(300,250,text='',font=(self.data.font, 30),tags='word')
card_downside.bind("<Button-1>", lambda e: swap_cards(self, 1))
self.cards.append(card_downside)
def swap_cards(self, index):
if index == 0:
self.cards[0].pack_forget()
self.cards[1].pack(pady=40)
else:
self.cards[0].pack(pady=40)
self.cards[1].pack_forget()
def update_cards(self):
while(True):
try:
random_word = random.choice(self.data.word_list[self.selected_lang].dropna().tolist())
if random_word != np.nan and random_word != np.NaN:
current_word_index = self.data.word_list.index[self.data.word_list[self.selected_lang] == random_word].tolist()[0]
self.words['native'] = self.data.word_list[self.data.native_lang][current_word_index]
self.words['learned'] = self.data.word_list[self.selected_lang][current_word_index]
self.cards[0].itemconfigure('word', text=f'{self.words['learned']}')
self.cards[1].itemconfigure('word', text=f'{self.words['native']}')
break
except IndexError as e:
self.cards[0].itemconfigure(tagOrId='headline',text='Congratulations')
self.cards[0].itemconfigure(tagOrId='word',text='Subject completed')
for button in self.buttons:
button.destroy()
break
try:
self.cards[0].pack_info()
except:
swap_cards(self,1)
def approval_word(self):
self.data.update_progress(subject=subject,learned_lang=self.selected_lang,word=self.words['learned'])
update_cards(self)
self.erase()
self.header.config(text=f"{subject}")
self.return_button.config(command=self.load_subjects)
load_cards(self)
update_cards(self)
check_button = LanguageSettingsButton(master=self.main_frame, image=self.data.generals['check_button'],
command=lambda : approval_word(self))
check_button.place(x=300, y=500, anchor='center')
self.buttons.append(check_button)
cancel_button = LanguageSettingsButton(master=self.main_frame, image=self.data.generals['cancel_button'],
command=lambda : update_cards(self))
cancel_button.place(x=500,y=500,anchor='center')
self.buttons.append(cancel_button)