├── Chapter01 ├── chapter1_01.py ├── chapter1_02.py ├── chapter1_03.py ├── chapter1_04.py ├── chapter1_05.py ├── chapter1_06.py ├── chapter1_07.py ├── chapter1_08.py ├── chapter1_09.py ├── chapter1_10.py ├── chapter1_11.py ├── chapter1_12.py ├── python.gif └── python.ico ├── Chapter02 └── code │ ├── chapter2_01.py │ ├── chapter2_02.py │ ├── chapter2_03.py │ ├── chapter2_04.py │ ├── chapter2_05.py │ ├── chapter2_06.py │ ├── chapter2_07.py │ └── python.gif ├── Chapter03 ├── code │ ├── chapter3_01.py │ ├── chapter3_02.py │ ├── chapter3_03.py │ ├── chapter3_04.py │ ├── chapter3_05.py │ └── chapter3_06.py └── images │ ├── B09199_03_01.png │ ├── B09199_03_03.png │ ├── B09199_03_04.png │ ├── B09199_03_05.png │ ├── B09199_03_06.png │ └── B09199_03_07.png ├── Chapter04 ├── code │ ├── chapter4_01.py │ ├── chapter4_02.py │ ├── chapter4_03.py │ ├── chapter4_04.py │ ├── chapter4_05.py │ ├── chapter4_06.py │ ├── chapter4_07.py │ ├── chapter4_07_disabled.py │ ├── chapter4_08.py │ ├── chapter4_09.py │ └── chapter4_10.py └── images │ ├── B09199_04_01.png │ ├── B09199_04_02.png │ ├── B09199_04_03.png │ ├── B09199_04_04.png │ ├── B09199_04_05.png │ ├── B09199_04_06.png │ ├── B09199_04_07.png │ ├── B09199_04_08.png │ ├── B09199_04_09.png │ ├── B09199_04_10.png │ ├── B09199_04_11.png │ ├── B09199_04_12.png │ ├── B09199_04_13.png │ └── B09199_04_14.png ├── Chapter05 ├── code │ ├── __pycache__ │ │ ├── chapter5_01.cpython-36.pyc │ │ └── chapter5_02.cpython-36.pyc │ ├── chapter5_01.py │ ├── chapter5_01b.py │ ├── chapter5_02.py │ ├── chapter5_03.py │ ├── chapter5_03_book.py │ ├── chapter5_04.py │ ├── chapter5_05 │ │ ├── __main__.py │ │ ├── __pycache__ │ │ │ ├── contact.cpython-36.pyc │ │ │ ├── contacts_controller.cpython-36.pyc │ │ │ ├── contacts_repository.cpython-36.pyc │ │ │ └── contacts_view.cpython-36.pyc │ │ ├── contact.py │ │ ├── contacts.db │ │ ├── contacts_controller.py │ │ ├── contacts_repository.py │ │ └── contacts_view.py │ ├── contacts.csv │ ├── contacts.db │ └── init_db.py └── images │ ├── B09199_05_01.png │ ├── B09199_05_02.png │ ├── B09199_05_03.png │ ├── B09199_05_04.jpg │ └── B09199_05_05.jpg ├── Chapter06 ├── code │ ├── chapter6_01a.py │ ├── chapter6_01b.py │ ├── chapter6_02.py │ ├── chapter6_03.py │ ├── chapter6_04.py │ ├── chapter6_05.py │ ├── chapter6_06.py │ ├── chapter6_07.py │ └── server.py └── images │ ├── B09199_06_01.png │ ├── B09199_06_02.png │ ├── B09199_06_03.jpg │ ├── B09199_06_04.png │ ├── B09199_06_05.png │ ├── B09199_06_06.png │ └── B09199_06_07.png ├── Chapter07 ├── code │ ├── chapter7_01.py │ ├── chapter7_02.py │ ├── chapter7_03.py │ ├── chapter7_04.py │ ├── chapter7_05.py │ ├── chapter7_06.py │ ├── chapter7_07.py │ ├── chapter7_08.py │ ├── chapter7_09.py │ ├── chapter7_10.py │ └── output.ps └── images │ ├── B09199_07_01.png │ ├── B09199_07_02.png │ ├── B09199_07_03.png │ ├── B09199_07_04.png │ ├── B09199_07_05.png │ ├── B09199_07_06.png │ ├── B09199_07_07.png │ ├── B09199_07_08.png │ ├── B09199_07_09.png │ ├── B09199_07_10.png │ ├── B09199_07_11.png │ └── B09199_07_12.png ├── Chapter08 ├── code │ ├── chapter8_01.py │ ├── chapter8_02.py │ ├── chapter8_03.py │ ├── chapter8_04.py │ ├── chapter8_05.py │ ├── chapter8_07.py │ └── contacts.csv └── images │ ├── B09199_08_01.png │ ├── B09199_08_02.png │ ├── B09199_08_03.png │ ├── B09199_08_04.png │ ├── B09199_08_05.png │ ├── B09199_08_06.png │ └── B09199_08_07.png ├── LICENSE └── README.md /Chapter01/chapter1_01.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.btn = tk.Button(self, text="Click me!", 7 | command=self.say_hello) 8 | self.btn.pack(padx=120, pady=30) 9 | 10 | def say_hello(self): 11 | print("Hello, Tkinter!") 12 | 13 | if __name__ == "__main__": 14 | app = App() 15 | app.title("My Tkinter app") 16 | app.mainloop() 17 | -------------------------------------------------------------------------------- /Chapter01/chapter1_02.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | RELIEFS = [tk.SUNKEN, tk.RAISED, tk.GROOVE, tk.RIDGE, tk.FLAT] 4 | 5 | class ButtonsApp(tk.Tk): 6 | def __init__(self): 7 | super().__init__() 8 | self.img = tk.PhotoImage(file="python.gif") 9 | self.btn = tk.Button(self, text="Button with image", 10 | image=self.img, compound=tk.LEFT, 11 | command=self.disable_btn) 12 | self.btns = [self.create_btn(r) for r in RELIEFS] 13 | self.btn.pack() 14 | for btn in self.btns: 15 | btn.pack(padx=10, pady=10, side=tk.LEFT) 16 | 17 | def create_btn(self, relief): 18 | return tk.Button(self, text=relief, relief=relief) 19 | 20 | def disable_btn(self): 21 | self.btn.config(state=tk.DISABLED) 22 | 23 | if __name__ == "__main__": 24 | app = ButtonsApp() 25 | app.mainloop() 26 | -------------------------------------------------------------------------------- /Chapter01/chapter1_03.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class LoginApp(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.username = tk.Entry(self) 7 | self.password = tk.Entry(self, show="*") 8 | self.login_btn = tk.Button(self, text="Log in", 9 | command=self.print_login) 10 | self.clear_btn = tk.Button(self, text="Clear", 11 | command=self.clear_form) 12 | self.username.pack() 13 | self.password.pack() 14 | self.login_btn.pack(fill=tk.BOTH) 15 | self.clear_btn.pack(fill=tk.BOTH) 16 | 17 | def print_login(self): 18 | print("Username: {}".format(self.username.get())) 19 | print("Password: {}".format(self.password.get())) 20 | 21 | def clear_form(self): 22 | self.username.delete(0, tk.END) 23 | self.password.delete(0, tk.END) 24 | self.username.focus_set() 25 | 26 | if __name__ == "__main__": 27 | app = LoginApp() 28 | app.mainloop() 29 | -------------------------------------------------------------------------------- /Chapter01/chapter1_04.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.var = tk.StringVar() 7 | self.var.trace("w", self.show_message) 8 | self.entry = tk.Entry(self, textvariable=self.var) 9 | self.btn = tk.Button(self, text="Clear", 10 | command=lambda: self.var.set("")) 11 | self.label = tk.Label(self) 12 | self.entry.pack() 13 | self.btn.pack() 14 | self.label.pack() 15 | 16 | def show_message(self, *args): 17 | value = self.var.get() 18 | text = "Hello, {}!".format(value) if value else "" 19 | self.label.config(text=text) 20 | 21 | if __name__ == "__main__": 22 | app = App() 23 | app.mainloop() 24 | -------------------------------------------------------------------------------- /Chapter01/chapter1_05.py: -------------------------------------------------------------------------------- 1 | import re 2 | import tkinter as tk 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.pattern = re.compile("^\w{0,10}$") 8 | self.label = tk.Label(self, text="Enter your username") 9 | vcmd = (self.register(self.validate_username), "%i", "%P") 10 | self.entry = tk.Entry(self, validate="key", 11 | validatecommand=vcmd, 12 | invalidcommand=self.print_error) 13 | self.label.pack() 14 | self.entry.pack(anchor=tk.W, padx=10, pady=10) 15 | 16 | def validate_username(self, index, username): 17 | print("Modification at index " + index) 18 | return self.pattern.match(username) is not None 19 | 20 | def print_error(self): 21 | print("Invalid username character") 22 | 23 | if __name__ == "__main__": 24 | app = App() 25 | app.mainloop() 26 | -------------------------------------------------------------------------------- /Chapter01/chapter1_06.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.spinbox = tk.Spinbox(self, from_=0, to=5) 7 | self.scale = tk.Scale(self, from_=0, to=5, 8 | orient=tk.HORIZONTAL) 9 | self.btn = tk.Button(self, text="Print values", 10 | command=self.print_values) 11 | self.spinbox.pack() 12 | self.scale.pack() 13 | self.btn.pack() 14 | 15 | def print_values(self): 16 | print("Spinbox: {}".format(self.spinbox.get())) 17 | print("Scale: {}".format(self.scale.get())) 18 | 19 | if __name__ == "__main__": 20 | app = App() 21 | app.mainloop() 22 | -------------------------------------------------------------------------------- /Chapter01/chapter1_07.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | COLORS = [("Red", "red"), ("Green", "green"), ("Blue", "blue")] 4 | 5 | class ChoiceApp(tk.Tk): 6 | def __init__(self): 7 | super().__init__() 8 | self.var = tk.StringVar() 9 | self.var.set("red") 10 | self.buttons = [self.create_radio(c) for c in COLORS] 11 | for button in self.buttons: 12 | button.pack(anchor=tk.W, padx=10, pady=5) 13 | 14 | def create_radio(self, option): 15 | text, value = option 16 | return tk.Radiobutton(self, text=text, value=value, 17 | command=self.print_option, 18 | variable=self.var) 19 | 20 | def print_option(self): 21 | print(self.var.get()) 22 | 23 | if __name__ == "__main__": 24 | app = ChoiceApp() 25 | app.mainloop() 26 | -------------------------------------------------------------------------------- /Chapter01/chapter1_08.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class SwitchApp(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.var = tk.IntVar() 7 | self.cb = tk.Checkbutton(self, text="Active?", 8 | variable=self.var, 9 | command=self.print_value) 10 | self.cb.pack() 11 | 12 | def print_value(self): 13 | print(self.var.get()) 14 | 15 | if __name__ == "__main__": 16 | app = SwitchApp() 17 | app.mainloop() 18 | -------------------------------------------------------------------------------- /Chapter01/chapter1_09.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", 4 | "Friday", "Saturday", "Sunday"] 5 | MODES = [tk.SINGLE, tk.BROWSE, tk.MULTIPLE, tk.EXTENDED] 6 | 7 | class ListApp(tk.Tk): 8 | def __init__(self): 9 | super().__init__() 10 | self.list = tk.Listbox(self) 11 | self.list.insert(0, *DAYS) 12 | self.print_btn = tk.Button(self, text="Print selection", 13 | command=self.print_selection) 14 | self.btns = [self.create_btn(m) for m in MODES] 15 | 16 | self.list.pack() 17 | self.print_btn.pack(fill=tk.BOTH) 18 | for btn in self.btns: 19 | btn.pack(side=tk.LEFT) 20 | 21 | def create_btn(self, mode): 22 | cmd = lambda: self.list.config(selectmode=mode) 23 | return tk.Button(self, command=cmd, 24 | text=mode.capitalize()) 25 | 26 | def print_selection(self): 27 | selection = self.list.curselection() 28 | print([self.list.get(i) for i in selection]) 29 | 30 | if __name__ == "__main__": 31 | app = ListApp() 32 | app.mainloop() 33 | -------------------------------------------------------------------------------- /Chapter01/chapter1_10.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | frame = tk.Frame(self, bg="green", 7 | height=100, width=100) 8 | frame.bind("", self.print_event) 9 | frame.bind("", self.print_event) 10 | frame.bind("", self.print_event) 11 | frame.bind("", self.print_event) 12 | frame.bind("", self.print_event) 13 | frame.bind("", self.print_event) 14 | frame.pack(padx=50, pady=50) 15 | 16 | def print_event(self, event): 17 | position = "(x={}, y={})".format(event.x, event.y) 18 | print(event.type, "event", position) 19 | 20 | if __name__ == "__main__": 21 | app = App() 22 | app.mainloop() 23 | -------------------------------------------------------------------------------- /Chapter01/chapter1_11.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | entry = tk.Entry(self) 7 | entry.bind("", self.print_type) 8 | entry.bind("", self.print_key) 9 | entry.pack(padx=20, pady=20) 10 | 11 | def print_type(self, event): 12 | print(event.type) 13 | 14 | def print_key(self, event): 15 | args = event.keysym, event.keycode, event.char 16 | print("Symbol: {}, Code: {}, Char: {}".format(*args)) 17 | 18 | if __name__ == "__main__": 19 | app = App() 20 | app.mainloop() 21 | -------------------------------------------------------------------------------- /Chapter01/chapter1_12.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.title("My Tkinter app") 7 | self.iconbitmap("python.ico") 8 | self.geometry("400x200+10+10") 9 | 10 | if __name__ == "__main__": 11 | app = App() 12 | app.mainloop() 13 | -------------------------------------------------------------------------------- /Chapter01/python.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter01/python.gif -------------------------------------------------------------------------------- /Chapter01/python.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter01/python.ico -------------------------------------------------------------------------------- /Chapter02/code/chapter2_01.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class ListFrame(tk.Frame): 4 | def __init__(self, master, items=[]): 5 | super().__init__(master) 6 | self.list = tk.Listbox(self) 7 | self.scroll = tk.Scrollbar(self, orient=tk.VERTICAL, 8 | command=self.list.yview) 9 | self.list.config(yscrollcommand=self.scroll.set) 10 | self.list.insert(0, *items) 11 | self.list.pack(side=tk.LEFT) 12 | self.scroll.pack(side=tk.LEFT, fill=tk.Y) 13 | 14 | def pop_selection(self): 15 | index = self.list.curselection() 16 | if index: 17 | value = self.list.get(index) 18 | self.list.delete(index) 19 | return value 20 | 21 | def insert_item(self, item): 22 | self.list.insert(tk.END, item) 23 | 24 | class App(tk.Tk): 25 | def __init__(self): 26 | super().__init__() 27 | months = ["January", "February", "March", "April", 28 | "May", "June", "July", "August", "September", 29 | "October", "November", "December"] 30 | self.frame_a = ListFrame(self, months) 31 | self.frame_b = ListFrame(self) 32 | self.btn_right = tk.Button(self, text=">", 33 | command=self.move_right) 34 | self.btn_left = tk.Button(self, text="<", 35 | command=self.move_left) 36 | 37 | self.frame_a.pack(side=tk.LEFT, padx=10, pady=10) 38 | self.frame_b.pack(side=tk.RIGHT, padx=10, pady=10) 39 | self.btn_right.pack(expand=True, ipadx=5) 40 | self.btn_left.pack(expand=True, ipadx=5) 41 | 42 | def move_right(self): 43 | self.move(self.frame_a, self.frame_b) 44 | 45 | def move_left(self): 46 | self.move(self.frame_b, self.frame_a) 47 | 48 | def move(self, frame_from, frame_to): 49 | value = frame_from.pop_selection() 50 | if value: 51 | frame_to.insert_item(value) 52 | 53 | if __name__ == "__main__": 54 | app = App() 55 | app.mainloop() 56 | -------------------------------------------------------------------------------- /Chapter02/code/chapter2_02.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | label_a = tk.Label(self, text="Label A", bg="yellow") 7 | label_b = tk.Label(self, text="Label B", bg="orange") 8 | label_c = tk.Label(self, text="Label C", bg="red") 9 | label_d = tk.Label(self, text="Label D", bg="green") 10 | label_e = tk.Label(self, text="Label E", bg="blue") 11 | 12 | opts = { 'ipadx': 10, 'ipady': 10, 'fill': tk.BOTH } 13 | label_a.pack(side=tk.TOP, **opts) 14 | label_b.pack(side=tk.TOP, **opts) 15 | label_c.pack(side=tk.LEFT, **opts) 16 | label_d.pack(side=tk.LEFT, **opts) 17 | label_e.pack(side=tk.LEFT, **opts) 18 | 19 | if __name__ == "__main__": 20 | app = App() 21 | app.mainloop() 22 | -------------------------------------------------------------------------------- /Chapter02/code/chapter2_03.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | label_a = tk.Label(self, text="Label A", bg="yellow") 7 | label_b = tk.Label(self, text="Label B", bg="orange") 8 | label_c = tk.Label(self, text="Label C", bg="red") 9 | label_d = tk.Label(self, text="Label D", bg="green") 10 | label_e = tk.Label(self, text="Label E", bg="blue") 11 | 12 | opts = { 'ipadx': 10, 'ipady': 10 , 'sticky': 'nswe' } 13 | label_a.grid(row=0, column=0, **opts) 14 | label_b.grid(row=1, column=0, **opts) 15 | label_c.grid(row=0, column=1, rowspan=2, **opts) 16 | label_d.grid(row=0, column=2, rowspan=2, **opts) 17 | label_e.grid(row=2, column=0, columnspan=3, **opts) 18 | 19 | if __name__ == "__main__": 20 | app = App() 21 | app.mainloop() 22 | -------------------------------------------------------------------------------- /Chapter02/code/chapter2_04.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | label_a = tk.Label(self, text="Label A", bg="yellow") 7 | label_b = tk.Label(self, text="Label B", bg="orange") 8 | label_c = tk.Label(self, text="Label C", bg="red") 9 | label_d = tk.Label(self, text="Label D", bg="green") 10 | label_e = tk.Label(self, text="Label E", bg="blue") 11 | 12 | label_a.place(relwidth=0.25, relheight=0.25) 13 | label_b.place(x=100, anchor=tk.N, 14 | width=100, height=50) 15 | label_c.place(relx=0.5, rely=0.5, anchor=tk.CENTER, 16 | relwidth=0.5, relheight=0.5) 17 | label_d.place(in_=label_c, anchor=tk.N + tk.W, 18 | x=2, y=2, relx=0.5, rely=0.5, 19 | relwidth=0.5, relheight=0.5) 20 | label_e.place(x=200, y=200, anchor=tk.S + tk.E, 21 | relwidth=0.25, relheight=0.25) 22 | 23 | if __name__ == "__main__": 24 | app = App() 25 | app.mainloop() 26 | -------------------------------------------------------------------------------- /Chapter02/code/chapter2_05.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | group_1 = tk.LabelFrame(self, padx=15, pady=10, 7 | text="Personal Information") 8 | group_1.pack(padx=10, pady=5) 9 | 10 | tk.Label(group_1, text="First name").grid(row=0) 11 | tk.Label(group_1, text="Last name").grid(row=1) 12 | tk.Entry(group_1).grid(row=0, column=1, sticky=tk.W) 13 | tk.Entry(group_1).grid(row=1, column=1, sticky=tk.W) 14 | 15 | group_2 = tk.LabelFrame(self, padx=15, pady=10, 16 | text="Address") 17 | group_2.pack(padx=10, pady=5) 18 | 19 | tk.Label(group_2, text="Street").grid(row=0) 20 | tk.Label(group_2, text="City").grid(row=1) 21 | tk.Label(group_2, text="ZIP Code").grid(row=2) 22 | tk.Entry(group_2).grid(row=0, column=1, sticky=tk.W) 23 | tk.Entry(group_2).grid(row=1, column=1, sticky=tk.W) 24 | tk.Entry(group_2, width=8).grid(row=2, column=1, 25 | sticky=tk.W) 26 | 27 | self.btn_submit = tk.Button(self, text="Submit") 28 | self.btn_submit.pack(padx=10, pady=10, side=tk.RIGHT) 29 | 30 | if __name__ == "__main__": 31 | app = App() 32 | app.mainloop() 33 | -------------------------------------------------------------------------------- /Chapter02/code/chapter2_06.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | fields = ["First name", "Last name", "Phone", "Email"] 7 | labels = [tk.Label(self, text=f) for f in fields] 8 | entries = [tk.Entry(self) for _ in fields] 9 | self.widgets = list(zip(labels, entries)) 10 | self.submit = tk.Button(self, text="Print info", 11 | command=self.print_info) 12 | 13 | for i, (label, entry) in enumerate(self.widgets): 14 | label.grid(row=i, column=0, padx=10, sticky=tk.W) 15 | entry.grid(row=i, column=1, padx=10, pady=5) 16 | self.submit.grid(row=len(fields), column=1, sticky=tk.E, 17 | padx=10, pady=10) 18 | 19 | def print_info(self): 20 | for label, entry in self.widgets: 21 | print("{} = {}".format(label.cget("text"), "=", entry.get())) 22 | 23 | if __name__ == "__main__": 24 | app = App() 25 | app.mainloop() 26 | -------------------------------------------------------------------------------- /Chapter02/code/chapter2_07.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.scroll_x = tk.Scrollbar(self, orient=tk.HORIZONTAL) 7 | self.scroll_y = tk.Scrollbar(self, orient=tk.VERTICAL) 8 | self.canvas = tk.Canvas(self, width=300, height=100, 9 | xscrollcommand=self.scroll_x.set, 10 | yscrollcommand=self.scroll_y.set) 11 | self.scroll_x.config(command=self.canvas.xview) 12 | self.scroll_y.config(command=self.canvas.yview) 13 | 14 | self.frame = tk.Frame(self.canvas) 15 | self.btn = tk.Button(self.frame, text="Load image", 16 | command=self.load_image) 17 | self.btn.pack() 18 | 19 | self.canvas.create_window((0, 0), window=self.frame, 20 | anchor=tk.N + tk.W) 21 | 22 | self.canvas.grid(row=0, column=0, sticky="nswe") 23 | self.scroll_x.grid(row=1, column=0, sticky="we") 24 | self.scroll_y.grid(row=0, column=1, sticky="ns") 25 | 26 | self.rowconfigure(0, weight=1) 27 | self.columnconfigure(0, weight=1) 28 | self.bind("", self.resize) 29 | self.update_idletasks() 30 | self.minsize(self.winfo_width(), self.winfo_height()) 31 | 32 | def resize(self, event): 33 | region = self.canvas.bbox(tk.ALL) 34 | self.canvas.configure(scrollregion=region) 35 | 36 | def load_image(self): 37 | self.btn.destroy() 38 | self.image = tk.PhotoImage(file="python.gif") 39 | tk.Label(self.frame, image=self.image).pack() 40 | 41 | if __name__ == "__main__": 42 | app = App() 43 | app.mainloop() 44 | -------------------------------------------------------------------------------- /Chapter02/code/python.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter02/code/python.gif -------------------------------------------------------------------------------- /Chapter03/code/chapter3_01.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | 3 | import tkinter as tk 4 | from tkinter.colorchooser import askcolor 5 | 6 | class App(tk.Tk): 7 | def __init__(self): 8 | super().__init__() 9 | self.title("Colors demo") 10 | text = "The quick brown fox jumps over the lazy dog" 11 | self.label = tk.Label(self, text=text) 12 | self.fg_btn = tk.Button(self, text="Set foreground color", 13 | command=partial(self.set_color, "fg")) 14 | self.bg_btn = tk.Button(self, text="Set background color", 15 | command=partial(self.set_color, "bg")) 16 | 17 | self.label.pack(padx=20, pady=20) 18 | self.fg_btn.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) 19 | self.bg_btn.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) 20 | 21 | def set_color(self, option): 22 | color = askcolor()[1] 23 | print("Chosen color:", color) 24 | self.label.config(**{option: color}) 25 | 26 | if __name__ == "__main__": 27 | app = App() 28 | app.mainloop() 29 | -------------------------------------------------------------------------------- /Chapter03/code/chapter3_02.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.title("Fonts demo") 7 | text = "The quick brown fox jumps over the lazy dog" 8 | self.label = tk.Label(self, text=text) 9 | 10 | self.family = tk.StringVar() 11 | self.family.trace("w", self.set_font) 12 | families = ("Times", "Courier", "Helvetica") 13 | self.option = tk.OptionMenu(self, self.family, *families) 14 | 15 | self.size = tk.StringVar() 16 | self.size.trace("w", self.set_font) 17 | self.spinbox = tk.Spinbox(self, from_=8, to=18, 18 | textvariable=self.size) 19 | 20 | self.family.set(families[0]) 21 | self.size.set("10") 22 | self.label.pack(padx=20, pady=20) 23 | self.option.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) 24 | self.spinbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) 25 | 26 | def set_font(self, *args): 27 | family = self.family.get() 28 | size = self.size.get() 29 | self.label.config(font=(family, size)) 30 | 31 | if __name__ == "__main__": 32 | app = App() 33 | app.mainloop() 34 | -------------------------------------------------------------------------------- /Chapter03/code/chapter3_03.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.title("Options demo") 7 | self.option_add("*font", "helvetica 10") 8 | self.option_add("*header.font", "helvetica 18 bold") 9 | self.option_add("*subtitle.font", "helvetica 14 italic") 10 | self.option_add("*Button.foreground", "blue") 11 | self.option_add("*Button.background", "white") 12 | self.option_add("*Button.activeBackground", "gray") 13 | self.option_add("*Button.activeForeground", "black") 14 | 15 | self.create_label(name="header", text="This is the header") 16 | self.create_label(name="subtitle", text="This is the subtitle") 17 | self.create_label(text="This is a paragraph") 18 | self.create_label(text="This is another paragraph") 19 | self.create_button(text="See more") 20 | 21 | def create_label(self, **options): 22 | tk.Label(self, **options).pack(padx=20, pady=5, anchor=tk.W) 23 | 24 | def create_button(self, **options): 25 | tk.Button(self, **options).pack(padx=5, pady=5, anchor=tk.E) 26 | 27 | if __name__ == "__main__": 28 | app = App() 29 | app.mainloop() 30 | -------------------------------------------------------------------------------- /Chapter03/code/chapter3_04.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.title("Cursors demo") 7 | self.resizable(0, 0) 8 | self.label = tk.Label(self, text="Click the button to start") 9 | self.btn_launch = tk.Button(self, text="Start!", 10 | command=self.perform_action) 11 | self.btn_help = tk.Button(self, text="Help", 12 | cursor="question_arrow") 13 | 14 | btn_opts = {"side": tk.LEFT, "expand":True, "fill": tk.X, 15 | "ipadx": 30, "padx": 20, "pady": 5} 16 | self.label.pack(pady=10) 17 | self.btn_launch.pack(**btn_opts) 18 | self.btn_help.pack(**btn_opts) 19 | 20 | def perform_action(self): 21 | self.btn_launch.config(state=tk.DISABLED) 22 | self.btn_help.config(state=tk.DISABLED) 23 | self.label.config(text="Working...") 24 | self.after(3000, self.end_action) 25 | self.config(cursor="watch") 26 | 27 | def end_action(self): 28 | self.btn_launch.config(state=tk.NORMAL) 29 | self.btn_help.config(state=tk.NORMAL) 30 | self.label.config(text="Done!") 31 | self.config(cursor="arrow") 32 | 33 | def set_watch_cursor(self, widget): 34 | widget._old_cursor = widget.cget("cursor") 35 | widget.config(cursor="watch") 36 | for w in widget.winfo_children(): 37 | self.set_watch_cursor(w) 38 | 39 | def restore_cursor(self, widget): 40 | widget.config(cursor=widget.old_cursor) 41 | for w in widget.winfo_children(): 42 | self.restore_cursor(w) 43 | 44 | if __name__ == "__main__": 45 | app = App() 46 | app.mainloop() 47 | -------------------------------------------------------------------------------- /Chapter03/code/chapter3_05.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.title("Text demo") 7 | self.resizable(0, 0) 8 | self.text = tk.Text(self, width=50, height=10) 9 | self.btn_clear = tk.Button(self, text="Clear text", 10 | command=self.clear_text) 11 | self.btn_insert = tk.Button(self, text="Insert text", 12 | command=self.insert_text) 13 | self.btn_print = tk.Button(self, text="Print selection", 14 | command=self.print_selection) 15 | self.text.pack() 16 | self.btn_clear.pack(side=tk.LEFT, expand=True, pady=10) 17 | self.btn_insert.pack(side=tk.LEFT, expand=True, pady=10) 18 | self.btn_print.pack(side=tk.LEFT, expand=True, pady=10) 19 | 20 | def clear_text(self): 21 | self.text.delete("1.0", tk.END) 22 | 23 | def insert_text(self): 24 | self.text.insert(tk.INSERT, "Hello, world") 25 | 26 | def print_selection(self): 27 | selection = self.text.tag_ranges(tk.SEL) 28 | if selection: 29 | content = self.text.get(*selection) 30 | print(content) 31 | 32 | if __name__ == "__main__": 33 | app = App() 34 | app.mainloop() 35 | -------------------------------------------------------------------------------- /Chapter03/code/chapter3_06.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import webbrowser 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.title("Text tags demo") 8 | self.text = tk.Text(self, width=50, height=10) 9 | self.btn_link = tk.Button(self, text="Add hyperlink", 10 | command=self.add_hyperlink) 11 | 12 | self.text.tag_config("link", foreground="blue", underline=1) 13 | self.text.tag_bind("link", "", self.open_link) 14 | self.text.tag_bind("link", "", 15 | lambda _: self.text.config(cursor="hand2")) 16 | self.text.tag_bind("link", "", 17 | lambda e: self.text.config(cursor="")) 18 | 19 | self.text.pack() 20 | self.btn_link.pack(expand=True) 21 | 22 | def add_hyperlink(self): 23 | selection = self.text.tag_ranges(tk.SEL) 24 | if selection: 25 | self.text.tag_add("link", *selection) 26 | 27 | def open_link(self, event): 28 | position = "@{},{} + 1c".format(event.x, event.y) 29 | index = self.text.index(position) 30 | prevrange = self.text.tag_prevrange("link", index) 31 | url = self.text.get(*prevrange) 32 | webbrowser.open(url) 33 | 34 | if __name__ == "__main__": 35 | app = App() 36 | app.mainloop() 37 | 38 | -------------------------------------------------------------------------------- /Chapter03/images/B09199_03_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter03/images/B09199_03_01.png -------------------------------------------------------------------------------- /Chapter03/images/B09199_03_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter03/images/B09199_03_03.png -------------------------------------------------------------------------------- /Chapter03/images/B09199_03_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter03/images/B09199_03_04.png -------------------------------------------------------------------------------- /Chapter03/images/B09199_03_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter03/images/B09199_03_05.png -------------------------------------------------------------------------------- /Chapter03/images/B09199_03_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter03/images/B09199_03_06.png -------------------------------------------------------------------------------- /Chapter03/images/B09199_03_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter03/images/B09199_03_07.png -------------------------------------------------------------------------------- /Chapter04/code/chapter4_01.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter.messagebox as mb 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | btn_info = tk.Button(self, text="Show Info", 8 | command=self.show_info) 9 | btn_warn = tk.Button(self, text="Show Warning", 10 | command=self.show_warning) 11 | btn_error = tk.Button(self, text="Show Error", 12 | command=self.show_error) 13 | 14 | opts = {'padx': 40, 'pady': 5, 'expand': True, 'fill': tk.BOTH} 15 | btn_info.pack(**opts) 16 | btn_warn.pack(**opts) 17 | btn_error.pack(**opts) 18 | 19 | def show_info(self): 20 | msg = "Your user preferences have been saved" 21 | mb.showinfo("Information", msg) 22 | 23 | def show_warning(self): 24 | msg = "Temporary files have not been correctly removed" 25 | mb.showwarning("Warning", msg) 26 | 27 | def show_error(self): 28 | msg = "The application has encountered an unknown error" 29 | mb.showerror("Error", msg) 30 | 31 | if __name__ == "__main__": 32 | app = App() 33 | app.mainloop() 34 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_02.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter.messagebox as mb 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.create_button(mb.askyesno, "Ask Yes/No", 8 | "Returns True or False") 9 | self.create_button(mb.askquestion, "Ask a question", 10 | "Returns 'yes' or 'no'") 11 | self.create_button(mb.askokcancel, "Ask Ok/Cancel", 12 | "Returns True or False") 13 | self.create_button(mb.askretrycancel, "Ask Retry/Cancel", 14 | "Returns True or False") 15 | self.create_button(mb.askyesnocancel, "Ask Yes/No/Cancel", 16 | "Returns True, False or None") 17 | 18 | def create_button(self, dialog, title, message): 19 | command = lambda: print(dialog(title, message)) 20 | btn = tk.Button(self, text=title, command=command) 21 | btn.pack(padx=40, pady=5, expand=True, fill=tk.BOTH) 22 | 23 | if __name__ == "__main__": 24 | app = App() 25 | app.mainloop() 26 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_03.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter.filedialog as fd 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | btn_file = tk.Button(self, text="Choose file", 8 | command=self.choose_file) 9 | btn_dir = tk.Button(self, text="Choose directory", 10 | command=self.choose_directory) 11 | btn_file.pack(padx=60, pady=10) 12 | btn_dir.pack(padx=60, pady=10) 13 | 14 | def choose_file(self): 15 | filetypes = (("Plain text files", "*.txt"), 16 | ("Images", "*.jpg *.gif *.png"), 17 | ("All files", "*")) 18 | filename = fd.askopenfilename(title="Open file", initialdir="/", 19 | filetypes=filetypes) 20 | if filename: 21 | print(filename) 22 | 23 | def choose_directory(self): 24 | directory = fd.askdirectory(title="Open directory", initialdir="/") 25 | if directory: 26 | print(directory) 27 | 28 | if __name__ == "__main__": 29 | app = App() 30 | app.mainloop() 31 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_04.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter.filedialog as fd 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.text = tk.Text(self, height=10, width=50) 8 | self.btn_save = tk.Button(self, text="Save", command=self.save_file) 9 | 10 | self.text.pack() 11 | self.btn_save.pack(pady=10, ipadx=5) 12 | 13 | def save_file(self): 14 | contents = self.text.get(1.0, tk.END) 15 | new_file = fd.asksaveasfile(title="Save file", defaultextension=".txt", 16 | filetypes=(("Text files", "*.txt"),)) 17 | if new_file: 18 | new_file.write(contents) 19 | new_file.close() 20 | 21 | if __name__ == "__main__": 22 | app = App() 23 | app.mainloop() 24 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_05.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | menu = tk.Menu(self) 7 | file_menu = tk.Menu(menu, tearoff=0) 8 | 9 | file_menu.add_command(label="New file") 10 | file_menu.add_command(label="Open") 11 | file_menu.add_separator() 12 | file_menu.add_command(label="Save") 13 | file_menu.add_command(label="Save as...") 14 | 15 | menu.add_cascade(label="File", menu=file_menu) 16 | menu.add_command(label="About") 17 | menu.add_command(label="Quit", command=self.destroy) 18 | self.config(menu=menu) 19 | 20 | if __name__ == "__main__": 21 | app = App() 22 | app.mainloop() 23 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_06.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.checked = tk.BooleanVar() 7 | self.checked.trace("w", self.mark_checked) 8 | self.radio = tk.StringVar() 9 | self.radio.set("1") 10 | self.radio.trace("w", self.mark_radio) 11 | 12 | menu = tk.Menu(self) 13 | submenu = tk.Menu(menu, tearoff=0) 14 | 15 | submenu.add_checkbutton(label="Checkbutton", onvalue=True, 16 | offvalue=False, variable=self.checked) 17 | submenu.add_separator() 18 | submenu.add_radiobutton(label="Radio 1", value="1", 19 | variable=self.radio) 20 | submenu.add_radiobutton(label="Radio 2", value="2", 21 | variable=self.radio) 22 | submenu.add_radiobutton(label="Radio 3", value="3", 23 | variable=self.radio) 24 | 25 | menu.add_cascade(label="Options", menu=submenu) 26 | menu.add_command(label="Quit", command=self.destroy) 27 | self.config(menu=menu) 28 | 29 | def mark_checked(self, *args): 30 | print(self.checked.get()) 31 | 32 | def mark_radio(self, *args): 33 | print(self.radio.get()) 34 | 35 | if __name__ == "__main__": 36 | app = App() 37 | app.mainloop() 38 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_07.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.menu = tk.Menu(self, tearoff=0) 7 | self.menu.add_command(label="Cut", command=self.cut_text) 8 | self.menu.add_command(label="Copy", command=self.copy_text) 9 | self.menu.add_command(label="Paste", command=self.paste_text) 10 | self.menu.add_command(label="Delete", command=self.delete_text) 11 | 12 | self.text = tk.Text(self, height=10, width=50) 13 | self.text.bind("", self.show_popup) 14 | self.text.pack() 15 | 16 | def show_popup(self, event): 17 | self.menu.post(event.x_root, event.y_root) 18 | 19 | def cut_text(self): 20 | self.copy_text() 21 | self.delete_text() 22 | 23 | def copy_text(self): 24 | selection = self.text.tag_ranges(tk.SEL) 25 | if selection: 26 | self.clipboard_clear() 27 | self.clipboard_append(self.text.get(*selection)) 28 | 29 | def paste_text(self): 30 | self.text.insert(tk.INSERT, self.clipboard_get()) 31 | 32 | def delete_text(self): 33 | selection = self.text.tag_ranges(tk.SEL) 34 | if selection: 35 | self.text.delete(*selection) 36 | 37 | 38 | if __name__ == "__main__": 39 | app = App() 40 | app.mainloop() 41 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_07_disabled.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | class App(tk.Tk): 3 | def __init__(self): 4 | super().__init__() 5 | self.menu = tk.Menu(self, tearoff=0, postcommand=self.enable_selection) 6 | self.menu.add_command(label="Cut", command=self.cut_text) 7 | self.menu.add_command(label="Copy", command=self.copy_text) 8 | self.menu.add_command(label="Paste", command=self.paste_text) 9 | self.menu.add_command(label="Delete", command=self.delete_text) 10 | 11 | self.text = tk.Text(self, height=10, width=50) 12 | self.text.bind("", self.show_popup) 13 | self.text.pack() 14 | def enable_selection(self): 15 | state_selection = tk.ACTIVE if self.text.tag_ranges(tk.SEL) else tk.DISABLED 16 | state_clipboard = tk.ACTIVE 17 | 18 | try: 19 | self.clipboard_get() 20 | except tk.TclError: 21 | state_clipboard = tk.DISABLED 22 | 23 | self.menu.entryconfig(0, state=state_selection) # Cut 24 | self.menu.entryconfig(1, state=state_selection) # Copy 25 | self.menu.entryconfig(2, state=state_clipboard) # Paste 26 | self.menu.entryconfig(3, state=state_selection) # Delete 27 | 28 | 29 | 30 | def show_popup(self, event): 31 | self.menu.post(event.x_root, event.y_root) 32 | 33 | def cut_text(self): 34 | self.copy_text() 35 | self.delete_text() 36 | 37 | def copy_text(self): 38 | selection = self.text.tag_ranges(tk.SEL) 39 | if selection: 40 | self.clipboard_clear() 41 | self.clipboard_append(self.text.get(*selection)) 42 | 43 | def paste_text(self): 44 | self.text.insert(tk.INSERT, self.clipboard_get()) 45 | 46 | def delete_text(self): 47 | selection = self.text.tag_ranges(tk.SEL) 48 | if selection: 49 | self.text.delete(*selection) 50 | 51 | 52 | if __name__ == "__main__": 53 | app = App() 54 | app.mainloop() 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_08.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class About(tk.Toplevel): 4 | def __init__(self, parent): 5 | super().__init__(parent) 6 | self.label = tk.Label(self, text="This is another window") 7 | self.button = tk.Button(self, text="Close", command=self.destroy) 8 | 9 | self.label.pack(padx=20, pady=20) 10 | self.button.pack(pady=5, ipadx=2, ipady=2) 11 | 12 | class App(tk.Tk): 13 | def __init__(self): 14 | super().__init__() 15 | self.btn = tk.Button(self, text="Open new window", 16 | command=self.open_window) 17 | self.btn.pack(padx=50, pady=20) 18 | 19 | def open_window(self): 20 | about = About(self) 21 | about.grab_set() 22 | 23 | if __name__ == "__main__": 24 | app = App() 25 | app.mainloop() 26 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_09.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter.messagebox as mb 3 | 4 | class Window(tk.Toplevel): 5 | def __init__(self, parent): 6 | super().__init__(parent) 7 | self.protocol("WM_DELETE_WINDOW", self.confirm_delete) 8 | 9 | self.label = tk.Label(self, text="This is another window") 10 | self.button = tk.Button(self, text="Close", command=self.destroy) 11 | 12 | self.label.pack(padx=20, pady=20) 13 | self.button.pack(pady=5, ipadx=2, ipady=2) 14 | 15 | def confirm_delete(self): 16 | message = "Are you sure you want to close this window?" 17 | if mb.askyesno(message=message, parent=self): 18 | self.destroy() 19 | 20 | class App(tk.Tk): 21 | def __init__(self): 22 | super().__init__() 23 | self.btn = tk.Button(self, text="Open new window", 24 | command=self.open_about) 25 | self.btn.pack(padx=50, pady=20) 26 | 27 | def open_about(self): 28 | window = Window(self) 29 | window.grab_set() 30 | 31 | if __name__ == "__main__": 32 | app = App() 33 | app.mainloop() 34 | -------------------------------------------------------------------------------- /Chapter04/code/chapter4_10.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from collections import namedtuple 3 | 4 | User = namedtuple("User", ["username", "password", "user_type"]) 5 | 6 | class UserForm(tk.Toplevel): 7 | def __init__(self, parent, user_type): 8 | super().__init__(parent) 9 | self.username = tk.StringVar() 10 | self.password = tk.StringVar() 11 | self.user_type = user_type 12 | 13 | label = tk.Label(self, text="Create a new " + user_type.lower()) 14 | entry_name = tk.Entry(self, textvariable=self.username) 15 | entry_pass = tk.Entry(self, textvariable=self.password, show="*") 16 | btn = tk.Button(self, text="Submit", command=self.destroy) 17 | 18 | label.grid(row=0, columnspan=2) 19 | tk.Label(self, text="Username:").grid(row=1, column=0) 20 | tk.Label(self, text="Password:").grid(row=2, column=0) 21 | entry_name.grid(row=1, column=1) 22 | entry_pass.grid(row=2, column=1) 23 | btn.grid(row=3, columnspan=2) 24 | 25 | def open(self): 26 | self.grab_set() 27 | self.wait_window() 28 | username = self.username.get() 29 | password = self.password.get() 30 | return User(username, password, self.user_type) 31 | 32 | 33 | class App(tk.Tk): 34 | def __init__(self): 35 | super().__init__() 36 | user_types = ("Administrator", "Supervisor", "Regular user") 37 | self.user_type = tk.StringVar() 38 | self.user_type.set(user_types[0]) 39 | 40 | label = tk.Label(self, text="Please, select the type of user") 41 | radios = [tk.Radiobutton(self, text=t, value=t, \ 42 | variable=self.user_type) for t in user_types] 43 | btn = tk.Button(self, text="Create user", command=self.open_window) 44 | 45 | label.pack(padx=10, pady=10) 46 | for radio in radios: 47 | radio.pack(padx=10, anchor=tk.W) 48 | btn.pack(pady=10) 49 | 50 | def open_window(self): 51 | window = UserForm(self, self.user_type.get()) 52 | user = window.open() 53 | print(user) 54 | 55 | if __name__ == "__main__": 56 | app = App() 57 | app.mainloop() 58 | -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_01.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_02.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_03.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_04.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_05.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_06.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_07.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_08.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_09.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_10.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_11.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_12.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_13.png -------------------------------------------------------------------------------- /Chapter04/images/B09199_04_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter04/images/B09199_04_14.png -------------------------------------------------------------------------------- /Chapter05/code/__pycache__/chapter5_01.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/code/__pycache__/chapter5_01.cpython-36.pyc -------------------------------------------------------------------------------- /Chapter05/code/__pycache__/chapter5_02.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/code/__pycache__/chapter5_02.cpython-36.pyc -------------------------------------------------------------------------------- /Chapter05/code/chapter5_01.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def required(value, message): 4 | if not value: 5 | raise ValueError(message) 6 | return value 7 | 8 | def matches(value, regex, message): 9 | if value and not regex.match(value): 10 | raise ValueError(message) 11 | return value 12 | 13 | class Contact(object): 14 | email_regex = re.compile(r"[^@]+@[^@]+\.[^@]+") 15 | phone_regex = re.compile(r"\([0-9]{3}\)\s[0-9]{7}") 16 | 17 | def __init__(self, last_name, first_name, email, phone): 18 | self.last_name = last_name 19 | self.first_name = first_name 20 | self.email = email 21 | self.phone = phone 22 | 23 | @property 24 | def last_name(self): 25 | return self._last_name 26 | 27 | @last_name.setter 28 | def last_name(self, value): 29 | self._last_name = required(value, "Last name is required") 30 | 31 | @property 32 | def first_name(self): 33 | return self._first_name 34 | 35 | @first_name.setter 36 | def first_name(self, value): 37 | self._first_name = required(value, "First name is required") 38 | 39 | @property 40 | def email(self): 41 | return self._email 42 | 43 | @email.setter 44 | def email(self, value): 45 | self._email = matches(value, self.email_regex, "Invalid email format") 46 | 47 | @property 48 | def phone(self): 49 | return self._phone 50 | 51 | @phone.setter 52 | def phone(self, value): 53 | self._phone = matches(value, self.phone_regex, "Invalid phone format") 54 | -------------------------------------------------------------------------------- /Chapter05/code/chapter5_01b.py: -------------------------------------------------------------------------------- 1 | import re 2 | import attr 3 | 4 | def required(message): 5 | def func(self, attr, val): 6 | if not val: raise ValueError(message) 7 | return func 8 | 9 | def match(pattern, message): 10 | regex = re.compile(pattern) 11 | def func(self, attr, val): 12 | if val and not regex.match(val): 13 | raise ValueError(message) 14 | return func 15 | 16 | @attr.s 17 | class Contact(object): 18 | last_name = attr.ib(validator=required("Last name is required")) 19 | first_name = attr.ib(validator=required("First name is required")) 20 | email = attr.ib(validator=match(r"[^@]+@[^@]+\.[^@]+", 21 | "Invalid email format")) 22 | phone = attr.ib(validator=match(r"\([0-9]{3}\)\s[0-9]{7}", 23 | "Invalid phone format")) 24 | -------------------------------------------------------------------------------- /Chapter05/code/chapter5_02.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter.messagebox as mb 3 | 4 | from chapter5_01 import Contact 5 | 6 | 7 | class ContactList(tk.Frame): 8 | def __init__(self, master, **kwargs): 9 | super().__init__(master) 10 | self.lb = tk.Listbox(self, **kwargs) 11 | scroll = tk.Scrollbar(self, command=self.lb.yview) 12 | 13 | self.lb.config(yscrollcommand=scroll.set) 14 | scroll.pack(side=tk.RIGHT, fill=tk.Y) 15 | self.lb.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) 16 | 17 | def insert(self, contact, index=tk.END): 18 | text = "{}, {}".format(contact.last_name, contact.first_name) 19 | self.lb.insert(index, text) 20 | 21 | def delete(self, index): 22 | self.lb.delete(index, index) 23 | 24 | def update(self, contact, index): 25 | self.delete(index) 26 | self.insert(contact, index) 27 | 28 | def bind_doble_click(self, callback): 29 | handler = lambda _: callback(self.lb.curselection()[0]) 30 | self.lb.bind("", handler) 31 | 32 | 33 | class ContactForm(tk.LabelFrame): 34 | fields = ("Last name", "First name", "Email", "Phone") 35 | 36 | def __init__(self, master, **kwargs): 37 | super().__init__(master, text="Contact", padx=10, pady=10, **kwargs) 38 | self.frame = tk.Frame(self) 39 | self.entries = list(map(self.create_field, enumerate(self.fields))) 40 | self.frame.pack() 41 | 42 | def create_field(self, field): 43 | position, text = field 44 | label = tk.Label(self.frame, text=text) 45 | entry = tk.Entry(self.frame, width=25) 46 | label.grid(row=position, column=0, pady=5) 47 | entry.grid(row=position, column=1, pady=5) 48 | return entry 49 | 50 | def load_details(self, contact): 51 | values = (contact.last_name, contact.first_name, 52 | contact.email, contact.phone) 53 | for entry, value in zip(self.entries, values): 54 | entry.delete(0, tk.END) 55 | entry.insert(0, value) 56 | 57 | def get_details(self): 58 | values = [e.get() for e in self.entries] 59 | try: 60 | return Contact(*values) 61 | except ValueError as e: 62 | mb.showerror("Validation error", str(e), parent=self) 63 | 64 | def clear(self): 65 | for entry in self.entries: 66 | entry.delete(0, tk.END) 67 | -------------------------------------------------------------------------------- /Chapter05/code/chapter5_03.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import tkinter as tk 3 | 4 | from chapter5_01 import Contact 5 | from chapter5_02 import ContactForm, ContactList 6 | 7 | 8 | class App(tk.Tk): 9 | def __init__(self): 10 | super().__init__() 11 | self.title("CSV Contact list") 12 | self.list = ContactList(self, height=12) 13 | self.form = ContactForm(self) 14 | self.contacts = self.load_contacts() 15 | 16 | for contact in self.contacts: 17 | self.list.insert(contact) 18 | self.list.pack(side=tk.LEFT, padx=10, pady=10) 19 | self.form.pack(side=tk.LEFT, padx=10, pady=10) 20 | self.list.bind_doble_click(self.show_contact) 21 | 22 | def load_contacts(self): 23 | with open("contacts.csv", encoding="utf-8", newline="") as f: 24 | return [Contact(*r) for r in csv.reader(f)] 25 | 26 | def show_contact(self, index): 27 | contact = self.contacts[index] 28 | self.form.load_details(contact) 29 | 30 | if __name__ == "__main__": 31 | app = App() 32 | app.mainloop() 33 | -------------------------------------------------------------------------------- /Chapter05/code/chapter5_03_book.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import tkinter as tk 3 | from chapter5_01 import Contact 4 | from chapter5_02 import ContactForm, ContactList 5 | class App(tk.Tk): 6 | def __init__(self): 7 | super().__init__() 8 | self.title("CSV Contact list") 9 | self.list = ContactList(self, height=12) 10 | self.form = ContactForm(self) 11 | self.contacts = self.load_contacts() 12 | for contact in self.contacts: 13 | self.list.insert(contact) 14 | self.list.pack(side=tk.LEFT, padx=10, pady=10) 15 | self.form.pack(side=tk.LEFT, padx=10, pady=10) 16 | self.list.bind_doble_click(self.show_contact) 17 | def load_contacts(self): 18 | with open("contacts.csv") as f: 19 | return [Contact(*r) for r in csv.reader(f)] 20 | def show_contact(self, index): 21 | contact = self.contacts[index] 22 | self.form.load_details(contact) 23 | if __name__ == "__main__": 24 | app = App() 25 | app.mainloop() -------------------------------------------------------------------------------- /Chapter05/code/chapter5_04.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | import tkinter as tk 3 | 4 | from chapter5_01 import Contact 5 | from chapter5_02 import ContactForm, ContactList 6 | 7 | 8 | class NewContact(tk.Toplevel): 9 | def __init__(self, parent): 10 | super().__init__(parent) 11 | self.contact = None 12 | self.form = ContactForm(self) 13 | self.btn_add = tk.Button(self, text="Confirm", command=self.confirm) 14 | self.form.pack(padx=10, pady=10) 15 | self.btn_add.pack(pady=10) 16 | 17 | def confirm(self): 18 | self.contact = self.form.get_details() 19 | if self.contact: 20 | self.destroy() 21 | 22 | def show(self): 23 | self.grab_set() 24 | self.wait_window() 25 | return self.contact 26 | 27 | 28 | class UpdateContactForm(ContactForm): 29 | def __init__(self, master, **kwargs): 30 | super().__init__(master, **kwargs) 31 | self.btn_save = tk.Button(self, text="Save") 32 | self.btn_delete = tk.Button(self, text="Delete") 33 | 34 | self.btn_save.pack(side=tk.RIGHT, ipadx=5, padx=5, pady=5) 35 | self.btn_delete.pack(side=tk.RIGHT, ipadx=5, padx=5, pady=5) 36 | 37 | def bind_save(self, callback): 38 | self.btn_save.config(command=callback) 39 | 40 | def bind_delete(self, callback): 41 | self.btn_delete.config(command=callback) 42 | 43 | 44 | class App(tk.Tk): 45 | def __init__(self, conn): 46 | super().__init__() 47 | self.title("SQLite Contacts list") 48 | self.conn = conn 49 | self.selection = None 50 | self.list = ContactList(self, height=15) 51 | self.form = UpdateContactForm(self) 52 | self.btn_new = tk.Button(self, text="Add new contact", 53 | command=self.add_contact) 54 | self.contacts = self.load_contacts() 55 | 56 | for contact in self.contacts: 57 | self.list.insert(contact) 58 | self.list.pack(side=tk.LEFT, padx=10, pady=10) 59 | self.form.pack(padx=10, pady=10) 60 | self.btn_new.pack(side=tk.BOTTOM, pady=5) 61 | 62 | self.list.bind_doble_click(self.show_contact) 63 | self.form.bind_save(self.update_contact) 64 | self.form.bind_delete(self.delete_contact) 65 | 66 | def load_contacts(self): 67 | contacts = [] 68 | sql = "SELECT rowid, last_name, first_name, email, phone FROM contacts" 69 | for row in self.conn.execute(sql): 70 | contact = Contact(*row[1:]) 71 | contact.rowid = row[0] 72 | contacts.append(contact) 73 | return contacts 74 | 75 | def show_contact(self, index): 76 | self.selection = index 77 | contact = self.contacts[index] 78 | self.form.load_details(contact) 79 | 80 | def to_values(self, c): 81 | return (c.last_name, c.first_name, c.email, c.phone) 82 | 83 | def add_contact(self): 84 | new_contact = NewContact(self) 85 | contact = new_contact.show() 86 | if not contact: 87 | return 88 | values = self.to_values(contact) 89 | with self.conn as c: 90 | cursor = c.cursor() 91 | cursor.execute("INSERT INTO contacts VALUES (?,?,?,?)", values) 92 | contact.rowid = cursor.lastrowid 93 | self.contacts.append(contact) 94 | self.list.insert(contact) 95 | 96 | def update_contact(self): 97 | if self.selection is None: 98 | return 99 | rowid = self.contacts[self.selection].rowid 100 | contact = self.form.get_details() 101 | if contact: 102 | values = self.to_values(contact) 103 | with self.conn as c: 104 | sql = """UPDATE contacts SET 105 | last_name = ?, 106 | first_name = ?, 107 | email = ?, 108 | phone = ? 109 | WHERE rowid = ?""" 110 | c.execute(sql, values + (rowid,)) 111 | contact.rowid = rowid 112 | self.contacts[self.selection] = contact 113 | self.list.update(contact, self.selection) 114 | 115 | def delete_contact(self): 116 | if self.selection is None: 117 | return 118 | rowid = self.contacts[self.selection].rowid 119 | with self.conn as c: 120 | c.execute("DELETE FROM contacts WHERE rowid = ?", (rowid,)) 121 | self.form.clear() 122 | self.list.delete(self.selection) 123 | self.selection = None 124 | 125 | def main(): 126 | with sqlite3.connect("contacts.db") as conn: 127 | app = App(conn) 128 | app.mainloop() 129 | 130 | 131 | if __name__ == "__main__": 132 | main() 133 | -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/__main__.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | from contacts_repository import ContactsRepository 4 | from contacts_view import ContactsView 5 | from contacts_controller import ContactsController 6 | 7 | 8 | def main(): 9 | with sqlite3.connect("contacts.db") as conn: 10 | repo = ContactsRepository(conn) 11 | view = ContactsView() 12 | ctrl = ContactsController(repo, view) 13 | 14 | view.set_ctrl(ctrl) 15 | ctrl.start() 16 | 17 | if __name__ == "__main__": 18 | main() 19 | -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/__pycache__/contact.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/code/chapter5_05/__pycache__/contact.cpython-36.pyc -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/__pycache__/contacts_controller.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/code/chapter5_05/__pycache__/contacts_controller.cpython-36.pyc -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/__pycache__/contacts_repository.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/code/chapter5_05/__pycache__/contacts_repository.cpython-36.pyc -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/__pycache__/contacts_view.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/code/chapter5_05/__pycache__/contacts_view.cpython-36.pyc -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/contact.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def required(value, message): 4 | if not value: 5 | raise ValueError(message) 6 | return value 7 | 8 | def matches(value, regex, message): 9 | if value and not regex.match(value): 10 | raise ValueError(message) 11 | return value 12 | 13 | class Contact(object): 14 | email_regex = re.compile(r"[^@]+@[^@]+\.[^@]+") 15 | phone_regex = re.compile(r"\([0-9]{3}\)\s[0-9]{7}") 16 | 17 | def __init__(self, last_name, first_name, email, phone): 18 | self.last_name = last_name 19 | self.first_name = first_name 20 | self.email = email 21 | self.phone = phone 22 | 23 | @property 24 | def last_name(self): 25 | return self._last_name 26 | 27 | @last_name.setter 28 | def last_name(self, value): 29 | self._last_name = required(value, "Last name is required") 30 | 31 | @property 32 | def first_name(self): 33 | return self._first_name 34 | 35 | @first_name.setter 36 | def first_name(self, value): 37 | self._first_name = required(value, "First name is required") 38 | 39 | @property 40 | def email(self): 41 | return self._email 42 | 43 | @email.setter 44 | def email(self, value): 45 | self._email = matches(value, self.email_regex, "Invalid email format") 46 | 47 | @property 48 | def phone(self): 49 | return self._phone 50 | 51 | @phone.setter 52 | def phone(self, value): 53 | self._phone = matches(value, self.phone_regex, "Invalid phone format") 54 | -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/contacts.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/code/chapter5_05/contacts.db -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/contacts_controller.py: -------------------------------------------------------------------------------- 1 | from contacts_view import ContactsView, NewContact 2 | 3 | 4 | class ContactsController(object): 5 | def __init__(self, repo, view): 6 | self.repo = repo 7 | self.view = view 8 | self.selection = None 9 | self.contacts = list(repo.get_contacts()) 10 | 11 | def create_contact(self): 12 | new_contact = NewContact(self.view).show() 13 | if new_contact: 14 | contact = self.repo.add_contact(new_contact) 15 | self.contacts.append(contact) 16 | self.view.add_contact(contact) 17 | 18 | def select_contact(self, index): 19 | self.selection = index 20 | contact = self.contacts[index] 21 | self.view.load_details(contact) 22 | 23 | def update_contact(self): 24 | if not self.selection: 25 | return 26 | rowid = self.contacts[self.selection].rowid 27 | update_contact = self.view.get_details() 28 | update_contact.rowid = rowid 29 | 30 | contact = self.repo.update_contact(update_contact) 31 | self.contacts[self.selection] = contact 32 | self.view.update_contact(contact, self.selection) 33 | 34 | def delete_contact(self): 35 | if not self.selection: 36 | return 37 | contact = self.contacts[self.selection] 38 | self.repo.delete_contact(contact) 39 | self.view.remove_contact(self.selection) 40 | 41 | def start(self): 42 | for c in self.contacts: 43 | self.view.add_contact(c) 44 | self.view.mainloop() 45 | -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/contacts_repository.py: -------------------------------------------------------------------------------- 1 | from contact import Contact 2 | 3 | class ContactsRepository(object): 4 | def __init__(self, conn): 5 | self.conn = conn 6 | 7 | def to_values(self, c): 8 | return c.last_name, c.first_name, c.email, c.phone 9 | 10 | def get_contacts(self): 11 | sql = """SELECT rowid, last_name, first_name, email, phone 12 | FROM contacts""" 13 | for row in self.conn.execute(sql): 14 | contact = Contact(*row[1:]) 15 | contact.rowid = row[0] 16 | yield contact 17 | 18 | def add_contact(self, contact): 19 | sql = "INSERT INTO contacts VALUES (?, ?, ?, ?)" 20 | with self.conn: 21 | cursor = self.conn.cursor() 22 | cursor.execute(sql, self.to_values(contact)) 23 | contact.rowid = cursor.lastrowid 24 | return contact 25 | 26 | def update_contact(self, contact): 27 | sql = """UPDATE contacts 28 | SET last_name = ?, first_name = ?, email = ?, phone = ? 29 | WHERE rowid = ?""" 30 | with self.conn: 31 | self.conn.execute(sql, self.to_values(contact) + (contact.rowid,)) 32 | return contact 33 | 34 | def delete_contact(self, contact): 35 | sql = "DELETE FROM contacts WHERE rowid = ?" 36 | with self.conn: 37 | self.conn.execute(sql, (contact.rowid,)) 38 | -------------------------------------------------------------------------------- /Chapter05/code/chapter5_05/contacts_view.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | from contact import Contact 4 | 5 | 6 | class ContactList(tk.Frame): 7 | def __init__(self, master, **kwargs): 8 | super().__init__(master) 9 | self.lb = tk.Listbox(self, **kwargs) 10 | scroll = tk.Scrollbar(self, command=self.lb.yview) 11 | 12 | self.lb.config(yscrollcommand=scroll.set) 13 | scroll.pack(side=tk.RIGHT, fill=tk.Y) 14 | self.lb.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) 15 | 16 | def insert(self, contact, index=tk.END): 17 | text = "{}, {}".format(contact.last_name, contact.first_name) 18 | self.lb.insert(index, text) 19 | 20 | def delete(self, index): 21 | self.lb.delete(index, index) 22 | 23 | def update(self, contact, index): 24 | self.delete(index) 25 | self.insert(contact, index) 26 | 27 | def bind_doble_click(self, callback): 28 | handler = lambda _: callback(self.lb.curselection()[0]) 29 | self.lb.bind("", handler) 30 | 31 | 32 | class ContactForm(tk.LabelFrame): 33 | fields = ("Last name", "First name", "Email", "Phone") 34 | 35 | def __init__(self, master, **kwargs): 36 | super().__init__(master, text="Contact", padx=10, pady=10, **kwargs) 37 | self.frame = tk.Frame(self) 38 | self.entries = list(map(self.create_field, enumerate(self.fields))) 39 | self.frame.pack() 40 | 41 | def create_field(self, field): 42 | position, text = field 43 | label = tk.Label(self.frame, text=text) 44 | entry = tk.Entry(self.frame, width=25) 45 | label.grid(row=position, column=0, pady=5) 46 | entry.grid(row=position, column=1, pady=5) 47 | return entry 48 | 49 | def load_details(self, contact): 50 | values = (contact.last_name, contact.first_name, 51 | contact.email, contact.phone) 52 | for entry, value in zip(self.entries, values): 53 | entry.delete(0, tk.END) 54 | entry.insert(0, value) 55 | 56 | def get_details(self): 57 | values = [e.get() for e in self.entries] 58 | try: 59 | return Contact(*values) 60 | except ValueError as e: 61 | mb.showerror("Validation error", str(e), parent=self) 62 | 63 | def clear(self): 64 | for entry in self.entries: 65 | entry.delete(0, tk.END) 66 | 67 | 68 | class NewContact(tk.Toplevel): 69 | def __init__(self, parent): 70 | super().__init__(parent) 71 | self.contact = None 72 | self.form = ContactForm(self) 73 | self.btn_add = tk.Button(self, text="Confirm", command=self.confirm) 74 | self.form.pack(padx=10, pady=10) 75 | self.btn_add.pack(pady=10) 76 | 77 | def confirm(self): 78 | self.contact = self.form.get_details() 79 | if self.contact: 80 | self.destroy() 81 | 82 | def show(self): 83 | self.grab_set() 84 | self.wait_window() 85 | return self.contact 86 | 87 | 88 | class UpdateContactForm(ContactForm): 89 | def __init__(self, master, **kwargs): 90 | super().__init__(master, **kwargs) 91 | self.btn_save = tk.Button(self, text="Save") 92 | self.btn_delete = tk.Button(self, text="Delete") 93 | 94 | self.btn_save.pack(side=tk.RIGHT, ipadx=5, padx=5, pady=5) 95 | self.btn_delete.pack(side=tk.RIGHT, ipadx=5, padx=5, pady=5) 96 | 97 | def bind_save(self, callback): 98 | self.btn_save.config(command=callback) 99 | 100 | def bind_delete(self, callback): 101 | self.btn_delete.config(command=callback) 102 | 103 | 104 | class ContactsView(tk.Tk): 105 | def __init__(self): 106 | super().__init__() 107 | self.title("SQLite Contacts list") 108 | self.list = ContactList(self, height=15) 109 | self.form = UpdateContactForm(self) 110 | self.btn_new = tk.Button(self, text="Add new contact") 111 | 112 | self.list.pack(side=tk.LEFT, padx=10, pady=10) 113 | self.form.pack(padx=10, pady=10) 114 | self.btn_new.pack(side=tk.BOTTOM, pady=5) 115 | 116 | def set_ctrl(self, ctrl): 117 | self.btn_new.config(command=ctrl.create_contact) 118 | self.list.bind_doble_click(ctrl.select_contact) 119 | self.form.bind_save(ctrl.update_contact) 120 | self.form.bind_delete(ctrl.delete_contact) 121 | 122 | def add_contact(self, contact): 123 | self.list.insert(contact) 124 | 125 | def update_contact(self, contact, index): 126 | self.list.update(contact, index) 127 | 128 | def remove_contact(self, index): 129 | self.form.clear() 130 | self.list.delete(index) 131 | 132 | def get_details(self): 133 | return self.form.get_details() 134 | 135 | def load_details(self, contact): 136 | self.form.load_details(contact) 137 | -------------------------------------------------------------------------------- /Chapter05/code/contacts.csv: -------------------------------------------------------------------------------- 1 | Gauford,Albertine,agauford0@acme.com,(614) 7171720 2 | Greger,Bryce,bgreger1@acme.com,(616) 3543513 3 | Wetherald,Rickey,rwetherald2@acme.com,(379) 3652495 4 | Onthank,Giustina,gonthank3@acme.com,(470) 1613459 5 | Clever,Ulric,uclever4@acme.com,(579) 3188349 6 | Guthrum,Amble,aguthrum5@acme.com,(191) 4356443 7 | Guppey,Austine,aguppey6@acme.com,(636) 7807866 8 | Farndale,Gerhardt,gfarndale7@acme.com,(129) 9236444 9 | Wolfenden,Caressa,cwolfenden8@acme.com,(160) 7019009 10 | Holliar,Robbyn,rholliar9@acme.com,(996) 8863254 11 | MacAllaster,Lisabeth,lmacallastera@acme.com,(830) 3076674 12 | Ottewell,Ketty,kottewellb@acme.com,(680) 5614534 13 | Dreghorn,Tallie,tdreghornc@acme.com,(385) 5801832 14 | Leverette,Brennen,bleveretted@acme.com,(257) 7707057 15 | Charteris,Vonny,vcharterise@acme.com,(957) 7090396 16 | Ennor,Link,lennorf@acme.com,(116) 8589409 17 | Snedden,Rosetta,rsneddeng@acme.com,(908) 5181175 18 | Ilyas,Ernesta,eilyash@acme.com,(108) 6077588 19 | Endon,Stevana,sendoni@acme.com,(368) 6447169 20 | Mathiasen,Daphne,dmathiasenj@163.com,(965) 1009795 21 | Rhodus,Florida,frhodusk@acme.com,(488) 9897785 22 | Jagels,Bryana,bjagelsl@acme.com,(722) 2442603 23 | Saynor,Nicol,nsaynorm@acme.com,(386) 2867726 24 | Binnall,Malachi,mbinnalln@acme.com,(237) 4258228 25 | Hould,Henka,hhouldo@acme.com,(969) 3822679 26 | Van Haeften,Selma,svanhaeftenp@acme.com,(327) 3416415 27 | Gonzalo,Raimundo,rgonzaloq@acme.com,(295) 3105088 28 | Hutson,Ettie,ehutsonr@acme.com,(870) 3659278 29 | Jeffries,Domenico,djeffriess@acme.com,(979) 2015367 30 | Colcomb,Melicent,mcolcombt@acme.com,(726) 4724236 -------------------------------------------------------------------------------- /Chapter05/code/contacts.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/code/contacts.db -------------------------------------------------------------------------------- /Chapter05/code/init_db.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import sqlite3 3 | 4 | def main(): 5 | with open("contacts.csv", encoding="utf-8", newline="") as f, \ 6 | sqlite3.connect("contacts.db") as conn: 7 | conn.execute("""CREATE TABLE contacts ( 8 | last_name text, 9 | first_name text, 10 | email text, 11 | phone text 12 | )""") 13 | conn.executemany("INSERT INTO contacts VALUES (?,?,?,?)", 14 | csv.reader(f)) 15 | 16 | if __name__ == "__main__": 17 | main() 18 | -------------------------------------------------------------------------------- /Chapter05/images/B09199_05_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/images/B09199_05_01.png -------------------------------------------------------------------------------- /Chapter05/images/B09199_05_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/images/B09199_05_02.png -------------------------------------------------------------------------------- /Chapter05/images/B09199_05_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/images/B09199_05_03.png -------------------------------------------------------------------------------- /Chapter05/images/B09199_05_04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/images/B09199_05_04.jpg -------------------------------------------------------------------------------- /Chapter05/images/B09199_05_05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter05/images/B09199_05_05.jpg -------------------------------------------------------------------------------- /Chapter06/code/chapter6_01a.py: -------------------------------------------------------------------------------- 1 | import time 2 | import tkinter as tk 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.button = tk.Button(self, command=self.start_action, 8 | text="Wait 5 seconds") 9 | self.button.pack(padx=50, pady=20) 10 | 11 | def start_action(self): 12 | self.button.config(state=tk.DISABLED) 13 | time.sleep(5) 14 | self.button.config(state=tk.NORMAL) 15 | 16 | if __name__ == "__main__": 17 | app = App() 18 | app.mainloop() 19 | -------------------------------------------------------------------------------- /Chapter06/code/chapter6_01b.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.button = tk.Button(self, command=self.start_action, 7 | text="Wait 5 seconds") 8 | self.button.pack(padx=50, pady=20) 9 | 10 | def start_action(self): 11 | self.button.config(state=tk.DISABLED) 12 | self.after(5000, lambda: self.button.config(state=tk.NORMAL)) 13 | 14 | if __name__ == "__main__": 15 | app = App() 16 | app.mainloop() 17 | -------------------------------------------------------------------------------- /Chapter06/code/chapter6_02.py: -------------------------------------------------------------------------------- 1 | import time 2 | import threading 3 | import tkinter as tk 4 | 5 | class App(tk.Tk): 6 | def __init__(self): 7 | super().__init__() 8 | self.button = tk.Button(self, command=self.start_action, 9 | text="Wait 5 seconds") 10 | self.button.pack(padx=50, pady=20) 11 | 12 | def start_action(self): 13 | self.button.config(state=tk.DISABLED) 14 | thread = threading.Thread(target=self.run_action) 15 | print(threading.main_thread().name) 16 | print(thread.name) 17 | thread.start() 18 | self.check_thread(thread) 19 | 20 | def check_thread(self, thread): 21 | if thread.is_alive(): 22 | self.after(100, lambda: self.check_thread(thread)) 23 | else: 24 | self.button.config(state=tk.NORMAL) 25 | 26 | def run_action(self): 27 | print("Starting long running action...") 28 | time.sleep(5) 29 | print("Long running action finished!") 30 | 31 | if __name__ == "__main__": 32 | app = App() 33 | app.mainloop() 34 | -------------------------------------------------------------------------------- /Chapter06/code/chapter6_03.py: -------------------------------------------------------------------------------- 1 | import json 2 | import threading 3 | import urllib.request 4 | import tkinter as tk 5 | 6 | 7 | class App(tk.Tk): 8 | def __init__(self): 9 | super().__init__() 10 | self.title("HTTP request example") 11 | self.label = tk.Label(self, text="Click 'Start' to get a random value") 12 | self.button = tk.Button(self, text="Start", 13 | command=self.start_action) 14 | 15 | self.label.pack(padx=60, pady=10) 16 | self.button.pack(pady=10) 17 | 18 | def start_action(self): 19 | self.button.config(state=tk.DISABLED) 20 | thread = AsyncAction() 21 | thread.start() 22 | self.check_thread(thread) 23 | 24 | def check_thread(self, thread): 25 | if thread.is_alive(): 26 | self.after(100, lambda: self.check_thread(thread)) 27 | else: 28 | text = "Random value: {}".format(thread.result) 29 | self.label.config(text=text) 30 | self.button.config(state=tk.NORMAL) 31 | 32 | 33 | class AsyncAction(threading.Thread): 34 | def run(self): 35 | self.result = None 36 | url = "http://localhost:8080" 37 | with urllib.request.urlopen(url) as f: 38 | obj = json.loads(f.read().decode("utf-8")) 39 | self.result = obj["random"] 40 | 41 | 42 | if __name__ == "__main__": 43 | app = App() 44 | app.mainloop() 45 | -------------------------------------------------------------------------------- /Chapter06/code/chapter6_04.py: -------------------------------------------------------------------------------- 1 | import time 2 | import queue 3 | import threading 4 | import tkinter as tk 5 | import tkinter.ttk as ttk 6 | import tkinter.messagebox as mb 7 | 8 | 9 | class App(tk.Tk): 10 | def __init__(self): 11 | super().__init__() 12 | self.title("Progressbar example") 13 | self.queue = queue.Queue() 14 | self.progressbar = ttk.Progressbar(self, length=300, 15 | orient=tk.HORIZONTAL) 16 | self.button = tk.Button(self, text="Start", 17 | command=self.start_action) 18 | 19 | self.progressbar.pack(padx=10, pady=10) 20 | self.button.pack(padx=10, pady=10) 21 | 22 | def start_action(self): 23 | self.button.config(state=tk.DISABLED) 24 | thread = AsyncAction(self.queue, 20) 25 | thread.start() 26 | self.poll_thread(thread) 27 | 28 | def poll_thread(self, thread): 29 | self.check_queue() 30 | if thread.is_alive(): 31 | self.after(100, lambda: self.poll_thread(thread)) 32 | else: 33 | self.button.config(state=tk.NORMAL) 34 | mb.showinfo("Done!", "Async action completed") 35 | 36 | def check_queue(self): 37 | while self.queue.qsize(): 38 | try: 39 | step = self.queue.get(0) 40 | self.progressbar.step(step * 100) 41 | except queue.Empty: 42 | pass 43 | 44 | 45 | class AsyncAction(threading.Thread): 46 | def __init__(self, queue, steps): 47 | super().__init__() 48 | self.queue = queue 49 | self.steps = steps 50 | 51 | def run(self): 52 | for _ in range(self.steps): 53 | time.sleep(1) 54 | self.queue.put(1 / self.steps) 55 | 56 | 57 | if __name__ == "__main__": 58 | app = App() 59 | app.mainloop() 60 | -------------------------------------------------------------------------------- /Chapter06/code/chapter6_05.py: -------------------------------------------------------------------------------- 1 | import time 2 | import tkinter as tk 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.button = tk.Button(self, command=self.start_action, 8 | text="Wait 5 seconds") 9 | self.cancel = tk.Button(self, command=self.cancel_action, 10 | text="Stop", state=tk.DISABLED) 11 | self.button.pack(padx=30, pady=20, side=tk.LEFT) 12 | self.cancel.pack(padx=30, pady=20, side=tk.LEFT) 13 | 14 | def start_action(self): 15 | self.button.config(state=tk.DISABLED) 16 | self.cancel.config(state=tk.NORMAL) 17 | self.scheduled_id = self.after(5000, self.init_buttons) 18 | 19 | def init_buttons(self): 20 | self.button.config(state=tk.NORMAL) 21 | self.cancel.config(state=tk.DISABLED) 22 | 23 | def cancel_action(self): 24 | print("Canceling scheduled", self.scheduled_id) 25 | self.after_cancel(self.scheduled_id) 26 | self.init_buttons() 27 | 28 | if __name__ == "__main__": 29 | app = App() 30 | app.mainloop() 31 | -------------------------------------------------------------------------------- /Chapter06/code/chapter6_06.py: -------------------------------------------------------------------------------- 1 | import time 2 | import tkinter as tk 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.button = tk.Button(self, command=self.start_action, 8 | text="Wait 1 second") 9 | self.button.pack(padx=30, pady=20) 10 | 11 | def start_action(self): 12 | self.button.config(state=tk.DISABLED) 13 | self.update_idletasks() 14 | time.sleep(1) 15 | self.button.config(state=tk.NORMAL) 16 | 17 | if __name__ == "__main__": 18 | app = App() 19 | app.mainloop() 20 | -------------------------------------------------------------------------------- /Chapter06/code/chapter6_07.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import subprocess 3 | import tkinter as tk 4 | 5 | class App(tk.Tk): 6 | def __init__(self): 7 | super().__init__() 8 | self.entry = tk.Entry(self) 9 | self.button = tk.Button(self, text="Ping!", 10 | command=self.do_ping) 11 | self.output = tk.Text(self, width=80, height=15) 12 | 13 | self.entry.grid(row=0, column=0, padx=5, pady=5) 14 | self.button.grid(row=0, column=1, padx=5, pady=5) 15 | self.output.grid(row=1, column=0, columnspan=2, 16 | padx=5, pady=5) 17 | 18 | def do_ping(self): 19 | self.button.config(state=tk.DISABLED) 20 | thread = AsyncAction(self.entry.get()) 21 | thread.start() 22 | self.poll_thread(thread) 23 | 24 | def poll_thread(self, thread): 25 | if thread.is_alive(): 26 | self.after(100, lambda: self.poll_thread(thread)) 27 | else: 28 | self.button.config(state=tk.NORMAL) 29 | self.output.delete(1.0, tk.END) 30 | self.output.insert(tk.END, thread.result) 31 | 32 | 33 | class AsyncAction(threading.Thread): 34 | def __init__(self, ip): 35 | super().__init__() 36 | self.ip = ip 37 | 38 | def run(self): 39 | self.result = subprocess.run(["ping", self.ip], shell=True, 40 | stdout=subprocess.PIPE).stdout 41 | 42 | if __name__ == "__main__": 43 | app = App() 44 | app.mainloop() 45 | -------------------------------------------------------------------------------- /Chapter06/code/server.py: -------------------------------------------------------------------------------- 1 | import time 2 | import json 3 | import random 4 | from http.server import HTTPServer, BaseHTTPRequestHandler 5 | 6 | 7 | class RandomRequestHandler(BaseHTTPRequestHandler): 8 | def do_GET(self): 9 | # Simulate latency 10 | time.sleep(3) 11 | 12 | # Write response headers 13 | self.send_response(200) 14 | self.send_header('Content-type', 'application/json') 15 | self.end_headers() 16 | 17 | # Write response body 18 | body = json.dumps({'random': random.random()}) 19 | self.wfile.write(bytes(body, "utf8")) 20 | 21 | 22 | def main(): 23 | """Starts the HTTP server on port 8080""" 24 | server_address = ('', 8080) 25 | httpd = HTTPServer(server_address, RandomRequestHandler) 26 | httpd.serve_forever() 27 | 28 | 29 | if __name__ == "__main__": 30 | main() 31 | -------------------------------------------------------------------------------- /Chapter06/images/B09199_06_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter06/images/B09199_06_01.png -------------------------------------------------------------------------------- /Chapter06/images/B09199_06_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter06/images/B09199_06_02.png -------------------------------------------------------------------------------- /Chapter06/images/B09199_06_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter06/images/B09199_06_03.jpg -------------------------------------------------------------------------------- /Chapter06/images/B09199_06_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter06/images/B09199_06_04.png -------------------------------------------------------------------------------- /Chapter06/images/B09199_06_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter06/images/B09199_06_05.png -------------------------------------------------------------------------------- /Chapter06/images/B09199_06_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter06/images/B09199_06_06.png -------------------------------------------------------------------------------- /Chapter06/images/B09199_06_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter06/images/B09199_06_07.png -------------------------------------------------------------------------------- /Chapter07/code/chapter7_01.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.title("Basic canvas") 8 | 9 | self.canvas = tk.Canvas(self, bg="white") 10 | self.label = tk.Label(self) 11 | self.canvas.bind("", self.mouse_motion) 12 | 13 | self.canvas.pack() 14 | self.label.pack() 15 | 16 | def mouse_motion(self, event): 17 | x, y = event.x, event.y 18 | text = "Mouse position: ({}, {})".format(x, y) 19 | self.label.config(text=text) 20 | 21 | if __name__ == "__main__": 22 | app = App() 23 | app.mainloop() 24 | -------------------------------------------------------------------------------- /Chapter07/code/chapter7_02.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | 4 | class LineForm(tk.LabelFrame): 5 | arrows = (tk.NONE, tk.FIRST, tk.LAST, tk.BOTH) 6 | colors = ("black", "red", "blue", "green") 7 | 8 | def __init__(self, master): 9 | super().__init__(master, text="Line options") 10 | 11 | self.arrow = tk.StringVar() 12 | self.arrow.set(self.arrows[0]) 13 | arrow_label = tk.Label(self, text="Arrow style") 14 | arrow_option = tk.OptionMenu(self, self.arrow, *self.arrows) 15 | 16 | self.color = tk.StringVar() 17 | self.color.set(self.colors[0]) 18 | color_label = tk.Label(self, text="Fill color") 19 | color_option = tk.OptionMenu(self, self.color, *self.colors) 20 | 21 | line_width_label = tk.Label(self, text="Line width") 22 | self.line_width = tk.Spinbox(self, values=(1, 2, 3, 4), width=5) 23 | 24 | arrow_label.grid(sticky=tk.W, row=0, column=0) 25 | arrow_option.grid(row=0, column=1, pady=10) 26 | color_label.grid(sticky=tk.W, row=1, column=0) 27 | color_option.grid(row=1, column=1, pady=10) 28 | line_width_label.grid(sticky=tk.W, row=2, column=0) 29 | self.line_width.grid(row=2, column=1, pady=10) 30 | 31 | def get_arrow(self): 32 | return self.arrow.get() 33 | 34 | def get_color(self): 35 | return self.color.get() 36 | 37 | def get_width(self): 38 | return int(self.line_width.get()) 39 | 40 | 41 | class App(tk.Tk): 42 | def __init__(self): 43 | super().__init__() 44 | self.title("Basic canvas") 45 | self.line_start = None 46 | self.form = LineForm(self) 47 | self.canvas = tk.Canvas(self, bg="white") 48 | self.canvas.bind("", self.draw) 49 | 50 | self.form.pack(side=tk.LEFT, padx=10, pady=10) 51 | self.canvas.pack(side=tk.LEFT) 52 | 53 | def draw(self, event): 54 | x, y = event.x, event.y 55 | if not self.line_start: 56 | self.line_start = (x, y) 57 | else: 58 | x_origin, y_origin = self.line_start 59 | self.line_start = None 60 | line = (x_origin, y_origin, x, y) 61 | arrow = self.form.get_arrow() 62 | color = self.form.get_color() 63 | width = self.form.get_width() 64 | self.canvas.create_line(*line, arrow=arrow, 65 | fill=color, width=width) 66 | 67 | if __name__ == "__main__": 68 | app = App() 69 | app.mainloop() 70 | -------------------------------------------------------------------------------- /Chapter07/code/chapter7_03.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.title("Canvas text items") 7 | self.geometry("300x100") 8 | 9 | self.var = tk.StringVar() 10 | self.entry = tk.Entry(self, textvariable=self.var) 11 | self.canvas = tk.Canvas(self, bg="white") 12 | 13 | self.entry.pack(pady=5) 14 | self.canvas.pack() 15 | self.update() 16 | 17 | w, h = self.canvas.winfo_width(), self.canvas.winfo_height() 18 | options = { "font": "courier", "fill": "blue", 19 | "activefill": "red" } 20 | self.text_id = self.canvas.create_text((w/2, h/2), **options) 21 | self.var.trace("w", self.write_text) 22 | 23 | def write_text(self, *args): 24 | self.canvas.itemconfig(self.text_id, text=self.var.get()) 25 | 26 | if __name__ == "__main__": 27 | app = App() 28 | app.mainloop() 29 | -------------------------------------------------------------------------------- /Chapter07/code/chapter7_04.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from functools import partial 3 | 4 | class App(tk.Tk): 5 | shapes = ("rectangle", "oval", "arc") 6 | def __init__(self): 7 | super().__init__() 8 | self.title("Drawing standard items") 9 | 10 | self.start = None 11 | self.shape = None 12 | self.canvas = tk.Canvas(self, bg="white") 13 | frame = tk.Frame(self) 14 | for shape in self.shapes: 15 | btn = tk.Button(frame, text=shape.capitalize()) 16 | btn.config(command=partial(self.set_selection, btn, shape)) 17 | btn.pack(side=tk.LEFT, expand=True, fill=tk.BOTH) 18 | 19 | self.canvas.bind("", self.draw_item) 20 | self.canvas.pack() 21 | frame.pack(fill=tk.BOTH) 22 | 23 | def set_selection(self, widget, shape): 24 | for w in widget.master.winfo_children(): 25 | w.config(relief=tk.RAISED) 26 | widget.config(relief=tk.SUNKEN) 27 | self.shape = shape 28 | 29 | def draw_item(self, event): 30 | x, y = event.x, event.y 31 | if not self.start: 32 | self.start = (x, y) 33 | else: 34 | x_origin, y_origin = self.start 35 | self.start = None 36 | bbox = (x_origin, y_origin, x, y) 37 | if self.shape == "rectangle": 38 | self.canvas.create_rectangle(*bbox, fill="blue", 39 | activefill="yellow") 40 | elif self.shape == "oval": 41 | self.canvas.create_oval(*bbox, fill="red", 42 | activefill="yellow") 43 | elif self.shape == "arc": 44 | self.canvas.create_arc(*bbox, fill="green", 45 | activefill="yellow") 46 | 47 | if __name__ == "__main__": 48 | app = App() 49 | app.mainloop() 50 | -------------------------------------------------------------------------------- /Chapter07/code/chapter7_05.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.title("Finding canvas items") 8 | 9 | self.current = None 10 | self.canvas = tk.Canvas(self, bg="white") 11 | self.canvas.bind("", self.mouse_motion) 12 | self.canvas.pack() 13 | 14 | self.update() 15 | w = self.canvas.winfo_width() 16 | h = self.canvas.winfo_height() 17 | positions = [(60, 60), (w-60, 60), (60, h-60), (w-60, h-60)] 18 | for x, y in positions: 19 | self.canvas.create_rectangle(x-10, y-10, x+10, y+10, 20 | fill="blue") 21 | 22 | def mouse_motion(self, event): 23 | self.canvas.itemconfig(self.current, fill="blue") 24 | self.current = self.canvas.find_closest(event.x, event.y) 25 | self.canvas.itemconfig(self.current, fill="yellow") 26 | 27 | 28 | if __name__ == "__main__": 29 | app = App() 30 | app.mainloop() 31 | -------------------------------------------------------------------------------- /Chapter07/code/chapter7_06.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.title("Moving canvas items") 7 | 8 | self.canvas = tk.Canvas(self, bg="white") 9 | self.canvas.pack() 10 | self.update() 11 | self.width = self.canvas.winfo_width() 12 | self.height = self.canvas.winfo_height() 13 | 14 | self.item = self.canvas.create_rectangle(30, 30, 60, 60, 15 | fill="blue") 16 | self.pressed_keys = {} 17 | self.bind("", self.key_press) 18 | self.bind("", self.key_release) 19 | self.process_movements() 20 | 21 | def key_press(self, event): 22 | self.pressed_keys[event.keysym] = True 23 | 24 | def key_release(self, event): 25 | self.pressed_keys.pop(event.keysym, None) 26 | 27 | def process_movements(self): 28 | off_x, off_y = 0, 0 29 | speed = 3 30 | if 'Right' in self.pressed_keys: 31 | off_x += speed 32 | if 'Left' in self.pressed_keys: 33 | off_x -= speed 34 | if 'Down' in self.pressed_keys: 35 | off_y += speed 36 | if 'Up' in self.pressed_keys: 37 | off_y -= speed 38 | 39 | x0, y0, x1, y1 = self.canvas.coords(self.item) 40 | pos_x = x0 + (x1 - x0) / 2 + off_x 41 | pos_y = y0 + (y1 - y0) / 2 + off_y 42 | if 0 <= pos_x <= self.width and 0 <= pos_y <= self.height: 43 | self.canvas.move(self.item, off_x, off_y) 44 | 45 | self.after(10, self.process_movements) 46 | 47 | if __name__ == "__main__": 48 | app = App() 49 | app.mainloop() 50 | -------------------------------------------------------------------------------- /Chapter07/code/chapter7_07.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.title("Detecting collisions between items") 7 | 8 | self.canvas = tk.Canvas(self, bg="white") 9 | self.canvas.pack() 10 | self.update() 11 | self.width = w = self.canvas.winfo_width() 12 | self.height = h = self.canvas.winfo_height() 13 | 14 | pos = (w/2 - 15, h/2 - 15, w/2 + 15, h/2 + 15) 15 | self.item = self.canvas.create_rectangle(*pos, fill="blue") 16 | positions = [(60, 60), (w-60, 60), (60, h-60), (w-60, h-60)] 17 | for x, y in positions: 18 | self.canvas.create_rectangle(x-10, y-10, x+10, y+10, 19 | fill="green") 20 | 21 | self.pressed_keys = {} 22 | self.bind("", self.key_press) 23 | self.bind("", self.key_release) 24 | self.process_movements() 25 | 26 | def key_press(self, event): 27 | self.pressed_keys[event.keysym] = True 28 | 29 | def key_release(self, event): 30 | self.pressed_keys.pop(event.keysym, None) 31 | 32 | def process_movements(self): 33 | all_items = self.canvas.find_all() 34 | for item in filter(lambda i: i is not self.item, all_items): 35 | self.canvas.itemconfig(item, fill="green") 36 | 37 | x0, y0, x1, y1 = self.canvas.coords(self.item) 38 | items = self.canvas.find_overlapping(x0, y0, x1, y1) 39 | for item in filter(lambda i: i is not self.item, items): 40 | self.canvas.itemconfig(item, fill="yellow") 41 | 42 | off_x, off_y = 0, 0 43 | speed = 3 44 | if 'Right' in self.pressed_keys: 45 | off_x += speed 46 | if 'Left' in self.pressed_keys: 47 | off_x -= speed 48 | if 'Down' in self.pressed_keys: 49 | off_y += speed 50 | if 'Up' in self.pressed_keys: 51 | off_y -= speed 52 | 53 | 54 | pos_x = x0 + (x1 - x0) / 2 + off_x 55 | pos_y = y0 + (y1 - y0) / 2 + off_y 56 | if 0 <= pos_x <= self.width and 0 <= pos_y <= self.height: 57 | self.canvas.move(self.item, off_x, off_y) 58 | 59 | self.after(10, self.process_movements) 60 | 61 | if __name__ == "__main__": 62 | app = App() 63 | app.mainloop() 64 | -------------------------------------------------------------------------------- /Chapter07/code/chapter7_08.py: -------------------------------------------------------------------------------- 1 | import random 2 | import tkinter as tk 3 | 4 | class App(tk.Tk): 5 | colors = ("red", "yellow", "green", "blue", "orange") 6 | 7 | def __init__(self): 8 | super().__init__() 9 | self.title("Removing canvas items") 10 | 11 | self.canvas = tk.Canvas(self, bg="white") 12 | frame = tk.Frame(self) 13 | generate_btn = tk.Button(frame, text="Generate items", 14 | command=self.generate_items) 15 | clear_btn = tk.Button(frame, text="Clear items", 16 | command=self.clear_items) 17 | 18 | self.canvas.pack() 19 | frame.pack(fill=tk.BOTH) 20 | generate_btn.pack(side=tk.LEFT, expand=True, fill=tk.BOTH) 21 | clear_btn.pack(side=tk.LEFT, expand=True, fill=tk.BOTH) 22 | 23 | self.update() 24 | self.width = self.canvas.winfo_width() 25 | self.height = self.canvas.winfo_height() 26 | 27 | self.canvas.bind("", self.on_click) 28 | self.generate_items() 29 | 30 | def on_click(self, event): 31 | item = self.canvas.find_withtag(tk.CURRENT) 32 | self.canvas.delete(item) 33 | 34 | def generate_items(self): 35 | self.clear_items() 36 | for _ in range(10): 37 | x = random.randint(0, self.width) 38 | y = random.randint(0, self.height) 39 | color = random.choice(self.colors) 40 | self.canvas.create_oval(x, y, x + 20, y + 20, fill=color) 41 | 42 | def clear_items(self): 43 | self.canvas.delete(tk.ALL) 44 | 45 | if __name__ == "__main__": 46 | app = App() 47 | app.mainloop() 48 | -------------------------------------------------------------------------------- /Chapter07/code/chapter7_09.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | class App(tk.Tk): 4 | def __init__(self): 5 | super().__init__() 6 | self.title("Drag and drop") 7 | 8 | self.dnd_item = None 9 | self.canvas = tk.Canvas(self, bg="white") 10 | self.canvas.pack() 11 | 12 | self.canvas.create_rectangle(30, 30, 60, 60, fill="green", 13 | tags="draggable") 14 | self.canvas.create_oval(120, 120, 150, 150, fill="red", 15 | tags="draggable") 16 | 17 | self.canvas.tag_bind("draggable", "", 18 | self.button_press) 19 | self.canvas.tag_bind("draggable", "", 20 | self.button_motion) 21 | 22 | def button_press(self, event): 23 | item = self.canvas.find_withtag(tk.CURRENT) 24 | self.dnd_item = (item, event.x, event.y) 25 | 26 | def button_motion(self, event): 27 | x, y = event.x, event.y 28 | item, x0, y0 = self.dnd_item 29 | self.canvas.move(item, x - x0, y - y0) 30 | self.dnd_item = (item, x, y) 31 | 32 | if __name__ == "__main__": 33 | app = App() 34 | app.mainloop() 35 | -------------------------------------------------------------------------------- /Chapter07/code/chapter7_10.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | 4 | class LineForm(tk.LabelFrame): 5 | arrows = (tk.NONE, tk.FIRST, tk.LAST, tk.BOTH) 6 | colors = ("black", "red", "blue", "green") 7 | 8 | def __init__(self, master): 9 | super().__init__(master, text="Line options") 10 | 11 | self.arrow = tk.StringVar() 12 | self.arrow.set(self.arrows[0]) 13 | arrow_label = tk.Label(self, text="Arrow style") 14 | arrow_option = tk.OptionMenu(self, self.arrow, *self.arrows) 15 | 16 | self.color = tk.StringVar() 17 | self.color.set(self.colors[0]) 18 | color_label = tk.Label(self, text="Fill color") 19 | color_option = tk.OptionMenu(self, self.color, *self.colors) 20 | 21 | line_width_label = tk.Label(self, text="Line width") 22 | self.line_width = tk.Spinbox(self, values=(1, 2, 3, 4), width=5) 23 | 24 | arrow_label.grid(sticky=tk.W, row=0, column=0) 25 | arrow_option.grid(row=0, column=1, pady=10) 26 | color_label.grid(sticky=tk.W, row=1, column=0) 27 | color_option.grid(row=1, column=1, pady=10) 28 | line_width_label.grid(sticky=tk.W, row=2, column=0) 29 | self.line_width.grid(row=2, column=1, pady=10) 30 | 31 | def get_arrow(self): 32 | return self.arrow.get() 33 | 34 | def get_color(self): 35 | return self.color.get() 36 | 37 | def get_width(self): 38 | return int(self.line_width.get()) 39 | 40 | 41 | class App(tk.Tk): 42 | def __init__(self): 43 | super().__init__() 44 | self.title("Basic canvas") 45 | 46 | self.line_start = None 47 | self.form = LineForm(self) 48 | self.render_btn = tk.Button(self, text="Render canvas", 49 | command=self.render_canvas) 50 | self.canvas = tk.Canvas(self, bg="white") 51 | self.canvas.bind("", self.draw) 52 | 53 | self.form.grid(row=0, column=0, padx=10, pady=10) 54 | self.render_btn.grid(row=1, column=0) 55 | self.canvas.grid(row=0, column=1, rowspan=2) 56 | 57 | def draw(self, event): 58 | x, y = event.x, event.y 59 | if not self.line_start: 60 | self.line_start = (x, y) 61 | else: 62 | x_origin, y_origin = self.line_start 63 | self.line_start = None 64 | line = (x_origin, y_origin, x, y) 65 | arrow = self.form.get_arrow() 66 | color = self.form.get_color() 67 | width = self.form.get_width() 68 | self.canvas.create_line(*line, arrow=arrow, 69 | fill=color, width=width) 70 | 71 | def render_canvas(self): 72 | self.canvas.postscript(file="output.ps", colormode="color") 73 | 74 | if __name__ == "__main__": 75 | app = App() 76 | app.mainloop() 77 | -------------------------------------------------------------------------------- /Chapter07/code/output.ps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-3.0 EPSF-3.0 2 | %%Creator: Tk Canvas Widget 3 | %%Title: Window .!canvas 4 | %%CreationDate: Sun Mar 4 20:15:36 2018 5 | %%BoundingBox: 162 295 450 498 6 | %%Pages: 1 7 | %%DocumentData: Clean7Bit 8 | %%Orientation: Portrait 9 | %%EndComments 10 | 11 | %%BeginProlog 12 | % This is a standard prolog for Postscript generated by Tk's canvas 13 | % widget. 14 | /CurrentEncoding [ 15 | /space/space/space/space/space/space/space/space 16 | /space/space/space/space/space/space/space/space 17 | /space/space/space/space/space/space/space/space 18 | /space/space/space/space/space/space/space/space 19 | /space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quotesingle 20 | /parenleft/parenright/asterisk/plus/comma/hyphen/period/slash 21 | /zero/one/two/three/four/five/six/seven 22 | /eight/nine/colon/semicolon/less/equal/greater/question 23 | /at/A/B/C/D/E/F/G 24 | /H/I/J/K/L/M/N/O 25 | /P/Q/R/S/T/U/V/W 26 | /X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore 27 | /grave/a/b/c/d/e/f/g 28 | /h/i/j/k/l/m/n/o 29 | /p/q/r/s/t/u/v/w 30 | /x/y/z/braceleft/bar/braceright/asciitilde/space 31 | /space/space/space/space/space/space/space/space 32 | /space/space/space/space/space/space/space/space 33 | /space/space/space/space/space/space/space/space 34 | /space/space/space/space/space/space/space/space 35 | /space/exclamdown/cent/sterling/currency/yen/brokenbar/section 36 | /dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered/macron 37 | /degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered 38 | /cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown 39 | /Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla 40 | /Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis 41 | /Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply 42 | /Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls 43 | /agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla 44 | /egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis 45 | /eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide 46 | /oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis 47 | ] def 48 | 50 dict begin 49 | /baseline 0 def 50 | /stipimage 0 def 51 | /height 0 def 52 | /justify 0 def 53 | /lineLength 0 def 54 | /spacing 0 def 55 | /stipple 0 def 56 | /strings 0 def 57 | /xoffset 0 def 58 | /yoffset 0 def 59 | /tmpstip null def 60 | /baselineSampler ( TXygqPZ) def 61 | baselineSampler 0 196 put 62 | /cstringshow {{ dup type /stringtype eq { show } { glyphshow } ifelse } forall } bind def 63 | /cstringwidth {0 exch 0 exch { dup type /stringtype eq { stringwidth } { currentfont /Encoding get exch 1 exch put (\001) stringwidth } ifelse exch 3 1 roll add 3 1 roll add exch } forall } bind def 64 | /ISOEncode {dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding CurrentEncoding def currentdict end /Temporary exch definefont } bind def 65 | /StrokeClip {{strokepath} stopped { (This Postscript printer gets limitcheck overflows when) = (stippling dashed lines; lines will be printed solid instead.) = [] 0 setdash strokepath} if clip } bind def 66 | /EvenPixels {dup 0 matrix currentmatrix dtransform dup mul exch dup mul add sqrt dup round dup 1 lt {pop 1} if exch div mul } bind def 67 | /StippleFill {/tmpstip 1 index def 1 EvenPixels dup scale pathbbox 4 2 roll 5 index div dup 0 lt {1 sub} if cvi 5 index mul 4 1 roll 6 index div dup 0 lt {1 sub} if cvi 6 index mul 3 2 roll 6 index exch { 2 index 5 index 3 index { gsave 1 index exch translate 5 index 5 index true matrix tmpstip imagemask grestore } for pop } for pop pop pop pop pop } bind def 68 | /AdjustColor {CL 2 lt { currentgray CL 0 eq { .5 lt {0} {1} ifelse } if setgray } if } bind def 69 | /DrawText {/stipple exch def /justify exch def /yoffset exch def /xoffset exch def /spacing exch def /strings exch def /lineLength 0 def strings { cstringwidth pop dup lineLength gt {/lineLength exch def} {pop} ifelse newpath } forall 0 0 moveto baselineSampler false charpath pathbbox dup /baseline exch def exch pop exch sub /height exch def pop newpath translate rotate lineLength xoffset mul strings length 1 sub spacing mul height add yoffset mul translate justify lineLength mul baseline neg translate strings { dup cstringwidth pop justify neg mul 0 moveto stipple { gsave /char (X) def { dup type /stringtype eq { { char 0 3 -1 roll put currentpoint gsave char true charpath clip StippleText grestore char stringwidth translate moveto } forall } { currentfont /Encoding get exch 1 exch put currentpoint gsave (\001) true charpath clip StippleText grestore (\001) stringwidth translate moveto } ifelse } forall grestore } {cstringshow} ifelse 0 spacing neg translate } forall } bind def 70 | /TkPhotoColor {gsave 32 dict begin /tinteger exch def /transparent 1 string def transparent 0 tinteger put /olddict exch def olddict /DataSource get dup type /filetype ne { olddict /DataSource 3 -1 roll 0 () /SubFileDecode filter put } { pop } ifelse /newdict olddict maxlength dict def olddict newdict copy pop /w newdict /Width get def /crpp newdict /Decode get length 2 idiv def /str w string def /pix w crpp mul string def /substrlen 2 w log 2 log div floor exp cvi def /substrs [ { substrlen string 0 1 substrlen 1 sub { 1 index exch tinteger put } for /substrlen substrlen 2 idiv def substrlen 0 eq {exit} if } loop ] def /h newdict /Height get def 1 w div 1 h div matrix scale olddict /ImageMatrix get exch matrix concatmatrix matrix invertmatrix concat newdict /Height 1 put newdict /DataSource pix put /mat [w 0 0 h 0 0] def newdict /ImageMatrix mat put 0 1 h 1 sub { mat 5 3 -1 roll neg put olddict /DataSource get str readstring pop pop /tail str def /x 0 def olddict /DataSource get pix readstring pop pop { tail transparent search dup /done exch not def {exch pop exch pop} if /w1 exch length def w1 0 ne { newdict /DataSource pix x crpp mul w1 crpp mul getinterval put newdict /Width w1 put mat 4 x neg put /x x w1 add def newdict image /tail tail w1 tail length w1 sub getinterval def } if done {exit} if tail substrs { anchorsearch {pop} if } forall /tail exch def tail length 0 eq {exit} if /x w tail length sub def } loop } for end grestore } bind def 71 | /TkPhotoMono {gsave 32 dict begin /dummyInteger exch def /olddict exch def olddict /DataSource get dup type /filetype ne { olddict /DataSource 3 -1 roll 0 () /SubFileDecode filter put } { pop } ifelse /newdict olddict maxlength dict def olddict newdict copy pop /w newdict /Width get def /pix w 7 add 8 idiv string def /h newdict /Height get def 1 w div 1 h div matrix scale olddict /ImageMatrix get exch matrix concatmatrix matrix invertmatrix concat newdict /Height 1 put newdict /DataSource pix put /mat [w 0 0 h 0 0] def newdict /ImageMatrix mat put 0 1 h 1 sub { mat 5 3 -1 roll neg put 0.000 0.000 0.000 setrgbcolor olddict /DataSource get pix readstring pop pop newdict /DataSource pix put newdict imagemask 1.000 1.000 1.000 setrgbcolor olddict /DataSource get pix readstring pop pop newdict /DataSource pix put newdict imagemask } for end grestore } bind def 72 | %%EndProlog 73 | %%BeginSetup 74 | /CL 2 def 75 | %%EndSetup 76 | 77 | %%Page: 1 1 78 | save 79 | 306.0 396.0 translate 80 | 0.7491 0.7491 scale 81 | -191 -134 translate 82 | 0 269 moveto 382 269 lineto 382 0 lineto 0 0 lineto closepath clip newpath 83 | gsave 84 | 93 149 moveto 85 | 171.624175431635 186.891168882715 lineto 86 | 0 setlinecap 87 | 1 setlinejoin 88 | 1 setlinewidth 89 | [] 0 setdash 90 | 0.000 0.000 1.000 setrgbcolor AdjustColor 91 | stroke 92 | 176 189 moveto 93 | 165.470723406501 187.81200319125 lineto 94 | 168.317961668191 185.852847607466 lineto 95 | 168.752103590133 184.952003119437 lineto 96 | 168.510585143938 181.50429008607 lineto 97 | 176 189 lineto 98 | fill 99 | grestore 100 | gsave 101 | 205 185 moveto 102 | 205 185 lineto 103 | 0 setlinecap 104 | 1 setlinejoin 105 | 1 setlinewidth 106 | [] 0 setdash 107 | 0.000 0.000 1.000 setrgbcolor AdjustColor 108 | stroke 109 | 205 185 moveto 110 | 205 185 lineto 111 | 205 185 lineto 112 | 205 185 lineto 113 | 205 185 lineto 114 | 205 185 lineto 115 | fill 116 | grestore 117 | gsave 118 | 106 176 moveto 119 | 106 176 lineto 120 | 0 setlinecap 121 | 1 setlinejoin 122 | 4 setlinewidth 123 | [] 0 setdash 124 | 0.000 0.000 1.000 setrgbcolor AdjustColor 125 | stroke 126 | 106 176 moveto 127 | 106 176 lineto 128 | 106 176 lineto 129 | 106 176 lineto 130 | 106 176 lineto 131 | 106 176 lineto 132 | fill 133 | grestore 134 | restore showpage 135 | 136 | %%Trailer 137 | end 138 | %%EOF 139 | -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_01.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_02.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_03.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_04.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_05.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_06.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_07.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_08.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_09.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_10.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_11.png -------------------------------------------------------------------------------- /Chapter07/images/B09199_07_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter07/images/B09199_07_12.png -------------------------------------------------------------------------------- /Chapter08/code/chapter8_01.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter as ttk 3 | 4 | class App(tk.Tk): 5 | greetings = ("Hello", "Ciao", "Hola") 6 | 7 | def __init__(self): 8 | super().__init__() 9 | self.title("Tk themed widgets") 10 | 11 | var = tk.StringVar() 12 | var.set(self.greetings[0]) 13 | label_frame = ttk.LabelFrame(self, text="Choose a greeting") 14 | for greeting in self.greetings: 15 | radio = ttk.Radiobutton(label_frame, text=greeting, 16 | variable=var, value=greeting) 17 | radio.pack() 18 | 19 | frame = ttk.Frame(self) 20 | label = ttk.Label(frame, text="Enter your name") 21 | entry = ttk.Entry(frame) 22 | 23 | command = lambda: print("{}, {}!".format(var.get(), entry.get())) 24 | button = ttk.Button(frame, text="Greet", command=command) 25 | 26 | label.grid(row=0, column=0, padx=5, pady=5) 27 | entry.grid(row=0, column=1, padx=5, pady=5) 28 | button.grid(row=1, column=0, columnspan=2, pady=5) 29 | 30 | label_frame.pack(side=tk.LEFT, padx=10, pady=10) 31 | frame.pack(side=tk.LEFT, padx=10, pady=10) 32 | 33 | if __name__ == "__main__": 34 | app = App() 35 | app.mainloop() 36 | -------------------------------------------------------------------------------- /Chapter08/code/chapter8_02.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter.ttk as ttk 3 | 4 | class App(tk.Tk): 5 | def __init__(self): 6 | super().__init__() 7 | self.title("Ttk Combobox") 8 | colors = ("Purple", "Yellow", "Red", "Blue") 9 | 10 | self.label = ttk.Label(self, text="Please select a color") 11 | self.combo = ttk.Combobox(self, values=colors) 12 | btn_submit = ttk.Button(self, text="Submit", 13 | command=self.display_color) 14 | btn_clear = ttk.Button(self, text="Clear", 15 | command=self.clear_color) 16 | 17 | self.combo.bind("<>", self.display_color) 18 | 19 | self.label.pack(pady=10) 20 | self.combo.pack(side=tk.LEFT, padx=10, pady=5) 21 | btn_submit.pack(side=tk.TOP, padx=10, pady=5) 22 | btn_clear.pack(padx=10, pady=5) 23 | 24 | def display_color(self, *args): 25 | color = self.combo.get() 26 | print("Your selection is", color) 27 | 28 | def clear_color(self): 29 | self.combo.set("") 30 | 31 | if __name__ == "__main__": 32 | app = App() 33 | app.mainloop() 34 | -------------------------------------------------------------------------------- /Chapter08/code/chapter8_03.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import tkinter as tk 3 | import tkinter.ttk as ttk 4 | 5 | 6 | class App(tk.Tk): 7 | def __init__(self, path): 8 | super().__init__() 9 | self.title("Ttk Treeview") 10 | 11 | columns = ("#1", "#2", "#3") 12 | self.tree = ttk.Treeview(self, show="headings", columns=columns) 13 | self.tree.heading("#1", text="Last name") 14 | self.tree.heading("#2", text="First name") 15 | self.tree.heading("#3", text="Email") 16 | ysb = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.tree.yview) 17 | self.tree.configure(yscroll=ysb.set) 18 | 19 | with open("contacts.csv", newline="") as f: 20 | for contact in csv.reader(f): 21 | self.tree.insert("", tk.END, values=contact) 22 | self.tree.bind("<>", self.print_selection) 23 | 24 | self.tree.grid(row=0, column=0) 25 | ysb.grid(row=0, column=1, sticky=tk.N + tk.S) 26 | self.rowconfigure(0, weight=1) 27 | self.columnconfigure(0, weight=1) 28 | 29 | def print_selection(self, event): 30 | for selection in self.tree.selection(): 31 | item = self.tree.item(selection) 32 | last_name, first_name, email = item["values"][0:3] 33 | text = "Selection: {}, {} <{}>" 34 | print(text.format(last_name, first_name, email)) 35 | 36 | 37 | if __name__ == "__main__": 38 | app = App(path=".") 39 | app.mainloop() 40 | -------------------------------------------------------------------------------- /Chapter08/code/chapter8_04.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tkinter as tk 3 | import tkinter.ttk as ttk 4 | 5 | class App(tk.Tk): 6 | def __init__(self, path): 7 | super().__init__() 8 | self.title("Ttk Treeview") 9 | 10 | abspath = os.path.abspath(path) 11 | self.nodes = {} 12 | self.tree = ttk.Treeview(self) 13 | self.tree.heading("#0", text=abspath, anchor=tk.W) 14 | ysb = ttk.Scrollbar(self, orient=tk.VERTICAL, 15 | command=self.tree.yview) 16 | xsb = ttk.Scrollbar(self, orient=tk.HORIZONTAL, 17 | command=self.tree.xview) 18 | self.tree.configure(yscroll=ysb.set, xscroll=xsb.set) 19 | 20 | self.tree.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W) 21 | ysb.grid(row=0, column=1, sticky=tk.N + tk.S) 22 | xsb.grid(row=1, column=0, sticky=tk.E + tk.W) 23 | self.rowconfigure(0, weight=1) 24 | self.columnconfigure(0, weight=1) 25 | 26 | self.tree.bind("<>", self.open_node) 27 | self.populate_node("", abspath) 28 | 29 | def populate_node(self, parent, abspath): 30 | for entry in os.listdir(abspath): 31 | entry_path = os.path.join(abspath, entry) 32 | node = self.tree.insert(parent, tk.END, text=entry, open=False) 33 | if os.path.isdir(entry_path): 34 | self.nodes[node] = entry_path 35 | self.tree.insert(node, tk.END) 36 | 37 | def open_node(self, event): 38 | item = self.tree.focus() 39 | abspath = self.nodes.pop(item, False) 40 | if abspath: 41 | children = self.tree.get_children(item) 42 | self.tree.delete(children) 43 | self.populate_node(item, abspath) 44 | 45 | 46 | if __name__ == "__main__": 47 | app = App(path=".") 48 | app.mainloop() 49 | -------------------------------------------------------------------------------- /Chapter08/code/chapter8_05.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkinter.ttk as ttk 3 | 4 | 5 | class App(tk.Tk): 6 | def __init__(self): 7 | super().__init__() 8 | self.title("Ttk Notebook") 9 | 10 | todos = { 11 | "Home": ["Do the laundry", "Go grocery shopping"], 12 | "Work": ["Install Python", "Learn Tkinter", "Reply emails"], 13 | "Vacations": ["Relax!"] 14 | } 15 | 16 | self.notebook = ttk.Notebook(self, width=250, height=100, padding=10) 17 | for key, value in todos.items(): 18 | frame = ttk.Frame(self.notebook) 19 | self.notebook.add(frame, text=key, underline=0, 20 | sticky=tk.NE + tk.SW) 21 | for text in value: 22 | ttk.Label(frame, text=text).pack(anchor=tk.W) 23 | self.label = ttk.Label(self) 24 | 25 | self.notebook.pack() 26 | self.label.pack(anchor=tk.W) 27 | self.notebook.enable_traversal() 28 | self.notebook.bind("<>", self.select_tab) 29 | 30 | def select_tab(self, event): 31 | tab_id = self.notebook.select() 32 | tab_name = self.notebook.tab(tab_id, "text") 33 | text = "Your current selection is: {}".format(tab_name) 34 | self.label.config(text=text) 35 | 36 | 37 | if __name__ == "__main__": 38 | app = App() 39 | app.mainloop() 40 | -------------------------------------------------------------------------------- /Chapter08/code/chapter8_07.py: -------------------------------------------------------------------------------- 1 | import calendar 2 | import datetime 3 | import tkinter as tk 4 | import tkinter.ttk as ttk 5 | import tkinter.font as tkfont 6 | from itertools import zip_longest 7 | 8 | class TtkCalendar(ttk.Frame): 9 | def __init__(self, master=None, **kw): 10 | now = datetime.datetime.now() 11 | fwday = kw.pop('firstweekday', calendar.MONDAY) 12 | year = kw.pop('year', now.year) 13 | month = kw.pop('month', now.month) 14 | sel_bg = kw.pop('selectbackground', '#ecffc4') 15 | sel_fg = kw.pop('selectforeground', '#05640e') 16 | 17 | super().__init__(master, **kw) 18 | 19 | self.selected = None 20 | self.date = datetime.date(year, month, 1) 21 | self.cal = calendar.TextCalendar(fwday) 22 | self.font = tkfont.Font(self) 23 | self.header = self.create_header() 24 | self.table = self.create_table() 25 | self.canvas = self.create_canvas(sel_bg, sel_fg) 26 | self.build_calendar() 27 | 28 | def create_header(self): 29 | left_arrow = {'children': [('Button.leftarrow', None)]} 30 | right_arrow = {'children': [('Button.rightarrow', None)]} 31 | style = ttk.Style(self) 32 | style.layout('L.TButton', [('Button.focus', left_arrow)]) 33 | style.layout('R.TButton', [('Button.focus', right_arrow)]) 34 | 35 | hframe = ttk.Frame(self) 36 | btn_left = ttk.Button(hframe, style='L.TButton', 37 | command=lambda: self.move_month(-1)) 38 | btn_right = ttk.Button(hframe, style='R.TButton', 39 | command=lambda: self.move_month(1)) 40 | label = ttk.Label(hframe, width=15, anchor='center') 41 | 42 | hframe.pack(pady=5, anchor=tk.CENTER) 43 | btn_left.grid(row=0, column=0) 44 | label.grid(row=0, column=1, padx=12) 45 | btn_right.grid(row=0, column=2) 46 | return label 47 | 48 | def move_month(self, offset): 49 | self.canvas.place_forget() 50 | month = self.date.month - 1 + offset 51 | year = self.date.year + month // 12 52 | month = month % 12 + 1 53 | self.date = datetime.date(year, month, 1) 54 | self.build_calendar() 55 | 56 | def create_table(self): 57 | cols = self.cal.formatweekheader(3).split() 58 | table = ttk.Treeview(self, show='', selectmode='none', 59 | height=7, columns=cols) 60 | table.bind('', self.minsize) 61 | table.pack(expand=1, fill=tk.BOTH) 62 | table.tag_configure('header', background='grey90') 63 | table.insert('', tk.END, values=cols, tag='header') 64 | for _ in range(6): 65 | table.insert('', tk.END) 66 | 67 | width = max(map(self.font.measure, cols)) 68 | for col in cols: 69 | table.column(col, width=width, minwidth=width, anchor=tk.E) 70 | return table 71 | 72 | def minsize(self, e): 73 | width, height = self.master.geometry().split('x') 74 | height = height[:height.index('+')] 75 | self.master.minsize(width, height) 76 | 77 | def create_canvas(self, bg, fg): 78 | canvas = tk.Canvas(self.table, background=bg, 79 | borderwidth=0, highlightthickness=0) 80 | canvas.text = canvas.create_text(0, 0, fill=fg, anchor=tk.W) 81 | handler = lambda _: canvas.place_forget() 82 | canvas.bind('', handler) 83 | self.table.bind('', handler) 84 | self.table.bind('', self.pressed) 85 | return canvas 86 | 87 | def build_calendar(self): 88 | year, month = self.date.year, self.date.month 89 | month_name = self.cal.formatmonthname(year, month, 0) 90 | month_weeks = self.cal.monthdayscalendar(year, month) 91 | 92 | self.header.config(text=month_name.title()) 93 | items = self.table.get_children()[1:] 94 | for week, item in zip_longest(month_weeks, items): 95 | week = week if week else [] 96 | fmt_week = ['%02d' % day if day else '' for day in week] 97 | self.table.item(item, values=fmt_week) 98 | 99 | def pressed(self, event): 100 | x, y, widget = event.x, event.y, event.widget 101 | item = widget.identify_row(y) 102 | column = widget.identify_column(x) 103 | items = self.table.get_children()[1:] 104 | 105 | if not column or not item in items: 106 | # clicked te header or outside the columns 107 | return 108 | 109 | index = int(column[1]) - 1 110 | values = widget.item(item)['values'] 111 | text = values[index] if len(values) else None 112 | bbox = widget.bbox(item, column) 113 | if bbox and text: 114 | self.selected = '%02d' % text 115 | self.show_selection(bbox) 116 | 117 | def show_selection(self, bbox): 118 | canvas, text = self.canvas, self.selected 119 | x, y, width, height = bbox 120 | textw = self.font.measure(text) 121 | canvas.configure(width=width, height=height) 122 | canvas.coords(canvas.text, width - textw, height / 2 - 1) 123 | canvas.itemconfigure(canvas.text, text=text) 124 | canvas.place(x=x, y=y) 125 | 126 | @property 127 | def selection(self): 128 | if self.selected: 129 | year, month = self.date.year, self.date.month 130 | return datetime.date(year, month, int(self.selected)) 131 | 132 | def main(): 133 | root = tk.Tk() 134 | root.title('Tkinter Calendar') 135 | ttkcal = TtkCalendar(firstweekday=calendar.SUNDAY) 136 | ttkcal.pack(expand=True, fill=tk.BOTH) 137 | root.mainloop() 138 | 139 | if __name__ == '__main__': 140 | main() 141 | -------------------------------------------------------------------------------- /Chapter08/code/contacts.csv: -------------------------------------------------------------------------------- 1 | Gauford,Albertine,agauford0@acme.com,(614) 7171720 2 | Greger,Bryce,bgreger1@acme.com,(616) 3543513 3 | Wetherald,Rickey,rwetherald2@acme.com,(379) 3652495 4 | Onthank,Giustina,gonthank3@acme.com,(470) 1613459 5 | Clever,Ulric,uclever4@acme.com,(579) 3188349 6 | Guthrum,Amble,aguthrum5@acme.com,(191) 4356443 7 | Guppey,Austine,aguppey6@acme.com,(636) 7807866 8 | Farndale,Gerhardt,gfarndale7@acme.com,(129) 9236444 9 | Wolfenden,Caressa,cwolfenden8@acme.com,(160) 7019009 10 | Holliar,Robbyn,rholliar9@acme.com,(996) 8863254 11 | MacAllaster,Lisabeth,lmacallastera@acme.com,(830) 3076674 12 | Ottewell,Ketty,kottewellb@acme.com,(680) 5614534 13 | Dreghorn,Tallie,tdreghornc@acme.com,(385) 5801832 14 | Leverette,Brennen,bleveretted@acme.com,(257) 7707057 15 | Charteris,Vonny,vcharterise@acme.com,(957) 7090396 16 | Ennor,Link,lennorf@acme.com,(116) 8589409 17 | Snedden,Rosetta,rsneddeng@acme.com,(908) 5181175 18 | Ilyas,Ernesta,eilyash@acme.com,(108) 6077588 19 | Endon,Stevana,sendoni@acme.com,(368) 6447169 20 | Mathiasen,Daphne,dmathiasenj@163.com,(965) 1009795 21 | Rhodus,Florida,frhodusk@acme.com,(488) 9897785 22 | Jagels,Bryana,bjagelsl@acme.com,(722) 2442603 23 | Saynor,Nicol,nsaynorm@acme.com,(386) 2867726 24 | Binnall,Malachi,mbinnalln@acme.com,(237) 4258228 25 | Hould,Henka,hhouldo@acme.com,(969) 3822679 26 | Van Haeften,Selma,svanhaeftenp@acme.com,(327) 3416415 27 | Gonzalo,Raimundo,rgonzaloq@acme.com,(295) 3105088 28 | Hutson,Ettie,ehutsonr@acme.com,(870) 3659278 29 | Jeffries,Domenico,djeffriess@acme.com,(979) 2015367 30 | Colcomb,Melicent,mcolcombt@acme.com,(726) 4724236 -------------------------------------------------------------------------------- /Chapter08/images/B09199_08_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter08/images/B09199_08_01.png -------------------------------------------------------------------------------- /Chapter08/images/B09199_08_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter08/images/B09199_08_02.png -------------------------------------------------------------------------------- /Chapter08/images/B09199_08_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter08/images/B09199_08_03.png -------------------------------------------------------------------------------- /Chapter08/images/B09199_08_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter08/images/B09199_08_04.png -------------------------------------------------------------------------------- /Chapter08/images/B09199_08_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter08/images/B09199_08_05.png -------------------------------------------------------------------------------- /Chapter08/images/B09199_08_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter08/images/B09199_08_06.png -------------------------------------------------------------------------------- /Chapter08/images/B09199_08_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Tkinter-GUI-Application-Development-Cookbook/ff63b41e4829ed8c894b65b2165eb0cdcc1fbd5f/Chapter08/images/B09199_08_07.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Tkinter GUI Application Development Cookbook 5 | 6 | 7 | This is the code repository for [Tkinter GUI Application Development Cookbook](https://www.packtpub.com/web-development/tkinter-gui-application-development-cookbook?utm_source=GitHub&utm_medium=repo&utm_campaign=9781788622301), published by [Packt](https://www.packtpub.com). It contains all the supporting project files necessary to work through the book from start to finish. 8 | 9 | ## About the Book 10 | 11 | Tkinter GUI Application Development Cookbook starts with an overview of Tkinter classes and at the same time provides recipes for basic topics, such as layout patterns and event handling. Next, we cover how to develop common GUI patterns, such as entering and saving data, navigating through menus and dialogs, and performing long-running actions in the background.You can then make your apps leverage network resources effectively and perform graphical operations on a canvas and related tasks such as detecting collisions between items. Finally, this book covers using themed widgets, an extension of Tk widgets that have a more native look and feel. Finally, this book covers using the canvas and themed widgets. 12 | 13 | By the end of the book, you will have an in-depth knowledge of Tkinter classes, and will know how to use them to build efficient and rich GUI applications. 14 | 15 | ## Instructions and Navigations 16 | All of the code is organized into folders. Each folder starts with a number followed by the application name. For example, Chapter01. 17 | 18 | 19 | 20 | The code will look like the following: 21 | ``` 22 | 23 | import tkinter as tk 24 | 25 | class App(tk.Tk): 26 | def __init__(self): 27 | super().__init__() 28 | self.btn = tk.Button(self, text="Click me!", 29 | command=self.say_hello) 30 | self.btn.pack(padx=120, pady=30) 31 | 32 | def say_hello(self): 33 | print("Hello, Tkinter!") 34 | 35 | if __name__ == "__main__": 36 | app = App() 37 | app.title("My Tkinter app") 38 | app.mainloop() 39 | 40 | 41 | ``` 42 | 43 | ## Related Products 44 | * [Tkinter GUI Application Development Blueprints - Second Edition](https://www.packtpub.com/application-development/tkinter-gui-application-development-blueprints-second-edition?utm_source=GitHub&utm_medium=repo&utm_campaign=9781788837460) 45 | 46 | * [Tkinter GUI Application Development Projects [Video]](https://www.packtpub.com/application-development/tkinter-gui-application-development-projects-video?utm_source=GitHub&utm_medium=repo&utm_campaign=9781787280151) 47 | 48 | * [Python GUI Programming Cookbook - Second Edition](https://www.packtpub.com/application-development/python-gui-programming-cookbook-second-edition?utm_source=GitHub&utm_medium=repo&utm_campaign=9781787129450) 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | ### Download a free PDF 58 | 59 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
60 |

https://packt.link/free-ebook/9781788622301

--------------------------------------------------------------------------------