Comenius University, Faculty of Mathematics Physics and Informatics,

Summer Semester 2022/2023


How to Set Up Python Tkinter (On Win64)?

1. Install Python: https://www.python.org/downloads/release/python-3112/
To verify, you should be able to run

> python
Python 3.10.5 (main, Jun 18 2022, 01:16:30)  [GCC 12.1.0 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.

in the cmd.exe.

2. Test Tkinter (should already be included in Python 3.11) with a basic “Hello World” example:

from tkinter import *
from tkinter import ttk
root = Tk()
frm = ttk.Frame(root, padding=10)
frm.grid()
ttk.Label(frm, text="Hello World!").grid(column=0, row=0)
ttk.Button(frm, text="Quit", command=root.destroy).grid(column=1, row=0) 
root.mainloop()

A window like this should appear:


Basic Concepts in Tkinter

https://docs.python.org/3/library/tkinter.html#module-tkinter

A Canvas Widget in Tkinter

from tkinter import *
from tkinter import ttk
root = Tk()

canvas = Canvas(root, bg="blue", height=250, width=300)
coord = 10, 50, 240, 210
arc = canvas.create_arc(coord, start=0, extent=150, fill="red")
canvas.pack()
root.mainloop()

The result should look like this:

Draw functions:

  • create_arc(coord, start=0, extent=150, fill=”blue”)
  • create_image(50, 50, anchor=NE, image=filename) # loads an image
  • create_line(x0, y0, x1, y1, …, xn, yn, options)
  • create_oval(x0, y0, x1, y1, options)
  • create_polygon(x0, y0, x1, y1,…xn, yn, options)
  • create_rectangle(xmin, ymin, xmax, ymax)

Mouse Drawing Example:

from tkinter import *
from tkinter import ttk
root = Tk()

canvas = Canvas(root, bg="blue", height=250, width=300)

def draw_pixel(p):
	x, y = p.x, p.y
	canvas.create_rectangle(x, y, x + 1, y + 1, fill="red", outline="")

canvas.pack()

root.bind('<ButtonPress-1>', draw_pixel)
root.bind('<B1-Motion>', draw_pixel)

root.mainloop()

You should be able to draw strokes which are 1×1 pixels in size:

Map Colorpicker Output to Brush

from tkinter import *
from tkinter import ttk
from tkinter.colorchooser import askcolor

root = Tk()
 
canvas = Canvas(root, bg="blue", height=400, width=500)
w = 50 # brush width

class PaintBrush():
    def __init__(self, color, width):
        self.color = color
        self.width = width

    def draw_pixel(self, p):
        x, y = p.x, p.y
        canvas.create_rectangle(x - w / 2, y - w / 2, x + w / 2, y + w / 2, fill=self.color, outline="")

brush = PaintBrush("red", w) # define active brush

def change_color(p):
    colors = askcolor(title="Tkinter Color Chooser")
    brush.color=colors[1]

canvas.pack()
 
root.bind('<ButtonPress-1>', brush.draw_pixel)
root.bind('<B1-Motion>', brush.draw_pixel)

 # map scroll wheel click to colorpicker
root.bind('<ButtonPress-2>', change_color)

root.mainloop()

Result:

OOP Application Design:

from tkinter import *
import tkinter as tk
from tkinter.colorchooser import askcolor

class PaintBrush():
    def __init__(self, canvas, color, width):
        self.color = color
        self.width = width
        self.canvas = canvas
 
    def draw_pixel(self, p):
        x, y = p.x, p.y
        w = self.width
        self.canvas.create_rectangle(x - w / 2, y - w / 2, x + w / 2, y + w / 2, fill = self.color, outline = "")

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        self.canvas = Canvas(self, bg = "blue", height = 400, width = 500)
        self.canvas.pack()
        self.brush = PaintBrush(self.canvas, "red", 50)
        root.bind('<ButtonPress-1>', self.brush.draw_pixel) # bind left button to self.brush.draw_pixel
        root.bind('<B1-Motion>', self.brush.draw_pixel) # bind mouse move to self.brush.draw_pixel         
        root.bind('<ButtonPress-2>', self.change_color) # bind scroll wheel click to colorpicker

    def change_color(self, p):
        colors = askcolor(title="Tkinter Color Chooser")
        self.brush.color = colors[1]

if __name__ == "__main__":
    root = tk.Tk()
    MainApplication(root).pack(side = "top", fill = "both", expand = True)
    root.mainloop()

Interesting demo: https://github.com/geosaleh/DoodleDrawing


GitHub Repo For Our Project This Semester:

https://github.com/MCInversion/ICG_Painter2023

Here’s an overview of how Git works:

DISCLAIMER: I prefer to use the terminal commands. The Git terminal can be opened by right-clicking a directory and choosing “Git Bash Here”. The Git GUI and other alternative tools like GitKraken are, of course, more user-friendly.


Foreword:

Git is an incredibly powerful tool for version control, and it has become a cornerstone of modern software development, especially for open source projects.

With Git, developers can easily keep track of changes to code, collaborate with others, and even revert to earlier versions of a project. This is critical because software development is an iterative process, and it’s not uncommon for developers to make mistakes or introduce bugs into their code. With Git, developers can quickly identify and fix issues, and they can collaborate with other developers to ensure that everyone is working on the same version of the project. Additionally, Git makes it easy to track changes over time, which can be incredibly useful for debugging or auditing purposes.

This will be a brief overview of the key functions useful for our workflow in this course. As the matter of fact, these are the functions I know from memory because I use them all the time without even thinking about them. Git is, of course, way more versatile and way more complicated than this.


Git Crash Course in: 3 … 2 … 1:

After installing Git for Windows, make sure to clone the repo to your local workspace to work on it:

$ git clone https://github.com/MCInversion/ICG_Painter2023.git

This command will create folder ICG_Painter2023 in the directory where it’s called. The local repository will have branch dev which is the main development branch. You cannot push to dev. You can only create a pull-request which needs to be accepted by the branch owner (me).

If you want to clone into a specific folder you can use:

$ git clone https://github.com/MCInversion/ICG_Painter2023.git MyICGPainterFolder

Now obviously, you want to switch your local repository to your own newly-created branch:

$ git pull
From https://github.com/MCInversion/ICG_Painter2023
 * [new branch]      MyNewBranch -> origin/MyNewBranch
Already up to date.
$ git checkout MyNewBranch

the first step git pull is important if the branch is created remotely (on Github) because the “branchspec” needs to be pulled from the remote. You can then view the available branches by typing git branch which will also display the current branch.

Now you can do your local coding work.


If you make any changes to the files in the repository, they will be marked into the index. You can check which files were modified/added/deleted by:

$ git status
On branch MyNewBranch
Your branch is up to date with 'origin/MyNewBranch'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   ICGPaint.py
        modified:   src/defaults.py
        modified:   src/image_project.py

You can also see the individual changes line-by-line using:

$ git diff

If you want to send your changes to the remote of MyNewBranch, you need to follow this process:

$ git add .

Adds all changes to index. If you want to add only specific files you need to specify them separated by whitespaces after the “add” command, for example git add src/defaults.py src/image_project.py.

After this, you need to commit:

$ git commit -m "Write a brief message about what you did in this change."

After this, the changes are committed, but still not sent to remote. To send them to remote, you need to:

$ git push

If there are changes on the remote branch, you can do git pull. However, this won’t work if you have unmerged changes or changes not yet indexed. git stash is a useful command for putting all your unindexed changes away without losing them. Stash works as a stack. You can restore the stashed changes with:

$ git stash pop

If there are changes merged to dev, chances are you’re going to need them locally. This means you need to keep you local branch BrushSizeSetting updated. One way to do this is to locally switch to dev, pull changes and merge with your branch:

$ git checkout dev
Switched to branch 'dev'
Your branch is behind 'origin/dev' by 6 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

Martin@DESKTOP-9AINJON MINGW64 ~/source/python/ICG_Painter2023 (dev)
$ git pull
Updating 075427e..ad71652
Fast-forward
 README.md                  |   6 +++++-
 readme_res/painterScrn.jpg | Bin 0 -> 80880 bytes
 2 files changed, 5 insertions(+), 1 deletion(-)
 create mode 100644 readme_res/painterScrn.jpg

Martin@DESKTOP-9AINJON MINGW64 ~/source/python/ICG_Painter2023 (dev)
$ git checkout BrushSizeSetting
Switched to branch 'BrushSizeSetting'
Your branch is up to date with 'origin/BrushSizeSetting'.

Martin@DESKTOP-9AINJON MINGW64 ~/source/python/ICG_Painter2023 (BrushSizeSetting)
$ git merge dev
Merge made by the 'recursive' strategy.
 README.md                  |   6 +++++-
 readme_res/painterScrn.jpg | Bin 0 -> 80880 bytes
 2 files changed, 5 insertions(+), 1 deletion(-)
 create mode 100644 readme_res/painterScrn.jpg

the final merge command may switch to a vim-like terminal where you can type a longer merge commit message. A similar thing can be done by just calling git commit without the message parameters. If you don’t want to change the default merge message, just type the quit command :q.


There are, of course, many many more options for these and other commands which may become useful. For more information see https://education.github.com/git-cheat-sheet-education.pdf .

https://www.git-tower.com/learn/cheat-sheets/cli

Leave a comment