Object-Oriented Programming/GUI Applications/Canvas
Appearance
"""This program demonstrates object-oriented Python GUI using tkinter.
Input:
None
Output:
Welcome frame
Cards frame
Canvas drawing area
Notes:
tkinter provides widgets for displaying text and graphics and a canvas
for drawing. The Welcome frame demonstrates text and buttons. The Cards
frame demonstrates images. The Canvas demonstrates drawing.
This program uses Internet-based Wikimedia Commons images to make copying
and pasting the code easier. Any images used in a production program should
be saved locally and/or downloaded and cached to improve performance. In that
case, the self.update() calls would not be necessary.
References:
https://www.tutorialspoint.com/python/python_gui_programming.htm
https://www.python-course.eu/python_tkinter.php
https://stackoverflow.com/questions/22785949/subclassing-with-tkinter-in-python
http://effbot.org/tkinterbook/canvas.htm
http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
"""
import tkinter
import urllib.request
# Requires pip install Pillow
import PIL.Image
import PIL.ImageTk
# Bypass certificate verification
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
class Root(tkinter.Tk):
"""Creates root window."""
def __init__(self, *args, **kwargs):
tkinter.Tk.__init__(self, *args, **kwargs)
self.title("tkinter Frame Example")
self.geometry("%dx%d+0+0" % self.maxsize())
self._menu = MainMenu(self)
self._container = None
self.show_welcome()
def show_welcome(self):
if self._container != None:
self._container.destroy()
self._container = Welcome(self)
def show_cards(self):
if self._container != None:
self._container.destroy()
self._container = Cards(self)
url = "https://upload.wikimedia.org/wikipedia/commons/thumb/"
self._container.add_image(
url + "f/f0/SuitHearts.svg/200px-SuitHearts.svg.png",
20, 20, "heart")
self.update()
self._container.add_image(
url + "5/5b/SuitSpades.svg/200px-SuitSpades.svg.png",
240, 20, "spade")
self.update()
self._container.add_image(
url + "d/db/SuitDiamonds.svg/200px-SuitDiamonds.svg.png",
460, 20, "diamond")
self.update()
self._container.add_image(
url + "8/8a/SuitClubs.svg/200px-SuitClubs.svg.png",
680, 20, "club")
self.update()
def show_canvas(self):
if self._container:
self._container.destroy()
self._container = Canvas(self)
url = "https://upload.wikimedia.org/wikipedia/commons/thumb/"
self._container.add_image(
url + "f/f0/SuitHearts.svg/200px-SuitHearts.svg.png",
20, 250, "heart")
self.update()
self._container.add_image(
url + "5/5b/SuitSpades.svg/200px-SuitSpades.svg.png",
240, 250, "spade")
self.update()
self._container.add_image(
url + "d/db/SuitDiamonds.svg/200px-SuitDiamonds.svg.png",
460, 250, "diamond")
self.update()
self._container.add_image(
url + "8/8a/SuitClubs.svg/200px-SuitClubs.svg.png",
680, 250, "club")
self.update()
class MainMenu(tkinter.Menu):
"""Creates Main menu."""
@property
def root(self):
return self._root
def __init__(self, root, *args, **kwargs):
tkinter.Menu.__init__(self, root, *args, **kwargs)
self._root = root
window_menu = WindowMenu(self, tearoff=0)
self.add_cascade(label="Window", menu=window_menu)
root.config(menu = self)
class WindowMenu(tkinter.Menu):
"""Creates Window menu."""
def __init__(self, parent, *args, **kwargs):
tkinter.Menu.__init__(self, parent, *args, **kwargs)
self.add_command(label="Welcome", command=parent.root.show_welcome)
self.add_command(label="Cards", command=parent.root.show_cards)
self.add_command(label="Canvas", command=parent.root.show_canvas)
self.add_command(label="Exit", command=parent.root.quit)
class Welcome(tkinter.Frame):
"""Creates welcome frame."""
def __init__(self, root, *args, **kwargs):
self._root = root
tkinter.Frame.__init__(self, root, *args, **kwargs)
self.pack(fill="both", expand=True)
welcome_label = tkinter.Label(self, text="Welcome to tkinter Frame Examples")
welcome_label.grid(row=1, column=1)
question_label = tkinter.Label(self, text="Are you ready to continue?")
question_label.grid(row=2, column=1)
buttons_frame = tkinter.Frame(self)
buttons_frame.grid(row=3, column=1)
cards_button = tkinter.Button(
buttons_frame,
text="Show Cards",
command=self.cards_click)
cards_button.grid(row=1, column=1)
canvas_button = tkinter.Button(
buttons_frame,
text="Show Canvas",
command=self.canvas_click)
canvas_button.grid(row=1, column=2)
quit_button = tkinter.Button(
buttons_frame,
text="Quit",
command=root.quit)
quit_button.grid(row=1, column=3)
def cards_click(self):
self._root.show_cards()
def canvas_click(self):
self._root.show_canvas()
class Cards(tkinter.Frame):
"""Creates card frame."""
_images = []
def __init__(self, root, *args, **kwargs):
self._root = root
tkinter.Frame.__init__(self, root, *args, **kwargs)
self.pack(fill="both", expand=True)
def add_image(self, url, x, y, tags=None):
"""Adds image from URL to frame at coordinates(x, y)."""
print(x, y, url)
response = urllib.request.urlopen(url)
image = PIL.Image.open(response)
photoimage = PIL.ImageTk.PhotoImage(image)
self._images.append(photoimage)
label = tkinter.Label(self, image=photoimage)
label.image = photoimage
label.place(x=x, y=y)
class Canvas(tkinter.Canvas):
"""Creates drawing canvas."""
_images = []
def __init__(self, root, *args, **kwargs):
tkinter.Canvas.__init__(self, root, *args, **kwargs)
self.bind("<Button-1>", self.on_click)
self.bind("<B1-Motion>", self.on_drag)
self.pack(fill="both", expand=True)
self.create_text(450, 50, font=("Purisa", 24), text="tkinter Canvas Drawing Examples")
self.create_line(175, 150, 275, 150, width=3, fill="darkred")
self.create_rectangle(325, 100, 425, 200, outline="gold", fill="gold")
self.create_oval(475, 100, 575, 200, outline="darkgreen", fill="darkgreen")
self.create_polygon(675, 100, 625, 200, 725, 200, outline="darkblue", fill="darkblue")
self.create_text(450, 510, font=("Purisa", 24), text="drag mouse to draw")
def add_image(self, url, x, y, tags=None):
"""Adds image from URL to canvas at coordinates(x, y)."""
response = urllib.request.urlopen(url)
image = PIL.Image.open(response)
photoimage = PIL.ImageTk.PhotoImage(image)
self._images.append(photoimage)
self.create_image(x, y, anchor=tkinter.NW, image=photoimage, tags=tags)
def on_click(self, event):
self.create_oval(event.x - 5, event.y - 5, event.x + 5, event.y + 5, outline="black", fill="black")
def on_drag(self, event):
self.create_oval(event.x - 5, event.y - 5, event.x + 5, event.y + 5, outline="black", fill="black")
if __name__ == "__main__":
if tkinter.TkVersion < 8.6:
print(f"tkinter.TkVersion is {tkinter.TkVersion}. Version 8.6 or higher is required.")
exit(1)
root = Root()
root.mainloop()