From ffc7b4830618e45a4076c1ac761ae6d5449dc029 Mon Sep 17 00:00:00 2001 From: Dvlv Date: Sat, 27 May 2017 12:28:55 +0100 Subject: [PATCH] moving around 2 --- Chapter1-1.py | 8 - Chapter1-2.py | 13 - Chapter2-1.py | 52 ---- Chapter2-2.py | 107 -------- Chapter2-3-abridged.py | 98 ------- Chapter2-3.py | 155 ----------- Chapter3-1.py | 65 ----- Chapter3-2-abridged.py | 71 ----- Chapter3-2.py | 107 -------- Chapter3-3-LanguageTab.py | 22 -- Chapter3-3-NewLanguageForm.py | 32 --- Chapter3-3-TranslateBook.py | 68 ----- Chapter3-3-ttk.py | 138 ---------- Chapter3-3.py | 138 ---------- Chapter4-1.py | 121 --------- Chapter4-2-abridged.py | 170 ------------ Chapter4-2.py | 220 ---------------- Chapter5-1.py | 130 ---------- Chapter5-2-abridged.py | 93 ------- Chapter5-2.py | 149 ----------- Chapter5-3-abridged.py | 166 ------------ Chapter5-3.py | 268 ------------------- Chapter6-1.py | 152 ----------- Chapter6-2-abridged.py | 143 ---------- Chapter6-2.py | 250 ------------------ Chapter6-3-abridged.py | 309 ---------------------- Chapter6-3.py | 474 ---------------------------------- Chapter6-regex-explain.py | 40 --- Chapter7-1.py | 128 --------- Chapter7-2-abridged.py | 156 ----------- Chapter7-2.py | 244 ----------------- Chapter7-3-abridged.py | 150 ----------- Chapter7-3.py | 299 --------------------- 33 files changed, 4736 deletions(-) delete mode 100644 Chapter1-1.py delete mode 100644 Chapter1-2.py delete mode 100644 Chapter2-1.py delete mode 100644 Chapter2-2.py delete mode 100644 Chapter2-3-abridged.py delete mode 100644 Chapter2-3.py delete mode 100644 Chapter3-1.py delete mode 100644 Chapter3-2-abridged.py delete mode 100644 Chapter3-2.py delete mode 100644 Chapter3-3-LanguageTab.py delete mode 100644 Chapter3-3-NewLanguageForm.py delete mode 100644 Chapter3-3-TranslateBook.py delete mode 100644 Chapter3-3-ttk.py delete mode 100644 Chapter3-3.py delete mode 100644 Chapter4-1.py delete mode 100644 Chapter4-2-abridged.py delete mode 100644 Chapter4-2.py delete mode 100644 Chapter5-1.py delete mode 100644 Chapter5-2-abridged.py delete mode 100644 Chapter5-2.py delete mode 100644 Chapter5-3-abridged.py delete mode 100644 Chapter5-3.py delete mode 100644 Chapter6-1.py delete mode 100644 Chapter6-2-abridged.py delete mode 100644 Chapter6-2.py delete mode 100644 Chapter6-3-abridged.py delete mode 100644 Chapter6-3.py delete mode 100644 Chapter6-regex-explain.py delete mode 100644 Chapter7-1.py delete mode 100644 Chapter7-2-abridged.py delete mode 100644 Chapter7-2.py delete mode 100644 Chapter7-3-abridged.py delete mode 100644 Chapter7-3.py diff --git a/Chapter1-1.py b/Chapter1-1.py deleted file mode 100644 index 537a866..0000000 --- a/Chapter1-1.py +++ /dev/null @@ -1,8 +0,0 @@ -import tkinter as tk - -root = tk.Tk() - -label = tk.Label(root, text="Hello World", padx=10, pady=10) -label.pack() - -root.mainloop() diff --git a/Chapter1-2.py b/Chapter1-2.py deleted file mode 100644 index b6bb868..0000000 --- a/Chapter1-2.py +++ /dev/null @@ -1,13 +0,0 @@ -import tkinter as tk - -class Root(tk.Tk): - def __init__(self): - super().__init__() - - self.label = tk.Label(self, text="Hello World", padx=5, pady=5) - - self.label.pack() - -if __name__ == "__main__": - root = Root() - root.mainloop() diff --git a/Chapter2-1.py b/Chapter2-1.py deleted file mode 100644 index e36737e..0000000 --- a/Chapter2-1.py +++ /dev/null @@ -1,52 +0,0 @@ -import tkinter as tk - -class Todo(tk.Tk): - def __init__(self, tasks=None): - super().__init__() - - if not tasks: - self.tasks = [] - else: - self.tasks = tasks - - self.title("To-Do App v1") - self.geometry("300x400") - - todo1 = tk.Label(self, text="--- Add Items Here ---", bg="lightgrey", fg="black", pady=10) - - self.tasks.append(todo1) - - for task in self.tasks: - task.pack(side=tk.TOP, fill=tk.X) - - self.task_create = tk.Text(self, height=3, bg="white", fg="black") - - self.task_create.pack(side=tk.BOTTOM, fill=tk.X) - self.task_create.focus_set() - - self.bind("", self.add_task) - - self.colour_schemes = [{"bg": "lightgrey", "fg": "black"}, {"bg": "grey", "fg": "white"}] - - def add_task(self, event=None): - task_text = self.task_create.get(1.0,tk.END).strip() - - if len(task_text) > 0: - new_task = tk.Label(self, text=task_text, pady=10) - - _, task_style_choice = divmod(len(self.tasks), 2) - - my_scheme_choice = self.colour_schemes[task_style_choice] - - new_task.configure(bg=my_scheme_choice["bg"]) - new_task.configure(fg=my_scheme_choice["fg"]) - - new_task.pack(side=tk.TOP, fill=tk.X) - - self.tasks.append(new_task) - - self.task_create.delete(1.0, tk.END) - -if __name__ == "__main__": - todo = Todo() - todo.mainloop() diff --git a/Chapter2-2.py b/Chapter2-2.py deleted file mode 100644 index bc3f6cb..0000000 --- a/Chapter2-2.py +++ /dev/null @@ -1,107 +0,0 @@ -import tkinter as tk -import tkinter.messagebox as msg - -class Todo(tk.Tk): - def __init__(self, tasks=None): - super().__init__() - - if not tasks: - self.tasks = [] - else: - self.tasks = tasks - - self.tasks_canvas = tk.Canvas(self) - - self.tasks_frame = tk.Frame(self.tasks_canvas) - self.text_frame = tk.Frame(self) - - self.scrollbar = tk.Scrollbar(self.tasks_canvas, orient="vertical", command=self.tasks_canvas.yview) - - self.tasks_canvas.configure(yscrollcommand=self.scrollbar.set) - - self.title("To-Do App v2") - self.geometry("300x400") - - self.task_create = tk.Text(self.text_frame, height=3, bg="white", fg="black") - - self.tasks_canvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) - - self.canvas_frame = self.tasks_canvas.create_window((0, 0), window=self.tasks_frame, anchor="n") - - self.task_create.pack(side=tk.BOTTOM, fill=tk.X) - self.text_frame.pack(side=tk.BOTTOM, fill=tk.X) - self.task_create.focus_set() - - todo1 = tk.Label(self.tasks_frame, text="--- Add Items Here ---", bg="lightgrey", fg="black", pady=10) - todo1.bind("", self.remove_task) - - self.tasks.append(todo1) - - for task in self.tasks: - task.pack(side=tk.TOP, fill=tk.X) - - self.bind("", self.add_task) - self.bind("", self.on_frame_configure) - self.bind_all("", self.mouse_scroll) - self.bind_all("", self.mouse_scroll) - self.bind_all("", self.mouse_scroll) - self.tasks_canvas.bind("", self.task_width) - - self.colour_schemes = [{"bg": "lightgrey", "fg": "black"}, {"bg": "grey", "fg": "white"}] - - def add_task(self, event=None): - task_text = self.task_create.get(1.0,tk.END).strip() - - if len(task_text) > 0: - new_task = tk.Label(self.tasks_frame, text=task_text, pady=10) - - self.set_task_colour(len(self.tasks), new_task) - - new_task.bind("", self.remove_task) - new_task.pack(side=tk.TOP, fill=tk.X) - - self.tasks.append(new_task) - - self.task_create.delete(1.0, tk.END) - - def remove_task(self, event): - task = event.widget - if msg.askyesno("Really Delete?", "Delete " + task.cget("text") + "?"): - self.tasks.remove(event.widget) - event.widget.destroy() - self.recolour_tasks() - - def recolour_tasks(self): - for index, task in enumerate(self.tasks): - self.set_task_colour(index, task) - - def set_task_colour(self, position, task): - _, task_style_choice = divmod(position, 2) - - my_scheme_choice = self.colour_schemes[task_style_choice] - - task.configure(bg=my_scheme_choice["bg"]) - task.configure(fg=my_scheme_choice["fg"]) - - def on_frame_configure(self, event=None): - self.tasks_canvas.configure(scrollregion=self.tasks_canvas.bbox("all")) - - def task_width(self, event): - canvas_width = event.width - self.tasks_canvas.itemconfig(self.canvas_frame, width = canvas_width) - - def mouse_scroll(self, event): - if event.delta: - self.tasks_canvas.yview_scroll(-1*(event.delta/120), "units") - else: - if event.num == 5: - move = 1 - else: - move = -1 - - self.tasks_canvas.yview_scroll(move, "units") - -if __name__ == "__main__": - todo = Todo() - todo.mainloop() diff --git a/Chapter2-3-abridged.py b/Chapter2-3-abridged.py deleted file mode 100644 index 965142b..0000000 --- a/Chapter2-3-abridged.py +++ /dev/null @@ -1,98 +0,0 @@ -import tkinter as tk -import tkinter.messagebox as msg -import os -import sqlite3 - -class Todo(tk.Tk): - def __init__(self, tasks=None): - ... - - self.title("To-Do App v3") - - ... - - self.colour_schemes = [{"bg": "lightgrey", "fg": "black"}, {"bg": "grey", "fg": "white"}] - - current_tasks = self.load_tasks() - for task in current_tasks: - task_text = task[0] - self.add_task(None, task_text, True) - - ... - - def add_task(self, event=None, task_text=None, from_db=False): - if not task_text: - task_text = self.task_create.get(1.0,tk.END).strip() - - if len(task_text) > 0: - new_task = tk.Label(self.tasks_frame, text=task_text, pady=10) - - self.set_task_colour(len(self.tasks), new_task) - - new_task.bind("", self.remove_task) - new_task.pack(side=tk.TOP, fill=tk.X) - - self.tasks.append(new_task) - - if not from_db: - self.save_task(task_text) - - self.task_create.delete(1.0, tk.END) - - def remove_task(self, event): - task = event.widget - if msg.askyesno("Really Delete?", "Delete " + task.cget("text") + "?"): - self.tasks.remove(event.widget) - - delete_task_query = "DELETE FROM tasks WHERE task=?" - delete_task_data = (task.cget("text"),) - self.runQuery(delete_task_query, delete_task_data) - - event.widget.destroy() - - self.recolour_tasks() - - ... - - def save_task(self, task): - insert_task_query = "INSERT INTO tasks VALUES (?)" - insert_task_data = (task,) - self.runQuery(insert_task_query, insert_task_data) - - def load_tasks(self): - load_tasks_query = "SELECT task FROM tasks" - my_tasks = self.runQuery(load_tasks_query, receive=True) - - return my_tasks - - @staticmethod - def runQuery(sql, data=None, receive=False): - conn = sqlite3.connect("tasks.db") - cursor = conn.cursor() - if data: - cursor.execute(sql, data) - else: - cursor.execute(sql) - - if receive: - return cursor.fetchall() - else: - conn.commit() - - conn.close() - - @staticmethod - def firstTimeDB(): - create_tables = "CREATE TABLE tasks (task TEXT)" - Todo.runQuery(create_tables) - - default_task_query = "INSERT INTO tasks VALUES (?)" - default_task_data = ("--- Add Items Here ---",) - Todo.runQuery(default_task_query, default_task_data) - - -if __name__ == "__main__": - if not os.path.isfile("tasks.db"): - Todo.firstTimeDB() - todo = Todo() - todo.mainloop() diff --git a/Chapter2-3.py b/Chapter2-3.py deleted file mode 100644 index 6195db8..0000000 --- a/Chapter2-3.py +++ /dev/null @@ -1,155 +0,0 @@ -import tkinter as tk -import tkinter.messagebox as msg -import os -import sqlite3 - -class Todo(tk.Tk): - def __init__(self, tasks=None): - super().__init__() - - if not tasks: - self.tasks = [] - else: - self.tasks = tasks - - self.tasks_canvas = tk.Canvas(self) - - self.tasks_frame = tk.Frame(self.tasks_canvas) - self.text_frame = tk.Frame(self) - - self.scrollbar = tk.Scrollbar(self.tasks_canvas, orient="vertical", command=self.tasks_canvas.yview) - - self.tasks_canvas.configure(yscrollcommand=self.scrollbar.set) - - self.title("To-Do App v3") - self.geometry("300x400") - - self.task_create = tk.Text(self.text_frame, height=3, bg="white", fg="black") - - self.tasks_canvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) - - self.canvas_frame = self.tasks_canvas.create_window((0, 0), window=self.tasks_frame, anchor="n") - - self.task_create.pack(side=tk.BOTTOM, fill=tk.X) - self.text_frame.pack(side=tk.BOTTOM, fill=tk.X) - self.task_create.focus_set() - - self.colour_schemes = [{"bg": "lightgrey", "fg": "black"}, {"bg": "grey", "fg": "white"}] - - current_tasks = self.load_tasks() - for task in current_tasks: - task_text = task[0] - self.add_task(None, task_text, True) - - self.bind("", self.add_task) - self.bind("", self.on_frame_configure) - self.bind_all("", self.mouse_scroll) - self.bind_all("", self.mouse_scroll) - self.bind_all("", self.mouse_scroll) - self.tasks_canvas.bind("", self.task_width) - - def add_task(self, event=None, task_text=None, from_db=False): - if not task_text: - task_text = self.task_create.get(1.0, tk.END).strip() - - if len(task_text) > 0: - new_task = tk.Label(self.tasks_frame, text=task_text, pady=10) - - self.set_task_colour(len(self.tasks), new_task) - - new_task.bind("", self.remove_task) - new_task.pack(side=tk.TOP, fill=tk.X) - - self.tasks.append(new_task) - - if not from_db: - self.save_task(task_text) - - self.task_create.delete(1.0, tk.END) - - def remove_task(self, event): - task = event.widget - if msg.askyesno("Really Delete?", "Delete " + task.cget("text") + "?"): - self.tasks.remove(event.widget) - - delete_task_query = "DELETE FROM tasks WHERE task=?" - delete_task_data = (task.cget("text"),) - self.runQuery(delete_task_query, delete_task_data) - - event.widget.destroy() - - self.recolour_tasks() - - def recolour_tasks(self): - for index, task in enumerate(self.tasks): - self.set_task_colour(index, task) - - def set_task_colour(self, position, task): - _, task_style_choice = divmod(position, 2) - - my_scheme_choice = self.colour_schemes[task_style_choice] - - task.configure(bg=my_scheme_choice["bg"]) - task.configure(fg=my_scheme_choice["fg"]) - - def on_frame_configure(self, event=None): - self.tasks_canvas.configure(scrollregion=self.tasks_canvas.bbox("all")) - - def task_width(self, event): - canvas_width = event.width - self.tasks_canvas.itemconfig(self.canvas_frame, width = canvas_width) - - def mouse_scroll(self, event): - if event.delta: - self.tasks_canvas.yview_scroll(-1*(event.delta/120), "units") - else: - if event.num == 5: - move = 1 - else: - move = -1 - - self.tasks_canvas.yview_scroll(move, "units") - - def save_task(self, task): - insert_task_query = "INSERT INTO tasks VALUES (?)" - insert_task_data = (task,) - self.runQuery(insert_task_query, insert_task_data) - - def load_tasks(self): - load_tasks_query = "SELECT task FROM tasks" - my_tasks = self.runQuery(load_tasks_query, receive=True) - - return my_tasks - - @staticmethod - def runQuery(sql, data=None, receive=False): - conn = sqlite3.connect("tasks.db") - cursor = conn.cursor() - if data: - cursor.execute(sql, data) - else: - cursor.execute(sql) - - if receive: - return cursor.fetchall() - else: - conn.commit() - - conn.close() - - @staticmethod - def firstTimeDB(): - create_tables = "CREATE TABLE tasks (task TEXT)" - Todo.runQuery(create_tables) - - default_task_query = "INSERT INTO tasks VALUES (?)" - default_task_data = ("--- Add Items Here ---",) - Todo.runQuery(default_task_query, default_task_data) - - -if __name__ == "__main__": - if not os.path.isfile("tasks.db"): - Todo.firstTimeDB() - todo = Todo() - todo.mainloop() diff --git a/Chapter3-1.py b/Chapter3-1.py deleted file mode 100644 index c48fc0e..0000000 --- a/Chapter3-1.py +++ /dev/null @@ -1,65 +0,0 @@ -import tkinter as tk -from tkinter import messagebox as msg -from tkinter.ttk import Notebook - -import requests - -class TranslateBook(tk.Tk): - def __init__(self): - super().__init__() - - self.title("Translation Book v1") - self.geometry("500x300") - - self.notebook = Notebook(self) - - english_tab = tk.Frame(self.notebook) - italian_tab = tk.Frame(self.notebook) - - self.translate_button = tk.Button(english_tab, text="Translate", command=self.translate) - self.translate_button.pack(side=tk.BOTTOM, fill=tk.X) - - self.english_entry = tk.Text(english_tab, bg="white", fg="black") - self.english_entry.pack(side=tk.TOP, expand=1) - - self.italian_copy_button = tk.Button(italian_tab, text="Copy to Clipboard", command=self.copy_to_clipboard) - self.italian_copy_button.pack(side=tk.BOTTOM, fill=tk.X) - - self.italian_translation = tk.StringVar(italian_tab) - self.italian_translation.set("") - - self.italian_label = tk.Label(italian_tab, textvar=self.italian_translation, bg="lightgrey", fg="black") - self.italian_label.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - - self.notebook.add(english_tab, text="English") - self.notebook.add(italian_tab, text="Italian") - - self.notebook.pack(fill=tk.BOTH, expand=1) - - def translate(self, target_language="it", text=None): - if not text: - text = self.english_entry.get(1.0, tk.END) - - url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl={}&tl={}&dt=t&q={}".format("en", target_language, text) - - try: - r = requests.get(url) - r.raise_for_status() - translation = r.json()[0][0][0] - self.italian_translation.set(translation) - msg.showinfo("Translation Successful", "Text successfully translated") - except Exception as e: - msg.showerror("Translation Failed", str(e)) - - def copy_to_clipboard(self, text=None): - if not text: - text = self.italian_translation.get() - - self.clipboard_clear() - self.clipboard_append(text) - msg.showinfo("Copied Successfully", "Text copied to clipboard") - - -if __name__ == "__main__": - translatebook = TranslateBook() - translatebook.mainloop() diff --git a/Chapter3-2-abridged.py b/Chapter3-2-abridged.py deleted file mode 100644 index 577857e..0000000 --- a/Chapter3-2-abridged.py +++ /dev/null @@ -1,71 +0,0 @@ -... - -class TranslateBook(tk.Tk): - def __init__(self): - - ... - - self.menu = tk.Menu(self, bg="lightgrey", fg="black") - - self.languages_menu = tk.Menu(self.menu, tearoff=0, bg="lightgrey", fg="black") - self.languages_menu.add_command(label="Portuguese", command=self.add_portuguese_tab) - - self.menu.add_cascade(label="Languages", menu=self.languages_menu) - - self.config(menu=self.menu) - - ... - - self.italian_translation = tk.StringVar(italian_tab) - self.italian_translation.set("") - - self.translate_button = tk.Button(english_tab, text="Translate", command=lambda langs=["it"], elems=[self.italian_translation]: self.translate(langs, None, elems)) - - ... - - def translate(self, target_languages=None, text=None, elements=None): - if not text: - text = self.english_entry.get(1.0, tk.END).strip() - if not elements: - elements = [self.italian_translation] - if not target_languages: - target_languages = ["it"] - - url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl={}&tl={}&dt=t&q={}" - - try: - for code, element in zip(target_languages, elements): - full_url = url.format("en", code, text) - r = requests.get(full_url) - r.raise_for_status() - translation = r.json()[0][0][0] - element.set(translation) - except Exception as e: - msg.showerror("Translation Failed", str(e)) - else: - msg.showinfo("Translations Successful", "Text successfully translated") - - def copy_to_clipboard(self, text=None): - ... - - def add_portuguese_tab(self): - portuguese_tab = tk.Frame(self.notebook) - self.portuguese_translation = tk.StringVar(portuguese_tab) - self.portuguese_translation.set("") - - self.portuguese_copy_button = tk.Button(portuguese_tab, text="Copy to Clipboard", command=lambda: self.copy_to_clipboard(self.portuguese_translation.get())) - self.portuguese_copy_button.pack(side=tk.BOTTOM, fill=tk.X) - - self.portuguese_label = tk.Label(portuguese_tab, textvar=self.portuguese_translation, bg="lightgrey", fg="black") - self.portuguese_label.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - - self.notebook.add(portuguese_tab, text="Portuguese") - - self.languages_menu.entryconfig("Portuguese", state="disabled") - - self.translate_button.config(command=lambda langs=["it","pt"], elems=[self.italian_translation, self.portuguese_translation]: self.translate(langs, None, elems)) - - -if __name__ == "__main__": - translatebook = TranslateBook() - translatebook.mainloop() diff --git a/Chapter3-2.py b/Chapter3-2.py deleted file mode 100644 index dd902c1..0000000 --- a/Chapter3-2.py +++ /dev/null @@ -1,107 +0,0 @@ -import tkinter as tk -from tkinter import messagebox as msg -from tkinter.ttk import Notebook - -import requests - -class TranslateBook(tk.Tk): - def __init__(self): - super().__init__() - - self.title("Translation Book v2") - self.geometry("500x300") - - self.menu = tk.Menu(self, bg="lightgrey", fg="black") - - self.languages_menu = tk.Menu(self.menu, tearoff=0, bg="lightgrey", fg="black") - self.languages_menu.add_command(label="Portuguese", command=self.add_portuguese_tab) - - self.menu.add_cascade(label="Languages", menu=self.languages_menu) - - self.config(menu=self.menu) - - self.notebook = Notebook(self) - - english_tab = tk.Frame(self.notebook) - italian_tab = tk.Frame(self.notebook) - - self.italian_translation = tk.StringVar(italian_tab) - self.italian_translation.set("") - - self.translate_button = tk.Button(english_tab, - text="Translate", - command=lambda langs=["it"], - elems=[self.italian_translation]: - self.translate(langs, None, elems)) - self.translate_button.pack(side=tk.BOTTOM, fill=tk.X) - - self.english_entry = tk.Text(english_tab, bg="white", fg="black") - self.english_entry.pack(side=tk.TOP, expand=1) - - self.italian_copy_button = tk.Button(italian_tab, text="Copy to Clipboard", command=self.copy_to_clipboard) - self.italian_copy_button.pack(side=tk.BOTTOM, fill=tk.X) - - self.italian_label = tk.Label(italian_tab, textvar=self.italian_translation, bg="lightgrey", fg="black") - self.italian_label.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - - self.notebook.add(english_tab, text="English") - self.notebook.add(italian_tab, text="Italian") - - self.notebook.pack(fill=tk.BOTH, expand=1) - - def translate(self, target_languages=None, text=None, elements=None): - if not text: - text = self.english_entry.get(1.0, tk.END).strip() - if not elements: - elements = [self.italian_translation] - if not target_languages: - target_languages = ["it"] - - url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl={}&tl={}&dt=t&q={}" - - try: - for code, element in zip(target_languages, elements): - full_url = url.format("en", code, text) - r = requests.get(full_url) - r.raise_for_status() - translation = r.json()[0][0][0] - element.set(translation) - except Exception as e: - msg.showerror("Translation Failed", str(e)) - else: - msg.showinfo("Translations Successful", "Text successfully translated") - - def copy_to_clipboard(self, text=None): - if not text: - text = self.italian_translation.get() - - self.clipboard_clear() - self.clipboard_append(text) - msg.showinfo("Copied Successfully", "Text copied to clipboard") - - def add_portuguese_tab(self): - portuguese_tab = tk.Frame(self.notebook) - self.portuguese_translation = tk.StringVar(portuguese_tab) - self.portuguese_translation.set("") - - self.portuguese_copy_button = tk.Button(portuguese_tab, - text="Copy to Clipboard", - command=lambda: - self.copy_to_clipboard(self.portuguese_translation.get())) - self.portuguese_copy_button.pack(side=tk.BOTTOM, fill=tk.X) - - self.portuguese_label = tk.Label(portuguese_tab, textvar=self.portuguese_translation, bg="lightgrey", fg="black") - self.portuguese_label.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - - self.notebook.add(portuguese_tab, text="Portuguese") - - self.languages_menu.entryconfig("Portuguese", state="disabled") - - self.translate_button.config(command=lambda langs=["it","pt"], - elems=[self.italian_translation, self.portuguese_translation]: - self.translate(langs, None, elems)) - - -if __name__ == "__main__": - translatebook = TranslateBook() - translatebook.mainloop() diff --git a/Chapter3-3-LanguageTab.py b/Chapter3-3-LanguageTab.py deleted file mode 100644 index 87c78dc..0000000 --- a/Chapter3-3-LanguageTab.py +++ /dev/null @@ -1,22 +0,0 @@ -class LanguageTab(tk.Frame): - def __init__(self, master, lang_name, lang_code): - super().__init__(master) - - self.lang_name = lang_name - self.lang_code = lang_code - - self.translation_var = tk.StringVar(self) - self.translation_var.set("") - - self.translated_label = tk.Label(self, textvar=self.translation_var, bg="lightgrey", fg="black") - - self.copy_button = tk.Button(self, text="Copy to Clipboard", command=self.copy_to_clipboard) - - self.copy_button.pack(side=tk.BOTTOM, fill=tk.X) - self.translated_label.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - - def copy_to_clipboard(self): - root = self.winfo_toplevel() - root.clipboard_clear() - root.clipboard_append(self.translation_var.get()) - msg.showinfo("Copied Successfully", "Text copied to clipboard") diff --git a/Chapter3-3-NewLanguageForm.py b/Chapter3-3-NewLanguageForm.py deleted file mode 100644 index 4bc1abb..0000000 --- a/Chapter3-3-NewLanguageForm.py +++ /dev/null @@ -1,32 +0,0 @@ -class NewLanguageForm(tk.Toplevel): - def __init__(self, master): - super().__init__() - - self.master = master - - self.title("Add new Language") - self.geometry("300x150") - - self.name_label = tk.Label(self, text="Language Name") - self.name_entry = tk.Entry(self, bg="white", fg="black") - self.code_label = tk.Label(self, text="Language Code") - self.code_entry = tk.Entry(self, bg="white", fg="black") - self.submit_button = tk.Button(self, text="Submit", command=self.submit) - - self.name_label.pack(fill=tk.BOTH, expand=1) - self.name_entry.pack(fill=tk.BOTH, expand=1) - self.code_label.pack(fill=tk.BOTH, expand=1) - self.code_entry.pack(fill=tk.BOTH, expand=1) - self.submit_button.pack(fill=tk.X) - - def submit(self): - lang_name = self.name_entry.get() - lang_code = self.code_entry.get() - - if lang_name and lang_code: - new_tab = LanguageTab(self.master, lang_name, lang_code) - self.master.languages_menu.add_command(label=lang_name, command=lambda: self.master.add_new_tab(new_tab)) - msg.showinfo("Language Option Added", "Language option " + lang_name + " added to menu") - self.destroy() - else: - msg.showerror("Missing Information", "Please add both a name and code") diff --git a/Chapter3-3-TranslateBook.py b/Chapter3-3-TranslateBook.py deleted file mode 100644 index adfd90d..0000000 --- a/Chapter3-3-TranslateBook.py +++ /dev/null @@ -1,68 +0,0 @@ -class TranslateBook(tk.Tk): - def __init__(self): - super().__init__() - - self.title("Translation Book v3") - self.geometry("500x300") - - self.menu = tk.Menu(self, bg="lightgrey", fg="black") - - self.languages_menu = tk.Menu(self.menu, tearoff=0, bg="lightgrey", fg="black") - self.languages_menu.add_command(label="Add New", command=self.show_new_language_popup) - self.languages_menu.add_command(label="Portuguese", command=lambda: self.add_new_tab(LanguageTab(self, "Portuguese", "pt"))) - - self.menu.add_cascade(label="Languages", menu=self.languages_menu) - - self.config(menu=self.menu) - - self.notebook = Notebook(self) - - self.language_tabs = [] - - english_tab = tk.Frame(self.notebook) - - self.translate_button = tk.Button(english_tab, text="Translate", command=self.translate) - self.translate_button.pack(side=tk.BOTTOM, fill=tk.X) - - self.english_entry = tk.Text(english_tab, bg="white", fg="black") - self.english_entry.pack(side=tk.TOP, expand=1) - - self.notebook.add(english_tab, text="English") - - self.notebook.pack(fill=tk.BOTH, expand=1) - - def translate(self, text=None): - if len(self.language_tabs) < 1: - msg.showerror("No Languages", "No languages added. Please add some from the menu") - return - - if not text: - text = self.english_entry.get(1.0, tk.END).strip() - - url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl={}&tl={}&dt=t&q={}" - - try: - for language in self.language_tabs: - full_url = url.format("en", language.lang_code, text) - r = requests.get(full_url) - r.raise_for_status() - translation = r.json()[0][0][0] - language.translation_var.set(translation) - except Exception as e: - msg.showerror("Translation Failed", str(e)) - else: - msg.showinfo("Translations Successful", "Text successfully translated") - - def add_new_tab(self, tab): - self.language_tabs.append(tab) - self.notebook.add(tab, text=tab.lang_name) - - try: - self.languages_menu.entryconfig(tab.lang_name, state="disabled") - except: - # language isn't in menu. - pass - - def show_new_language_popup(self): - NewLanguageForm(self) - diff --git a/Chapter3-3-ttk.py b/Chapter3-3-ttk.py deleted file mode 100644 index 5fb2a79..0000000 --- a/Chapter3-3-ttk.py +++ /dev/null @@ -1,138 +0,0 @@ -import tkinter as tk -from tkinter import messagebox as msg -from tkinter.ttk import Notebook -from tkinter import ttk -import requests - -class LanguageTab(ttk.Frame): - def __init__(self, master, lang_name, lang_code): - super().__init__(master) - - self.lang_name = lang_name - self.lang_code = lang_code - - self.translation_var = tk.StringVar(self) - self.translation_var.set("") - - self.translated_label = ttk.Label(self, textvar=self.translation_var, anchor="center") - - self.copy_button = ttk.Button(self, text="Copy to Clipboard", command=self.copy_to_clipboard) - - self.copy_button.pack(side=tk.BOTTOM, fill=tk.X) - self.translated_label.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - - def copy_to_clipboard(self): - root = self.winfo_toplevel() - root.clipboard_clear() - root.clipboard_append(self.translation_var.get()) - msg.showinfo("Copied Successfully", "Text copied to clipboard") - - -class NewLanguageForm(tk.Toplevel): - def __init__(self, master): - super().__init__() - - self.master = master - - self.title("Add new Language") - self.geometry("300x150") - - self.name_label = ttk.Label(self, text="Language Name", anchor="center") - self.name_entry = ttk.Entry(self) - self.code_label = ttk.Label(self, text="Language Code", anchor="center") - self.code_entry = ttk.Entry(self) - self.submit_button = ttk.Button(self, text="Submit", command=self.submit) - - self.name_label.pack(fill=tk.BOTH, expand=1) - self.name_entry.pack(fill=tk.BOTH) - self.code_label.pack(fill=tk.BOTH, expand=1) - self.code_entry.pack(fill=tk.BOTH, expand=1) - self.submit_button.pack(fill=tk.X) - - def submit(self): - lang_name = self.name_entry.get() - lang_code = self.code_entry.get() - - if lang_name and lang_code: - new_tab = LanguageTab(self.master, lang_name, lang_code) - self.master.languages_menu.add_command(label=lang_name, command=lambda: self.master.add_new_tab(new_tab)) - msg.showinfo("Language Option Added", "Language option " + lang_name + " added to menu") - self.destroy() - else: - msg.showerror("Missing Information", "Please add both a name and code") - - -class TranslateBook(tk.Tk): - def __init__(self): - super().__init__() - - self.title("Translation Book v3") - self.geometry("500x300") - - self.menu = tk.Menu(self, bg="lightgrey", fg="black") - - self.languages_menu = tk.Menu(self.menu, tearoff=0, bg="lightgrey", fg="black") - self.languages_menu.add_command(label="Add New", command=self.show_new_language_popup) - self.languages_menu.add_command(label="Portuguese", command=lambda: self.add_new_tab(LanguageTab(self, "Portuguese", "pt"))) - - self.menu.add_cascade(label="Languages", menu=self.languages_menu) - - self.config(menu=self.menu) - - self.notebook = Notebook(self) - - self.language_tabs = [] - - english_tab = ttk.Frame(self.notebook) - - self.translate_button = ttk.Button(english_tab, text="Translate", command=self.translate) - self.translate_button.pack(side=tk.BOTTOM, fill=tk.X) - - self.english_entry = tk.Text(english_tab, bg="white", fg="black") - self.english_entry.pack(side=tk.TOP, expand=1) - - self.notebook.add(english_tab, text="English") - - self.notebook.pack(fill=tk.BOTH, expand=1) - - def translate(self, text=None): - if len(self.language_tabs) < 1: - msg.showerror("No Languages", "No languages added. Please add some from the menu") - return - - if not text: - text = self.english_entry.get(1.0, tk.END).strip() - - url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl={}&tl={}&dt=t&q={}" - - try: - for language in self.language_tabs: - full_url = url.format("en", language.lang_code, text) - r = requests.get(full_url) - r.raise_for_status() - translation = r.json()[0][0][0] - language.translation_var.set(translation) - except Exception as e: - msg.showerror("Translation Failed", str(e)) - else: - msg.showinfo("Translations Successful", "Text successfully translated") - - def add_new_tab(self, tab): - self.language_tabs.append(tab) - self.notebook.add(tab, text=tab.lang_name) - - try: - self.languages_menu.entryconfig(tab.lang_name, state="disabled") - except: - # language isn't in menu. - pass - - def show_new_language_popup(self): - NewLanguageForm(self) - - -if __name__ == "__main__": - translatebook = TranslateBook() - italian_tab = LanguageTab(translatebook, "Italian", "it") - translatebook.add_new_tab(italian_tab) - translatebook.mainloop() diff --git a/Chapter3-3.py b/Chapter3-3.py deleted file mode 100644 index 78d0c02..0000000 --- a/Chapter3-3.py +++ /dev/null @@ -1,138 +0,0 @@ -import tkinter as tk -from tkinter import messagebox as msg -from tkinter.ttk import Notebook - -import requests - -class LanguageTab(tk.Frame): - def __init__(self, master, lang_name, lang_code): - super().__init__(master) - - self.lang_name = lang_name - self.lang_code = lang_code - - self.translation_var = tk.StringVar(self) - self.translation_var.set("") - - self.translated_label = tk.Label(self, textvar=self.translation_var, bg="lightgrey", fg="black") - - self.copy_button = tk.Button(self, text="Copy to Clipboard", command=self.copy_to_clipboard) - - self.copy_button.pack(side=tk.BOTTOM, fill=tk.X) - self.translated_label.pack(side=tk.TOP, fill=tk.BOTH, expand=1) - - def copy_to_clipboard(self): - root = self.winfo_toplevel() - root.clipboard_clear() - root.clipboard_append(self.translation_var.get()) - msg.showinfo("Copied Successfully", "Text copied to clipboard") - - -class NewLanguageForm(tk.Toplevel): - def __init__(self, master): - super().__init__() - - self.master = master - - self.title("Add new Language") - self.geometry("300x150") - - self.name_label = tk.Label(self, text="Language Name") - self.name_entry = tk.Entry(self, bg="white", fg="black") - self.code_label = tk.Label(self, text="Language Code") - self.code_entry = tk.Entry(self, bg="white", fg="black") - self.submit_button = tk.Button(self, text="Submit", command=self.submit) - - self.name_label.pack(fill=tk.BOTH, expand=1) - self.name_entry.pack(fill=tk.BOTH, expand=1) - self.code_label.pack(fill=tk.BOTH, expand=1) - self.code_entry.pack(fill=tk.BOTH, expand=1) - self.submit_button.pack(fill=tk.X) - - def submit(self): - lang_name = self.name_entry.get() - lang_code = self.code_entry.get() - - if lang_name and lang_code: - new_tab = LanguageTab(self.master, lang_name, lang_code) - self.master.languages_menu.add_command(label=lang_name, command=lambda: self.master.add_new_tab(new_tab)) - msg.showinfo("Language Option Added", "Language option " + lang_name + " added to menu") - self.destroy() - else: - msg.showerror("Missing Information", "Please add both a name and code") - - -class TranslateBook(tk.Tk): - def __init__(self): - super().__init__() - - self.title("Translation Book v3") - self.geometry("500x300") - - self.menu = tk.Menu(self, bg="lightgrey", fg="black") - - self.languages_menu = tk.Menu(self.menu, tearoff=0, bg="lightgrey", fg="black") - self.languages_menu.add_command(label="Add New", command=self.show_new_language_popup) - self.languages_menu.add_command(label="Portuguese", command=lambda: self.add_new_tab(LanguageTab(self, "Portuguese", "pt"))) - - self.menu.add_cascade(label="Languages", menu=self.languages_menu) - - self.config(menu=self.menu) - - self.notebook = Notebook(self) - - self.language_tabs = [] - - english_tab = tk.Frame(self.notebook) - - self.translate_button = tk.Button(english_tab, text="Translate", command=self.translate) - self.translate_button.pack(side=tk.BOTTOM, fill=tk.X) - - self.english_entry = tk.Text(english_tab, bg="white", fg="black") - self.english_entry.pack(side=tk.TOP, expand=1) - - self.notebook.add(english_tab, text="English") - - self.notebook.pack(fill=tk.BOTH, expand=1) - - def translate(self, text=None): - if len(self.language_tabs) < 1: - msg.showerror("No Languages", "No languages added. Please add some from the menu") - return - - if not text: - text = self.english_entry.get(1.0, tk.END).strip() - - url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl={}&tl={}&dt=t&q={}" - - try: - for language in self.language_tabs: - full_url = url.format("en", language.lang_code, text) - r = requests.get(full_url) - r.raise_for_status() - translation = r.json()[0][0][0] - language.translation_var.set(translation) - except Exception as e: - msg.showerror("Translation Failed", str(e)) - else: - msg.showinfo("Translations Successful", "Text successfully translated") - - def add_new_tab(self, tab): - self.language_tabs.append(tab) - self.notebook.add(tab, text=tab.lang_name) - - try: - self.languages_menu.entryconfig(tab.lang_name, state="disabled") - except: - # language isn't in menu. - pass - - def show_new_language_popup(self): - NewLanguageForm(self) - - -if __name__ == "__main__": - translatebook = TranslateBook() - italian_tab = LanguageTab(translatebook, "Italian", "it") - translatebook.add_new_tab(italian_tab) - translatebook.mainloop() diff --git a/Chapter4-1.py b/Chapter4-1.py deleted file mode 100644 index cecd276..0000000 --- a/Chapter4-1.py +++ /dev/null @@ -1,121 +0,0 @@ -import tkinter as tk -from tkinter import font - -class GameScreen(): - def __init__(self, master, image, roi, inventory_item=None, help_text=None): - self.master = master - self.roi = roi - self.image = tk.PhotoImage(file=image) - self.inventory_item = inventory_item - self.help_text = help_text - - def on_click(self, event): - if (self.roi[0] <= event.x <= self.roi[2] - and self.roi[1] <= event.y <= self.roi[3]): - - if self.inventory_item: - self.master.add_inventory_item(self.inventory_item) - self.master.show_next_screen() - - -class Game(tk.Tk): - def __init__(self): - super().__init__() - - self.inventory_slots = [] - self.inventory_slots_in_use = [] - self.current_screen_number = 0 - self.success_font = font.Font(family="ubuntu", size=50, weight=font.BOLD) - - self.title("Point and Click") - self.geometry("800x640") - self.resizable(False, False) - - self.key_image = tk.PhotoImage(file="assets/key.png") - self.question_mark_image = tk.PhotoImage(file="assets/questionmark.png") - - self.screen = tk.Canvas(self, bg="white", width=500, height=800) - self.right_frame = tk.Frame(self, width=300, height=800) - self.right_frame.pack_propagate(0) - - self.help_var = tk.StringVar(self.right_frame) - self.help_var.set("Try Clicking Something") - - self.help_box = tk.Label(self.right_frame, textvar=self.help_var, background="black", foreground="white", padx=10, pady=20) - self.help_box.pack(side=tk.TOP, fill=tk.X, padx=10, pady=10) - - inventory_title = tk.Label(self.right_frame, text="Inventory:", background="grey", foreground="white") - - inventory_space = tk.Frame(self.right_frame, background="lightgrey", width=300, height=320) - inventory_space.pack_propagate(0) - - inventory_space.pack(side=tk.BOTTOM) - inventory_title.pack(side=tk.BOTTOM, fill=tk.X) - - inventory_slot_1 = tk.Button(inventory_space, image=self.question_mark_image, width=50, height=50) - inventory_slot_2 = tk.Button(inventory_space, image=self.question_mark_image, width=50, height=50) - inventory_slot_3 = tk.Button(inventory_space, image=self.question_mark_image, width=50, height=50) - - inventory_slot_1.pack(pady=(40,20), padx=20) - inventory_slot_2.pack(pady=20, padx=20) - inventory_slot_3.pack(pady=(20,0), padx=20) - - self.inventory_slots.append(inventory_slot_1) - self.inventory_slots.append(inventory_slot_2) - self.inventory_slots.append(inventory_slot_3) - - self.right_frame.pack(side=tk.RIGHT) - self.screen.pack(side=tk.LEFT) - - self.screen.bind("", self.handle_click) - - def handle_click(self, event): - self.active_screen.on_click(event) - - def set_game_screens(self, game_screens): - self.game_screens = game_screens - - def display_screen(self, game_screen_number): - self.active_screen = self.game_screens[game_screen_number] - self.screen.delete("all") - self.screen.create_image((250,400), image=self.active_screen.image) - self.help_var.set(self.active_screen.help_text) - - def show_next_screen(self): - self.current_screen_number += 1; - if self.current_screen_number < len(self.game_screens): - self.display_screen(self.current_screen_number) - else: - self.screen.delete("all") - self.screen.configure(bg="black") - self.screen.create_text((250,300), text="You Win!", font=self.success_font, fill="white") - - def add_inventory_item(self, item_name): - next_available_inventory_slot = len(self.inventory_slots_in_use) - if next_available_inventory_slot < len(self.inventory_slots): - next_slot = self.inventory_slots[next_available_inventory_slot] - - if item_name == "key": - next_slot.configure(image=self.key_image) - - self.inventory_slots_in_use.append(item_name) - - def play(self): - if not self.game_screens: - print("No screens added!") - else: - self.display_screen(0) - - -if __name__ == "__main__": - game = Game() - - scene1 = GameScreen(game, "assets/scene1.png", (378,135,427,217), "key", "You Need To Leave but the Door is Locked!") - scene2 = GameScreen(game, "assets/scene2.png", (117,54,329,412), None, "You Got the Key!") - scene3 = GameScreen(game, "assets/scene3.png", (117,54,329,412), None, "The Door is Open!") - - all_screens = [scene1, scene2, scene3] - - game.set_game_screens(all_screens) - game.play() - game.mainloop() diff --git a/Chapter4-2-abridged.py b/Chapter4-2-abridged.py deleted file mode 100644 index 4ae4b88..0000000 --- a/Chapter4-2-abridged.py +++ /dev/null @@ -1,170 +0,0 @@ -import tkinter as tk -from tkinter import font -from functools import partial - -class GameScreen(): - def __init__(self, master, image, roi, inventory_item=None, help_text=None, required_item=None): - ... - self.required_item = required_item - - def on_click(self, event, item_in_use): - if self.master.has_won: - return - - if item_in_use and not self.required_item: - self.master.show_cannot_use_message() - elif (self.roi[0] <= event.x <= self.roi[2] - and self.roi[1] <= event.y <= self.roi[3]): - - if self.inventory_item: - self.master.add_inventory_item(self.inventory_item) - - if self.required_item: - if item_in_use == self.required_item: - self.master.show_next_screen() - else: - self.master.show_next_screen() - else: - if item_in_use: - self.master.show_cannot_use_message() - - -class Game(tk.Tk): - def __init__(self): - ... - self.cannot_use_font = font.Font(family="ubuntu", size=28, weight=font.BOLD) - self.item_in_use = "" - self.has_won = False - - ... - - self.help_history_var_1 = tk.StringVar(self.right_frame) - self.help_history_var_2 = tk.StringVar(self.right_frame) - self.help_history_var_3 = tk.StringVar(self.right_frame) - - help_history_box_1 = tk.Label(self.right_frame, textvar=self.help_history_var_1, bg="black", fg="white", padx=10, pady=10) - help_history_box_2 = tk.Label(self.right_frame, textvar=self.help_history_var_2, bg="black", fg="white", padx=10, pady=10) - help_history_box_3 = tk.Label(self.right_frame, textvar=self.help_history_var_3, bg="black", fg="white", padx=10, pady=10) - - help_history_box_1.pack(side=tk.TOP, fill=tk.X, padx=10) - help_history_box_2.pack(side=tk.TOP, fill=tk.X, padx=10) - help_history_box_3.pack(side=tk.TOP, fill=tk.X, padx=10) - - ... - - inventory_row_1 = tk.Frame(self.inventory_space, pady=10) - inventory_row_2 = tk.Frame(self.inventory_space, pady=10) - inventory_row_3 = tk.Frame(self.inventory_space, pady=10) - - inventory_slot_1 = tk.Button(self.inventory_row_1, - image=self.question_mark_image, - width=50, height=50, - bg="black", - command=lambda: self.use_item(0)) - - inventory_slot_2 = tk.Button(self.inventory_row_2, - image=self.question_mark_image, - width=50, height=50, - bg="black", - command=lambda: self.use_item(1)) - - inventory_slot_3 = tk.Button(self.inventory_row_3, - image=self.question_mark_image, - width=50, height=50, - bg="black", - command=lambda: self.use_item(2)) - - item_name_1 = tk.StringVar(self.inventory_row_1) - item_name_2 = tk.StringVar(self.inventory_row_2) - item_name_3 = tk.StringVar(self.inventory_row_3) - - self.item_label_vars = [self.item_name_1, self.item_name_2, self.item_name_3] - - item_label_1 = tk.Label(self.inventory_row_1, textvar=self.item_name_1, anchor="w") - item_label_2 = tk.Label(self.inventory_row_2, textvar=self.item_name_2, anchor="w") - item_label_3 = tk.Label(self.inventory_row_3, textvar=self.item_name_3, anchor="w") - - inventory_row_1.pack(fill=tk.X, expand=1) - inventory_row_2.pack(fill=tk.X, expand=1) - inventory_row_3.pack(fill=tk.X, expand=1) - - inventory_slot_1.pack(side=tk.LEFT, padx=(100,20)) - item_label_1.pack(side=tk.LEFT, fill=tk.X, expand=1) - inventory_slot_2.pack(side=tk.LEFT, padx=(100,20)) - item_label_2.pack(side=tk.LEFT, fill=tk.X, expand=1) - inventory_slot_3.pack(side=tk.LEFT, padx=(100,20)) - item_label_3.pack(side=tk.LEFT, fill=tk.X, expand=1) - - ... - - def handle_click(self, event): - ... - - def set_game_screens(self, game_screens): - ... - - def display_screen(self, game_screen_number): - ... - self.show_help_text(self.active_screen.help_text) - - def show_next_screen(self): - self.current_screen_number += 1; - if self.current_screen_number < len(self.game_screens): - self.display_screen(self.current_screen_number) - self.clear_used_item() - else: - self.screen.delete("all") - self.screen.configure(bg="black") - self.screen.create_text((250,300), text="You Win!", font=self.success_font, fill="white") - self.has_won = True - - def show_help_text(self, text): - self.help_history_var_3.set(self.help_history_var_2.get()) - self.help_history_var_2.set(self.help_history_var_1.get()) - self.help_history_var_1.set(self.help_var.get()) - self.help_var.set(text) - - def add_inventory_item(self, item_name): - next_available_inventory_slot = len(self.inventory_slots_in_use) - if next_available_inventory_slot < len(self.inventory_slots): - next_slot = self.inventory_slots[next_available_inventory_slot] - next_label_var = self.item_label_vars[next_available_inventory_slot] - - if item_name == "key": - next_slot.configure(image=self.key_image) - - next_label_var.set(item_name.title()) - self.inventory_slots_in_use.append(item_name) - - def use_item(self, item_number): - if item_number < len(self.inventory_slots_in_use): - item_name = self.inventory_slots_in_use[item_number] - if item_name: - self.item_in_use = item_name - - for button in self.inventory_slots: - button.configure(bg="black") - - self.inventory_slots[item_number].configure(bg="white") - self.inventory_slots[item_number].configure(command=self.clear_used_item) - - def clear_used_item(self): - self.item_in_use = "" - for index, button in enumerate(self.inventory_slots): - button.configure(bg="black") - - use_cmd = partial(self.use_item, item_number=index) - button.configure(command=use_cmd) - - def show_cannot_use_message(self): - text_id = self.screen.create_text((250,25), text="You cannot use that there!", font=self.cannot_use_font, fill="white") - self.after(2000, lambda: self.screen.delete(text_id)) - - def play(self): - ... - - -if __name__ == "__main__": - ... - scene2 = GameScreen(game, "assets/scene2.png", (117,54,329,412), None, "You Got the Key!", "key") - ... diff --git a/Chapter4-2.py b/Chapter4-2.py deleted file mode 100644 index e050f68..0000000 --- a/Chapter4-2.py +++ /dev/null @@ -1,220 +0,0 @@ -import tkinter as tk -from tkinter import font -from functools import partial - -class GameScreen(): - def __init__(self, master, image, roi, inventory_item=None, help_text=None, required_item=None): - self.master = master - self.roi = roi - self.image = tk.PhotoImage(file=image) - self.inventory_item = inventory_item - self.help_text = help_text - self.required_item = required_item - - def on_click(self, event, item_in_use): - if self.master.has_won: - return - - if item_in_use and not self.required_item: - self.master.show_cannot_use_message() - elif (self.roi[0] <= event.x <= self.roi[2] - and self.roi[1] <= event.y <= self.roi[3]): - - if self.inventory_item: - self.master.add_inventory_item(self.inventory_item) - - if self.required_item: - if item_in_use == self.required_item: - self.master.show_next_screen() - else: - self.master.show_next_screen() - else: - if item_in_use: - self.master.show_cannot_use_message() - - -class Game(tk.Tk): - def __init__(self): - super().__init__() - - self.inventory_slots = [] - self.inventory_slots_in_use = [] - self.current_screen_number = 0 - self.success_font = font.Font(family="ubuntu", size=50, weight=font.BOLD) - self.cannot_use_font = font.Font(family="ubuntu", size=28, weight=font.BOLD) - self.item_in_use = "" - self.has_won = False - - self.title("Point and Click") - self.geometry("800x640") - self.resizable(False, False) - - self.key_image = tk.PhotoImage(file="assets/key.png") - self.question_mark_image = tk.PhotoImage(file="assets/questionmark.png") - - self.screen = tk.Canvas(self, bg="white", width=500, height=800) - self.right_frame = tk.Frame(self, width=300, height=800) - self.right_frame.pack_propagate(0) - - self.help_var = tk.StringVar(self.right_frame) - self.help_var.set("") - - self.help_box = tk.Label(self.right_frame, textvar=self.help_var, bg="black", fg="white", padx=10, pady=20) - self.help_box.pack(side=tk.TOP, fill=tk.X, padx=10, pady=10) - - self.help_history_var_1 = tk.StringVar(self.right_frame) - self.help_history_var_2 = tk.StringVar(self.right_frame) - self.help_history_var_3 = tk.StringVar(self.right_frame) - - help_history_box_1 = tk.Label(self.right_frame, textvar=self.help_history_var_1, bg="black", fg="white", padx=10, pady=10) - help_history_box_2 = tk.Label(self.right_frame, textvar=self.help_history_var_2, bg="black", fg="white", padx=10, pady=10) - help_history_box_3 = tk.Label(self.right_frame, textvar=self.help_history_var_3, bg="black", fg="white", padx=10, pady=10) - - help_history_box_1.pack(side=tk.TOP, fill=tk.X, padx=10) - help_history_box_2.pack(side=tk.TOP, fill=tk.X, padx=10) - help_history_box_3.pack(side=tk.TOP, fill=tk.X, padx=10) - - inventory_title = tk.Label(self.right_frame, text="Inventory:", background="grey", foreground="white") - - inventory_space = tk.Frame(self.right_frame, width=300, height=320) - inventory_space.pack_propagate(0) - - inventory_space.pack(side=tk.BOTTOM) - inventory_title.pack(side=tk.BOTTOM, fill=tk.X) - - inventory_row_1 = tk.Frame(inventory_space, pady=10) - inventory_row_2 = tk.Frame(inventory_space, pady=10) - inventory_row_3 = tk.Frame(inventory_space, pady=10) - - inventory_slot_1 = tk.Button(inventory_row_1, - image=self.question_mark_image, - width=50, height=50, - bg="black", - command=lambda: self.use_item(0)) - - inventory_slot_2 = tk.Button(inventory_row_2, - image=self.question_mark_image, - width=50, height=50, - bg="black", - command=lambda: self.use_item(1)) - - inventory_slot_3 = tk.Button(inventory_row_3, - image=self.question_mark_image, - width=50, height=50, - bg="black", - command=lambda: self.use_item(2)) - - item_name_1 = tk.StringVar(inventory_row_1) - item_name_2 = tk.StringVar(inventory_row_2) - item_name_3 = tk.StringVar(inventory_row_3) - - self.item_label_vars = [item_name_1, item_name_2, item_name_3] - - item_label_1 = tk.Label(inventory_row_1, textvar=item_name_1, anchor="w") - item_label_2 = tk.Label(inventory_row_2, textvar=item_name_2, anchor="w") - item_label_3 = tk.Label(inventory_row_3, textvar=item_name_3, anchor="w") - - inventory_row_1.pack(fill=tk.X, expand=1) - inventory_row_2.pack(fill=tk.X, expand=1) - inventory_row_3.pack(fill=tk.X, expand=1) - - inventory_slot_1.pack(side=tk.LEFT, padx=(100,20)) - item_label_1.pack(side=tk.LEFT, fill=tk.X, expand=1) - inventory_slot_2.pack(side=tk.LEFT, padx=(100,20)) - item_label_2.pack(side=tk.LEFT, fill=tk.X, expand=1) - inventory_slot_3.pack(side=tk.LEFT, padx=(100,20)) - item_label_3.pack(side=tk.LEFT, fill=tk.X, expand=1) - - self.inventory_slots.append(inventory_slot_1) - self.inventory_slots.append(inventory_slot_2) - self.inventory_slots.append(inventory_slot_3) - - self.right_frame.pack(side=tk.RIGHT) - self.screen.pack(side=tk.LEFT) - - self.screen.bind("", self.handle_click) - - def handle_click(self, event): - self.active_screen.on_click(event, self.item_in_use) - - def set_game_screens(self, game_screens): - self.game_screens = game_screens - - def display_screen(self, game_screen_number): - self.active_screen = self.game_screens[game_screen_number] - self.screen.delete("all") - self.screen.create_image((250,400), image=self.active_screen.image) - self.show_help_text(self.active_screen.help_text) - - def show_next_screen(self): - self.current_screen_number += 1; - if self.current_screen_number < len(self.game_screens): - self.display_screen(self.current_screen_number) - self.clear_used_item() - else: - self.screen.delete("all") - self.screen.configure(bg="black") - self.screen.create_text((250,300), text="You Win!", font=self.success_font, fill="white") - self.has_won = True - - def show_help_text(self, text): - self.help_history_var_3.set(self.help_history_var_2.get()) - self.help_history_var_2.set(self.help_history_var_1.get()) - self.help_history_var_1.set(self.help_var.get()) - self.help_var.set(text) - - def add_inventory_item(self, item_name): - next_available_inventory_slot = len(self.inventory_slots_in_use) - if next_available_inventory_slot < len(self.inventory_slots): - next_slot = self.inventory_slots[next_available_inventory_slot] - next_label_var = self.item_label_vars[next_available_inventory_slot] - - if item_name == "key": - next_slot.configure(image=self.key_image) - - next_label_var.set(item_name.title()) - self.inventory_slots_in_use.append(item_name) - - def use_item(self, item_number): - if item_number < len(self.inventory_slots_in_use): - item_name = self.inventory_slots_in_use[item_number] - if item_name: - self.item_in_use = item_name - - for button in self.inventory_slots: - button.configure(bg="black") - - self.inventory_slots[item_number].configure(bg="white") - self.inventory_slots[item_number].configure(command=self.clear_used_item) - - def clear_used_item(self): - self.item_in_use = "" - for index, button in enumerate(self.inventory_slots): - button.configure(bg="black") - - use_cmd = partial(self.use_item, item_number=index) - button.configure(command=use_cmd) - - def show_cannot_use_message(self): - text_id = self.screen.create_text((250,25), text="You cannot use that there!", font=self.cannot_use_font, fill="white") - self.after(2000, lambda: self.screen.delete(text_id)) - - def play(self): - if not self.game_screens: - print("No screens added!") - else: - self.display_screen(0) - - -if __name__ == "__main__": - game = Game() - - scene1 = GameScreen(game, "assets/scene1.png", (378,135,427,217), "key", "You Need To Leave but the Door is Locked!") - scene2 = GameScreen(game, "assets/scene2.png", (117,54,329,412), None, "You Got the Key!", "key") - scene3 = GameScreen(game, "assets/scene3.png", (117,54,329,412), None, "The Door is Open!") - - all_screens = [scene1, scene2, scene3] - - game.set_game_screens(all_screens) - game.play() - game.mainloop() diff --git a/Chapter5-1.py b/Chapter5-1.py deleted file mode 100644 index c3c979c..0000000 --- a/Chapter5-1.py +++ /dev/null @@ -1,130 +0,0 @@ -import tkinter as tk -from tkinter import filedialog -import tkinter.messagebox as msg -import configparser as cp -import ntpath - -class IniEditor(tk.Tk): - - def __init__(self): - super().__init__() - - self.title("Config File Editor") - self.geometry("600x600") - - self.active_ini = "" - self.active_ini_filename = "" - self.ini_elements = {} - - self.menubar = tk.Menu(self, bg="lightgrey", fg="black") - - self.file_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black") - self.file_menu.add_command(label="Open", command=self.file_open, accelerator="Ctrl+O") - self.file_menu.add_command(label="Save", command=self.file_save, accelerator="Ctrl+S") - - self.menubar.add_cascade(label="File", menu=self.file_menu) - - self.config(menu=self.menubar) - - self.left_frame = tk.Frame(self, width=200, height=600, bg="grey") - self.left_frame.pack_propagate(0) - - self.right_frame = tk.Frame(self, width=400, height=600, bg="lightgrey") - self.right_frame.pack_propagate(0) - - self.file_name_var = tk.StringVar(self) - self.file_name_label = tk.Label(self, textvar=self.file_name_var, fg="black", bg="white", font=(None, 12)) - self.file_name_label.pack(side=tk.TOP, expand=1, fill=tk.X) - - self.section_select = tk.Listbox(self.left_frame, selectmode=tk.SINGLE) - self.section_select.configure(exportselection=False) - self.section_select.pack(expand=1) - self.section_select.bind("<>", self.display_section_contents) - - self.left_frame.pack(side=tk.LEFT, fill=tk.BOTH) - self.right_frame.pack(side=tk.LEFT, expand=1, fill=tk.BOTH) - - self.bind("", self.file_open) - self.bind("", self.file_save) - - def file_open(self, event=None): - ini_file = filedialog.askopenfilename() - - while ini_file and not ini_file.endswith(".ini"): - msg.showerror("Wrong Filetype", "Please select an ini file") - ini_file = filedialog.askopenfilename() - - if ini_file: - self.parse_ini_file(ini_file) - - def file_save(self, event=None): - if not self.active_ini: - msg.showerror("No File Open", "Please open an ini file first") - return - - chosen_section = self.section_select.get(self.section_select.curselection()) - - for key in self.active_ini[chosen_section]: - self.active_ini[chosen_section][key] = self.ini_elements[key].get() - - with open(self.active_ini_filename, "w") as ini_file: - self.active_ini.write(ini_file) - - msg.showinfo("Saved", "File Saved Successfully") - - def parse_ini_file(self, ini_file): - self.active_ini = cp.ConfigParser() - self.active_ini.read(ini_file) - self.active_ini_filename = ini_file - - self.section_select.delete(0, tk.END) - - for index, section in enumerate(self.active_ini.sections()): - self.section_select.insert(index, section) - if "DEFAULT" in self.active_ini: - self.section_select.insert(len(self.active_ini.sections()) + 1, "DEFAULT") - - file_name = ": ".join([ntpath.basename(ini_file), ini_file]) - self.file_name_var.set(file_name) - - self.clear_right_frame() - - def clear_right_frame(self): - for child in self.right_frame.winfo_children(): - child.destroy() - - def display_section_contents(self, event=None): - if not self.active_ini: - msg.showerror("No File Open", "Please open an ini file first") - return - - self.clear_right_frame() - - self.ini_elements = {} - - chosen_section = self.section_select.get(self.section_select.curselection()) - - for key in sorted(self.active_ini[chosen_section]): - new_label = tk.Label(self.right_frame, text=key, font=(None, 12), bg="black", fg="white") - new_label.pack(fill=tk.X, side=tk.TOP, pady=(10,0)) - - value = self.active_ini[chosen_section][key] - - if value.isnumeric(): - spinbox_default = tk.IntVar(self.right_frame) - spinbox_default.set(int(value)) - ini_element = tk.Spinbox(self.right_frame, from_=0, to=99999, textvariable=spinbox_default, bg="white", fg="black", justify="center") - else: - ini_element = tk.Entry(self.right_frame, bg="white", fg="black", justify="center") - ini_element.insert(0, value) - - ini_element.pack(fill=tk.X, side=tk.TOP, pady=(0,10)) - self.ini_elements[key] = ini_element - - save_button = tk.Button(self.right_frame, text="Save Changes", command=self.file_save) - save_button.pack(side=tk.BOTTOM, pady=(0,20)) - - -if __name__ == "__main__": - ini_editor = IniEditor() - ini_editor.mainloop() diff --git a/Chapter5-2-abridged.py b/Chapter5-2-abridged.py deleted file mode 100644 index 016653e..0000000 --- a/Chapter5-2-abridged.py +++ /dev/null @@ -1,93 +0,0 @@ -... - -class IniEditor(tk.Tk): - - def __init__(self): - ... - self.left_frame = tk.Frame(self, width=200, bg="grey") - self.left_frame.pack_propagate(0) - - self.right_frame = tk.Frame(self, width=400, bg="lightgrey") - self.right_frame.pack_propagate(0) - ... - self.file_name_label.pack(side=tk.TOP, expand=1, fill=tk.X, anchor="n") - ... - self.right_frame.bind("", self.frame_height) - ... - - def frame_height(self, event=None): - new_height = self.winfo_height() - self.right_frame.configure(height=new_height) - - def file_open(self, event=None): - ... - - def file_save(self, event=None): - ... - - for section in self.active_ini: - for key in self.active_ini[section]: - try: - self.active_ini[section][key] = self.ini_elements[section][key].get() - except KeyError: - # wasn't changed, no need to save it - pass - - ... - - def parse_ini_file(self, ini_file): - ... - - for index, section in enumerate(self.active_ini.sections()): - self.section_select.insert(index, section) - self.ini_elements[section] = {} - if "DEFAULT" in self.active_ini: - self.section_select.insert(len(self.active_ini.sections()) + 1, "DEFAULT") - self.ini_elements["DEFAULT"] = {} - ... - - def clear_right_frame(self): - ... - - def display_section_contents(self, event): - if not self.active_ini: - msg.showerror("No File Open", "Please open an ini file first") - return - - chosen_section = self.section_select.get(self.section_select.curselection()) - - for child in self.right_frame.winfo_children(): - child.pack_forget() - - for key in sorted(self.active_ini[chosen_section]): - new_label = tk.Label(self.right_frame, text=key, font=(None, 12), bg="black", fg="white") - new_label.pack(fill=tk.X, side=tk.TOP, pady=(10,0)) - - try: - section_elements = self.ini_elements[chosen_section] - except KeyError: - section_elements = {} - - try: - ini_element = section_elements[key] - except KeyError: - value = self.active_ini[chosen_section][key] - - if value.isnumeric(): - spinbox_default = tk.IntVar(self.right_frame) - spinbox_default.set(int(value)) - ini_element = tk.Spinbox(self.right_frame, from_=0, to=99999, textvariable=spinbox_default, bg="white", fg="black", justify="center") - else: - ini_element = tk.Entry(self.right_frame, bg="white", fg="black", justify="center") - ini_element.insert(0, value) - - self.ini_elements[chosen_section][key] = ini_element - - ini_element.pack(fill=tk.X, side=tk.TOP, pady=(0,10)) - - save_button = tk.Button(self.right_frame, text="Save Changes", command=self.file_save) - save_button.pack(side=tk.BOTTOM, pady=(0,20)) - - -if __name__ == "__main__": - ... diff --git a/Chapter5-2.py b/Chapter5-2.py deleted file mode 100644 index d8ba89f..0000000 --- a/Chapter5-2.py +++ /dev/null @@ -1,149 +0,0 @@ -import tkinter as tk -from tkinter import filedialog -import tkinter.messagebox as msg -import configparser as cp -import ntpath - -class IniEditor(tk.Tk): - - def __init__(self): - super().__init__() - - self.title("Config File Editor") - self.geometry("600x600") - - self.active_ini = "" - self.active_ini_filename = "" - self.ini_elements = {} - - self.menubar = tk.Menu(self, bg="lightgrey", fg="black") - - self.file_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black") - self.file_menu.add_command(label="Open", command=self.file_open, accelerator="Ctrl+O") - self.file_menu.add_command(label="Save", command=self.file_save, accelerator="Ctrl+S") - - self.menubar.add_cascade(label="File", menu=self.file_menu) - - self.config(menu=self.menubar) - - self.left_frame = tk.Frame(self, width=200, bg="grey") - self.left_frame.pack_propagate(0) - - self.right_frame = tk.Frame(self, width=400, bg="lightgrey") - self.right_frame.pack_propagate(0) - - self.file_name_var = tk.StringVar(self) - self.file_name_label = tk.Label(self, textvar=self.file_name_var, fg="black", bg="white", font=(None, 12)) - self.file_name_label.pack(side=tk.TOP, expand=1, fill=tk.X, anchor="n") - - self.section_select = tk.Listbox(self.left_frame, selectmode=tk.SINGLE) - self.section_select.configure(exportselection=False) - self.section_select.pack(expand=1) - self.section_select.bind("<>", self.display_section_contents) - - self.left_frame.pack(side=tk.LEFT, fill=tk.BOTH) - self.right_frame.pack(side=tk.LEFT, expand=1, fill=tk.BOTH) - - self.right_frame.bind("", self.frame_height) - - self.bind("", self.file_open) - self.bind("", self.file_save) - - def frame_height(self, event=None): - new_height = self.winfo_height() - self.right_frame.configure(height=new_height) - - def file_open(self, event=None): - ini_file = filedialog.askopenfilename() - - while ini_file and not ini_file.endswith(".ini"): - msg.showerror("Wrong Filetype", "Please select an ini file") - ini_file = filedialog.askopenfilename() - - if ini_file: - self.parse_ini_file(ini_file) - - def file_save(self, event=None): - if not self.active_ini: - msg.showerror("No File Open", "Please open an ini file first") - return - - for section in self.active_ini: - for key in self.active_ini[section]: - try: - self.active_ini[section][key] = self.ini_elements[section][key].get() - except KeyError: - # wasn't changed, no need to save it - pass - - with open(self.active_ini_filename, "w") as ini_file: - self.active_ini.write(ini_file) - - msg.showinfo("Saved", "File Saved Successfully") - - def parse_ini_file(self, ini_file): - self.active_ini = cp.ConfigParser() - self.active_ini.read(ini_file) - self.active_ini_filename = ini_file - - self.section_select.delete(0, tk.END) - - for index, section in enumerate(self.active_ini.sections()): - self.section_select.insert(index, section) - self.ini_elements[section] = {} - if "DEFAULT" in self.active_ini: - self.section_select.insert(len(self.active_ini.sections()) + 1, "DEFAULT") - self.ini_elements["DEFAULT"] = {} - - file_name = ": ".join([ntpath.basename(ini_file), ini_file]) - self.file_name_var.set(file_name) - - self.clear_right_frame() - - def clear_right_frame(self): - for child in self.right_frame.winfo_children(): - child.destroy() - - def display_section_contents(self, event=None): - if not self.active_ini: - msg.showerror("No File Open", "Please open an ini file first") - return - - chosen_section = self.section_select.get(self.section_select.curselection()) - - for child in self.right_frame.winfo_children(): - child.pack_forget() - - for key in sorted(self.active_ini[chosen_section]): - new_label = tk.Label(self.right_frame, text=key, font=(None, 12), bg="black", fg="white") - new_label.pack(fill=tk.X, side=tk.TOP, pady=(10,0)) - - try: - section_elements = self.ini_elements[chosen_section] - except KeyError: - section_elements = {} - - try: - ini_element = section_elements[key] - except KeyError: - value = self.active_ini[chosen_section][key] - - if value.isnumeric(): - spinbox_default = tk.IntVar(self.right_frame) - spinbox_default.set(int(value)) - ini_element = tk.Spinbox(self.right_frame, from_=0, to=99999, textvariable=spinbox_default, bg="white", fg="black", justify="center") - else: - ini_element = tk.Entry(self.right_frame, bg="white", fg="black", justify="center") - ini_element.insert(0, value) - - self.ini_elements[chosen_section][key] = ini_element - - ini_element.pack(fill=tk.X, side=tk.TOP, pady=(0,10)) - - save_button = tk.Button(self.right_frame, text="Save Changes", command=self.file_save) - save_button.pack(side=tk.BOTTOM, pady=(0,20)) - - -if __name__ == "__main__": - ini_editor = IniEditor() - ini_editor.mainloop() diff --git a/Chapter5-3-abridged.py b/Chapter5-3-abridged.py deleted file mode 100644 index 7d1c64f..0000000 --- a/Chapter5-3-abridged.py +++ /dev/null @@ -1,166 +0,0 @@ -... - -class CentralForm(tk.Toplevel): - def __init__(self, master, my_height=80): - super().__init__() - self.master = master - - master_pos_x = self.master.winfo_x() - master_pos_y = self.master.winfo_y() - - master_width = self.master.winfo_width() - master_height = self.master.winfo_height() - - my_width = 300 - - pos_x = (master_pos_x + (master_width // 2)) - (my_width // 2) - pos_y = (master_pos_y + (master_height // 2)) - (my_height // 2) - - geometry = "{}x{}+{}+{}".format(my_width, my_height, pos_x, pos_y) - self.geometry(geometry) - - -class AddSectionForm(CentralForm): - def __init__(self, master): - super().__init__(master) - - self.title("Add New Section") - - self.main_frame = tk.Frame(self, bg="lightgrey") - self.name_label = tk.Label(self.main_frame, text="Section Name", bg="lightgrey", fg="black") - self.name_entry = tk.Entry(self.main_frame, bg="white", fg="black") - self.submit_button = tk.Button(self.main_frame, text="Create", command=self.create_section) - - self.main_frame.pack(expand=1, fill=tk.BOTH) - self.name_label.pack(side=tk.TOP, fill=tk.X) - self.name_entry.pack(side=tk.TOP, fill=tk.X, padx=10) - self.submit_button.pack(side=tk.TOP, fill=tk.X, pady=(10,0), padx=10) - - def create_section(self): - section_name = self.name_entry.get() - if section_name: - self.master.add_section(section_name) - self.destroy() - msg.showinfo("Section Added", "Section " + section_name + " successfully added") - else: - msg.showerror("No Name", "Please enter a section name", parent=self) - - -class AddItemForm(CentralForm): - def __init__(self, master): - - my_height = 120 - - super().__init__(master, my_height) - - self.title("Add New Item") - - self.main_frame = tk.Frame(self, bg="lightgrey") - self.name_label = tk.Label(self.main_frame, text="Item Name", bg="lightgrey", fg="black") - self.name_entry = tk.Entry(self.main_frame, bg="white", fg="black") - self.value_label = tk.Label(self.main_frame, text="Item Value", bg="lightgrey", fg="black") - self.value_entry = tk.Entry(self.main_frame, bg="white", fg="black") - self.submit_button = tk.Button(self.main_frame, text="Create", command=self.create_item) - - self.main_frame.pack(fill=tk.BOTH, expand=1) - self.name_label.pack(side=tk.TOP, fill=tk.X) - self.name_entry.pack(side=tk.TOP, fill=tk.X, padx=10) - self.value_label.pack(side=tk.TOP, fill=tk.X) - self.value_entry.pack(side=tk.TOP, fill=tk.X, padx=10) - self.submit_button.pack(side=tk.TOP, fill=tk.X, pady=(10,0), padx=10) - - def create_item(self): - item_name = self.name_entry.get() - item_value = self.value_entry.get() - if item_name and item_value: - self.master.add_item(item_name, item_value) - self.destroy() - msg.showinfo("Item Added", item_name + " successfully added") - else: - msg.showerror("Missing Info", "Please enter a name and value", parent=self) - - -class IniEditor(tk.Tk): - - def __init__(self): - ... - self.file_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black") - ... - self.bind("", self.file_new) - ... - - def add_section_form(self): - if not self.active_ini: - msg.showerror("No File Open", "Please open an ini file first") - return - - AddSectionForm(self) - - def add_section(self, section_name): - self.active_ini[section_name] = {} - self.populate_section_select_box() - - def frame_height(self, event=None): - ... - - def file_new(self, event=None): - ini_file = filedialog.asksaveasfilename(filetypes=[("Configuration file", "*.ini")]) - - while ini_file and not ini_file.endswith(".ini"): - msg.showerror("Wrong Filetype", "Filename must end in .ini") - ini_file = filedialog.askopenfilename() - - if ini_file: - self.parse_ini_file(ini_file) - - def file_open(self, event=None): - ini_file = filedialog.askopenfilename(filetypes=[("Configuration file", "*.ini")]) - ... - - def file_save(self, event=None): - ... - - def add_item_form(self): - AddItemForm(self) - - def add_item(self, item_name, item_value): - chosen_section = self.section_select.get(self.section_select.curselection()) - self.active_ini[chosen_section][item_name] = item_value - self.display_section_contents() - - def parse_ini_file(self, ini_file): - self.active_ini = cp.ConfigParser() - self.active_ini.read(ini_file) - self.active_ini_filename = ini_file - self.populate_section_select_box() - - file_name = ": ".join([ntpath.basename(ini_file), ini_file]) - self.file_name_var.set(file_name) - - self.clear_right_frame() - - def clear_right_frame(self): - ... - - def populate_section_select_box(self): - self.section_select.delete(0, tk.END) - - for index, section in enumerate(self.active_ini.sections()): - self.section_select.insert(index, section) - self.ini_elements[section] = {} - if "DEFAULT" in self.active_ini: - self.section_select.insert(len(self.active_ini.sections()) + 1, "DEFAULT") - self.ini_elements["DEFAULT"] = {} - - def display_section_contents(self, event=None): - ... - - save_button = tk.Button(self.right_frame, text="Save Changes", command=self.file_save) - save_button.pack(side=tk.BOTTOM, pady=(0,20)) - - add_button = tk.Button(self.right_frame, text="Add Item", command=self.add_item_form) - add_button.pack(side=tk.BOTTOM, pady=(0,20)) - - -if __name__ == "__main__": - ... diff --git a/Chapter5-3.py b/Chapter5-3.py deleted file mode 100644 index 9c42c64..0000000 --- a/Chapter5-3.py +++ /dev/null @@ -1,268 +0,0 @@ -import tkinter as tk -from tkinter import filedialog -import tkinter.messagebox as msg -import configparser as cp -import ntpath - -class CentralForm(tk.Toplevel): - def __init__(self, master, my_height=80): - super().__init__() - self.master = master - - master_pos_x = self.master.winfo_x() - master_pos_y = self.master.winfo_y() - - master_width = self.master.winfo_width() - master_height = self.master.winfo_height() - - my_width = 300 - - pos_x = (master_pos_x + (master_width // 2)) - (my_width // 2) - pos_y = (master_pos_y + (master_height // 2)) - (my_height // 2) - - geometry = "{}x{}+{}+{}".format(my_width, my_height, pos_x, pos_y) - self.geometry(geometry) - - -class AddSectionForm(CentralForm): - def __init__(self, master): - super().__init__(master) - - self.title("Add New Section") - - self.main_frame = tk.Frame(self, bg="lightgrey") - self.name_label = tk.Label(self.main_frame, text="Section Name", bg="lightgrey", fg="black") - self.name_entry = tk.Entry(self.main_frame, bg="white", fg="black") - self.submit_button = tk.Button(self.main_frame, text="Create", command=self.create_section) - - self.main_frame.pack(expand=1, fill=tk.BOTH) - self.name_label.pack(side=tk.TOP, fill=tk.X) - self.name_entry.pack(side=tk.TOP, fill=tk.X, padx=10) - self.submit_button.pack(side=tk.TOP, fill=tk.X, pady=(10,0), padx=10) - - def create_section(self): - section_name = self.name_entry.get() - if section_name: - self.master.add_section(section_name) - self.destroy() - msg.showinfo("Section Added", "Section " + section_name + " successfully added") - else: - msg.showerror("No Name", "Please enter a section name", parent=self) - - -class AddItemForm(CentralForm): - def __init__(self, master): - - my_height = 120 - - super().__init__(master, my_height) - - self.title("Add New Item") - - self.main_frame = tk.Frame(self, bg="lightgrey") - self.name_label = tk.Label(self.main_frame, text="Item Name", bg="lightgrey", fg="black") - self.name_entry = tk.Entry(self.main_frame, bg="white", fg="black") - self.value_label = tk.Label(self.main_frame, text="Item Value", bg="lightgrey", fg="black") - self.value_entry = tk.Entry(self.main_frame, bg="white", fg="black") - self.submit_button = tk.Button(self.main_frame, text="Create", command=self.create_item) - - self.main_frame.pack(fill=tk.BOTH, expand=1) - self.name_label.pack(side=tk.TOP, fill=tk.X) - self.name_entry.pack(side=tk.TOP, fill=tk.X, padx=10) - self.value_label.pack(side=tk.TOP, fill=tk.X) - self.value_entry.pack(side=tk.TOP, fill=tk.X, padx=10) - self.submit_button.pack(side=tk.TOP, fill=tk.X, pady=(10,0), padx=10) - - def create_item(self): - item_name = self.name_entry.get() - item_value = self.value_entry.get() - if item_name and item_value: - self.master.add_item(item_name, item_value) - self.destroy() - msg.showinfo("Item Added", item_name + " successfully added") - else: - msg.showerror("Missing Info", "Please enter a name and value", parent=self) - - -class IniEditor(tk.Tk): - - def __init__(self): - super().__init__() - - self.title("Config File Editor") - self.geometry("600x600") - - self.active_ini = "" - self.active_ini_filename = "" - self.ini_elements = {} - - self.menubar = tk.Menu(self, bg="lightgrey", fg="black") - - self.file_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black") - self.file_menu.add_command(label="New", command=self.file_new, accelerator="Ctrl+N") - self.file_menu.add_command(label="Open", command=self.file_open, accelerator="Ctrl+O") - self.file_menu.add_command(label="Save", command=self.file_save, accelerator="Ctrl+S") - - self.menubar.add_cascade(label="File", menu=self.file_menu) - - self.config(menu=self.menubar) - - self.left_frame = tk.Frame(self, width=200, bg="grey") - self.left_frame.pack_propagate(0) - - self.right_frame = tk.Frame(self, width=400, bg="lightgrey") - self.right_frame.pack_propagate(0) - - self.file_name_var = tk.StringVar(self) - self.file_name_label = tk.Label(self, textvar=self.file_name_var, fg="black", bg="white", font=(None, 12)) - self.file_name_label.pack(side=tk.TOP, expand=1, fill=tk.X, anchor="n") - - self.section_select = tk.Listbox(self.left_frame, selectmode=tk.SINGLE) - self.section_select.configure(exportselection=False) - self.section_select.pack(expand=1) - self.section_select.bind("<>", self.display_section_contents) - - self.section_add_button = tk.Button(self.left_frame, text="Add Section", command=self.add_section_form) - self.section_add_button.pack(pady=(0,20)) - - self.left_frame.pack(side=tk.LEFT, fill=tk.BOTH) - self.right_frame.pack(side=tk.LEFT, expand=1, fill=tk.BOTH) - - self.right_frame.bind("", self.frame_height) - - self.bind("", self.file_new) - self.bind("", self.file_open) - self.bind("", self.file_save) - - def add_section_form(self): - if not self.active_ini: - msg.showerror("No File Open", "Please open an ini file first") - return - - AddSectionForm(self) - - def add_section(self, section_name): - self.active_ini[section_name] = {} - self.populate_section_select_box() - - def frame_height(self, event=None): - new_height = self.winfo_height() - self.right_frame.configure(height=new_height) - - def file_new(self, event=None): - ini_file = filedialog.asksaveasfilename(filetypes=[("Configuration file", "*.ini")]) - - while ini_file and not ini_file.endswith(".ini"): - msg.showerror("Wrong Filetype", "Filename must end in .ini") - ini_file = filedialog.askopenfilename() - - if ini_file: - self.parse_ini_file(ini_file) - - def file_open(self, event=None): - ini_file = filedialog.askopenfilename(filetypes=[("Configuration file", "*.ini")]) - - while ini_file and not ini_file.endswith(".ini"): - msg.showerror("Wrong Filetype", "Please select an ini file") - ini_file = filedialog.askopenfilename() - - if ini_file: - self.parse_ini_file(ini_file) - - def file_save(self, event=None): - if not self.active_ini: - msg.showerror("No File Open", "Please open an ini file first") - return - - for section in self.active_ini: - for key in self.active_ini[section]: - try: - self.active_ini[section][key] = self.ini_elements[section][key].get() - except KeyError: - # wasn't changed, no need to save it - pass - - with open(self.active_ini_filename, "w") as ini_file: - self.active_ini.write(ini_file) - - msg.showinfo("Saved", "File Saved Successfully") - - def add_item_form(self): - AddItemForm(self) - - def add_item(self, item_name, item_value): - chosen_section = self.section_select.get(self.section_select.curselection()) - self.active_ini[chosen_section][item_name] = item_value - self.display_section_contents() - - def parse_ini_file(self, ini_file): - self.active_ini = cp.ConfigParser() - self.active_ini.read(ini_file) - self.active_ini_filename = ini_file - self.populate_section_select_box() - - file_name = ": ".join([ntpath.basename(ini_file), ini_file]) - self.file_name_var.set(file_name) - - self.clear_right_frame() - - def clear_right_frame(self): - for child in self.right_frame.winfo_children(): - child.destroy() - - def populate_section_select_box(self): - self.section_select.delete(0, tk.END) - - for index, section in enumerate(self.active_ini.sections()): - self.section_select.insert(index, section) - self.ini_elements[section] = {} - if "DEFAULT" in self.active_ini: - self.section_select.insert(len(self.active_ini.sections()) + 1, "DEFAULT") - self.ini_elements["DEFAULT"] = {} - - def display_section_contents(self, event=None): - if not self.active_ini: - msg.showerror("No File Open", "Please open an ini file first") - return - - chosen_section = self.section_select.get(self.section_select.curselection()) - - for child in self.right_frame.winfo_children(): - child.pack_forget() - - for key in sorted(self.active_ini[chosen_section]): - new_label = tk.Label(self.right_frame, text=key, font=(None, 12), bg="black", fg="white") - new_label.pack(fill=tk.X, side=tk.TOP, pady=(10,0)) - - try: - section_elements = self.ini_elements[chosen_section] - except KeyError: - section_elements = {} - - try: - ini_element = section_elements[key] - except KeyError: - value = self.active_ini[chosen_section][key] - - if value.isnumeric(): - spinbox_default = tk.IntVar(self.right_frame) - spinbox_default.set(int(value)) - ini_element = tk.Spinbox(self.right_frame, from_=0, to=99999, textvariable=spinbox_default, bg="white", fg="black", justify="center") - else: - ini_element = tk.Entry(self.right_frame, bg="white", fg="black", justify="center") - ini_element.insert(0, value) - - self.ini_elements[chosen_section][key] = ini_element - - ini_element.pack(fill=tk.X, side=tk.TOP, pady=(0,10)) - - save_button = tk.Button(self.right_frame, text="Save Changes", command=self.file_save) - save_button.pack(side=tk.BOTTOM, pady=(0,20)) - - add_button = tk.Button(self.right_frame, text="Add Item", command=self.add_item_form) - add_button.pack(side=tk.BOTTOM, pady=(0,20)) - - -if __name__ == "__main__": - ini_editor = IniEditor() - ini_editor.mainloop() diff --git a/Chapter6-1.py b/Chapter6-1.py deleted file mode 100644 index 1ace920..0000000 --- a/Chapter6-1.py +++ /dev/null @@ -1,152 +0,0 @@ -import tkinter as tk -from tkinter import filedialog -from functools import partial - -class Editor(tk.Tk): - def __init__(self): - super().__init__() - - self.FONT_SIZE = 12 - self.AUTOCOMPLETE_WORDS = ["def", "import", "if", "else", "while", "for","try:", "except:", "print(", "True", "False"] - self.WINDOW_TITLE = "Text Editor" - - self.open_file = "" - - self.title(self.WINDOW_TITLE) - self.geometry("800x600") - - self.menubar = tk.Menu(self, bg="lightgrey", fg="black") - - self.file_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black") - self.file_menu.add_command(label="New", command=self.file_new, accelerator="Ctrl+N") - self.file_menu.add_command(label="Open", command=self.file_open, accelerator="Ctrl+O") - self.file_menu.add_command(label="Save", command=self.file_save, accelerator="Ctrl+S") - - self.menubar.add_cascade(label="File", menu=self.file_menu) - - self.configure(menu=self.menubar) - - self.main_text = tk.Text(self, bg="white", fg="black", font=("Ubuntu Mono", self.FONT_SIZE)) - - self.main_text.pack(expand=1, fill=tk.BOTH) - - self.main_text.bind("", self.destroy_autocomplete_menu) - self.main_text.bind("", self.display_autocomplete_menu) - self.main_text.bind("", self.insert_spaces) - - self.bind("", self.file_save) - self.bind("", self.file_open) - self.bind("", self.file_new) - - def file_new(self, event=None): - file_name = filedialog.asksaveasfilename() - if file_name: - self.open_file = file_name - self.main_text.delete(1.0, tk.END) - self.title(" - ".join([self.WINDOW_TITLE, self.open_file])) - - def file_open(self, event=None): - file_to_open = filedialog.askopenfilename() - - if file_to_open: - self.open_file = file_to_open - self.main_text.delete(1.0, tk.END) - - with open(file_to_open, "r") as file_contents: - file_lines = file_contents.readlines() - if len(file_lines) > 0: - for index, line in enumerate(file_lines): - index = float(index) + 1.0 - self.main_text.insert(index, line) - - self.title(" - ".join([self.WINDOW_TITLE, self.open_file])) - - def file_save(self, event=None): - if not self.open_file: - new_file_name = filedialog.asksaveasfilename() - if new_file_name: - self.open_file = new_file_name - - if self.open_file: - new_contents = self.main_text.get(1.0, tk.END) - with open(self.open_file, "w") as open_file: - open_file.write(new_contents) - - def insert_spaces(self, event=None): - self.main_text.insert(tk.INSERT, " ") - - return "break" - - def get_menu_coordinates(self): - bbox = self.main_text.bbox(tk.INSERT) - menu_x = bbox[0] + self.winfo_x() + self.main_text.winfo_x() - menu_y = bbox[1] + self.winfo_y() + self.main_text.winfo_y() + self.FONT_SIZE + 2 - - return (menu_x, menu_y) - - def display_autocomplete_menu(self, event=None): - current_index = self.main_text.index(tk.INSERT) - start = self.adjust_floating_index(current_index) - - try: - currently_typed_word = self.main_text.get(start + " wordstart", tk.INSERT) - except tk.TclError: - currently_typed_word = "" - - currently_typed_word = str(currently_typed_word).strip() - - if currently_typed_word: - self.destroy_autocomplete_menu() - - suggestions = [] - for word in self.AUTOCOMPLETE_WORDS: - if word.startswith(currently_typed_word) and not currently_typed_word == word: - suggestions.append(word) - - if len(suggestions) > 0: - x, y = self.get_menu_coordinates() - self.complete_menu = tk.Menu(self, tearoff=0, bg="lightgrey", fg="black") - - for word in suggestions: - insert_word_callback = partial(self.insert_word, word=word, part=currently_typed_word, index=current_index) - self.complete_menu.add_command(label=word, command=insert_word_callback) - - self.complete_menu.post(x, y) - self.main_text.bind("", self.focus_menu_item) - - def destroy_autocomplete_menu(self, event=None): - try: - self.complete_menu.destroy() - self.main_text.unbind("") - self.main_text.focus_force() - except AttributeError: - pass - - def insert_word(self, word, part, index): - amount_typed = len(part) - remaining_word = word[amount_typed:] - remaining_word_offset = " +" + str(len(remaining_word)) + "c" - self.main_text.insert(index, remaining_word) - self.main_text.mark_set(tk.INSERT, index + remaining_word_offset) - self.destroy_autocomplete_menu() - self.main_text.focus_force() - - def adjust_floating_index(self, number): - indices = number.split(".") - x_index = indices[0] - y_index = indices[1] - y_as_number = int(y_index) - y_previous = y_as_number - 1 - - return ".".join([x_index, str(y_previous)]) - - def focus_menu_item(self, event=None): - try: - self.complete_menu.focus_force() - self.complete_menu.entryconfig(0, state="active") - except tk.TclError: - pass - -if __name__ == "__main__": - editor = Editor() - editor.mainloop() diff --git a/Chapter6-2-abridged.py b/Chapter6-2-abridged.py deleted file mode 100644 index 2b5722e..0000000 --- a/Chapter6-2-abridged.py +++ /dev/null @@ -1,143 +0,0 @@ -import re -... - -class Editor(tk.Tk): - def __init__(self): - ... - - self.AUTOCOMPLETE_WORDS = [ - "def", "import", "as", "if", "elif", "else", "while", - "for", "try", "except", "print", "True", "False", - "self", "None", "return", "with" - ] - self.KEYWORDS_1 = ["import", "as", "from", "def", "try", "except", "self"] - self.KEYWORDS_FLOW = ["if", "else", "elif", "try", "except", "for", "in", "while", "return", "with"] - - self.SPACES_REGEX = re.compile("^\s*") - self.STRING_REGEX_SINGLE = re.compile("'[^'\r\n]*'") - self.STRING_REGEX_DOUBLE = re.compile('"[^"\r\n]*"') - self.NUMBER_REGEX = re.compile(r"\b(?=\(*)\d+\.?\d*(?=\)*\,*)\b") - self.KEYWORDS_REGEX = re.compile("(?=\(*)(?", self.on_key_release) - self.main_text.bind("", self.destroy_autocomplete_menu) - ... - - def file_new(self, event=None): - ... - - def file_open(self, event=None): - ... - - final_index = self.main_text.index(tk.END) - final_line_number = int(final_index.split(".")[0]) - - for line_number in range(final_line_number): - line_to_tag = ".".join([str(line_number), "0"]) - self.tag_keywords(None, line_to_tag) - - - def file_save(self, event=None): - ... - - def insert_spaces(self, event=None): - ... - - def get_menu_coordinates(self): - ... - - def display_autocomplete_menu(self, event=None): - ... - self.complete_menu.post(x, y) - self.complete_menu.bind("", self.destroy_autocomplete_menu) - self.main_text.bind("", self.focus_menu_item) - - def destroy_autocomplete_menu(self, event=None): - ... - - def insert_word(self, word, part, index): - ... - - def adjust_floating_index(self, number): - ... - - def focus_menu_item(self, event=None): - ... - - def tag_keywords(self, event=None, current_index=None): - if not current_index: - current_index = self.main_text.index(tk.INSERT) - line_number = current_index.split(".")[0] - line_beginning = ".".join([line_number, "0"]) - line_text = self.main_text.get(line_beginning, line_beginning + " lineend") - line_words = line_text.split() - number_of_spaces = self.number_of_leading_spaces(line_text) - y_position = number_of_spaces - - for tag in self.main_text.tag_names(): - self.main_text.tag_remove(tag, line_beginning, line_beginning + " lineend") - - self.add_regex_tags(line_number, line_text) - - for word in line_words: - stripped_word = word.strip("():,") - word_start = str(y_position) - word_end = str(y_position + len(stripped_word)) - start_index = ".".join([line_number, word_start]) - end_index = ".".join([line_number, word_end]) - - if stripped_word in self.KEYWORDS_1: - self.main_text.tag_add("keyword1", start_index, end_index) - elif stripped_word in self.KEYWORDS_FLOW: - self.main_text.tag_add("keywordflow", start_index, end_index) - elif stripped_word.startswith("@"): - self.main_text.tag_add("decorator", start_index, end_index) - - y_position += len(word) + 1 - - def number_of_leading_spaces(self, line): - spaces = re.search(self.SPACES_REGEX, line) - if spaces.group(0) is not None: - number_of_spaces = len(spaces.group(0)) - else: - number_of_spaces = 0 - - return number_of_spaces - - def add_regex_tags(self, line_number, line_text): - for regex, tag in self.REGEX_TO_TAG.items(): - for match in regex.finditer(line_text): - start, end = match.span() - start_index = ".".join([line_number, str(start)]) - end_index = ".".join([line_number, str(end)]) - self.main_text.tag_add(tag, start_index, end_index) - - def on_key_release(self, event=None): - if not event.keysym in ("Up", "Down", "Left", "Right", "BackSpace", "Delete", "Escape"): - self.display_autocomplete_menu() - self.tag_keywords() - -if __name__ == "__main__": - ... diff --git a/Chapter6-2.py b/Chapter6-2.py deleted file mode 100644 index f5671db..0000000 --- a/Chapter6-2.py +++ /dev/null @@ -1,250 +0,0 @@ -import re -import tkinter as tk -from tkinter import filedialog -from functools import partial - -class Editor(tk.Tk): - def __init__(self): - super().__init__() - - self.FONT_SIZE = 12 - self.WINDOW_TITLE = "Text Editor" - - self.AUTOCOMPLETE_WORDS = [ - "def", "import", "as", "if", "elif", "else", "while", - "for", "try", "except", "print", "True", "False", - "self", "None", "return", "with" - ] - self.KEYWORDS_1 = ["import", "as", "from", "def", "try", "except", "self"] - self.KEYWORDS_FLOW = ["if", "else", "elif", "try", "except", "for", "in", "while", "return", "with"] - self.KEYWORDS_FUNCTIONS = ["print", "list", "dict", "set", "int", "float", "str"] - - self.SPACES_REGEX = re.compile("^\s*") - self.STRING_REGEX_SINGLE = re.compile("'[^'\r\n]*'") - self.STRING_REGEX_DOUBLE = re.compile('"[^"\r\n]*"') - self.NUMBER_REGEX = re.compile(r"\b(?=\(*)\d+\.?\d*(?=\)*\,*)\b") - self.KEYWORDS_REGEX = re.compile("(?=\(*)(?", self.destroy_autocomplete_menu) - self.main_text.bind("", self.on_key_release) - self.main_text.bind("", self.insert_spaces) - self.main_text.bind("", self.destroy_autocomplete_menu) - - self.bind("", self.file_save) - self.bind("", self.file_open) - self.bind("", self.file_new) - - def file_new(self, event=None): - file_name = filedialog.asksaveasfilename() - if file_name: - self.open_file = file_name - self.main_text.delete(1.0, tk.END) - self.title(" - ".join([self.WINDOW_TITLE, self.open_file])) - - def file_open(self, event=None): - file_to_open = filedialog.askopenfilename() - - if file_to_open: - self.open_file = file_to_open - self.main_text.delete(1.0, tk.END) - - with open(file_to_open, "r") as file_contents: - file_lines = file_contents.readlines() - if len(file_lines) > 0: - for index, line in enumerate(file_lines): - index = float(index) + 1.0 - self.main_text.insert(index, line) - - self.title(" - ".join([self.WINDOW_TITLE, self.open_file])) - - final_index = self.main_text.index(tk.END) - final_line_number = int(final_index.split(".")[0]) - - for line_number in range(final_line_number): - line_to_tag = ".".join([str(line_number), "0"]) - self.tag_keywords(None, line_to_tag) - - - def file_save(self, event=None): - if not self.open_file: - new_file_name = filedialog.asksaveasfilename() - if new_file_name: - self.open_file = new_file_name - - if self.open_file: - new_contents = self.main_text.get(1.0, tk.END) - with open(self.open_file, "w") as open_file: - open_file.write(new_contents) - - def insert_spaces(self, event=None): - self.main_text.insert(tk.INSERT, " ") - - return "break" - - def get_menu_coordinates(self): - bbox = self.main_text.bbox(tk.INSERT) - menu_x = bbox[0] + self.winfo_x() + self.main_text.winfo_x() - menu_y = bbox[1] + self.winfo_y() + self.main_text.winfo_y() + self.FONT_SIZE + 2 - - return (menu_x, menu_y) - - def display_autocomplete_menu(self, event=None): - current_index = self.main_text.index(tk.INSERT) - start = self.adjust_floating_index(current_index) - - try: - currently_typed_word = self.main_text.get(start + " wordstart", tk.INSERT) - except tk.TclError: - currently_typed_word = "" - - currently_typed_word = str(currently_typed_word).strip() - - if currently_typed_word: - self.destroy_autocomplete_menu() - - suggestions = [] - for word in self.AUTOCOMPLETE_WORDS: - if word.startswith(currently_typed_word) and not currently_typed_word == word: - suggestions.append(word) - - if len(suggestions) > 0: - x, y = self.get_menu_coordinates() - self.complete_menu = tk.Menu(self, tearoff=0, bg="lightgrey", fg="black") - - for word in suggestions: - insert_word_callback = partial(self.insert_word, word=word, part=currently_typed_word, index=current_index) - self.complete_menu.add_command(label=word, command=insert_word_callback) - - self.complete_menu.post(x, y) - self.complete_menu.bind("", self.destroy_autocomplete_menu) - self.main_text.bind("", self.focus_menu_item) - - def destroy_autocomplete_menu(self, event=None): - try: - self.complete_menu.destroy() - self.main_text.unbind("") - self.main_text.focus_force() - except AttributeError: - pass - - def insert_word(self, word, part, index): - amount_typed = len(part) - remaining_word = word[amount_typed:] - remaining_word_offset = " +" + str(len(remaining_word)) + "c" - self.main_text.insert(index, remaining_word) - self.main_text.mark_set(tk.INSERT, index + remaining_word_offset) - self.destroy_autocomplete_menu() - self.main_text.focus_force() - - def adjust_floating_index(self, number): - indices = number.split(".") - x_index = indices[0] - y_index = indices[1] - y_as_number = int(y_index) - y_previous = y_as_number - 1 - - return ".".join([x_index, str(y_previous)]) - - def focus_menu_item(self, event=None): - try: - self.complete_menu.focus_force() - self.complete_menu.entryconfig(0, state="active") - except tk.TclError: - pass - - def tag_keywords(self, event=None, current_index=None): - if not current_index: - current_index = self.main_text.index(tk.INSERT) - line_number = current_index.split(".")[0] - line_beginning = ".".join([line_number, "0"]) - line_text = self.main_text.get(line_beginning, line_beginning + " lineend") - line_words = line_text.split() - number_of_spaces = self.number_of_leading_spaces(line_text) - y_position = number_of_spaces - - for tag in self.main_text.tag_names(): - self.main_text.tag_remove(tag, line_beginning, line_beginning + " lineend") - - self.add_regex_tags(line_number, line_text) - - for word in line_words: - stripped_word = word.strip("():,") - - word_start = str(y_position) - word_end = str(y_position + len(stripped_word)) - start_index = ".".join([line_number, word_start]) - end_index = ".".join([line_number, word_end]) - - if stripped_word in self.KEYWORDS_1: - self.main_text.tag_add("keyword1", start_index, end_index) - elif stripped_word in self.KEYWORDS_FLOW: - self.main_text.tag_add("keywordflow", start_index, end_index) - elif stripped_word.startswith("@"): - self.main_text.tag_add("decorator", start_index, end_index) - - y_position += len(word) + 1 - - def number_of_leading_spaces(self, line): - spaces = re.search(self.SPACES_REGEX, line) - if spaces.group(0) is not None: - number_of_spaces = len(spaces.group(0)) - else: - number_of_spaces = 0 - - return number_of_spaces - - def add_regex_tags(self, line_number, line_text): - for regex, tag in self.REGEX_TO_TAG.items(): - for match in regex.finditer(line_text): - start, end = match.span() - start_index = ".".join([line_number, str(start)]) - end_index = ".".join([line_number, str(end)]) - self.main_text.tag_add(tag, start_index, end_index) - - def on_key_release(self, event=None): - if not event.keysym in ("Up", "Down", "Left", "Right", "BackSpace", "Delete", "Escape"): - self.display_autocomplete_menu() - self.tag_keywords() - -if __name__ == "__main__": - editor = Editor() - editor.mainloop() diff --git a/Chapter6-3-abridged.py b/Chapter6-3-abridged.py deleted file mode 100644 index 5c3064e..0000000 --- a/Chapter6-3-abridged.py +++ /dev/null @@ -1,309 +0,0 @@ -... -import tkinter.messagebox as msg - -class FindPopup(tk.Toplevel): - def __init__(self, master): - super().__init__() - - self.master = master - - self.title("Find in file") - self.center_window() - - self.transient(master) - - self.matches_are_highlighted = True - - self.main_frame = tk.Frame(self, bg="lightgrey") - self.button_frame = tk.Frame(self.main_frame, bg="lightgrey") - - self.find_label = tk.Label(self.main_frame, text="Find: ", bg="lightgrey", fg="black") - self.find_entry = tk.Entry(self.main_frame, bg="white", fg="black") - self.find_button = tk.Button(self.button_frame, text="Find All", bg="lightgrey", fg="black", command=self.find) - self.next_button = tk.Button(self.button_frame, text="Next", bg="lightgrey", fg="black", command=self.jump_to_next_match) - self.cancel_button = tk.Button(self.button_frame, text="Cancel", bg="lightgrey", fg="black", command=self.cancel) - - self.main_frame.pack(fill=tk.BOTH, expand=1) - - self.find_button.pack(side=tk.LEFT, pady=(0,10), padx=(20,20)) - self.next_button.pack(side=tk.LEFT, pady=(0,10), padx=(15,20)) - self.cancel_button.pack(side=tk.LEFT, pady=(0,10), padx=(15,0)) - self.button_frame.pack(side=tk.BOTTOM, fill=tk.BOTH) - self.find_label.pack(side=tk.LEFT, fill=tk.X, padx=(20,0)) - self.find_entry.pack(side=tk.LEFT, fill=tk.X, expand=1, padx=(0,20)) - - self.find_entry.focus_force() - self.find_entry.bind("", self.jump_to_next_match) - self.find_entry.bind("", self.matches_are_not_highlighted) - self.bind("", self.cancel) - - self.protocol("WM_DELETE_WINDOW", self.cancel) - - def find(self, event=None): - text_to_find = self.find_entry.get() - if text_to_find and not self.matches_are_highlighted: - self.master.remove_all_find_tags() - self.master.highlight_matches(text_to_find) - self.matches_are_highlighted = True - - def jump_to_next_match(self, event=None): - text_to_find = self.find_entry.get() - if text_to_find: - if not self.matches_are_highlighted: - self.find() - self.master.next_match() - - def cancel(self, event=None): - self.master.remove_all_find_tags() - self.destroy() - - def matches_are_not_highlighted(self, event): - key_pressed = event.keysym - if not key_pressed == "Return": - self.matches_are_highlighted = False - - def center_window(self): - master_pos_x = self.master.winfo_x() - master_pos_y = self.master.winfo_y() - - master_width = self.master.winfo_width() - master_height = self.master.winfo_height() - - my_width = 300 - my_height = 100 - - pos_x = (master_pos_x + (master_width // 2)) - (my_width // 2) - pos_y = (master_pos_y + (master_height // 2)) - (my_height // 2) - - geometry = "{}x{}+{}+{}".format(my_width, my_height, pos_x, pos_y) - self.geometry(geometry) - - - -class Editor(tk.Tk): - def __init__(self): - ... - self.edit_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black") - self.edit_menu.add_command(label="Cut", command=self.edit_cut, accelerator="Ctrl+X") - self.edit_menu.add_command(label="Paste", command=self.edit_paste, accelerator="Ctrl+V") - self.edit_menu.add_command(label="Undo", command=self.edit_undo, accelerator="Ctrl+Z") - self.edit_menu.add_command(label="Redo", command=self.edit_redo, accelerator="Ctrl+Y") - - self.menubar.add_cascade(label="File", menu=self.file_menu) - self.menubar.add_cascade(label="Edit", menu=self.edit_menu) - - ... - - self.line_numbers = tk.Text(self, bg="lightgrey", fg="black", width=6) - self.line_numbers.insert(1.0, "1 \n") - self.line_numbers.configure(state="disabled") - self.line_numbers.pack(side=tk.LEFT, fill=tk.Y) - - ... - - self.scrollbar = tk.Scrollbar(self, orient="vertical", command=self.scroll_text_and_line_numbers) - self.main_text.configure(yscrollcommand=self.scrollbar.set) - - self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) - self.main_text.pack(expand=1, fill=tk.BOTH) - - ... - self.main_text.tag_config("findmatch", background="yellow") - - ... - - self.main_text.bind("", self.edit_redo) - - ... - - self.bind("", self.select_all) - self.bind("", self.show_find_window) - - self.main_text.bind("", self.scroll_text_and_line_numbers) - self.main_text.bind("", self.scroll_text_and_line_numbers) - self.main_text.bind("", self.scroll_text_and_line_numbers) - - self.line_numbers.bind("", self.skip_event) - self.line_numbers.bind("", self.skip_event) - self.line_numbers.bind("", self.skip_event) - - def skip_event(self, event=None): - return "break" - - def scroll_text_and_line_numbers(self, *args): - try: - # from scrollbar - self.main_text.yview_moveto(args[1]) - self.line_numbers.yview_moveto(args[1]) - except IndexError: - #from MouseWheel - event = args[0] - if event.delta: - move = -1*(event.delta/120) - else: - if event.num == 5: - move = 1 - else: - move = -1 - - self.main_text.yview_scroll(move, "units") - self.line_numbers.yview_scroll(move, "units") - - return "break" - - def file_new(self, event=None): - ... - - def file_open(self, event=None): - file_to_open = filedialog.askopenfilename() - - if file_to_open: - self.open_file = file_to_open - self.main_text.delete(1.0, tk.END) - - with open(file_to_open, "r") as file_contents: - file_lines = file_contents.readlines() - if len(file_lines) > 0: - for index, line in enumerate(file_lines): - index = float(index) + 1.0 - self.main_text.insert(index, line) - - self.title(" - ".join([self.WINDOW_TITLE, self.open_file])) - - self.tag_all_lines() - - - def file_save(self, event=None): - ... - - def select_all(self, event=None): - self.main_text.tag_add("sel", 1.0, tk.END) - - return "break" - - def edit_cut(self, event=None): - self.main_text.event_generate("<>") - - return "break" - - def edit_paste(self, event=None): - self.main_text.event_generate("<>") - self.on_key_release() - self.tag_all_lines() - - return "break" - - def edit_undo(self, event=None): - self.main_text.event_generate("<>") - - return "break" - - def edit_redo(self, event=None): - self.main_text.event_generate("<>") - - return "break" - - def insert_spaces(self, event=None): - ... - - def get_menu_coordinates(self): - ... - - def display_autocomplete_menu(self, event=None): - ... - - def destroy_autocomplete_menu(self, event=None): - ... - - def insert_word(self, word, part, index): - ... - - def adjust_floating_index(self, number): - ... - - def focus_menu_item(self, event=None): - ... - - def tag_keywords(self, event=None, current_index=None): - ... - - def number_of_leading_spaces(self, line): - ... - - def add_regex_tags(self, line_number, line_text): - ... - - def on_key_release(self, event=None): - ... - self.update_line_numbers() - - def tag_all_lines(self): - final_index = self.main_text.index(tk.END) - final_line_number = int(final_index.split(".")[0]) - - for line_number in range(final_line_number): - line_to_tag = ".".join([str(line_number), "0"]) - self.tag_keywords(None, line_to_tag) - - self.update_line_numbers() - - def update_line_numbers(self): - self.line_numbers.configure(state="normal") - self.line_numbers.delete(1.0, tk.END) - number_of_lines = self.main_text.index(tk.END).split(".")[0] - line_number_string = "\n".join(str(no+1) for no in range(int(number_of_lines))) - self.line_numbers.insert(1.0, line_number_string) - self.line_numbers.configure(state="disabled") - - def show_find_window(self, event=None): - FindPopup(self) - - def highlight_matches(self, text_to_find): - self.main_text.tag_remove("findmatch", 1.0, tk.END) - self.match_coordinates = [] - self.current_match = -1 - - find_regex = re.compile(text_to_find) - search_text_lines = self.main_text.get(1.0, tk.END).split("\n") - - for line_number, line in enumerate(search_text_lines): - line_number += 1 - for match in find_regex.finditer(line): - start, end = match.span() - start_index = ".".join([str(line_number), str(start)]) - end_index = ".".join([str(line_number), str(end)]) - self.main_text.tag_add("findmatch", start_index, end_index) - self.match_coordinates.append((start_index, end_index)) - - def next_match(self, event=None): - try: - current_target, current_target_end = self.match_coordinates[self.current_match] - self.main_text.tag_remove("sel", current_target, current_target_end) - self.main_text.tag_add("findmatch", current_target, current_target_end) - except IndexError: - pass - - try: - self.current_match = self.current_match + 1 - next_target, target_end = self.match_coordinates[self.current_match] - except IndexError: - if len(self.match_coordinates) == 0: - msg.showinfo("No Matches", "No Matches Found") - else: - if msg.askyesno("Wrap Search?", "Reached end of file. Continue from the top?"): - self.current_match = -1 - self.next_match() - else: - self.main_text.mark_set(tk.INSERT, next_target) - self.main_text.tag_remove("findmatch", next_target, target_end) - self.main_text.tag_add("sel", next_target, target_end) - self.main_text.see(next_target) - - def remove_all_find_tags(self): - self.main_text.tag_remove("findmatch", 1.0, tk.END) - self.main_text.tag_remove("sel", 1.0, tk.END) - - -if __name__ == "__main__": - editor = Editor() - editor.mainloop() diff --git a/Chapter6-3.py b/Chapter6-3.py deleted file mode 100644 index e23b886..0000000 --- a/Chapter6-3.py +++ /dev/null @@ -1,474 +0,0 @@ -import re -import tkinter as tk -import tkinter.messagebox as msg -from tkinter import filedialog -from functools import partial - -class FindPopup(tk.Toplevel): - def __init__(self, master): - super().__init__() - - self.master = master - - self.title("Find in file") - self.center_window() - - self.transient(master) - - self.matches_are_highlighted = False - - self.main_frame = tk.Frame(self, bg="lightgrey") - self.button_frame = tk.Frame(self.main_frame, bg="lightgrey") - - self.find_label = tk.Label(self.main_frame, text="Find: ", bg="lightgrey", fg="black") - self.find_entry = tk.Entry(self.main_frame, bg="white", fg="black") - self.find_button = tk.Button(self.button_frame, text="Find All", bg="lightgrey", fg="black", command=self.find) - self.next_button = tk.Button(self.button_frame, text="Next", bg="lightgrey", fg="black", command=self.jump_to_next_match) - self.cancel_button = tk.Button(self.button_frame, text="Cancel", bg="lightgrey", fg="black", command=self.cancel) - - self.main_frame.pack(fill=tk.BOTH, expand=1) - - self.find_button.pack(side=tk.LEFT, pady=(0,10), padx=(20,20)) - self.next_button.pack(side=tk.LEFT, pady=(0,10), padx=(15,20)) - self.cancel_button.pack(side=tk.LEFT, pady=(0,10), padx=(15,0)) - self.button_frame.pack(side=tk.BOTTOM, fill=tk.BOTH) - self.find_label.pack(side=tk.LEFT, fill=tk.X, padx=(20,0)) - self.find_entry.pack(side=tk.LEFT, fill=tk.X, expand=1, padx=(0,20)) - - self.find_entry.focus_force() - self.find_entry.bind("", self.jump_to_next_match) - self.find_entry.bind("", self.matches_are_not_highlighted) - self.bind("", self.cancel) - - self.protocol("WM_DELETE_WINDOW", self.cancel) - - def find(self, event=None): - text_to_find = self.find_entry.get() - if text_to_find and not self.matches_are_highlighted: - self.master.remove_all_find_tags() - self.master.highlight_matches(text_to_find) - self.matches_are_highlighted = True - - def jump_to_next_match(self, event=None): - text_to_find = self.find_entry.get() - if text_to_find: - if not self.matches_are_highlighted: - self.find() - self.master.next_match() - - def cancel(self, event=None): - self.master.remove_all_find_tags() - self.destroy() - - def matches_are_not_highlighted(self, event): - key_pressed = event.keysym - if not key_pressed == "Return": - self.matches_are_highlighted = False - - def center_window(self): - master_pos_x = self.master.winfo_x() - master_pos_y = self.master.winfo_y() - - master_width = self.master.winfo_width() - master_height = self.master.winfo_height() - - my_width = 300 - my_height = 100 - - pos_x = (master_pos_x + (master_width // 2)) - (my_width // 2) - pos_y = (master_pos_y + (master_height // 2)) - (my_height // 2) - - geometry = "{}x{}+{}+{}".format(my_width, my_height, pos_x, pos_y) - self.geometry(geometry) - - - -class Editor(tk.Tk): - def __init__(self): - super().__init__() - - self.FONT_SIZE = 12 - self.WINDOW_TITLE = "Text Editor" - - self.AUTOCOMPLETE_WORDS = [ - "def", "import", "as", "if", "elif", "else", "while", - "for", "try", "except", "print", "True", "False", - "self", "None", "return", "with" - ] - self.KEYWORDS_1 = ["import", "as", "from", "def", "try", "except", "self"] - self.KEYWORDS_FLOW = ["if", "else", "elif", "try", "except", "for", "in", "while", "return", "with"] - self.KEYWORDS_FUNCTIONS = ["print", "list", "dict", "set", "int", "float", "str"] - - self.SPACES_REGEX = re.compile("^\s*") - self.STRING_REGEX_SINGLE = re.compile("'[^'\r\n]*'") - self.STRING_REGEX_DOUBLE = re.compile('"[^"\r\n]*"') - self.NUMBER_REGEX = re.compile(r"\b(?=\(*)\d+\.?\d*(?=\)*\,*)\b") - self.KEYWORDS_REGEX = re.compile("(?=\(*)(?", self.destroy_autocomplete_menu) - self.main_text.bind("", self.on_key_release) - self.main_text.bind("", self.insert_spaces) - self.main_text.bind("", self.destroy_autocomplete_menu) - - self.main_text.bind("", self.edit_redo) - - self.bind("", self.file_save) - self.bind("", self.file_open) - self.bind("", self.file_new) - - self.bind("", self.select_all) - self.bind("", self.show_find_window) - self.bind("", self.edit_paste) - - self.main_text.bind("", self.scroll_text_and_line_numbers) - self.main_text.bind("", self.scroll_text_and_line_numbers) - self.main_text.bind("", self.scroll_text_and_line_numbers) - - self.line_numbers.bind("", self.skip_event) - self.line_numbers.bind("", self.skip_event) - self.line_numbers.bind("", self.skip_event) - - def skip_event(self, event=None): - return "break" - - def scroll_text_and_line_numbers(self, *args): - try: # from scrollbar - self.main_text.yview_moveto(args[1]) - self.line_numbers.yview_moveto(args[1]) - except IndexError: - #from mouse MouseWheel - event = args[0] - if event.delta: - move = -1*(event.delta/120) - else: - if event.num == 5: - move = 1 - else: - move = -1 - - self.main_text.yview_scroll(move, "units") - self.line_numbers.yview_scroll(move, "units") - - return "break" - - def file_new(self, event=None): - file_name = filedialog.asksaveasfilename() - if file_name: - self.open_file = file_name - self.main_text.delete(1.0, tk.END) - self.title(" - ".join([self.WINDOW_TITLE, self.open_file])) - - def file_open(self, event=None): - file_to_open = filedialog.askopenfilename() - - if file_to_open: - self.open_file = file_to_open - self.main_text.delete(1.0, tk.END) - - with open(file_to_open, "r") as file_contents: - file_lines = file_contents.readlines() - if len(file_lines) > 0: - for index, line in enumerate(file_lines): - index = float(index) + 1.0 - self.main_text.insert(index, line) - - self.title(" - ".join([self.WINDOW_TITLE, self.open_file])) - - self.tag_all_lines() - - - def file_save(self, event=None): - if not self.open_file: - new_file_name = filedialog.asksaveasfilename() - if new_file_name: - self.open_file = new_file_name - - if self.open_file: - new_contents = self.main_text.get(1.0, tk.END) - with open(self.open_file, "w") as open_file: - open_file.write(new_contents) - - def select_all(self, event=None): - self.main_text.tag_add("sel", 1.0, tk.END) - - return "break" - - def edit_cut(self, event=None): - self.main_text.event_generate("<>") - - return "break" - - def edit_paste(self, event=None): - self.main_text.event_generate("<>") - self.on_key_release() - self.tag_all_lines() - - return "break" - - def edit_undo(self, event=None): - self.main_text.event_generate("<>") - - return "break" - - def edit_redo(self, event=None): - self.main_text.event_generate("<>") - - return "break" - - def insert_spaces(self, event=None): - self.main_text.insert(tk.INSERT, " ") - - return "break" - - def get_menu_coordinates(self): - bbox = self.main_text.bbox(tk.INSERT) - menu_x = bbox[0] + self.winfo_x() + self.main_text.winfo_x() - menu_y = bbox[1] + self.winfo_y() + self.main_text.winfo_y() + self.FONT_SIZE + 2 - - return (menu_x, menu_y) - - def display_autocomplete_menu(self, event=None): - current_index = self.main_text.index(tk.INSERT) - start = self.adjust_floating_index(current_index) - - try: - currently_typed_word = self.main_text.get(start + " wordstart", tk.INSERT) - except tk.TclError: - currently_typed_word = "" - - currently_typed_word = str(currently_typed_word).strip() - - if currently_typed_word: - self.destroy_autocomplete_menu() - - suggestions = [] - for word in self.AUTOCOMPLETE_WORDS: - if word.startswith(currently_typed_word) and not currently_typed_word == word: - suggestions.append(word) - - if len(suggestions) > 0: - x, y = self.get_menu_coordinates() - self.complete_menu = tk.Menu(self, tearoff=0, bg="lightgrey", fg="black") - - for word in suggestions: - insert_word_callback = partial(self.insert_word, word=word, part=currently_typed_word, index=current_index) - self.complete_menu.add_command(label=word, command=insert_word_callback) - - self.complete_menu.post(x, y) - self.complete_menu.bind("", self.destroy_autocomplete_menu) - self.main_text.bind("", self.focus_menu_item) - - def destroy_autocomplete_menu(self, event=None): - try: - self.complete_menu.destroy() - self.main_text.unbind("") - self.main_text.focus_force() - except AttributeError: - pass - - def insert_word(self, word, part, index): - amount_typed = len(part) - remaining_word = word[amount_typed:] - remaining_word_offset = " +" + str(len(remaining_word)) + "c" - self.main_text.insert(index, remaining_word) - self.main_text.mark_set(tk.INSERT, index + remaining_word_offset) - self.destroy_autocomplete_menu() - self.main_text.focus_force() - - def adjust_floating_index(self, number): - indices = number.split(".") - x_index = indices[0] - y_index = indices[1] - y_as_number = int(y_index) - y_previous = y_as_number - 1 - - return ".".join([x_index, str(y_previous)]) - - def focus_menu_item(self, event=None): - try: - self.complete_menu.focus_force() - self.complete_menu.entryconfig(0, state="active") - except tk.TclError: - pass - - def tag_all_lines(self): - final_index = self.main_text.index(tk.END) - final_line_number = int(final_index.split(".")[0]) - - for line_number in range(final_line_number): - line_to_tag = ".".join([str(line_number), "0"]) - self.tag_keywords(None, line_to_tag) - - self.update_line_numbers() - - def tag_keywords(self, event=None, current_index=None): - if not current_index: - current_index = self.main_text.index(tk.INSERT) - line_number = current_index.split(".")[0] - line_beginning = ".".join([line_number, "0"]) - line_text = self.main_text.get(line_beginning, line_beginning + " lineend") - line_words = line_text.split() - number_of_spaces = self.number_of_leading_spaces(line_text) - y_position = number_of_spaces - - for tag in self.main_text.tag_names(): - if tag != "sel": - self.main_text.tag_remove(tag, line_beginning, line_beginning + " lineend") - - self.add_regex_tags(line_number, line_text) - - for word in line_words: - stripped_word = word.strip("():,") - - word_start = str(y_position) - word_end = str(y_position + len(stripped_word)) - start_index = ".".join([line_number, word_start]) - end_index = ".".join([line_number, word_end]) - - if stripped_word in self.KEYWORDS_1: - self.main_text.tag_add("keyword1", start_index, end_index) - elif stripped_word in self.KEYWORDS_FLOW: - self.main_text.tag_add("keywordflow", start_index, end_index) - elif stripped_word.startswith("@"): - self.main_text.tag_add("decorator", start_index, end_index) - - y_position += len(word) + 1 - - def number_of_leading_spaces(self, line): - spaces = re.search(self.SPACES_REGEX, line) - if spaces.group(0) is not None: - number_of_spaces = len(spaces.group(0)) - else: - number_of_spaces = 0 - - return number_of_spaces - - def add_regex_tags(self, line_number, line_text): - for regex, tag in self.REGEX_TO_TAG.items(): - for match in regex.finditer(line_text): - start, end = match.span() - start_index = ".".join([line_number, str(start)]) - end_index = ".".join([line_number, str(end)]) - self.main_text.tag_add(tag, start_index, end_index) - - def on_key_release(self, event): - if not event.keysym in ("Up", "Down", "Left", "Right", "BackSpace", "Delete", "Escape"): - self.display_autocomplete_menu() - self.tag_keywords() - self.update_line_numbers() - - def update_line_numbers(self): - self.line_numbers.configure(state="normal") - self.line_numbers.delete(1.0, tk.END) - number_of_lines = self.main_text.index(tk.END).split(".")[0] - line_number_string = "\n".join(str(no+1) for no in range(int(number_of_lines))) - self.line_numbers.insert(1.0, line_number_string) - self.line_numbers.configure(state="disabled") - - def show_find_window(self, event=None): - FindPopup(self) - - def highlight_matches(self, text_to_find): - self.main_text.tag_remove("findmatch", 1.0, tk.END) - self.match_coordinates = [] - self.current_match = -1 - - find_regex = re.compile(text_to_find) - search_text_lines = self.main_text.get(1.0, tk.END).split("\n") - - for line_number, line in enumerate(search_text_lines): - line_number += 1 - for match in find_regex.finditer(line): - start, end = match.span() - start_index = ".".join([str(line_number), str(start)]) - end_index = ".".join([str(line_number), str(end)]) - self.main_text.tag_add("findmatch", start_index, end_index) - self.match_coordinates.append((start_index, end_index)) - - def next_match(self, event=None): - try: - current_target, current_target_end = self.match_coordinates[self.current_match] - self.main_text.tag_remove("sel", current_target, current_target_end) - self.main_text.tag_add("findmatch", current_target, current_target_end) - except IndexError: - pass - - try: - self.current_match = self.current_match + 1 - next_target, target_end = self.match_coordinates[self.current_match] - except IndexError: - if len(self.match_coordinates) == 0: - msg.showinfo("No Matches", "No Matches Found") - else: - if msg.askyesno("Wrap Search?", "Reached end of file. Continue from the top?"): - self.current_match = -1 - self.next_match() - else: - self.main_text.mark_set(tk.INSERT, next_target) - self.main_text.tag_remove("findmatch", next_target, target_end) - self.main_text.tag_add("sel", next_target, target_end) - self.main_text.see(next_target) - - def remove_all_find_tags(self): - self.main_text.tag_remove("findmatch", 1.0, tk.END) - self.main_text.tag_remove("sel", 1.0, tk.END) - - -if __name__ == "__main__": - editor = Editor() - editor.mainloop() diff --git a/Chapter6-regex-explain.py b/Chapter6-regex-explain.py deleted file mode 100644 index 5cc3174..0000000 --- a/Chapter6-regex-explain.py +++ /dev/null @@ -1,40 +0,0 @@ -self.STRING_REGEX_SINGLE = "'[^'\r\n]*'" -# a literal ' -# anything which isn't ' or a newline 0 or more times -# a literal ' - -self.STRING_REGEX_DOUBLE = re.compile('"[^"\r\n]*"') -# a literal ", -# anything which isn't " or a newline 0 or more times -# a literal " - -self.NUMBER_REGEX = re.compile( - \b # begin with a word boundry (punctuation or space) - (?=\(*) # match but don't highlight 0 or more opening brackets - \d+\.?\d* # match 1 or more numbers, 0 or 1 decimal points, 0 or more numbers - (?=\)*\,*) # match but don't highlight 0 or more closing brackets or commas - \b # end with a word boundry (punctuation or space) -) - - -self.KEYWORDS_REGEX = re.compile( - (?=\(*) # match but don't highlight 0 or more opening brackets - (?= self.end_time: - if not self.force_quit: - self.master.finish() - break - elif self.end_now: - self.master.finish() - break - elif self.force_quit: - del self.master.worker - return - else: - continue - return - - def main_loop(self): - now = datetime.datetime.now() - if now < self.end_time: - time_difference = self.end_time - now - mins, secs = divmod(time_difference.seconds, 60) - time_string = "{:02d}:{:02d}".format(mins, secs) - if not self.force_quit: - self.master.update_time_remaining(time_string) - - -class Timer(tk.Tk): - def __init__(self): - super().__init__() - - self.title("Pomodoro Timer") - self.geometry("500x300") - self.resizable(False, False) - - self.standard_font = (None, 16) - - self.main_frame = tk.Frame(self, width=500, height=300, bg="lightgrey") - - self.task_name_label = tk.Label(self.main_frame, text="Task Name:", bg="lightgrey", fg="black", font=self.standard_font) - self.task_name_entry = tk.Entry(self.main_frame, bg="white", fg="black", font=self.standard_font) - self.start_button = tk.Button(self.main_frame, text="Start", bg="lightgrey", fg="black", command=self.start, font=self.standard_font) - self.time_remaining_var = tk.StringVar(self.main_frame) - self.time_remaining_var.set("25:00") - self.time_remaining_label = tk.Label(self.main_frame, textvar=self.time_remaining_var, bg="lightgrey", fg="black", font=(None, 40)) - self.pause_button = tk.Button(self.main_frame, text="Pause", bg="lightgrey", fg="black", command=self.pause, font=self.standard_font, state="disabled") - - self.main_frame.pack(fill=tk.BOTH, expand=1) - - self.task_name_label.pack(fill=tk.X, pady=15) - self.task_name_entry.pack(fill=tk.X, padx=50, pady=(0,20)) - self.start_button.pack(fill=tk.X, padx=50) - self.time_remaining_label.pack(fill=tk.X ,pady=15) - self.pause_button.pack(fill=tk.X, padx=50) - - self.protocol("WM_DELETE_WINDOW", self.safe_destroy) - - def setup_worker(self): - now = datetime.datetime.now() - in_25_mins = now + datetime.timedelta(minutes=25) - #in_25_mins = now + datetime.timedelta(seconds=3) - worker = CountingThread(self, now, in_25_mins) - self.worker = worker - - def start(self): - if not hasattr(self, "worker"): - self.setup_worker() - - self.task_name_entry.configure(state="disabled") - self.start_button.configure(text="Finish", command=self.finish_early) - self.time_remaining_var.set("25:00") - self.pause_button.configure(state="normal") - self.worker.start() - - def pause(self): - self.worker.paused = not self.worker.paused - if self.worker.paused: - self.pause_button.configure(text="Resume") - self.worker.start_time = datetime.datetime.now() - else: - self.pause_button.configure(text="Pause") - end_timedelta = datetime.datetime.now() - self.worker.start_time - self.worker.end_time = self.worker.end_time + datetime.timedelta(seconds=end_timedelta.seconds) - - def finish_early(self): - self.start_button.configure(text="Start", command=self.start) - self.worker.end_now = True - - def finish(self): - self.task_name_entry.configure(state="normal") - self.time_remaining_var.set("25:00") - self.pause_button.configure(text="Pause", state="disabled") - self.start_button.configure(text="Start", command=self.start) - del self.worker - msg.showinfo("Pomodoro Finished!", "Task completed, take a break!") - - def update_time_remaining(self, time_string): - self.time_remaining_var.set(time_string) - self.update_idletasks() - - def safe_destroy(self): - if hasattr(self, "worker"): - self.worker.force_quit = True - self.after(100, self.safe_destroy) - else: - self.destroy() - -if __name__ == "__main__": - timer = Timer() - timer.mainloop() diff --git a/Chapter7-2-abridged.py b/Chapter7-2-abridged.py deleted file mode 100644 index 5af8df7..0000000 --- a/Chapter7-2-abridged.py +++ /dev/null @@ -1,156 +0,0 @@ -import sqlite3 -import os -import functools -from tkinter import ttk - -class CountingThread(threading.Thread): - ... - - -class LogWindow(tk.Toplevel): - def __init__(self, master): - super().__init__() - - self.title("Log") - self.geometry("600x300") - - self.notebook = ttk.Notebook(self) - - dates_sql = "SELECT DISTINCT date FROM pymodoros ORDER BY date DESC" - dates = self.master.runQuery(dates_sql, None, True) - - for index, date in enumerate(dates): - dates[index] = date[0].split()[0] - - dates = sorted(set(dates), reverse=True) - - for date in dates: - tab = tk.Frame(self.notebook) - - columns = ("name", "finished", "time") - - tree = ttk.Treeview(tab, columns=columns, show="headings") - - tree.heading("name", text="Name") - tree.heading("finished", text="Full 25 Minutes") - tree.heading("time", text="Time") - - tree.column("name", anchor="center") - tree.column("finished", anchor="center") - tree.column("time", anchor="center") - - tasks_sql = "SELECT * FROM pymodoros WHERE date LIKE ?" - date_like = date + "%" - data = (date_like,) - - tasks = self.master.runQuery(tasks_sql, data, True) - - for task_name, task_finished, task_date in tasks: - task_finished_text = "Yes" if task_finished else "No" - task_time = task_date.split()[1] - task_time_pieces = task_time.split(":") - task_time_pretty = "{}:{}".format(task_time_pieces[0], task_time_pieces[1]) - tree.insert("", tk.END, values=(task_name, task_finished_text, task_time_pretty)) - - tree.pack(fill=tk.BOTH, expand=1) - - self.notebook.add(tab, text=date) - - self.notebook.pack(fill=tk.BOTH, expand=1) - - -class Timer(tk.Tk): - def __init__(self): - ... - - self.menubar = tk.Menu(self, bg="lightgrey", fg="black") - - self.log_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black") - self.log_menu.add_command(label="View Log", command=self.show_log_window, accelerator="Ctrl+L") - - self.menubar.add_cascade(label="Log", menu=self.log_menu) - self.configure(menu=self.menubar) - - ... - - self.bind("", self.show_log_window) - - ... - - def setup_worker(self): - ... - - def start(self): - if not self.task_name_entry.get(): - msg.showerror("No Task", "Please enter a task name") - return - - ... - self.task_finished_early = False - ... - - def pause(self): - ... - - def finish_early(self): - self.start_button.configure(text="Start", command=self.start) - self.task_finished_early = True - self.worker.end_now = True - - def finish(self): - ... - if not self.task_finished_early: - self.mark_finished_task() - del self.worker - msg.showinfo("Pomodoro Finished!", "Task completed, take a break!") - - def update_time_remaining(self, time_string): - ... - - def add_new_task(self): - task_name = self.task_name_entry.get() - self.task_started_time = datetime.datetime.now() - add_task_sql = "INSERT INTO pymodoros VALUES (?, 0, ?)" - self.runQuery(add_task_sql, (task_name, self.task_started_time)) - - def mark_finished_task(self): - task_name = self.task_name_entry.get() - add_task_sql = "UPDATE pymodoros SET finished = ? WHERE task = ? and date = ?" - self.runQuery(add_task_sql, ("1", task_name, self.task_started_time)) - - def show_log_window(self, event=None): - LogWindow(self) - - def safe_destroy(self): - ... - - @staticmethod - def runQuery(sql, data=None, receive=False): - conn = sqlite3.connect("pymodoro.db") - cursor = conn.cursor() - if data: - cursor.execute(sql, data) - else: - cursor.execute(sql) - - if receive: - return cursor.fetchall() - else: - conn.commit() - - conn.close() - - @staticmethod - def firstTimeDB(): - create_tables = "CREATE TABLE pymodoros (task text, finished integer, date text)" - Timer.runQuery(create_tables) - - -if __name__ == "__main__": - timer = Timer() - - if not os.path.isfile("pymodoro.db"): - timer.firstTimeDB() - - timer.mainloop() - diff --git a/Chapter7-2.py b/Chapter7-2.py deleted file mode 100644 index ef0f5f8..0000000 --- a/Chapter7-2.py +++ /dev/null @@ -1,244 +0,0 @@ -import threading -import time -import datetime -import sqlite3 -import os -import functools -import tkinter as tk -from tkinter import ttk -from tkinter import messagebox as msg - -class CountingThread(threading.Thread): - def __init__(self, master, start_time, end_time): - super().__init__() - self.master = master - self.start_time = start_time - self.end_time = end_time - - self.end_now = False - self.paused = False - self.force_quit = False - - def run(self): - while True: - if not self.paused and not self.end_now and not self.force_quit: - self.main_loop() - if datetime.datetime.now() >= self.end_time: - if not self.force_quit: - self.master.finish() - break - elif self.end_now: - self.master.finish() - break - elif self.force_quit: - del self.master.worker - return - else: - continue - return - - def main_loop(self): - now = datetime.datetime.now() - if now < self.end_time: - time_difference = self.end_time - now - mins, secs = divmod(time_difference.seconds, 60) - time_string = "{:02d}:{:02d}".format(mins, secs) - if not self.force_quit: - self.master.update_time_remaining(time_string) - - -class LogWindow(tk.Toplevel): - def __init__(self, master): - super().__init__() - - self.title("Log") - self.geometry("600x300") - - self.notebook = ttk.Notebook(self) - - dates_sql = "SELECT DISTINCT date FROM pymodoros ORDER BY date DESC" - dates = self.master.runQuery(dates_sql, None, True) - - for index, date in enumerate(dates): - dates[index] = date[0].split()[0] - - dates = sorted(set(dates), reverse=True) - - for date in dates: - tab = tk.Frame(self.notebook) - - columns = ("name", "finished", "time") - - tree = ttk.Treeview(tab, columns=columns, show="headings") - - tree.heading("name", text="Name") - tree.heading("finished", text="Full 25 Minutes") - tree.heading("time", text="Time") - - tree.column("name", anchor="center") - tree.column("finished", anchor="center") - tree.column("time", anchor="center") - - tasks_sql = "SELECT * FROM pymodoros WHERE date LIKE ?" - date_like = date + "%" - data = (date_like,) - - tasks = self.master.runQuery(tasks_sql, data, True) - - for task_name, task_finished, task_date in tasks: - task_finished_text = "Yes" if task_finished else "No" - task_time = task_date.split()[1] - task_time_pieces = task_time.split(":") - task_time_pretty = "{}:{}".format(task_time_pieces[0], task_time_pieces[1]) - tree.insert("", tk.END, values=(task_name, task_finished_text, task_time_pretty)) - - - tree.pack(fill=tk.BOTH, expand=1) - self.notebook.add(tab, text=date) - - self.notebook.pack(fill=tk.BOTH, expand=1) - - -class Timer(tk.Tk): - def __init__(self): - super().__init__() - - self.title("Pomodoro Timer") - self.geometry("500x300") - self.resizable(False, False) - - self.standard_font = (None, 16) - - self.menubar = tk.Menu(self, bg="lightgrey", fg="black") - - self.log_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black") - self.log_menu.add_command(label="View Log", command=self.show_log_window, accelerator="Ctrl+L") - - self.menubar.add_cascade(label="Log", menu=self.log_menu) - self.configure(menu=self.menubar) - - self.main_frame = tk.Frame(self, width=500, height=300, bg="lightgrey") - - self.task_name_label = tk.Label(self.main_frame, text="Task Name:", bg="lightgrey", fg="black", font=self.standard_font) - self.task_name_entry = tk.Entry(self.main_frame, bg="white", fg="black", font=self.standard_font) - self.start_button = tk.Button(self.main_frame, text="Start", bg="lightgrey", fg="black", command=self.start, font=self.standard_font) - self.time_remaining_var = tk.StringVar(self.main_frame) - self.time_remaining_var.set("25:00") - self.time_remaining_label = tk.Label(self.main_frame, textvar=self.time_remaining_var, bg="lightgrey", fg="black", font=(None, 40)) - self.pause_button = tk.Button(self.main_frame, text="Pause", bg="lightgrey", fg="black", command=self.pause, font=self.standard_font, state="disabled") - - self.main_frame.pack(fill=tk.BOTH, expand=1) - - self.task_name_label.pack(fill=tk.X, pady=15) - self.task_name_entry.pack(fill=tk.X, padx=50, pady=(0,20)) - self.start_button.pack(fill=tk.X, padx=50) - self.time_remaining_label.pack(fill=tk.X ,pady=15) - self.pause_button.pack(fill=tk.X, padx=50) - - self.bind("", self.show_log_window) - - self.protocol("WM_DELETE_WINDOW", self.safe_destroy) - - def setup_worker(self): - now = datetime.datetime.now() - in_25_mins = now + datetime.timedelta(minutes=25) - #in_25_mins = now + datetime.timedelta(seconds=3) - worker = CountingThread(self, now, in_25_mins) - self.worker = worker - - def start(self): - if not self.task_name_entry.get(): - msg.showerror("No Task", "Please enter a task name") - return - - if not hasattr(self, "worker"): - self.setup_worker() - - self.task_name_entry.configure(state="disabled") - self.start_button.configure(text="Finish", command=self.finish_early) - self.time_remaining_var.set("25:00") - self.pause_button.configure(state="normal") - self.add_new_task() - self.task_finished_early = False - self.worker.start() - - def pause(self): - self.worker.paused = not self.worker.paused - if self.worker.paused: - self.pause_button.configure(text="Resume") - self.worker.start_time = datetime.datetime.now() - else: - self.pause_button.configure(text="Pause") - end_timedelta = datetime.datetime.now() - self.worker.start_time - self.worker.end_time = self.worker.end_time + datetime.timedelta(seconds=end_timedelta.seconds) - - def finish_early(self): - self.start_button.configure(text="Start", command=self.start) - self.task_finished_early = True - self.worker.end_now = True - - def finish(self): - self.task_name_entry.configure(state="normal") - self.time_remaining_var.set("25:00") - self.pause_button.configure(text="Pause", state="disabled") - self.start_button.configure(text="Start", command=self.start) - if not self.task_finished_early: - self.mark_finished_task() - del self.worker - msg.showinfo("Pomodoro Finished!", "Task completed, take a break!") - - def update_time_remaining(self, time_string): - self.time_remaining_var.set(time_string) - self.update_idletasks() - - def add_new_task(self): - task_name = self.task_name_entry.get() - self.task_started_time = datetime.datetime.now() - add_task_sql = "INSERT INTO pymodoros VALUES (?, 0, ?)" - self.runQuery(add_task_sql, (task_name, self.task_started_time)) - - def mark_finished_task(self): - task_name = self.task_name_entry.get() - add_task_sql = "UPDATE pymodoros SET finished = ? WHERE task = ? and date = ?" - self.runQuery(add_task_sql, ("1", task_name, self.task_started_time)) - - def show_log_window(self, event=None): - LogWindow(self) - - def safe_destroy(self): - if hasattr(self, "worker"): - self.worker.force_quit = True - self.after(100, self.safe_destroy) - else: - self.destroy() - - @staticmethod - def runQuery(sql, data=None, receive=False): - conn = sqlite3.connect("pymodoro.db") - cursor = conn.cursor() - if data: - cursor.execute(sql, data) - else: - cursor.execute(sql) - - if receive: - return cursor.fetchall() - else: - conn.commit() - - conn.close() - - @staticmethod - def firstTimeDB(): - create_tables = "CREATE TABLE pymodoros (task text, finished integer, date text)" - Timer.runQuery(create_tables) - - -if __name__ == "__main__": - timer = Timer() - - if not os.path.isfile("pymodoro.db"): - timer.firstTimeDB() - - timer.mainloop() - diff --git a/Chapter7-3-abridged.py b/Chapter7-3-abridged.py deleted file mode 100644 index dce67d6..0000000 --- a/Chapter7-3-abridged.py +++ /dev/null @@ -1,150 +0,0 @@ -... - -class CountingThread(threading.Thread): - ... - - -class LogWindow(tk.Toplevel): - def __init__(self, master): - ... - self.tab_trees = {} - - style = ttk.Style() - style.configure("Treeview", font=(None,12)) - style.configure("Treeview.Heading", font=(None, 14)) - - dates = self.master.get_unique_dates() - - for index, date in enumerate(dates): - dates[index] = date[0].split()[0] - - dates = sorted(set(dates), reverse=True) - - for date in dates: - ... - - tree.pack(fill=tk.BOTH, expand=1) - tree.bind("", self.confirm_delete) - self.tab_trees[date] = tree - - self.notebook.add(tab, text=date) - - self.notebook.pack(fill=tk.BOTH, expand=1) - - def confirm_delete(self, event=None): - current_tab = self.notebook.tab(self.notebook.select(), "text") - tree = self.tab_trees[current_tab] - selected_item_id = tree.selection() - selected_item = tree.item(selected_item_id) - - if msg.askyesno("Delete Item?", "Delete " + selected_item["values"][0] + "?", parent=self): - task_name = selected_item["values"][0] - task_time = selected_item["values"][2] - task_date = " ".join([current_tab, task_time]) - self.master.delete_task(task_name, task_date) - tree.delete(selected_item_id) - -class Timer(tk.Tk): - def __init__(self): - ... - - style = ttk.Style() - style.configure("TLabel", foreground="black", background="lightgrey", font=(None, 16), anchor="center") - style.configure("B.TLabel", font=(None, 40)) - style.configure("B.TButton", foreground="black", background="lightgrey", font=(None, 16), anchor="center") - style.configure("TEntry", foregound="black", background="white") - - ... - - self.task_name_label = ttk.Label(self.main_frame, text="Task Name:") - self.task_name_entry = ttk.Entry(self.main_frame, font=(None, 16)) - self.start_button = ttk.Button(self.main_frame, text="Start", command=self.start, style="B.TButton") - self.time_remaining_var = tk.StringVar(self.main_frame) - self.time_remaining_var.set("25:00") - self.time_remaining_label = ttk.Label(self.main_frame, textvar=self.time_remaining_var, style="B.TLabel") - self.pause_button = ttk.Button(self.main_frame, text="Pause", command=self.pause, state="disabled", style="B.TButton") - - ... - - self.task_name_entry.focus_set() - - def setup_worker(self): - ... - - def start(self): - if not self.task_name_entry.get(): - ... - - if self.task_is_duplicate(): - msg.showerror("Task Duplicate", "Please enter a different task name") - return - - ... - - def pause(self): - ... - - def finish_early(self): - ... - - def finish(self): - ... - - def update_time_remaining(self, time_string): - ... - - def add_new_task(self): - ... - - def mark_finished_task(self): - ... - - def show_log_window(self, event=None): - ... - - def safe_destroy(self): - ... - - def get_unique_dates(self): - dates_sql = "SELECT DISTINCT date FROM pymodoros ORDER BY date DESC" - dates = self.runQuery(dates_sql, None, True) - - return dates - - def get_tasks_by_date(self, date): - tasks_sql = "SELECT * FROM pymodoros WHERE date LIKE ?" - date_like = date + "%" - data = (date_like,) - - tasks = self.runQuery(tasks_sql, data, True) - - return tasks - - def delete_task(self, task_name, task_date): - delete_task_sql = "DELETE FROM pymodoros WHERE task = ? AND date LIKE ?" - task_date_like = task_date + "%" - data = (task_name, task_date_like) - self.runQuery(delete_task_sql, data) - - def task_is_duplicate(self): - task_name = self.task_name_entry.get() - today = datetime.datetime.now().date() - task_exists_sql = "SELECT task FROM pymodoros WHERE task = ? AND date LIKE ?" - today_like = str(today) + "%" - data = (task_name, today_like) - tasks = self.runQuery(task_exists_sql, data, True) - - return len(tasks) - - @staticmethod - def runQuery(sql, data=None, receive=False): - ... - - @staticmethod - def firstTimeDB(): - ... - - -if __name__ == "__main__": - ... - diff --git a/Chapter7-3.py b/Chapter7-3.py deleted file mode 100644 index 22c5bf1..0000000 --- a/Chapter7-3.py +++ /dev/null @@ -1,299 +0,0 @@ -import threading -import time -import datetime -import sqlite3 -import os -import functools -import tkinter as tk -from tkinter import ttk -from tkinter import messagebox as msg - -class CountingThread(threading.Thread): - def __init__(self, master, start_time, end_time): - super().__init__() - self.master = master - self.start_time = start_time - self.end_time = end_time - - self.end_now = False - self.paused = False - self.force_quit = False - - def run(self): - while True: - if not self.paused and not self.end_now and not self.force_quit: - self.main_loop() - if datetime.datetime.now() >= self.end_time: - if not self.force_quit: - self.master.finish() - break - elif self.end_now: - self.master.finish() - break - elif self.force_quit: - del self.master.worker - return - else: - continue - return - - def main_loop(self): - now = datetime.datetime.now() - if now < self.end_time: - time_difference = self.end_time - now - mins, secs = divmod(time_difference.seconds, 60) - time_string = "{:02d}:{:02d}".format(mins, secs) - if not self.force_quit: - self.master.update_time_remaining(time_string) - - -class LogWindow(tk.Toplevel): - def __init__(self, master): - super().__init__() - - self.title("Log") - self.geometry("600x300") - - self.notebook = ttk.Notebook(self) - self.tab_trees = {} - - style = ttk.Style() - style.configure("Treeview", font=(None,12)) - style.configure("Treeview.Heading", font=(None, 14)) - - dates = self.master.get_unique_dates() - - for index, date in enumerate(dates): - dates[index] = date[0].split()[0] - - dates = sorted(set(dates), reverse=True) - - for date in dates: - tab = tk.Frame(self.notebook) - - columns = ("name", "finished", "time") - - tree = ttk.Treeview(tab, columns=columns, show="headings") - - tree.heading("name", text="Name") - tree.heading("finished", text="Full 25 Minutes") - tree.heading("time", text="Time") - - tree.column("name", anchor="center") - tree.column("finished", anchor="center") - tree.column("time", anchor="center") - - tasks = self.master.get_tasks_by_date(date) - - for task_name, task_finished, task_date in tasks: - task_finished_text = "Yes" if task_finished else "No" - task_time = task_date.split()[1] - task_time_pieces = task_time.split(":") - task_time_pretty = "{}:{}".format(task_time_pieces[0], task_time_pieces[1]) - tree.insert("", tk.END, values=(task_name, task_finished_text, task_time_pretty)) - - tree.pack(fill=tk.BOTH, expand=1) - tree.bind("", self.confirm_delete) - self.tab_trees[date] = tree - - self.notebook.add(tab, text=date) - - self.notebook.pack(fill=tk.BOTH, expand=1) - - def confirm_delete(self, event=None): - current_tab = self.notebook.tab(self.notebook.select(), "text") - tree = self.tab_trees[current_tab] - selected_item_id = tree.selection() - selected_item = tree.item(selected_item_id) - - if msg.askyesno("Delete Item?", "Delete " + selected_item["values"][0] + "?", parent=self): - task_name = selected_item["values"][0] - task_time = selected_item["values"][2] - task_date = " ".join([current_tab, task_time]) - self.master.delete_task(task_name, task_date) - tree.delete(selected_item_id) - -class Timer(tk.Tk): - def __init__(self): - super().__init__() - - self.title("Pomodoro Timer") - self.geometry("500x300") - self.resizable(False, False) - - style = ttk.Style() - style.configure("TLabel", foreground="black", background="lightgrey", font=(None, 16), anchor="center") - style.configure("B.TLabel", font=(None, 40)) - style.configure("B.TButton", foreground="black", background="lightgrey", font=(None, 16), anchor="center") - style.configure("TEntry", foregound="black", background="white") - - self.menubar = tk.Menu(self, bg="lightgrey", fg="black") - - self.log_menu = tk.Menu(self.menubar, tearoff=0, bg="lightgrey", fg="black") - self.log_menu.add_command(label="View Log", command=self.show_log_window, accelerator="Ctrl+L") - - self.menubar.add_cascade(label="Log", menu=self.log_menu) - self.configure(menu=self.menubar) - - self.main_frame = tk.Frame(self, width=500, height=300, bg="lightgrey") - - self.task_name_label = ttk.Label(self.main_frame, text="Task Name:") - self.task_name_entry = ttk.Entry(self.main_frame, font=(None, 16)) - self.start_button = ttk.Button(self.main_frame, text="Start", command=self.start, style="B.TButton") - self.time_remaining_var = tk.StringVar(self.main_frame) - self.time_remaining_var.set("25:00") - self.time_remaining_label = ttk.Label(self.main_frame, textvar=self.time_remaining_var, style="B.TLabel") - self.pause_button = ttk.Button(self.main_frame, text="Pause", command=self.pause, state="disabled", style="B.TButton") - - self.main_frame.pack(fill=tk.BOTH, expand=1) - - self.task_name_label.pack(fill=tk.X, pady=15) - self.task_name_entry.pack(fill=tk.X, padx=50, pady=(0,20)) - self.start_button.pack(fill=tk.X, padx=50) - self.time_remaining_label.pack(fill=tk.X ,pady=15) - self.pause_button.pack(fill=tk.X, padx=50) - - self.bind("", self.show_log_window) - - self.protocol("WM_DELETE_WINDOW", self.safe_destroy) - - self.task_name_entry.focus_set() - - def setup_worker(self): - now = datetime.datetime.now() - in_25_mins = now + datetime.timedelta(minutes=25) - #in_25_mins = now + datetime.timedelta(seconds=2) - worker = CountingThread(self, now, in_25_mins) - self.worker = worker - - def start(self): - if not self.task_name_entry.get(): - msg.showerror("No Task", "Please enter a task name") - return - - if self.task_is_duplicate(): - msg.showerror("Task Duplicate", "Please enter a different task name") - return - - if not hasattr(self, "worker"): - self.setup_worker() - - self.task_name_entry.configure(state="disabled") - self.start_button.configure(text="Finish", command=self.finish_early) - self.time_remaining_var.set("25:00") - self.pause_button.configure(state="normal") - self.add_new_task() - self.task_finished_early = False - self.worker.start() - - def pause(self): - self.worker.paused = not self.worker.paused - if self.worker.paused: - self.pause_button.configure(text="Resume") - self.worker.start_time = datetime.datetime.now() - else: - self.pause_button.configure(text="Pause") - end_timedelta = datetime.datetime.now() - self.worker.start_time - self.worker.end_time = self.worker.end_time + datetime.timedelta(seconds=end_timedelta.seconds) - - def finish_early(self): - self.start_button.configure(text="Start", command=self.start) - self.task_finished_early = True - self.worker.end_now = True - - def finish(self): - self.task_name_entry.configure(state="normal") - self.time_remaining_var.set("25:00") - self.pause_button.configure(text="Pause", state="disabled") - self.start_button.configure(text="Start", command=self.start) - if not self.task_finished_early: - self.mark_finished_task() - del self.worker - msg.showinfo("Pomodoro Finished!", "Task completed, take a break!") - - def update_time_remaining(self, time_string): - self.time_remaining_var.set(time_string) - self.update_idletasks() - - def add_new_task(self): - task_name = self.task_name_entry.get() - self.task_started_time = datetime.datetime.now() - add_task_sql = "INSERT INTO pymodoros VALUES (?, 0, ?)" - self.runQuery(add_task_sql, (task_name, self.task_started_time)) - - def mark_finished_task(self): - task_name = self.task_name_entry.get() - add_task_sql = "UPDATE pymodoros SET finished = ? WHERE task = ? AND date = ?" - self.runQuery(add_task_sql, ("1", task_name, self.task_started_time)) - - def show_log_window(self, event=None): - LogWindow(self) - - def safe_destroy(self): - if hasattr(self, "worker"): - self.worker.force_quit = True - self.after(100, self.safe_destroy) - else: - self.destroy() - - def get_unique_dates(self): - dates_sql = "SELECT DISTINCT date FROM pymodoros ORDER BY date DESC" - dates = self.runQuery(dates_sql, None, True) - - return dates - - def get_tasks_by_date(self, date): - tasks_sql = "SELECT * FROM pymodoros WHERE date LIKE ?" - date_like = date + "%" - data = (date_like,) - - tasks = self.runQuery(tasks_sql, data, True) - - return tasks - - def delete_task(self, task_name, task_date): - delete_task_sql = "DELETE FROM pymodoros WHERE task = ? AND date LIKE ?" - task_date_like = task_date + "%" - data = (task_name, task_date_like) - self.runQuery(delete_task_sql, data) - - def task_is_duplicate(self): - task_name = self.task_name_entry.get() - today = datetime.datetime.now().date() - task_exists_sql = "SELECT task FROM pymodoros WHERE task = ? AND date LIKE ?" - today_like = str(today) + "%" - data = (task_name, today_like) - tasks = self.runQuery(task_exists_sql, data, True) - - return len(tasks) - - @staticmethod - def runQuery(sql, data=None, receive=False): - conn = sqlite3.connect("pymodoro.db") - cursor = conn.cursor() - if data: - cursor.execute(sql, data) - else: - cursor.execute(sql) - - if receive: - return cursor.fetchall() - else: - conn.commit() - - conn.close() - - @staticmethod - def firstTimeDB(): - create_tables = "CREATE TABLE pymodoros (task text, finished integer, date text)" - Timer.runQuery(create_tables) - - -if __name__ == "__main__": - timer = Timer() - - if not os.path.isfile("pymodoro.db"): - timer.firstTimeDB() - - timer.mainloop() -