Tkinter application to manage school tasksPython tkinter GUIAutoclicker Tkinter ProgramCalculator using...
Can a person refuse a presidential pardon?
Check if the digits in the number are in increasing sequence in python
Grade 10 Analytic Geometry Question 23- Incredibly hard
Can an insurance company drop you after receiving a bill and refusing to pay?
What is the wife of a henpecked husband called?
What's the most convenient time of year to end the world?
Compress command output by piping to bzip2
Explain the objections to these measures against human trafficking
Would a National Army of mercenaries be a feasible idea?
How do you funnel food off a cutting board?
How to prevent cleaner from hanging my lock screen in Ubuntu 16.04
Why Normality assumption in linear regression
Why do neural networks need so many training examples to perform?
What is better: yes / no radio, or simple checkbox?
How to prevent users from executing commands through browser URL
What is the purpose of easy combat scenarios that don't need resource expenditure?
Groups acting on trees
How would a Dictatorship make a country more successful?
Every character has a name - does this lead to too many named characters?
Pre-1980's science fiction short story: alien disguised as a woman shot by a gangster, has tentacles coming out of her breasts when remaking her body
How would one buy a used TIE Fighter or X-Wing?
Why do members of Congress in committee hearings ask witnesses the same question multiple times?
Why zero tolerance on nudity in space?
Using only 1s, make 29 with the minimum number of digits
Tkinter application to manage school tasks
Python tkinter GUIAutoclicker Tkinter ProgramCalculator using TkinterCalendar made with tkinterQuiz application with tkinterpython tkinter Monty Hall GUI visualizationRolling Dice Simulation using TkinterTkinter Application to Read & Update a CSV FileSnake Game using python and tkinterPython tkinter Snake
$begingroup$
I'm a beginner in OOP programming and I'm wondering what is the best way to put all the windows and functions of a window application in the code.
My biggest questions are:
- Am I using classes and function in the right way?
- There is an efficient way to create windows and widgets?
- Why do I see so many peoples inheriting from
tk.Frame
in window classes? - In the example of application given in Tkinter documentation, they put the widgets inside a method called "create_widgets", is this recommended instead put them in the
__init__
method?
I translated the interface from the original Brazilian Portuguese before posting the question here.
"""Componentes Curriculares V0.1.
This program is meant to be a task manager to your School Year.
It is composed by various functions such as:
-List of all your tasks and tests, and a complete school report based on these
tasks. (This last one still is a work in progress.)
You can also add your topics for each subject that you are having along the
year.
The main language of the interface is Portuguese and their source code was
written in English.
Python 3.7 is the current version.
"""
import tkinter as tk
from tkinter import ttk, messagebox
from tkinter.scrolledtext import ScrolledText
from datetime import datetime
import pickle
import getpass
# Standard variables used for multiple widgets.
fontlab_std = 'Tahoma 12 bold'
fontbut_std = 'Tahoma 9'
bg_std = 'cornsilk2'
hover_std = 'Created by Wilson Cazarré - 3° Mecatrônica. Alpha 0.1'
icon_windows = 'book.ico'
my_subjects = ['LPL',
'Matemática',
'Biologia',
'Geografia',
'História',
'Química',
'Física',
'Filosofia',
'Sociologia',
'Educação Física',
'Inglês',
'Tecnologia de Manufatura 3',
'Linguagem de Programação Aplicada a Mecatrônica',
'Automação e Instrumentação Industrial 3',
'Microcontroladores',
'Tecnologia de Qualidade e processos',
'Robótica e Manufatura Flexível',
'Eletrônica Industrial e de Potência',
'Planejamento e Desenvolvimento do Trabalho de Conclusão de '
'Curso']
grades = ['MB',
'B',
'R',
'I']
days = list(range(1, 32))
mouths = ['Janeiro',
'Fevereiro',
'Março',
'Abril',
'Maio',
'Junho',
'Julho',
'Agosto',
'Setembro',
'Outubro',
'Novembro',
'Dezembro']
years = list(range(2019, 2030))
weekdays = ['Segunda',
'Terça-feira',
'Quarta-feira',
'Quinta-feira',
'Sexta-feira',
'Sábado',
'Domingo']
# ---------------------------------
def load_pickle(file) -> list:
try:
with open(file, 'rb') as infile:
tasks_objects = pickle.load(infile)
tasks_objects.sort(key=lambda task: task.full_date)
return tasks_objects
except FileNotFoundError:
return []
except PermissionError:
messagebox.showerror('Acesso Negado',
'Erro ao ler o arquivo. Iniciar como administrador')
def dump_pickle(file, obj):
with open(file, 'wb') as outfile:
pickle.dump(obj, outfile, pickle.HIGHEST_PROTOCOL)
# --------------------------------- Custom Widgets with default option
class MyButton(tk.Button):
"""Create a custom button widget, with default options."""
def __init__(self, master=None, hovertext=None, **kw):
tk.Button.__init__(self, master=master, **kw)
self.configure(font=fontbut_std, relief='groove') # Default options
if hovertext is not None:
self.bind('<Enter>', lambda x: self.on_hover(hovertext))
self.bind('<Leave>', lambda x: self.on_hover(hover_std))
@staticmethod
def on_hover(text):
app.hover_box.configure(text=text)
class MyLabel(tk.Label):
"""Create a custom button widget, with default options."""
def __init__(self, master=None, cnf=None, **kw):
tk.Label.__init__(self, master=master, cnf=cnf, **kw)
self.configure(bg=bg_std)
# --------------------------------- All windows, and the Task Class
class Task:
"""Objects listed in the 'MainWindow.tasks_widget'.
Tasks are saved in the following lists:
list: open_tasks: tasks not completed.
list: ended_tasks: tasks completed.
"""
def __init__(self, subject, title, day, month, year, category,
description=None, is_done=False, grade=None):
self.subject = subject
self.title = title
self.day = day
self.month = month
self.year = year
self.description = description
self.is_done = is_done
self.grade = grade
self.category = category
self.full_date = datetime(int(self.year), mouths.index(self.month) + 1,
int(self.day))
self.weekday = self.full_date.weekday()
def __str__(self):
return '{} - {}: "{}" '
'para o dia {}/{}/{} ({})'.format(self.subject, self.category,
self.title, self.day,
self.month, self.year,
weekdays[self.
weekday])
def str_task_complete(self):
return '{}: "{}" Menção: {} - {}/{}/{}'.format(self.category,
self.title,
self.grade,
self.day,
self.month,
self.year)
class MainWindow:
"""Create the first window of the program.
self.add_button - invoke AddTaskWindow -> create a task object.
self.done_button - invoke EndTaskWindow -> set the task object as done.
"""
def __init__(self, master):
self.master = master
# Master window configs
master.title('Componentes Curriculares')
master.minsize(width=900, height=520)
master.maxsize(width=900, height=520)
master.geometry('+360+100')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
# Setup Widgets
self.title = MyLabel(self.master, text='My Subjects',
font='Tahoma 15 bold',
bg=bg_std,
fg='DeepSkyBlue2',
anchor='e',
width=67)
self.tasks_title = MyLabel(self.master,
text='Tasks, tests and events',
font='Tahoma 12 bold')
self.tasks_widget = tk.Listbox(self.master,
width=100, height=25,
relief='solid',
highlightthickness=0)
for task in open_tasks:
self.tasks_widget.insert('end', task)
self.tasks_widget.bind('<Enter>', lambda x: MyButton.on_hover
('Double click to set a task as done.'))
self.tasks_widget.bind('<Leave>', lambda x: MyButton.on_hover
(hover_std))
self.tasks_widget.bind('<Double-Button-1>',
lambda x: EndTaskWindow(tk.Toplevel(),
self.tasks_widget.
curselection()))
self.add_button = MyButton(self.master,
hovertext='Add a task.',
text='+',
fg='green3',
command=self.open_task_window,
width=1)
self.sub_button = MyButton(self.master,
hovertext='Remove current selected task.',
text='-',
fg='red',
command=lambda: self.delete_task
(self.tasks_widget.curselection()),
width=1)
self.done_button = MyButton(self.master,
hovertext='Finalizar tarefa e registar a '
'menção.',
text='Complete',
command=lambda: EndTaskWindow(
tk.Toplevel(),
self.tasks_widget.curselection()))
self.view_button = MyButton(self.master,
hovertext='Show task information.',
text='Open',
command=lambda: ViewTaskWindow(
tk.Toplevel(),
self.tasks_widget.curselection()))
self.tasks_widget.bind('<Delete>', lambda x: self.delete_task(
self.tasks_widget.curselection()))
self.hover_box = tk.Label(self.master, text=hover_std, bg='white',
anchor='w')
self.combo_title = MyLabel(self.master,
text='Show subjects information:',
font='Tahoma 9 bold')
self.combo_subjects = ttk.Combobox(self.master, values=my_subjects,
width=30)
self.combo_confirm = MyButton(self.master, text='Open',
hovertext='Exibir janela de informações '
'da matéria selecionada',
command=lambda: SubjectWindow(
tk.Toplevel(),
self.combo_subjects.get()))
self.combo_confirm['font'] = 'Tahoma 9'
# Place Widgets
self.title.place(x=10, y=5)
self.tasks_title.place(x=10, y=30)
self.tasks_widget.place(x=10, y=58)
self.add_button.place(x=10, y=463)
self.sub_button.place(x=28, y=463)
self.done_button.place(x=46, y=463)
self.view_button.place(x=110, y=463)
self.combo_title.place(x=630, y=180)
self.combo_subjects.place(x=630, y=200)
self.combo_confirm.place(x=835, y=198)
self.hover_box.pack(side='bottom', fill='x')
def open_task_window(self):
"""Hey"""
window2 = tk.Toplevel()
self.add_button['state'] = 'disable'
self.sub_button['state'] = 'disable'
self.done_button['state'] = 'disable'
self.view_button['state'] = 'disable'
self.combo_confirm['state'] = 'disable'
self.taskwindow = AddTaskWindow(window2)
def delete_task(self, index):
delete_box = 'no'
if index != ():
delete_box = messagebox.askquestion('Deletar Tarefa',
'Deletar tarefa selecionada?')
if delete_box == 'yes':
self.tasks_widget.delete(index)
open_tasks.pop(index[0])
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
class AddTaskWindow:
"""Launch the window for create a task in
MainWindow.tasks_widget(tk.Listbox)
self.register_button -> self.create_task -> Task -> Create task object.
"""
def __init__(self, master):
self.master = master
app.done_button['state'] = 'disable'
master.title('Criar Tarefa')
master.geometry('600x400+500+200')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.protocol('WM_DELETE_WINDOW', self.close_window)
master.focus_force()
self.radio_var = tk.StringVar()
# Setup Widgets
self.title_radio = MyLabel(self.master, text='Task type:',
font='Tahoma 8 bold')
self.radio1 = tk.Radiobutton(self.master, text='Test',
variable=self.radio_var, value='Prova',
bg=bg_std,
activebackground=bg_std)
self.radio2 = tk.Radiobutton(self.master, text='Homework',
variable=self.radio_var, value='Trabalho',
bg=bg_std,
activebackground=bg_std)
self.radio3 = tk.Radiobutton(self.master, text='Other',
variable=self.radio_var,
value='Outro(Sem menção)', bg=bg_std,
activebackground=bg_std)
self.title_entry = MyLabel(self.master, text='Task title:',
font='Tahoma 8 bold')
self.entry = tk.Entry(self.master, width=60, relief='groove')
self.title_combo_subjects = MyLabel(self.master,
text='Task subject:',
font='Tahoma 8 bold')
self.combo_subjects = ttk.Combobox(self.master, values=my_subjects,
width=60)
self.title_date = MyLabel(self.master, text='Task date:',
font='Tahoma 8 bold')
self.combo_day = ttk.Combobox(self.master, values=days, width=3)
self.combo_day.current(days.index(datetime.now().day))
self.combo_mouth = ttk.Combobox(self.master, values=mouths, width=10)
self.combo_mouth.current(datetime.now().month - 1)
self.combo_year = ttk.Combobox(self.master, values=years, width=5)
self.combo_year.current(years.index(datetime.now().year))
self.register_button = MyButton(self.master, text='Criar tarefa',
command=self.create_task)
self.description_box_title = MyLabel(self.master,
text='Task description:',
font='Tahoma 10 bold')
self.description_box = ScrolledText(self.master, font='Consolas 9',
width=60, height=10)
# Place Widgets
self.title_radio.place(x=10, y=10)
self.radio1.place(x=150, y=10)
self.radio2.place(x=210, y=10)
self.radio3.place(x=285, y=10)
self.title_entry.place(x=10, y=35)
self.entry.place(x=150, y=35)
self.title_combo_subjects.place(x=10, y=60)
self.combo_subjects.place(x=150, y=60)
self.title_date.place(x=10, y=85)
self.combo_day.place(x=150, y=85)
self.combo_mouth.place(x=190, y=85)
self.combo_year.place(x=271, y=85)
self.register_button.place(x=360, y=122)
self.description_box_title.place(x=10, y=125)
self.description_box.place(x=10, y=150)
def create_task(self):
"""Create the task object and update the '
MainWindow.tasks_widget(tk.Listbox)'."""
new_task = Task(subject=self.combo_subjects.get(),
title=self.entry.get(),
day=self.combo_day.get(),
month=self.combo_mouth.get(),
year=self.combo_year.get(),
category=self.radio_var.get(),
description=self.description_box.get('1.0', 'end'))
app.tasks_widget.delete(0, 'end')
open_tasks.insert(0, new_task)
open_tasks.sort(key=lambda task: task.full_date)
for task in open_tasks:
app.tasks_widget.insert('end', task)
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
self.close_window()
def close_window(self):
app.add_button['state'] = 'active'
app.sub_button['state'] = 'active'
app.done_button['state'] = 'active'
app.view_button['state'] = 'active'
app.combo_confirm['state'] = 'active'
self.master.destroy()
class EndTaskWindow:
"""Launch the window for end a task.
Invoked from MainWindow.done_button -> returns the current selection on
the MainWindow.tasks_widget
-> task_index -> EndTaskWindow.__init__.
"""
def __init__(self, master, task_index):
self.master = master
if task_index != ():
self.task_index = task_index
self.task = open_tasks[task_index[0]]
master.title('Finalizar Tarefa')
master.minsize(width=250, height=190)
master.maxsize(width=250, height=190)
master.geometry('+500+200')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.focus()
master.protocol('WM_DELETE_WINDOW', self.close_window)
# Setup Widgets
self.title_info = MyLabel(self.master, text='Dados da Atividade',
font='Tahoma 14 bold')
self.info_label_header = MyLabel(self.master,
text='Tipo:nTítulo:nMatéria:'
'nData:',
justify='left',
font='Tamoha 10 bold')
self.info_label = MyLabel(self.master, justify='left',
font='Tahoma 10 italic',
text='{}n{}n{}n{}'.format(
self.task.category, self.task.title,
self.task.subject,
self.task.full_date))
self.title_combo_grades = MyLabel(self.master,
text='Insira a menção final:',
font='Tahoma 11 bold')
self.combo_grades = ttk.Combobox(self.master, values=grades, width=3)
self.finish_button = MyButton(self.master, text='Finalizar',
command=lambda: self.end_task(
self.combo_grades.get()),
anchor='center')
# Place Widgets
self.title_info.place(x=10, y=10)
self.info_label_header.place(x=10, y=40)
self.info_label.place(x=75, y=40)
self.title_combo_grades.place(x=10, y=125)
self.combo_grades.place(x=180, y=127)
self.finish_button.place(x=95, y=155)
def end_task(self, grade):
"""Set the task as done.
self.finish_button -> returns the current selection in
self.combo_grades(tk.Combobox)
Define task.is_done as True and grade.
Remove this object from the list: open_task, append to list:
ended_tasks
"""
self.task.is_done = True
self.task.grade = grade
self.close_window()
print(self.task.grade)
print(self.task.is_done)
ended_tasks.append(self.task)
open_tasks.remove(self.task)
app.tasks_widget.delete(0, 'end')
for task in open_tasks:
app.tasks_widget.insert('end', task)
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
def close_window(self):
self.master.destroy()
class ViewTaskWindow:
def __init__(self, master, task_index):
self.master = master
if task_index != ():
self.task_index = task_index
self.task = open_tasks[task_index[0]]
master.title('Finalizar Tarefa')
master.minsize(width=500, height=450)
master.maxsize(width=500, height=450)
master.geometry('+500+75')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.focus()
master.protocol('WM_DELETE_WINDOW', self.close_window)
if self.task.description == 'n':
self.description = 'Nothing to show'
else:
self.description = self.task.description
# Setup Widgets
self.title_info = MyLabel(self.master, text='Task information',
font='Tahoma 14 bold')
self.info_label_header = MyLabel(self.master,
text='Type:nTitle:nSubject:'
'nDate:',
justify='left',
font='Tamoha 10 bold')
self.date_text = str(self.task.full_date).split(' ')
self.info_label = MyLabel(self.master, justify='left',
font='Tahoma 10 italic',
text='{}n{}n{}n{}'.format(
self.task.category, self.task.title,
self.task.subject,
self.date_text[0]))
self.description_title = MyLabel(self.master,
text='Task description:',
font='Tahoma 11 bold')
self.description_label = MyLabel(self.master,
text=self.description,
font='Consolas 9', justify='left')
self.description_text = ScrolledText(self.master, width=60,
height=20, font='Consolas 9')
self.description_text.insert('1.0', self.description)
self.description_text['state'] = 'disable'
# Place Widgets
self.title_info.place(x=10, y=10)
self.info_label_header.place(x=10, y=40)
self.info_label.place(x=75, y=40)
self.description_title.place(x=10, y=120)
self.description_text.place(x=10, y=150)
# self.description_label.place(x=10, y=150)
def close_window(self):
self.master.destroy()
class SubjectWindow:
"""Launch the window with all completed tasks of specified subject
Invoke by MainApplication.combo_confirm(tk.Button) ->
returns the selection on MainApplication.combo_subjects
-> subject -> SubjectWindow.__init__.
"""
def __init__(self, master, subject):
if subject in my_subjects:
self.master = master
self.subject = subject
self.text_tasks_label = ''
app.combo_confirm['state'] = 'disabled'
master.title(subject)
master.geometry('800x400')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.protocol('WM_DELETE_WINDOW', self.close_window)
else:
master.destroy()
# Setup Widgets
self.title = MyLabel(self.master,
text=self.subject,
font='Tahoma 15 bold')
self.label1 = MyLabel(self.master,
text='Bases Tecnológicas',
font='Tahoma 12 bold')
self.label2 = MyLabel(self.master,
text='Atividades e Menções',
font='Tahoma 12 bold')
for task in ended_tasks:
if task.subject == self.subject:
print(task)
print(task.str_task_complete())
self.text_tasks_label += task.str_task_complete() + 'n'
self.tasks_label = MyLabel(self.master,
font='Tahoma 9',
text='nothing here',
justify='left')
self.tasks_label.configure(text=self.text_tasks_label)
# Place Widgets
self.title.place(x=10, y=10)
self.label2.place(x=10, y=55)
self.tasks_label.place(x=10, y=80)
def close_window(self):
self.tasks_label.configure(text='')
dump_pickle(file_ended_tasks, ended_tasks)
self.master.destroy()
app.combo_confirm['state'] = 'active'
username = getpass.getuser()
file_open_tasks = r'C:Users{}AppDataLocaltasks_open.pkl'.format(username)
file_ended_tasks = r'C:Users{}AppDataLocaltasks_ended.pkl'.format(
username)
if __name__ == '__main__':
open_tasks: list = load_pickle(file_open_tasks)
ended_tasks: list = load_pickle(file_ended_tasks)
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
python beginner object-oriented tkinter to-do-list
$endgroup$
add a comment |
$begingroup$
I'm a beginner in OOP programming and I'm wondering what is the best way to put all the windows and functions of a window application in the code.
My biggest questions are:
- Am I using classes and function in the right way?
- There is an efficient way to create windows and widgets?
- Why do I see so many peoples inheriting from
tk.Frame
in window classes? - In the example of application given in Tkinter documentation, they put the widgets inside a method called "create_widgets", is this recommended instead put them in the
__init__
method?
I translated the interface from the original Brazilian Portuguese before posting the question here.
"""Componentes Curriculares V0.1.
This program is meant to be a task manager to your School Year.
It is composed by various functions such as:
-List of all your tasks and tests, and a complete school report based on these
tasks. (This last one still is a work in progress.)
You can also add your topics for each subject that you are having along the
year.
The main language of the interface is Portuguese and their source code was
written in English.
Python 3.7 is the current version.
"""
import tkinter as tk
from tkinter import ttk, messagebox
from tkinter.scrolledtext import ScrolledText
from datetime import datetime
import pickle
import getpass
# Standard variables used for multiple widgets.
fontlab_std = 'Tahoma 12 bold'
fontbut_std = 'Tahoma 9'
bg_std = 'cornsilk2'
hover_std = 'Created by Wilson Cazarré - 3° Mecatrônica. Alpha 0.1'
icon_windows = 'book.ico'
my_subjects = ['LPL',
'Matemática',
'Biologia',
'Geografia',
'História',
'Química',
'Física',
'Filosofia',
'Sociologia',
'Educação Física',
'Inglês',
'Tecnologia de Manufatura 3',
'Linguagem de Programação Aplicada a Mecatrônica',
'Automação e Instrumentação Industrial 3',
'Microcontroladores',
'Tecnologia de Qualidade e processos',
'Robótica e Manufatura Flexível',
'Eletrônica Industrial e de Potência',
'Planejamento e Desenvolvimento do Trabalho de Conclusão de '
'Curso']
grades = ['MB',
'B',
'R',
'I']
days = list(range(1, 32))
mouths = ['Janeiro',
'Fevereiro',
'Março',
'Abril',
'Maio',
'Junho',
'Julho',
'Agosto',
'Setembro',
'Outubro',
'Novembro',
'Dezembro']
years = list(range(2019, 2030))
weekdays = ['Segunda',
'Terça-feira',
'Quarta-feira',
'Quinta-feira',
'Sexta-feira',
'Sábado',
'Domingo']
# ---------------------------------
def load_pickle(file) -> list:
try:
with open(file, 'rb') as infile:
tasks_objects = pickle.load(infile)
tasks_objects.sort(key=lambda task: task.full_date)
return tasks_objects
except FileNotFoundError:
return []
except PermissionError:
messagebox.showerror('Acesso Negado',
'Erro ao ler o arquivo. Iniciar como administrador')
def dump_pickle(file, obj):
with open(file, 'wb') as outfile:
pickle.dump(obj, outfile, pickle.HIGHEST_PROTOCOL)
# --------------------------------- Custom Widgets with default option
class MyButton(tk.Button):
"""Create a custom button widget, with default options."""
def __init__(self, master=None, hovertext=None, **kw):
tk.Button.__init__(self, master=master, **kw)
self.configure(font=fontbut_std, relief='groove') # Default options
if hovertext is not None:
self.bind('<Enter>', lambda x: self.on_hover(hovertext))
self.bind('<Leave>', lambda x: self.on_hover(hover_std))
@staticmethod
def on_hover(text):
app.hover_box.configure(text=text)
class MyLabel(tk.Label):
"""Create a custom button widget, with default options."""
def __init__(self, master=None, cnf=None, **kw):
tk.Label.__init__(self, master=master, cnf=cnf, **kw)
self.configure(bg=bg_std)
# --------------------------------- All windows, and the Task Class
class Task:
"""Objects listed in the 'MainWindow.tasks_widget'.
Tasks are saved in the following lists:
list: open_tasks: tasks not completed.
list: ended_tasks: tasks completed.
"""
def __init__(self, subject, title, day, month, year, category,
description=None, is_done=False, grade=None):
self.subject = subject
self.title = title
self.day = day
self.month = month
self.year = year
self.description = description
self.is_done = is_done
self.grade = grade
self.category = category
self.full_date = datetime(int(self.year), mouths.index(self.month) + 1,
int(self.day))
self.weekday = self.full_date.weekday()
def __str__(self):
return '{} - {}: "{}" '
'para o dia {}/{}/{} ({})'.format(self.subject, self.category,
self.title, self.day,
self.month, self.year,
weekdays[self.
weekday])
def str_task_complete(self):
return '{}: "{}" Menção: {} - {}/{}/{}'.format(self.category,
self.title,
self.grade,
self.day,
self.month,
self.year)
class MainWindow:
"""Create the first window of the program.
self.add_button - invoke AddTaskWindow -> create a task object.
self.done_button - invoke EndTaskWindow -> set the task object as done.
"""
def __init__(self, master):
self.master = master
# Master window configs
master.title('Componentes Curriculares')
master.minsize(width=900, height=520)
master.maxsize(width=900, height=520)
master.geometry('+360+100')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
# Setup Widgets
self.title = MyLabel(self.master, text='My Subjects',
font='Tahoma 15 bold',
bg=bg_std,
fg='DeepSkyBlue2',
anchor='e',
width=67)
self.tasks_title = MyLabel(self.master,
text='Tasks, tests and events',
font='Tahoma 12 bold')
self.tasks_widget = tk.Listbox(self.master,
width=100, height=25,
relief='solid',
highlightthickness=0)
for task in open_tasks:
self.tasks_widget.insert('end', task)
self.tasks_widget.bind('<Enter>', lambda x: MyButton.on_hover
('Double click to set a task as done.'))
self.tasks_widget.bind('<Leave>', lambda x: MyButton.on_hover
(hover_std))
self.tasks_widget.bind('<Double-Button-1>',
lambda x: EndTaskWindow(tk.Toplevel(),
self.tasks_widget.
curselection()))
self.add_button = MyButton(self.master,
hovertext='Add a task.',
text='+',
fg='green3',
command=self.open_task_window,
width=1)
self.sub_button = MyButton(self.master,
hovertext='Remove current selected task.',
text='-',
fg='red',
command=lambda: self.delete_task
(self.tasks_widget.curselection()),
width=1)
self.done_button = MyButton(self.master,
hovertext='Finalizar tarefa e registar a '
'menção.',
text='Complete',
command=lambda: EndTaskWindow(
tk.Toplevel(),
self.tasks_widget.curselection()))
self.view_button = MyButton(self.master,
hovertext='Show task information.',
text='Open',
command=lambda: ViewTaskWindow(
tk.Toplevel(),
self.tasks_widget.curselection()))
self.tasks_widget.bind('<Delete>', lambda x: self.delete_task(
self.tasks_widget.curselection()))
self.hover_box = tk.Label(self.master, text=hover_std, bg='white',
anchor='w')
self.combo_title = MyLabel(self.master,
text='Show subjects information:',
font='Tahoma 9 bold')
self.combo_subjects = ttk.Combobox(self.master, values=my_subjects,
width=30)
self.combo_confirm = MyButton(self.master, text='Open',
hovertext='Exibir janela de informações '
'da matéria selecionada',
command=lambda: SubjectWindow(
tk.Toplevel(),
self.combo_subjects.get()))
self.combo_confirm['font'] = 'Tahoma 9'
# Place Widgets
self.title.place(x=10, y=5)
self.tasks_title.place(x=10, y=30)
self.tasks_widget.place(x=10, y=58)
self.add_button.place(x=10, y=463)
self.sub_button.place(x=28, y=463)
self.done_button.place(x=46, y=463)
self.view_button.place(x=110, y=463)
self.combo_title.place(x=630, y=180)
self.combo_subjects.place(x=630, y=200)
self.combo_confirm.place(x=835, y=198)
self.hover_box.pack(side='bottom', fill='x')
def open_task_window(self):
"""Hey"""
window2 = tk.Toplevel()
self.add_button['state'] = 'disable'
self.sub_button['state'] = 'disable'
self.done_button['state'] = 'disable'
self.view_button['state'] = 'disable'
self.combo_confirm['state'] = 'disable'
self.taskwindow = AddTaskWindow(window2)
def delete_task(self, index):
delete_box = 'no'
if index != ():
delete_box = messagebox.askquestion('Deletar Tarefa',
'Deletar tarefa selecionada?')
if delete_box == 'yes':
self.tasks_widget.delete(index)
open_tasks.pop(index[0])
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
class AddTaskWindow:
"""Launch the window for create a task in
MainWindow.tasks_widget(tk.Listbox)
self.register_button -> self.create_task -> Task -> Create task object.
"""
def __init__(self, master):
self.master = master
app.done_button['state'] = 'disable'
master.title('Criar Tarefa')
master.geometry('600x400+500+200')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.protocol('WM_DELETE_WINDOW', self.close_window)
master.focus_force()
self.radio_var = tk.StringVar()
# Setup Widgets
self.title_radio = MyLabel(self.master, text='Task type:',
font='Tahoma 8 bold')
self.radio1 = tk.Radiobutton(self.master, text='Test',
variable=self.radio_var, value='Prova',
bg=bg_std,
activebackground=bg_std)
self.radio2 = tk.Radiobutton(self.master, text='Homework',
variable=self.radio_var, value='Trabalho',
bg=bg_std,
activebackground=bg_std)
self.radio3 = tk.Radiobutton(self.master, text='Other',
variable=self.radio_var,
value='Outro(Sem menção)', bg=bg_std,
activebackground=bg_std)
self.title_entry = MyLabel(self.master, text='Task title:',
font='Tahoma 8 bold')
self.entry = tk.Entry(self.master, width=60, relief='groove')
self.title_combo_subjects = MyLabel(self.master,
text='Task subject:',
font='Tahoma 8 bold')
self.combo_subjects = ttk.Combobox(self.master, values=my_subjects,
width=60)
self.title_date = MyLabel(self.master, text='Task date:',
font='Tahoma 8 bold')
self.combo_day = ttk.Combobox(self.master, values=days, width=3)
self.combo_day.current(days.index(datetime.now().day))
self.combo_mouth = ttk.Combobox(self.master, values=mouths, width=10)
self.combo_mouth.current(datetime.now().month - 1)
self.combo_year = ttk.Combobox(self.master, values=years, width=5)
self.combo_year.current(years.index(datetime.now().year))
self.register_button = MyButton(self.master, text='Criar tarefa',
command=self.create_task)
self.description_box_title = MyLabel(self.master,
text='Task description:',
font='Tahoma 10 bold')
self.description_box = ScrolledText(self.master, font='Consolas 9',
width=60, height=10)
# Place Widgets
self.title_radio.place(x=10, y=10)
self.radio1.place(x=150, y=10)
self.radio2.place(x=210, y=10)
self.radio3.place(x=285, y=10)
self.title_entry.place(x=10, y=35)
self.entry.place(x=150, y=35)
self.title_combo_subjects.place(x=10, y=60)
self.combo_subjects.place(x=150, y=60)
self.title_date.place(x=10, y=85)
self.combo_day.place(x=150, y=85)
self.combo_mouth.place(x=190, y=85)
self.combo_year.place(x=271, y=85)
self.register_button.place(x=360, y=122)
self.description_box_title.place(x=10, y=125)
self.description_box.place(x=10, y=150)
def create_task(self):
"""Create the task object and update the '
MainWindow.tasks_widget(tk.Listbox)'."""
new_task = Task(subject=self.combo_subjects.get(),
title=self.entry.get(),
day=self.combo_day.get(),
month=self.combo_mouth.get(),
year=self.combo_year.get(),
category=self.radio_var.get(),
description=self.description_box.get('1.0', 'end'))
app.tasks_widget.delete(0, 'end')
open_tasks.insert(0, new_task)
open_tasks.sort(key=lambda task: task.full_date)
for task in open_tasks:
app.tasks_widget.insert('end', task)
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
self.close_window()
def close_window(self):
app.add_button['state'] = 'active'
app.sub_button['state'] = 'active'
app.done_button['state'] = 'active'
app.view_button['state'] = 'active'
app.combo_confirm['state'] = 'active'
self.master.destroy()
class EndTaskWindow:
"""Launch the window for end a task.
Invoked from MainWindow.done_button -> returns the current selection on
the MainWindow.tasks_widget
-> task_index -> EndTaskWindow.__init__.
"""
def __init__(self, master, task_index):
self.master = master
if task_index != ():
self.task_index = task_index
self.task = open_tasks[task_index[0]]
master.title('Finalizar Tarefa')
master.minsize(width=250, height=190)
master.maxsize(width=250, height=190)
master.geometry('+500+200')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.focus()
master.protocol('WM_DELETE_WINDOW', self.close_window)
# Setup Widgets
self.title_info = MyLabel(self.master, text='Dados da Atividade',
font='Tahoma 14 bold')
self.info_label_header = MyLabel(self.master,
text='Tipo:nTítulo:nMatéria:'
'nData:',
justify='left',
font='Tamoha 10 bold')
self.info_label = MyLabel(self.master, justify='left',
font='Tahoma 10 italic',
text='{}n{}n{}n{}'.format(
self.task.category, self.task.title,
self.task.subject,
self.task.full_date))
self.title_combo_grades = MyLabel(self.master,
text='Insira a menção final:',
font='Tahoma 11 bold')
self.combo_grades = ttk.Combobox(self.master, values=grades, width=3)
self.finish_button = MyButton(self.master, text='Finalizar',
command=lambda: self.end_task(
self.combo_grades.get()),
anchor='center')
# Place Widgets
self.title_info.place(x=10, y=10)
self.info_label_header.place(x=10, y=40)
self.info_label.place(x=75, y=40)
self.title_combo_grades.place(x=10, y=125)
self.combo_grades.place(x=180, y=127)
self.finish_button.place(x=95, y=155)
def end_task(self, grade):
"""Set the task as done.
self.finish_button -> returns the current selection in
self.combo_grades(tk.Combobox)
Define task.is_done as True and grade.
Remove this object from the list: open_task, append to list:
ended_tasks
"""
self.task.is_done = True
self.task.grade = grade
self.close_window()
print(self.task.grade)
print(self.task.is_done)
ended_tasks.append(self.task)
open_tasks.remove(self.task)
app.tasks_widget.delete(0, 'end')
for task in open_tasks:
app.tasks_widget.insert('end', task)
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
def close_window(self):
self.master.destroy()
class ViewTaskWindow:
def __init__(self, master, task_index):
self.master = master
if task_index != ():
self.task_index = task_index
self.task = open_tasks[task_index[0]]
master.title('Finalizar Tarefa')
master.minsize(width=500, height=450)
master.maxsize(width=500, height=450)
master.geometry('+500+75')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.focus()
master.protocol('WM_DELETE_WINDOW', self.close_window)
if self.task.description == 'n':
self.description = 'Nothing to show'
else:
self.description = self.task.description
# Setup Widgets
self.title_info = MyLabel(self.master, text='Task information',
font='Tahoma 14 bold')
self.info_label_header = MyLabel(self.master,
text='Type:nTitle:nSubject:'
'nDate:',
justify='left',
font='Tamoha 10 bold')
self.date_text = str(self.task.full_date).split(' ')
self.info_label = MyLabel(self.master, justify='left',
font='Tahoma 10 italic',
text='{}n{}n{}n{}'.format(
self.task.category, self.task.title,
self.task.subject,
self.date_text[0]))
self.description_title = MyLabel(self.master,
text='Task description:',
font='Tahoma 11 bold')
self.description_label = MyLabel(self.master,
text=self.description,
font='Consolas 9', justify='left')
self.description_text = ScrolledText(self.master, width=60,
height=20, font='Consolas 9')
self.description_text.insert('1.0', self.description)
self.description_text['state'] = 'disable'
# Place Widgets
self.title_info.place(x=10, y=10)
self.info_label_header.place(x=10, y=40)
self.info_label.place(x=75, y=40)
self.description_title.place(x=10, y=120)
self.description_text.place(x=10, y=150)
# self.description_label.place(x=10, y=150)
def close_window(self):
self.master.destroy()
class SubjectWindow:
"""Launch the window with all completed tasks of specified subject
Invoke by MainApplication.combo_confirm(tk.Button) ->
returns the selection on MainApplication.combo_subjects
-> subject -> SubjectWindow.__init__.
"""
def __init__(self, master, subject):
if subject in my_subjects:
self.master = master
self.subject = subject
self.text_tasks_label = ''
app.combo_confirm['state'] = 'disabled'
master.title(subject)
master.geometry('800x400')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.protocol('WM_DELETE_WINDOW', self.close_window)
else:
master.destroy()
# Setup Widgets
self.title = MyLabel(self.master,
text=self.subject,
font='Tahoma 15 bold')
self.label1 = MyLabel(self.master,
text='Bases Tecnológicas',
font='Tahoma 12 bold')
self.label2 = MyLabel(self.master,
text='Atividades e Menções',
font='Tahoma 12 bold')
for task in ended_tasks:
if task.subject == self.subject:
print(task)
print(task.str_task_complete())
self.text_tasks_label += task.str_task_complete() + 'n'
self.tasks_label = MyLabel(self.master,
font='Tahoma 9',
text='nothing here',
justify='left')
self.tasks_label.configure(text=self.text_tasks_label)
# Place Widgets
self.title.place(x=10, y=10)
self.label2.place(x=10, y=55)
self.tasks_label.place(x=10, y=80)
def close_window(self):
self.tasks_label.configure(text='')
dump_pickle(file_ended_tasks, ended_tasks)
self.master.destroy()
app.combo_confirm['state'] = 'active'
username = getpass.getuser()
file_open_tasks = r'C:Users{}AppDataLocaltasks_open.pkl'.format(username)
file_ended_tasks = r'C:Users{}AppDataLocaltasks_ended.pkl'.format(
username)
if __name__ == '__main__':
open_tasks: list = load_pickle(file_open_tasks)
ended_tasks: list = load_pickle(file_ended_tasks)
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
python beginner object-oriented tkinter to-do-list
$endgroup$
add a comment |
$begingroup$
I'm a beginner in OOP programming and I'm wondering what is the best way to put all the windows and functions of a window application in the code.
My biggest questions are:
- Am I using classes and function in the right way?
- There is an efficient way to create windows and widgets?
- Why do I see so many peoples inheriting from
tk.Frame
in window classes? - In the example of application given in Tkinter documentation, they put the widgets inside a method called "create_widgets", is this recommended instead put them in the
__init__
method?
I translated the interface from the original Brazilian Portuguese before posting the question here.
"""Componentes Curriculares V0.1.
This program is meant to be a task manager to your School Year.
It is composed by various functions such as:
-List of all your tasks and tests, and a complete school report based on these
tasks. (This last one still is a work in progress.)
You can also add your topics for each subject that you are having along the
year.
The main language of the interface is Portuguese and their source code was
written in English.
Python 3.7 is the current version.
"""
import tkinter as tk
from tkinter import ttk, messagebox
from tkinter.scrolledtext import ScrolledText
from datetime import datetime
import pickle
import getpass
# Standard variables used for multiple widgets.
fontlab_std = 'Tahoma 12 bold'
fontbut_std = 'Tahoma 9'
bg_std = 'cornsilk2'
hover_std = 'Created by Wilson Cazarré - 3° Mecatrônica. Alpha 0.1'
icon_windows = 'book.ico'
my_subjects = ['LPL',
'Matemática',
'Biologia',
'Geografia',
'História',
'Química',
'Física',
'Filosofia',
'Sociologia',
'Educação Física',
'Inglês',
'Tecnologia de Manufatura 3',
'Linguagem de Programação Aplicada a Mecatrônica',
'Automação e Instrumentação Industrial 3',
'Microcontroladores',
'Tecnologia de Qualidade e processos',
'Robótica e Manufatura Flexível',
'Eletrônica Industrial e de Potência',
'Planejamento e Desenvolvimento do Trabalho de Conclusão de '
'Curso']
grades = ['MB',
'B',
'R',
'I']
days = list(range(1, 32))
mouths = ['Janeiro',
'Fevereiro',
'Março',
'Abril',
'Maio',
'Junho',
'Julho',
'Agosto',
'Setembro',
'Outubro',
'Novembro',
'Dezembro']
years = list(range(2019, 2030))
weekdays = ['Segunda',
'Terça-feira',
'Quarta-feira',
'Quinta-feira',
'Sexta-feira',
'Sábado',
'Domingo']
# ---------------------------------
def load_pickle(file) -> list:
try:
with open(file, 'rb') as infile:
tasks_objects = pickle.load(infile)
tasks_objects.sort(key=lambda task: task.full_date)
return tasks_objects
except FileNotFoundError:
return []
except PermissionError:
messagebox.showerror('Acesso Negado',
'Erro ao ler o arquivo. Iniciar como administrador')
def dump_pickle(file, obj):
with open(file, 'wb') as outfile:
pickle.dump(obj, outfile, pickle.HIGHEST_PROTOCOL)
# --------------------------------- Custom Widgets with default option
class MyButton(tk.Button):
"""Create a custom button widget, with default options."""
def __init__(self, master=None, hovertext=None, **kw):
tk.Button.__init__(self, master=master, **kw)
self.configure(font=fontbut_std, relief='groove') # Default options
if hovertext is not None:
self.bind('<Enter>', lambda x: self.on_hover(hovertext))
self.bind('<Leave>', lambda x: self.on_hover(hover_std))
@staticmethod
def on_hover(text):
app.hover_box.configure(text=text)
class MyLabel(tk.Label):
"""Create a custom button widget, with default options."""
def __init__(self, master=None, cnf=None, **kw):
tk.Label.__init__(self, master=master, cnf=cnf, **kw)
self.configure(bg=bg_std)
# --------------------------------- All windows, and the Task Class
class Task:
"""Objects listed in the 'MainWindow.tasks_widget'.
Tasks are saved in the following lists:
list: open_tasks: tasks not completed.
list: ended_tasks: tasks completed.
"""
def __init__(self, subject, title, day, month, year, category,
description=None, is_done=False, grade=None):
self.subject = subject
self.title = title
self.day = day
self.month = month
self.year = year
self.description = description
self.is_done = is_done
self.grade = grade
self.category = category
self.full_date = datetime(int(self.year), mouths.index(self.month) + 1,
int(self.day))
self.weekday = self.full_date.weekday()
def __str__(self):
return '{} - {}: "{}" '
'para o dia {}/{}/{} ({})'.format(self.subject, self.category,
self.title, self.day,
self.month, self.year,
weekdays[self.
weekday])
def str_task_complete(self):
return '{}: "{}" Menção: {} - {}/{}/{}'.format(self.category,
self.title,
self.grade,
self.day,
self.month,
self.year)
class MainWindow:
"""Create the first window of the program.
self.add_button - invoke AddTaskWindow -> create a task object.
self.done_button - invoke EndTaskWindow -> set the task object as done.
"""
def __init__(self, master):
self.master = master
# Master window configs
master.title('Componentes Curriculares')
master.minsize(width=900, height=520)
master.maxsize(width=900, height=520)
master.geometry('+360+100')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
# Setup Widgets
self.title = MyLabel(self.master, text='My Subjects',
font='Tahoma 15 bold',
bg=bg_std,
fg='DeepSkyBlue2',
anchor='e',
width=67)
self.tasks_title = MyLabel(self.master,
text='Tasks, tests and events',
font='Tahoma 12 bold')
self.tasks_widget = tk.Listbox(self.master,
width=100, height=25,
relief='solid',
highlightthickness=0)
for task in open_tasks:
self.tasks_widget.insert('end', task)
self.tasks_widget.bind('<Enter>', lambda x: MyButton.on_hover
('Double click to set a task as done.'))
self.tasks_widget.bind('<Leave>', lambda x: MyButton.on_hover
(hover_std))
self.tasks_widget.bind('<Double-Button-1>',
lambda x: EndTaskWindow(tk.Toplevel(),
self.tasks_widget.
curselection()))
self.add_button = MyButton(self.master,
hovertext='Add a task.',
text='+',
fg='green3',
command=self.open_task_window,
width=1)
self.sub_button = MyButton(self.master,
hovertext='Remove current selected task.',
text='-',
fg='red',
command=lambda: self.delete_task
(self.tasks_widget.curselection()),
width=1)
self.done_button = MyButton(self.master,
hovertext='Finalizar tarefa e registar a '
'menção.',
text='Complete',
command=lambda: EndTaskWindow(
tk.Toplevel(),
self.tasks_widget.curselection()))
self.view_button = MyButton(self.master,
hovertext='Show task information.',
text='Open',
command=lambda: ViewTaskWindow(
tk.Toplevel(),
self.tasks_widget.curselection()))
self.tasks_widget.bind('<Delete>', lambda x: self.delete_task(
self.tasks_widget.curselection()))
self.hover_box = tk.Label(self.master, text=hover_std, bg='white',
anchor='w')
self.combo_title = MyLabel(self.master,
text='Show subjects information:',
font='Tahoma 9 bold')
self.combo_subjects = ttk.Combobox(self.master, values=my_subjects,
width=30)
self.combo_confirm = MyButton(self.master, text='Open',
hovertext='Exibir janela de informações '
'da matéria selecionada',
command=lambda: SubjectWindow(
tk.Toplevel(),
self.combo_subjects.get()))
self.combo_confirm['font'] = 'Tahoma 9'
# Place Widgets
self.title.place(x=10, y=5)
self.tasks_title.place(x=10, y=30)
self.tasks_widget.place(x=10, y=58)
self.add_button.place(x=10, y=463)
self.sub_button.place(x=28, y=463)
self.done_button.place(x=46, y=463)
self.view_button.place(x=110, y=463)
self.combo_title.place(x=630, y=180)
self.combo_subjects.place(x=630, y=200)
self.combo_confirm.place(x=835, y=198)
self.hover_box.pack(side='bottom', fill='x')
def open_task_window(self):
"""Hey"""
window2 = tk.Toplevel()
self.add_button['state'] = 'disable'
self.sub_button['state'] = 'disable'
self.done_button['state'] = 'disable'
self.view_button['state'] = 'disable'
self.combo_confirm['state'] = 'disable'
self.taskwindow = AddTaskWindow(window2)
def delete_task(self, index):
delete_box = 'no'
if index != ():
delete_box = messagebox.askquestion('Deletar Tarefa',
'Deletar tarefa selecionada?')
if delete_box == 'yes':
self.tasks_widget.delete(index)
open_tasks.pop(index[0])
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
class AddTaskWindow:
"""Launch the window for create a task in
MainWindow.tasks_widget(tk.Listbox)
self.register_button -> self.create_task -> Task -> Create task object.
"""
def __init__(self, master):
self.master = master
app.done_button['state'] = 'disable'
master.title('Criar Tarefa')
master.geometry('600x400+500+200')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.protocol('WM_DELETE_WINDOW', self.close_window)
master.focus_force()
self.radio_var = tk.StringVar()
# Setup Widgets
self.title_radio = MyLabel(self.master, text='Task type:',
font='Tahoma 8 bold')
self.radio1 = tk.Radiobutton(self.master, text='Test',
variable=self.radio_var, value='Prova',
bg=bg_std,
activebackground=bg_std)
self.radio2 = tk.Radiobutton(self.master, text='Homework',
variable=self.radio_var, value='Trabalho',
bg=bg_std,
activebackground=bg_std)
self.radio3 = tk.Radiobutton(self.master, text='Other',
variable=self.radio_var,
value='Outro(Sem menção)', bg=bg_std,
activebackground=bg_std)
self.title_entry = MyLabel(self.master, text='Task title:',
font='Tahoma 8 bold')
self.entry = tk.Entry(self.master, width=60, relief='groove')
self.title_combo_subjects = MyLabel(self.master,
text='Task subject:',
font='Tahoma 8 bold')
self.combo_subjects = ttk.Combobox(self.master, values=my_subjects,
width=60)
self.title_date = MyLabel(self.master, text='Task date:',
font='Tahoma 8 bold')
self.combo_day = ttk.Combobox(self.master, values=days, width=3)
self.combo_day.current(days.index(datetime.now().day))
self.combo_mouth = ttk.Combobox(self.master, values=mouths, width=10)
self.combo_mouth.current(datetime.now().month - 1)
self.combo_year = ttk.Combobox(self.master, values=years, width=5)
self.combo_year.current(years.index(datetime.now().year))
self.register_button = MyButton(self.master, text='Criar tarefa',
command=self.create_task)
self.description_box_title = MyLabel(self.master,
text='Task description:',
font='Tahoma 10 bold')
self.description_box = ScrolledText(self.master, font='Consolas 9',
width=60, height=10)
# Place Widgets
self.title_radio.place(x=10, y=10)
self.radio1.place(x=150, y=10)
self.radio2.place(x=210, y=10)
self.radio3.place(x=285, y=10)
self.title_entry.place(x=10, y=35)
self.entry.place(x=150, y=35)
self.title_combo_subjects.place(x=10, y=60)
self.combo_subjects.place(x=150, y=60)
self.title_date.place(x=10, y=85)
self.combo_day.place(x=150, y=85)
self.combo_mouth.place(x=190, y=85)
self.combo_year.place(x=271, y=85)
self.register_button.place(x=360, y=122)
self.description_box_title.place(x=10, y=125)
self.description_box.place(x=10, y=150)
def create_task(self):
"""Create the task object and update the '
MainWindow.tasks_widget(tk.Listbox)'."""
new_task = Task(subject=self.combo_subjects.get(),
title=self.entry.get(),
day=self.combo_day.get(),
month=self.combo_mouth.get(),
year=self.combo_year.get(),
category=self.radio_var.get(),
description=self.description_box.get('1.0', 'end'))
app.tasks_widget.delete(0, 'end')
open_tasks.insert(0, new_task)
open_tasks.sort(key=lambda task: task.full_date)
for task in open_tasks:
app.tasks_widget.insert('end', task)
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
self.close_window()
def close_window(self):
app.add_button['state'] = 'active'
app.sub_button['state'] = 'active'
app.done_button['state'] = 'active'
app.view_button['state'] = 'active'
app.combo_confirm['state'] = 'active'
self.master.destroy()
class EndTaskWindow:
"""Launch the window for end a task.
Invoked from MainWindow.done_button -> returns the current selection on
the MainWindow.tasks_widget
-> task_index -> EndTaskWindow.__init__.
"""
def __init__(self, master, task_index):
self.master = master
if task_index != ():
self.task_index = task_index
self.task = open_tasks[task_index[0]]
master.title('Finalizar Tarefa')
master.minsize(width=250, height=190)
master.maxsize(width=250, height=190)
master.geometry('+500+200')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.focus()
master.protocol('WM_DELETE_WINDOW', self.close_window)
# Setup Widgets
self.title_info = MyLabel(self.master, text='Dados da Atividade',
font='Tahoma 14 bold')
self.info_label_header = MyLabel(self.master,
text='Tipo:nTítulo:nMatéria:'
'nData:',
justify='left',
font='Tamoha 10 bold')
self.info_label = MyLabel(self.master, justify='left',
font='Tahoma 10 italic',
text='{}n{}n{}n{}'.format(
self.task.category, self.task.title,
self.task.subject,
self.task.full_date))
self.title_combo_grades = MyLabel(self.master,
text='Insira a menção final:',
font='Tahoma 11 bold')
self.combo_grades = ttk.Combobox(self.master, values=grades, width=3)
self.finish_button = MyButton(self.master, text='Finalizar',
command=lambda: self.end_task(
self.combo_grades.get()),
anchor='center')
# Place Widgets
self.title_info.place(x=10, y=10)
self.info_label_header.place(x=10, y=40)
self.info_label.place(x=75, y=40)
self.title_combo_grades.place(x=10, y=125)
self.combo_grades.place(x=180, y=127)
self.finish_button.place(x=95, y=155)
def end_task(self, grade):
"""Set the task as done.
self.finish_button -> returns the current selection in
self.combo_grades(tk.Combobox)
Define task.is_done as True and grade.
Remove this object from the list: open_task, append to list:
ended_tasks
"""
self.task.is_done = True
self.task.grade = grade
self.close_window()
print(self.task.grade)
print(self.task.is_done)
ended_tasks.append(self.task)
open_tasks.remove(self.task)
app.tasks_widget.delete(0, 'end')
for task in open_tasks:
app.tasks_widget.insert('end', task)
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
def close_window(self):
self.master.destroy()
class ViewTaskWindow:
def __init__(self, master, task_index):
self.master = master
if task_index != ():
self.task_index = task_index
self.task = open_tasks[task_index[0]]
master.title('Finalizar Tarefa')
master.minsize(width=500, height=450)
master.maxsize(width=500, height=450)
master.geometry('+500+75')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.focus()
master.protocol('WM_DELETE_WINDOW', self.close_window)
if self.task.description == 'n':
self.description = 'Nothing to show'
else:
self.description = self.task.description
# Setup Widgets
self.title_info = MyLabel(self.master, text='Task information',
font='Tahoma 14 bold')
self.info_label_header = MyLabel(self.master,
text='Type:nTitle:nSubject:'
'nDate:',
justify='left',
font='Tamoha 10 bold')
self.date_text = str(self.task.full_date).split(' ')
self.info_label = MyLabel(self.master, justify='left',
font='Tahoma 10 italic',
text='{}n{}n{}n{}'.format(
self.task.category, self.task.title,
self.task.subject,
self.date_text[0]))
self.description_title = MyLabel(self.master,
text='Task description:',
font='Tahoma 11 bold')
self.description_label = MyLabel(self.master,
text=self.description,
font='Consolas 9', justify='left')
self.description_text = ScrolledText(self.master, width=60,
height=20, font='Consolas 9')
self.description_text.insert('1.0', self.description)
self.description_text['state'] = 'disable'
# Place Widgets
self.title_info.place(x=10, y=10)
self.info_label_header.place(x=10, y=40)
self.info_label.place(x=75, y=40)
self.description_title.place(x=10, y=120)
self.description_text.place(x=10, y=150)
# self.description_label.place(x=10, y=150)
def close_window(self):
self.master.destroy()
class SubjectWindow:
"""Launch the window with all completed tasks of specified subject
Invoke by MainApplication.combo_confirm(tk.Button) ->
returns the selection on MainApplication.combo_subjects
-> subject -> SubjectWindow.__init__.
"""
def __init__(self, master, subject):
if subject in my_subjects:
self.master = master
self.subject = subject
self.text_tasks_label = ''
app.combo_confirm['state'] = 'disabled'
master.title(subject)
master.geometry('800x400')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.protocol('WM_DELETE_WINDOW', self.close_window)
else:
master.destroy()
# Setup Widgets
self.title = MyLabel(self.master,
text=self.subject,
font='Tahoma 15 bold')
self.label1 = MyLabel(self.master,
text='Bases Tecnológicas',
font='Tahoma 12 bold')
self.label2 = MyLabel(self.master,
text='Atividades e Menções',
font='Tahoma 12 bold')
for task in ended_tasks:
if task.subject == self.subject:
print(task)
print(task.str_task_complete())
self.text_tasks_label += task.str_task_complete() + 'n'
self.tasks_label = MyLabel(self.master,
font='Tahoma 9',
text='nothing here',
justify='left')
self.tasks_label.configure(text=self.text_tasks_label)
# Place Widgets
self.title.place(x=10, y=10)
self.label2.place(x=10, y=55)
self.tasks_label.place(x=10, y=80)
def close_window(self):
self.tasks_label.configure(text='')
dump_pickle(file_ended_tasks, ended_tasks)
self.master.destroy()
app.combo_confirm['state'] = 'active'
username = getpass.getuser()
file_open_tasks = r'C:Users{}AppDataLocaltasks_open.pkl'.format(username)
file_ended_tasks = r'C:Users{}AppDataLocaltasks_ended.pkl'.format(
username)
if __name__ == '__main__':
open_tasks: list = load_pickle(file_open_tasks)
ended_tasks: list = load_pickle(file_ended_tasks)
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
python beginner object-oriented tkinter to-do-list
$endgroup$
I'm a beginner in OOP programming and I'm wondering what is the best way to put all the windows and functions of a window application in the code.
My biggest questions are:
- Am I using classes and function in the right way?
- There is an efficient way to create windows and widgets?
- Why do I see so many peoples inheriting from
tk.Frame
in window classes? - In the example of application given in Tkinter documentation, they put the widgets inside a method called "create_widgets", is this recommended instead put them in the
__init__
method?
I translated the interface from the original Brazilian Portuguese before posting the question here.
"""Componentes Curriculares V0.1.
This program is meant to be a task manager to your School Year.
It is composed by various functions such as:
-List of all your tasks and tests, and a complete school report based on these
tasks. (This last one still is a work in progress.)
You can also add your topics for each subject that you are having along the
year.
The main language of the interface is Portuguese and their source code was
written in English.
Python 3.7 is the current version.
"""
import tkinter as tk
from tkinter import ttk, messagebox
from tkinter.scrolledtext import ScrolledText
from datetime import datetime
import pickle
import getpass
# Standard variables used for multiple widgets.
fontlab_std = 'Tahoma 12 bold'
fontbut_std = 'Tahoma 9'
bg_std = 'cornsilk2'
hover_std = 'Created by Wilson Cazarré - 3° Mecatrônica. Alpha 0.1'
icon_windows = 'book.ico'
my_subjects = ['LPL',
'Matemática',
'Biologia',
'Geografia',
'História',
'Química',
'Física',
'Filosofia',
'Sociologia',
'Educação Física',
'Inglês',
'Tecnologia de Manufatura 3',
'Linguagem de Programação Aplicada a Mecatrônica',
'Automação e Instrumentação Industrial 3',
'Microcontroladores',
'Tecnologia de Qualidade e processos',
'Robótica e Manufatura Flexível',
'Eletrônica Industrial e de Potência',
'Planejamento e Desenvolvimento do Trabalho de Conclusão de '
'Curso']
grades = ['MB',
'B',
'R',
'I']
days = list(range(1, 32))
mouths = ['Janeiro',
'Fevereiro',
'Março',
'Abril',
'Maio',
'Junho',
'Julho',
'Agosto',
'Setembro',
'Outubro',
'Novembro',
'Dezembro']
years = list(range(2019, 2030))
weekdays = ['Segunda',
'Terça-feira',
'Quarta-feira',
'Quinta-feira',
'Sexta-feira',
'Sábado',
'Domingo']
# ---------------------------------
def load_pickle(file) -> list:
try:
with open(file, 'rb') as infile:
tasks_objects = pickle.load(infile)
tasks_objects.sort(key=lambda task: task.full_date)
return tasks_objects
except FileNotFoundError:
return []
except PermissionError:
messagebox.showerror('Acesso Negado',
'Erro ao ler o arquivo. Iniciar como administrador')
def dump_pickle(file, obj):
with open(file, 'wb') as outfile:
pickle.dump(obj, outfile, pickle.HIGHEST_PROTOCOL)
# --------------------------------- Custom Widgets with default option
class MyButton(tk.Button):
"""Create a custom button widget, with default options."""
def __init__(self, master=None, hovertext=None, **kw):
tk.Button.__init__(self, master=master, **kw)
self.configure(font=fontbut_std, relief='groove') # Default options
if hovertext is not None:
self.bind('<Enter>', lambda x: self.on_hover(hovertext))
self.bind('<Leave>', lambda x: self.on_hover(hover_std))
@staticmethod
def on_hover(text):
app.hover_box.configure(text=text)
class MyLabel(tk.Label):
"""Create a custom button widget, with default options."""
def __init__(self, master=None, cnf=None, **kw):
tk.Label.__init__(self, master=master, cnf=cnf, **kw)
self.configure(bg=bg_std)
# --------------------------------- All windows, and the Task Class
class Task:
"""Objects listed in the 'MainWindow.tasks_widget'.
Tasks are saved in the following lists:
list: open_tasks: tasks not completed.
list: ended_tasks: tasks completed.
"""
def __init__(self, subject, title, day, month, year, category,
description=None, is_done=False, grade=None):
self.subject = subject
self.title = title
self.day = day
self.month = month
self.year = year
self.description = description
self.is_done = is_done
self.grade = grade
self.category = category
self.full_date = datetime(int(self.year), mouths.index(self.month) + 1,
int(self.day))
self.weekday = self.full_date.weekday()
def __str__(self):
return '{} - {}: "{}" '
'para o dia {}/{}/{} ({})'.format(self.subject, self.category,
self.title, self.day,
self.month, self.year,
weekdays[self.
weekday])
def str_task_complete(self):
return '{}: "{}" Menção: {} - {}/{}/{}'.format(self.category,
self.title,
self.grade,
self.day,
self.month,
self.year)
class MainWindow:
"""Create the first window of the program.
self.add_button - invoke AddTaskWindow -> create a task object.
self.done_button - invoke EndTaskWindow -> set the task object as done.
"""
def __init__(self, master):
self.master = master
# Master window configs
master.title('Componentes Curriculares')
master.minsize(width=900, height=520)
master.maxsize(width=900, height=520)
master.geometry('+360+100')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
# Setup Widgets
self.title = MyLabel(self.master, text='My Subjects',
font='Tahoma 15 bold',
bg=bg_std,
fg='DeepSkyBlue2',
anchor='e',
width=67)
self.tasks_title = MyLabel(self.master,
text='Tasks, tests and events',
font='Tahoma 12 bold')
self.tasks_widget = tk.Listbox(self.master,
width=100, height=25,
relief='solid',
highlightthickness=0)
for task in open_tasks:
self.tasks_widget.insert('end', task)
self.tasks_widget.bind('<Enter>', lambda x: MyButton.on_hover
('Double click to set a task as done.'))
self.tasks_widget.bind('<Leave>', lambda x: MyButton.on_hover
(hover_std))
self.tasks_widget.bind('<Double-Button-1>',
lambda x: EndTaskWindow(tk.Toplevel(),
self.tasks_widget.
curselection()))
self.add_button = MyButton(self.master,
hovertext='Add a task.',
text='+',
fg='green3',
command=self.open_task_window,
width=1)
self.sub_button = MyButton(self.master,
hovertext='Remove current selected task.',
text='-',
fg='red',
command=lambda: self.delete_task
(self.tasks_widget.curselection()),
width=1)
self.done_button = MyButton(self.master,
hovertext='Finalizar tarefa e registar a '
'menção.',
text='Complete',
command=lambda: EndTaskWindow(
tk.Toplevel(),
self.tasks_widget.curselection()))
self.view_button = MyButton(self.master,
hovertext='Show task information.',
text='Open',
command=lambda: ViewTaskWindow(
tk.Toplevel(),
self.tasks_widget.curselection()))
self.tasks_widget.bind('<Delete>', lambda x: self.delete_task(
self.tasks_widget.curselection()))
self.hover_box = tk.Label(self.master, text=hover_std, bg='white',
anchor='w')
self.combo_title = MyLabel(self.master,
text='Show subjects information:',
font='Tahoma 9 bold')
self.combo_subjects = ttk.Combobox(self.master, values=my_subjects,
width=30)
self.combo_confirm = MyButton(self.master, text='Open',
hovertext='Exibir janela de informações '
'da matéria selecionada',
command=lambda: SubjectWindow(
tk.Toplevel(),
self.combo_subjects.get()))
self.combo_confirm['font'] = 'Tahoma 9'
# Place Widgets
self.title.place(x=10, y=5)
self.tasks_title.place(x=10, y=30)
self.tasks_widget.place(x=10, y=58)
self.add_button.place(x=10, y=463)
self.sub_button.place(x=28, y=463)
self.done_button.place(x=46, y=463)
self.view_button.place(x=110, y=463)
self.combo_title.place(x=630, y=180)
self.combo_subjects.place(x=630, y=200)
self.combo_confirm.place(x=835, y=198)
self.hover_box.pack(side='bottom', fill='x')
def open_task_window(self):
"""Hey"""
window2 = tk.Toplevel()
self.add_button['state'] = 'disable'
self.sub_button['state'] = 'disable'
self.done_button['state'] = 'disable'
self.view_button['state'] = 'disable'
self.combo_confirm['state'] = 'disable'
self.taskwindow = AddTaskWindow(window2)
def delete_task(self, index):
delete_box = 'no'
if index != ():
delete_box = messagebox.askquestion('Deletar Tarefa',
'Deletar tarefa selecionada?')
if delete_box == 'yes':
self.tasks_widget.delete(index)
open_tasks.pop(index[0])
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
class AddTaskWindow:
"""Launch the window for create a task in
MainWindow.tasks_widget(tk.Listbox)
self.register_button -> self.create_task -> Task -> Create task object.
"""
def __init__(self, master):
self.master = master
app.done_button['state'] = 'disable'
master.title('Criar Tarefa')
master.geometry('600x400+500+200')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.protocol('WM_DELETE_WINDOW', self.close_window)
master.focus_force()
self.radio_var = tk.StringVar()
# Setup Widgets
self.title_radio = MyLabel(self.master, text='Task type:',
font='Tahoma 8 bold')
self.radio1 = tk.Radiobutton(self.master, text='Test',
variable=self.radio_var, value='Prova',
bg=bg_std,
activebackground=bg_std)
self.radio2 = tk.Radiobutton(self.master, text='Homework',
variable=self.radio_var, value='Trabalho',
bg=bg_std,
activebackground=bg_std)
self.radio3 = tk.Radiobutton(self.master, text='Other',
variable=self.radio_var,
value='Outro(Sem menção)', bg=bg_std,
activebackground=bg_std)
self.title_entry = MyLabel(self.master, text='Task title:',
font='Tahoma 8 bold')
self.entry = tk.Entry(self.master, width=60, relief='groove')
self.title_combo_subjects = MyLabel(self.master,
text='Task subject:',
font='Tahoma 8 bold')
self.combo_subjects = ttk.Combobox(self.master, values=my_subjects,
width=60)
self.title_date = MyLabel(self.master, text='Task date:',
font='Tahoma 8 bold')
self.combo_day = ttk.Combobox(self.master, values=days, width=3)
self.combo_day.current(days.index(datetime.now().day))
self.combo_mouth = ttk.Combobox(self.master, values=mouths, width=10)
self.combo_mouth.current(datetime.now().month - 1)
self.combo_year = ttk.Combobox(self.master, values=years, width=5)
self.combo_year.current(years.index(datetime.now().year))
self.register_button = MyButton(self.master, text='Criar tarefa',
command=self.create_task)
self.description_box_title = MyLabel(self.master,
text='Task description:',
font='Tahoma 10 bold')
self.description_box = ScrolledText(self.master, font='Consolas 9',
width=60, height=10)
# Place Widgets
self.title_radio.place(x=10, y=10)
self.radio1.place(x=150, y=10)
self.radio2.place(x=210, y=10)
self.radio3.place(x=285, y=10)
self.title_entry.place(x=10, y=35)
self.entry.place(x=150, y=35)
self.title_combo_subjects.place(x=10, y=60)
self.combo_subjects.place(x=150, y=60)
self.title_date.place(x=10, y=85)
self.combo_day.place(x=150, y=85)
self.combo_mouth.place(x=190, y=85)
self.combo_year.place(x=271, y=85)
self.register_button.place(x=360, y=122)
self.description_box_title.place(x=10, y=125)
self.description_box.place(x=10, y=150)
def create_task(self):
"""Create the task object and update the '
MainWindow.tasks_widget(tk.Listbox)'."""
new_task = Task(subject=self.combo_subjects.get(),
title=self.entry.get(),
day=self.combo_day.get(),
month=self.combo_mouth.get(),
year=self.combo_year.get(),
category=self.radio_var.get(),
description=self.description_box.get('1.0', 'end'))
app.tasks_widget.delete(0, 'end')
open_tasks.insert(0, new_task)
open_tasks.sort(key=lambda task: task.full_date)
for task in open_tasks:
app.tasks_widget.insert('end', task)
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
self.close_window()
def close_window(self):
app.add_button['state'] = 'active'
app.sub_button['state'] = 'active'
app.done_button['state'] = 'active'
app.view_button['state'] = 'active'
app.combo_confirm['state'] = 'active'
self.master.destroy()
class EndTaskWindow:
"""Launch the window for end a task.
Invoked from MainWindow.done_button -> returns the current selection on
the MainWindow.tasks_widget
-> task_index -> EndTaskWindow.__init__.
"""
def __init__(self, master, task_index):
self.master = master
if task_index != ():
self.task_index = task_index
self.task = open_tasks[task_index[0]]
master.title('Finalizar Tarefa')
master.minsize(width=250, height=190)
master.maxsize(width=250, height=190)
master.geometry('+500+200')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.focus()
master.protocol('WM_DELETE_WINDOW', self.close_window)
# Setup Widgets
self.title_info = MyLabel(self.master, text='Dados da Atividade',
font='Tahoma 14 bold')
self.info_label_header = MyLabel(self.master,
text='Tipo:nTítulo:nMatéria:'
'nData:',
justify='left',
font='Tamoha 10 bold')
self.info_label = MyLabel(self.master, justify='left',
font='Tahoma 10 italic',
text='{}n{}n{}n{}'.format(
self.task.category, self.task.title,
self.task.subject,
self.task.full_date))
self.title_combo_grades = MyLabel(self.master,
text='Insira a menção final:',
font='Tahoma 11 bold')
self.combo_grades = ttk.Combobox(self.master, values=grades, width=3)
self.finish_button = MyButton(self.master, text='Finalizar',
command=lambda: self.end_task(
self.combo_grades.get()),
anchor='center')
# Place Widgets
self.title_info.place(x=10, y=10)
self.info_label_header.place(x=10, y=40)
self.info_label.place(x=75, y=40)
self.title_combo_grades.place(x=10, y=125)
self.combo_grades.place(x=180, y=127)
self.finish_button.place(x=95, y=155)
def end_task(self, grade):
"""Set the task as done.
self.finish_button -> returns the current selection in
self.combo_grades(tk.Combobox)
Define task.is_done as True and grade.
Remove this object from the list: open_task, append to list:
ended_tasks
"""
self.task.is_done = True
self.task.grade = grade
self.close_window()
print(self.task.grade)
print(self.task.is_done)
ended_tasks.append(self.task)
open_tasks.remove(self.task)
app.tasks_widget.delete(0, 'end')
for task in open_tasks:
app.tasks_widget.insert('end', task)
with open(file_open_tasks, 'wb') as outfile:
pickle.dump(open_tasks, outfile, pickle.HIGHEST_PROTOCOL)
def close_window(self):
self.master.destroy()
class ViewTaskWindow:
def __init__(self, master, task_index):
self.master = master
if task_index != ():
self.task_index = task_index
self.task = open_tasks[task_index[0]]
master.title('Finalizar Tarefa')
master.minsize(width=500, height=450)
master.maxsize(width=500, height=450)
master.geometry('+500+75')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.attributes('-topmost', True)
master.focus()
master.protocol('WM_DELETE_WINDOW', self.close_window)
if self.task.description == 'n':
self.description = 'Nothing to show'
else:
self.description = self.task.description
# Setup Widgets
self.title_info = MyLabel(self.master, text='Task information',
font='Tahoma 14 bold')
self.info_label_header = MyLabel(self.master,
text='Type:nTitle:nSubject:'
'nDate:',
justify='left',
font='Tamoha 10 bold')
self.date_text = str(self.task.full_date).split(' ')
self.info_label = MyLabel(self.master, justify='left',
font='Tahoma 10 italic',
text='{}n{}n{}n{}'.format(
self.task.category, self.task.title,
self.task.subject,
self.date_text[0]))
self.description_title = MyLabel(self.master,
text='Task description:',
font='Tahoma 11 bold')
self.description_label = MyLabel(self.master,
text=self.description,
font='Consolas 9', justify='left')
self.description_text = ScrolledText(self.master, width=60,
height=20, font='Consolas 9')
self.description_text.insert('1.0', self.description)
self.description_text['state'] = 'disable'
# Place Widgets
self.title_info.place(x=10, y=10)
self.info_label_header.place(x=10, y=40)
self.info_label.place(x=75, y=40)
self.description_title.place(x=10, y=120)
self.description_text.place(x=10, y=150)
# self.description_label.place(x=10, y=150)
def close_window(self):
self.master.destroy()
class SubjectWindow:
"""Launch the window with all completed tasks of specified subject
Invoke by MainApplication.combo_confirm(tk.Button) ->
returns the selection on MainApplication.combo_subjects
-> subject -> SubjectWindow.__init__.
"""
def __init__(self, master, subject):
if subject in my_subjects:
self.master = master
self.subject = subject
self.text_tasks_label = ''
app.combo_confirm['state'] = 'disabled'
master.title(subject)
master.geometry('800x400')
master.iconbitmap(icon_windows)
master.configure(bg=bg_std)
master.protocol('WM_DELETE_WINDOW', self.close_window)
else:
master.destroy()
# Setup Widgets
self.title = MyLabel(self.master,
text=self.subject,
font='Tahoma 15 bold')
self.label1 = MyLabel(self.master,
text='Bases Tecnológicas',
font='Tahoma 12 bold')
self.label2 = MyLabel(self.master,
text='Atividades e Menções',
font='Tahoma 12 bold')
for task in ended_tasks:
if task.subject == self.subject:
print(task)
print(task.str_task_complete())
self.text_tasks_label += task.str_task_complete() + 'n'
self.tasks_label = MyLabel(self.master,
font='Tahoma 9',
text='nothing here',
justify='left')
self.tasks_label.configure(text=self.text_tasks_label)
# Place Widgets
self.title.place(x=10, y=10)
self.label2.place(x=10, y=55)
self.tasks_label.place(x=10, y=80)
def close_window(self):
self.tasks_label.configure(text='')
dump_pickle(file_ended_tasks, ended_tasks)
self.master.destroy()
app.combo_confirm['state'] = 'active'
username = getpass.getuser()
file_open_tasks = r'C:Users{}AppDataLocaltasks_open.pkl'.format(username)
file_ended_tasks = r'C:Users{}AppDataLocaltasks_ended.pkl'.format(
username)
if __name__ == '__main__':
open_tasks: list = load_pickle(file_open_tasks)
ended_tasks: list = load_pickle(file_ended_tasks)
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
python beginner object-oriented tkinter to-do-list
python beginner object-oriented tkinter to-do-list
edited 5 hours ago
Wilson Cazarré
asked 6 hours ago
Wilson CazarréWilson Cazarré
62
62
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214583%2ftkinter-application-to-manage-school-tasks%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f214583%2ftkinter-application-to-manage-school-tasks%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown