Интересные проекты Tkinter

1. Инструмент для обновления PIP в Windows

Разберем простой инструмент для обновления PIP.

Обратите внимание, что вам нужно добавить Python к Windows PATH для использования данного инструмента.

Далее дан полный код Python для инструмента обновления PIP используя Tkinter:

# Импортируем модули
import os
import tkinter as tk

# создание экземпляра класса Tk(), для отображенния окна приложения
root= tk.Tk()

# создаем холст с размерами, цветом
canvas1 = tk.Canvas(root, width = 300, height = 350, bg = 'lightsteelblue2', relief = 'raised')
canvas1.pack()

# создаем текстовую метку
label1 = tk.Label(root, text='Upgrade PIP', bg = 'lightsteelblue2')
label1.config(font=('helvetica', 20))
canvas1.create_window(150, 80, window=label1)

# создаем функцию с вызовом командной строки и командой обновления
def upgradePIP ():
    os.system('start cmd /k python.exe -m pip install --upgrade pip') 
    
# создаем кнопку с текстом и размерами
button1 = tk.Button(text='      Upgrade PIP     ', command=upgradePIP, bg='green', fg='white', font=('helvetica', 12, 'bold'))
canvas1.create_window(150, 180, window=button1)

# запуск цикла программы
root.mainloop()

Просто запустите код и затем нажмите на кнопку Upgrade PIP, после чего команда выполнится.

2. Электронные часы

В сегодняшней статье мы рассмотрим, как создать цифровые часы при помощи Python и Tkinter. Также нам понадобится модуль time. Мы создадим окно, затем добавим к нему метку Lable, в которой будут отображаться цифровые знаки, обновляющиеся по логике часов. Так мы будем имитировать изменение времени. И так, приступим.

# Для начала импортируем все элементы из модуля

from  tkinter import *

from tkinter.ttk import *

# импорт модуля для преобразования кортежей через format
from  time import  strftime


# создание экземпляра класса Tk(), для отображенния окна приложения
root = Tk()
# добавление заголовка к окну
root.title('Часы')

# создание текстовой метки в окне прилржения, для отображения цифровых знаков. Цифры будут белыми на черном фоне
lable = Label(root, font=('aerial', 30), background='black', foreground='white')


# функция отображения времени
def time():
    string = strftime('%H:%M:%S %p')
    lable.config(text=string)
    lable.after(1000, time)


# азмещение метки времени по центру
lable.pack(anchor='center')
time()


# запуск цикла программы
mainloop()

3. Ну что дружок, погоняем кружок

Зеленый кружок можно двигать клавишами стрелок

# Импортируем модуль
from tkinter import *


# создаем окно
root = Tk()
c = Canvas(width=300, height=300, 
           bg='white')
c.focus_set()
c.pack()
 

# создаем круг
ball = c.create_oval(140, 140, 160, 160, 
                     fill='green')

# реагируем на клавиши
c.bind('<Up>', 
       lambda event: c.move(ball, 0, -2))
c.bind('<Down>', 
       lambda event: c.move(ball, 0, 2))
c.bind('<Left>', 
       lambda event: c.move(ball, -2, 0))
c.bind('<Right>', 
       lambda event: c.move(ball, 2, 0))
 

# создаем цикл
root.mainloop()

В данном примере круг двигается по холсту с помощью стрелок на клавиатуре. Когда создавался круг, его идентификатор был присвоен переменной ball. Метод move объекта Canvas принимает идентификатор и смещение по осям.

4. AwesomeTkinter предлагает несколько симпатичных виджетов tkinter.

Эти виджеты представляют собой всего лишь виджеты tkinter с пользовательскими стилями и изображениями.

Не забываем pip install awesometkinter

import tkinter as tk
from tkinter import ttk
import awesometkinter as atk

# our root
root = tk.Tk()
root.config(background=atk.DEFAULT_COLOR)

# select tkinter theme required for things to be right on windows,
# only 'alt', 'default', or 'classic' can work fine on windows 10
s = ttk.Style()
s.theme_use('default')

# 3d frame
f1 = atk.Frame3d(root)
f1.pack(side='left', expand=True, fill='both', padx=3, pady=3)

# 3d progressbar
bar = atk.RadialProgressbar3d(f1, fg='cyan', size=120)
bar.pack(padx=20, pady=20)
bar.start()

# 3d button
atk.Button3d(f1, text='3D Button').pack(pady=10)

f2 = atk.Frame3d(root)
f2.pack(side='left', expand=True, fill='both', padx=3, pady=3)

# flat radial progressbar
bar = atk.RadialProgressbar(f2, fg='green')
bar.pack(padx=30, pady=30)
bar.start()

atk.Button3d(f2, text='Pressed Button').pack(pady=10)

f3 = atk.Frame3d(root)
f3.pack(side='left', expand=True, fill='both', padx=3, pady=3)

atk.Radiobutton(f3, text="Radiobutton 1").pack(padx=20, pady=(20, 5))
atk.Radiobutton(f3, text="Radiobutton 2", ind_outline_color='white', ind_bg='yellow',
                ind_mark_color='red').pack(padx=20, pady=5)

atk.Checkbutton(f3, text=" Checkbutton 1", check_mark_color='red', size=12).pack(padx=20, pady=(20, 5))
atk.Checkbutton(f3, text=" Checkbutton 2").pack(padx=20, pady=5)


root.mainloop()
)

Радиокнопки

import tkinter as tk
from tkinter import ttk
import awesometkinter as atk

root = tk.Tk()
root.title('AwesomeTkinter')

# select tkinter theme required for things to be right on windows,
# only 'alt', 'default', or 'classic' can work fine on windows 10
s = ttk.Style()
s.theme_use('default')

f = tk.Frame(root, bg='white')
f.pack(expand=True, fill='both')

# radio buttons' variable
var = tk.StringVar()
var.set('test')

# lets print selection value
var.trace_add('write', lambda *args: print(var.get()))

# atk radiobutton, you can control indicator ring, fill, and mark color
atk.Radiobutton(f, text='AwesomeTkinter Radiobutton', variable=var).pack(padx=17, pady=10, anchor='w')
atk.Radiobutton(f, text='AwesomeTkinter Radiobutton, selected', value='test', variable=var).pack(padx=17, pady=10, anchor='w')

ttk.Separator(f).pack(expand=True, fill='x')

# standard tk button
tk.Radiobutton(f, text='standard tk Radiobutton', variable=var, value='standard tk Radiobutton', fg='black',
               bg='white').pack(padx=10, pady=10, anchor='w')
tk.Radiobutton(f, text='standard tk Radiobutton, selected', variable=var, value='test', bg='white',
               fg='black').pack(padx=10, pady=10, anchor='w')

ttk.Separator(f).pack(expand=True, fill='x')

# standard ttk Radiobutton
ttk.Radiobutton(f, text='standard ttk Radiobutton', variable=var).pack(padx=15, pady=10, anchor='w')
ttk.Radiobutton(f, text='standard ttk Radiobutton, selected', variable=var, value='test').pack(padx=15, pady=10, anchor='w')

ttk.Separator(f).pack(expand=True, fill='x')

# atk with custom colors
atk.Radiobutton(f, text='AwesomeTkinter Radiobutton, with custom colors', ind_bg='yellow', ind_outline_color='red',
                ind_mark_color='blue', variable=var, value='test').pack(padx=17, pady=10, anchor='w')
root.mainloop()
)

5. Переводчик (используем translate)

не забываем про: pip install tranlate

Ссылка

from tkinter import *
from translate import Translator

#Функция перевода 
def translate():
    translator= Translator(from_lang=lan1.get(),to_lang=lan2.get())
    translation = translator.translate(var.get())
    var1.set(translation)

#Корневое окно Tkinter с заголовком
root = Tk()
root.title("Переводчик")

#Создание рамки и сетки для размещения содержимого
mainframe = Frame(root)
mainframe.grid(column=0,row=0, sticky=(N,W,E,S) )
mainframe.columnconfigure(0, weight = 1)
mainframe.rowconfigure(0, weight = 1)
mainframe.pack(pady = 100, padx = 100)

#переменные для выпадающего списка
lan1 = StringVar(root)
lan2 = StringVar(root)

#варианты для отображения в выпадающем меню
choices = { 'English','Hindi','Gujarati','Spanish','German', 'Russian'}
#default selection for dropdownlists
lan1.set('English')
lan2.set('Russian')

#создание выпадающего списка и упорядочивание в сетке
lan1menu = OptionMenu( mainframe, lan1, *choices)
Label(mainframe,text="Выбор языка").grid(row = 0, column = 1)
lan1menu.grid(row = 1, column =1)

lan2menu = OptionMenu( mainframe, lan2, *choices)
Label(mainframe,text="Выбор языка").grid(row = 0, column = 2)
lan2menu.grid(row = 1, column =2)

#Текстовое поле для ввода пользователем
Label(mainframe, text = "Введите текст").grid(row=2,column=0)
var = StringVar()
textbox = Entry(mainframe, textvariable=var).grid(row=2,column=1)

#текстовое поле для отображения выходных данных
#также можно использовать этикетку
Label(mainframe, text = "Выход").grid(row=2,column=2)
var1 = StringVar()
textbox = Entry(mainframe, textvariable=var1).grid(row=2,column=3)

#создание кнопки для вызова функции переводчика
b=Button(mainframe,text='Перевод',command=translate).grid(row=3,column=1,columnspan=3)

root.mainloop()


6. Аккуратный калькулятор

Стандартный калькулятор с графическим интерфейсом, использующий полный графический калькулятор на основе Tkinter (python)

from tkinter import *
import parser
root = Tk()

root.title('Calculator')
i = 0
def get_variables(num):
	global i
	display.insert(i,num)
	i += 1

def clear_all():
	display.delete(0, END)

def undo():
	entire_string = display.get()
	if len(entire_string):
		new_string = entire_string[:-1]
		clear_all()
		display.insert(0,new_string)
	else:
		clear_all()
		display.insert(0, "Error")


def get_operation(operator):
	global i
	length = len(operator)
	display.insert(i,operator)
	i += length

def calculate():
	entire_string = display.get()
	try:
		a = parser.expr(entire_string).compile()
		result = eval(a)
		clear_all()
		display.insert(0,result)
	except Exception:
		clear_all()
		display.insert(0,"Error")

def calcFact():
	try:
		number = int(display.get())
		res = 1
		for i in xrange(1,number + 1):
			res *= i
		clear_all()
		display.insert(0,res)

	except Exception:
		clear_all()
		display.insert(0,"Error")

display = Entry(root)

display.grid(row = 1, columnspan=6, sticky = W + E)
#adding buttons to the calculator
Button(root,text = "1", command = lambda : get_variables(1)).grid(row = 2 ,column = 0)
Button(root,text = "2", command = lambda : get_variables(2)).grid(row = 2 ,column = 1)
Button(root,text = "3", command = lambda : get_variables(3)).grid(row = 2 ,column = 2)

Button(root,text = "4", command = lambda : get_variables(4)).grid(row = 3 ,column = 0)
Button(root,text = "5", command = lambda : get_variables(5)).grid(row = 3 ,column = 1)
Button(root,text = "6", command = lambda : get_variables(6)).grid(row = 3 ,column = 2)

Button(root,text = "7", command = lambda : get_variables(7)).grid(row = 4 ,column = 0)
Button(root,text = "8", command = lambda : get_variables(8)).grid(row = 4 ,column = 1)
Button(root,text = "9", command = lambda : get_variables(9)).grid(row = 4 ,column = 2)

Button(root, text = "AC", command = lambda: clear_all()).grid(row=5, column =0)
Button(root, text = "0", command = lambda : get_variables(0)).grid(row=5, column =1)
Button(root, text = "=", command = lambda: calculate()).grid(row=5, column =2)


Button(root, text = "+", command = lambda: get_operation("+")).grid(row=2, column =3)
Button(root, text = "-", command = lambda: get_operation("-")).grid(row=3, column =3)
Button(root, text = "x", command = lambda: get_operation("*")).grid(row=4, column =3)

Button(root, text = "pi", command = lambda:get_operation("*3.14")).grid(row=2, column =4)
Button(root, text = "%", command = lambda:get_operation("%")).grid(row=3, column =4)
Button(root, text = "(", command = lambda:get_operation("(")).grid(row=4, column =4)
Button(root, text = "exp", command = lambda:get_operation("**")).grid(row=5, column =4)


Button(root, text = "<-", command = lambda : undo()).grid(row=2, column =5)
Button(root, text = "x!", command = lambda: calcFact()).grid(row=3, column =5)
Button(root, text = ")", command = lambda: get_operation(")")).grid(row=4, column =5)
Button(root, text = "^2", command = lambda: get_operation("**2")).grid(row=5, column =5)



root.mainloop()

7. tkinter-подсказка (всплывающее окно)

Ссылка

Это простая, но полностью настраиваемая реализация всплывающей подсказки/всплывающего окна для tkinterвиджетов. Он способен полностью интегрироваться с пользовательскими tkinter темами, как светлыми, так и темными.

Функции

  • обычные всплывающие подсказки
  • показать всплывающую подсказку с sсекундамиdelay
  • всплывающая подсказка отслеживает курсор мыши
  • всплывающая подсказка отображает строки и функции, возвращающие строки
  • полностью настраиваемый, всплывающая подсказка наследует основной стиль темы

Установить

pip install tkinter-tooltip

Примеры

Обычные всплывающие подсказки

По умолчанию всплывающая подсказка активируется при входе и/или перемещении внутри виджета и деактивируется при выходе и/или нажатии любой кнопки.

альтернативный
import tkinter as tk
import tkinter.ttk as ttk
from tktooltip import ToolTip

app = tk.Tk()
b = ttk.Button(app, text="Button")
b.pack()
ToolTip(b, msg="Hover info")
app.mainloop()

Отложенная подсказка

альтернативный
import tkinter as tk
import tkinter.ttk as ttk
from tktooltip import ToolTip

app = tk.Tk()
b = ttk.Button(app, text="Button")
b.pack()
ToolTip(b, msg="Hover info", delay=2.0)   # True by default
app.mainloop()

Подсказка отслеживания

Пусть всплывающая подсказка следует за курсором мусса при движении.

альтернативный
import tkinter as tk
import tkinter.ttk as ttk
from tktooltip import ToolTip

app = tk.Tk()
b = ttk.Button(app, text="Button")
b.pack()
ToolTip(b, msg="Hover info", follow=True)   # True by default
app.mainloop()

Функция как всплывающая подсказка

Здесь всплывающая подсказка возвращает значение, которое time.asctime()обновляется при каждом движении. Вы можете управлять частотой обновления сквозного ToolTipаргумента refresh , по умолчанию для него установлено значение 1s.

альтернативный
альтернативный
import time
import tkinter as tk
import tkinter.ttk as ttk
from tktooltip import ToolTip

app = tk.Tk()
b = ttk.Button(app, text="Button")
b.pack()
# NOTE: pass the function itself not the return value
ToolTip(b, msg=time.asctime, delay=0)
app.mainloop()

Тематическая подсказка

tkinter-tooltipполностью осведомлен о базовой теме (в данном случае темной теме) и даже может быть дополнительно настроен путем передачи tkаргументов стиля во всплывающую подсказку.

альтернативный

Стиль всплывающей подсказки и основы кнопки. Если использовалась полная тема, то ToolTipпо умолчанию будут унаследованы настройки темы.

import tkinter as tk
import tkinter.ttk as ttk
from tktooltip import ToolTip

app = tk.Tk()
s = ttk.Style()
s.configure("custom.TButton", foreground="#ffffff", background="#1c1c1c")
b = ttk.Button(app, text="Button", style="custom.TButton")
b.pack()
ToolTip(b, msg="Hover info", delay=0,
        parent_kwargs={"bg": "black", "padx": 5, "pady": 5},
        fg="#ffffff", bg="#1c1c1c", padx=10, pady=10)
app.mainloop()

8. ttkScrollableNotebook

Горизонтальные прокручиваемые вкладки для виджета ноутбука Tkinter Ссылка

9. TkDial

Это библиотека, содержащая некоторые виджеты с круговыми вращающимися ручками для Tkinter. Его можно использовать вместо обычных ползунков и шкалы. Ссылка

10. Таблица стилей Tkinter — Tkss

Эта библиотека поможет установить стиль для виджета по умолчанию tkinter с использованием таблицы стилей безнадежной безопасности. Ссылка

11. TkFontAwesome

Библиотека, которая позволяет вам использовать значки FontAwesome в вашем приложении tkinter. Ссылка

pip install tkfontawesome

Вы можете использовать любую из 1000+ бесплатных иконок FontAwesome 5.0 . Цвет и размер заливки настраиваются в соответствии с вашими требованиями, а затем преобразуются в объект с помощью tksvg , который можно использовать везде, где вы будете использовать tkinter.PhotoImageобъект.

12. Notepad-Tk

Блокнот, созданный с помощью Tkinter. Ссылка

13. Графический интерфейс на Python с использованием Pandas и Tkinter

Ссылка

14. Создание QR кода

#pip install qrcode pillow
import qrcode, PIL
from PIL import Image,ImageTk
import tkinter as tk
from tkinter import ttk,messagebox,filedialog



def createQR(*args):
    data = text_entry.get()
    if data:
        img = qrcode.make(data) #generate QRcode  
        res_img = img.resize((280,250)) # reszie QR Code Size
        #Convert To photoimage
        tkimage= ImageTk.PhotoImage(res_img)
        qr_canvas.create_image(0,0,anchor=tk.NW, image=tkimage)
        qr_canvas.image = tkimage
    else:
        messagebox.showwarning("Warning",'Enter Data in Entry First')

def saveQR():
    data = text_entry.get()
    if data:
        img = qrcode.make(data) #generate QRcode  
        res_img = img.resize((280,250)) # reszie QR Code Size
        
        path = filedialog.asksaveasfilename(defaultextension=".png",)
        if path:
            res_img.save(path)
            messagebox.showinfo("Sucess","QR Code is Saved ")
    else:
        messagebox.showwarning("Warning",'Enter Data in Entry First')
    



root = tk.Tk()
root.title("QR Code Generator")
root.geometry("300x380")
root.config(bg='white')
root.resizable(0,0)


frame1 = tk.Frame(root,bd=2,relief=tk.RAISED)
frame1.place(x=10,y=5,width=280,height=250)

frame2 = tk.Frame(root,bd=2,relief=tk.SUNKEN)
frame2.place(x=10,y=260,width=280,height=100)

qr_canvas = tk.Canvas(frame1)
qr_canvas.pack(fill=tk.BOTH)

text_entry = ttk.Entry(frame2,width=26,font=("Sitka Small",11),justify=tk.CENTER)
text_entry.bind("<Return>",createQR)
text_entry.place(x=5,y=5)

btn_1 = ttk.Button(frame2,text="Create",width=10,command=createQR)
btn_1.place(x=25,y=50)

btn_2 = ttk.Button(frame2,text="Save",width=10,command=saveQR)
btn_2.place(x=100,y=50)

btn_3 = ttk.Button(frame2,text="Exit",width=10,command=root.quit)
btn_3.place(x=175,y=50)


root.mainloop()

15. Выбор цвета

Создаем приложение для выбора цвета в фомате Hex и RGB .

# >> @dynamic.coding <<


"""
Python Tkinter Color Picker to choose color in Hex and RGB Format ...
"""
import tkinter as tk
from tkinter import Entry, Frame, Label
from tkinter.constants import  HORIZONTAL, RAISED, SUNKEN

class Colorpicker:
    def __init__(self,root):
        self.root = root
        self.root.title("Color Picker")
        self.root.geometry("300x420")
        self.root.resizable(0,0)

        self.R = tk.IntVar()
        self.G = tk.IntVar()
        self.B = tk.IntVar()
        self.hex = tk.IntVar()




        self.color_canvas = Label(self.root,bg="#8400ff",width=40,height=10,bd=2,relief=RAISED)
        self.color_canvas.place(x=7,y=2)
        self.color_canvas.bind("<Double-1>",self.copy_color)

        frame = Frame(self.root,bd=2,relief=SUNKEN)
        frame.place(x=7,y=170,height=180,width=285)

        r_label = Label(frame,text="R",width=5,fg="#ff0000",font=('arial',10,'bold'))
        r_label.place(x=5,y=24)

        self.R_Scale = tk.Scale(frame,from_=0,to=255,length=210,fg="#ff0000"
        ,orient=HORIZONTAL,command=self.scaleMove)
        self.R_Scale.set(132)
        self.R_Scale.place(x=40,y=6)

        g_label = Label(frame,text="G",width=5,fg="#00a200",font=('arial',10,'bold'))
        g_label.place(x=5,y=68)

        self.G_Scale = tk.Scale(frame,from_=0,to=255,length=210,fg="#00a200"
        ,orient=HORIZONTAL,command=self.scaleMove)
        self.G_Scale.place(x=40,y=50)

        b_label = Label(frame,text="B",width=5,fg="#0000ff",font=('arial',10,'bold'))
        b_label.place(x=5,y=122)

        self.B_Scale = tk.Scale(frame,from_=0,to=255,length=210,fg="#0000ff"
        ,orient=HORIZONTAL,command=self.scaleMove)
        self.B_Scale.set(255)
        self.B_Scale.place(x=40,y=105)

        hex_label = Label(self.root,text="Hex Code :",font=('arial',10,'bold'))
        hex_label.place(x=7,y=360)

        self.hex_entry = Entry(self.root,width=12,font=('arial',10))
        self.hex_entry.insert(tk.END,'##8400ff')
        self.hex_entry.place(x=90,y=360)

        rbg_label = Label(self.root,text="RGB Code :",font=('arial',10,'bold'))
        rbg_label.place(x=7,y=390)

        self.rgb_entry = Entry(self.root,width=12,font=('arial',10))
        self.rgb_entry.place(x=90,y=390)

    def scaleMove(self,*args):
        self.R = int(self.R_Scale.get())
        self.G = int(self.G_Scale.get())
        self.B = int(self.B_Scale.get())
        rgb = f"{self.R},{self.G},{self.B}"

        #print(r,g,b)
        self.hex =  "#%02x%02X%02x"%(self.R,self.G,self.B)
        self.color_canvas.config(bg=self.hex)
        # Hex to RGB
        #h = color_hex.lstrip('#')
        #print('RGB =', tuple(int(h[i:i+2], 16) for i in (0, 2, 4)))

        self.hex_entry.delete(0,tk.END)
        self.hex_entry.insert(0,self.hex)

        self.rgb_entry.delete(0,tk.END)
        self.rgb_entry.insert(0,rgb)

    
    def copy_color(self,*args):
        root.clipboard_clear()  # clear clipboard contents
        root.clipboard_append(self.hex)  # append new value to clipbaord
        


root = tk.Tk()
Colorpicker(root)
root.mainloop()

16. Крестики-Нолики

# Instagram : @dynamic.coding
# >> FOLLOW ME <<

from tkinter import *
from tkinter import messagebox
import random as r
def button(frame):          #Function to define a button
    b=Button(frame,padx=1,bg="#D4D4D4",width=3,text="   ",
             font=('arial',60,'bold'),relief=RAISED,bd=5)
    return b
def change_a():             #Function to change the operand for the next player
    global a
    for i in ['O','X']:
        if not(i==a):
            a=i
            break
def reset():                #Resets the game
    global a
    for i in range(3):
        for j in range(3):
                b[i][j]["text"]=" "
                b[i][j]["state"]=NORMAL
    a=r.choice(['O','X'])
def check():                #Checks for victory or Draw
    for i in range(3):
            if(b[i][0]["text"]==b[i][1]["text"]==b[i][2]["text"]==a or b[0][i]["text"]==b[1][i]["text"]==b[2][i]["text"]==a):
                    messagebox.showinfo("Congrats!!","'"+a+"' Победил")
                    reset()
    if(b[0][0]["text"]==b[1][1]["text"]==b[2][2]["text"]==a or b[0][2]["text"]==b[1][1]["text"]==b[2][0]["text"]==a):
        messagebox.showinfo("Congrats!!","'"+a+"' победил")
        reset()   
    elif(b[0][0]["state"]==b[0][1]["state"]==b[0][2]["state"]==b[1][0]["state"]==b[1][1]["state"]==b[1][2]["state"]==b[2][0]["state"]==b[2][1]["state"]==b[2][2]["state"]==DISABLED):
        messagebox.showinfo("Tied!!","The match ended in a draw")
        reset()
def click(row,col):
        b[row][col].config(text=a,state=DISABLED,disabledforeground=colour[a])
        check()
        change_a()
###############   Main Program #################
root=Tk()                   #Window defined
root.title("Крестики-Нолики")   #Title given
a=r.choice(['O','X'])       #Two operators defined
colour={'O':"deep sky blue",'X':"lawn green"}
b=[[],[],[]]
for i in range(3):
        for j in range(3):
                b[i].append(button(root))
                b[i][j].config(command= lambda row=i,col=j:click(row,col))
                b[i][j].grid(row=i,column=j)
reset_btn = Button(text="Играть сначало",font=('arial',15,'bold'),command=reset)
reset_btn.grid(row=3,column=0,columnspan=3)
root.mainloop()

17. Еще один калькулятор

from tkinter import *
from math import *

root = Tk()
root.title("Calculator")
root.resizable(width=False, height=False)

screen = StringVar()
screen.set("0")

current = ""
power = ""

firstnum = ""
secondnum = ""
mathsign = ""

exponentiation = False
percent_active = False


def math_button_pressed():
    if mathsign == '+':
        button_plus.config(relief=SUNKEN)
    elif mathsign == '-':
        button_minus.config(relief=SUNKEN)
    elif mathsign == '*':
        button_multiply.config(relief=SUNKEN)
    elif mathsign == '/':
        button_division.config(relief=SUNKEN)


def math_button_raised():
    button_plus.config(relief=RAISED)
    button_minus.config(relief=RAISED)
    button_multiply.config(relief=RAISED)
    button_division.config(relief=RAISED)


def is_int(num):
    if int(num) == float(num):
        return int(num)
    else:
        return float(num)

def set_screen(num):
    screen.set(is_int(num))

def number_pressed(butt):
    global current, power, firstnum, secondnum

    if mathsign == "" and not exponentiation:
        current = current + str(butt)
        firstnum = float(current)

    elif mathsign != "" and not exponentiation:
        math_button_raised()
        current = current + str(butt)
        secondnum = float(current)

    elif mathsign == "" and exponentiation:
        power = power + str(butt)
        current = current + str(butt)

    elif mathsign != "" and exponentiation:
        power = power + str(butt)
        current = current + str(butt)
        print(power)
    screen.set(current)

def math_pressed(math):
    global current, power, mathsign, firstnum, secondnum, exponentiation, percent_active

    if mathsign == "" and not exponentiation and not percent_active and firstnum != "":
        mathsign = str(math)
        math_button_pressed()
        current = ""

    elif mathsign != "" and not exponentiation and not percent_active:
        if mathsign == '+':
            firstnum = float(firstnum + secondnum)
        elif mathsign == '-':
            firstnum = float(firstnum - secondnum)
        elif mathsign == '*':
            firstnum = float(firstnum * secondnum)
        elif mathsign == '/':
            firstnum = float(firstnum / secondnum)
        firstnum = round(firstnum, 6)
        set_screen(firstnum)

    elif mathsign != "" and exponentiation and not percent_active:
        if mathsign == '+':
            firstnum = firstnum + secondnum ** int(power)
        elif mathsign == '-':
            firstnum = firstnum - secondnum ** int(power)
        elif mathsign == '*':
            firstnum = firstnum * secondnum ** int(power)
        elif mathsign == '/':
            firstnum = firstnum / secondnum ** int(power)
        firstnum = round(firstnum, 6)
        exponentiation = False
        set_screen(firstnum)
        exponentiation = False
        power = ""

    elif exponentiation and not percent_active:
        firstnum = round(firstnum ** int(power), 6)
        exponentiation = False
        set_screen(firstnum)
        power = ""


    elif percent_active:
        if mathsign == '+':
            firstnum = float(firstnum + firstnum / 100 * secondnum)
        elif mathsign == '-':
            firstnum = float(firstnum - firstnum / 100 * secondnum)
        firstnum = round(firstnum, 6)
        set_screen(firstnum)
        percent_active = False
    mathsign = str(math)
    math_button_pressed()
    current = ""


def squareroot():
    global firstnum, secondnum, mathsign, current

    if mathsign == "":
        firstnum = round(sqrt(firstnum), 6)
        set_screen(firstnum)

    elif mathsign != "":
        if mathsign == '+':
            firstnum = sqrt(firstnum + float(secondnum))
        elif mathsign == '-':
            firstnum = sqrt(firstnum - float(secondnum))
        elif mathsign == '*':
            firstnum = sqrt(firstnum * float(secondnum))
        elif mathsign == '/':
            firstnum = sqrt(firstnum / float(secondnum))
        firstnum = round(firstnum, 6)
        set_screen(firstnum)
        secondnum = ""
        mathsign = ""
        current = ""


def x():
    global firstnum, secondnum, mathsign, current, exponentiation

    if mathsign == "":
        current = str(is_int(firstnum)) + '^'

    elif mathsign != "":
        current = str(is_int(secondnum)) + '^'

    screen.set(current)
    exponentiation = True


def result():
    global firstnum, secondnum, mathsign, current, power, exponentiation, percent_active
    if not exponentiation and not percent_active:
        if mathsign == '+':
            firstnum = float(firstnum + secondnum)
        elif mathsign == '-':
            firstnum = float(firstnum - secondnum)
        elif mathsign == '*':
            firstnum = float(firstnum * secondnum)
        elif mathsign == '/':
            firstnum = float(firstnum / secondnum)
        firstnum = round(firstnum, 6)
        set_screen(firstnum)

    elif mathsign == "" and exponentiation and not percent_active:
        firstnum = round(firstnum ** int(power), 6)
        exponentiation = False
        set_screen(firstnum)

    elif mathsign != "" and exponentiation and not percent_active:
        if mathsign == '+':
            firstnum = firstnum + secondnum ** int(power)
        elif mathsign == '-':
            firstnum = firstnum - secondnum ** int(power)
        elif mathsign == '*':
            firstnum = firstnum * secondnum ** int(power)
        elif mathsign == '/':
            firstnum = firstnum / secondnum ** int(power)
        firstnum = round(firstnum, 6)
        exponentiation = False
        set_screen(firstnum)

    elif not exponentiation and percent_active:
        if mathsign == '+':
            firstnum = float(firstnum + firstnum / 100 * secondnum)
        elif mathsign == '-':
            firstnum = float(firstnum - firstnum / 100 * secondnum)
        firstnum = round(firstnum, 6)
        set_screen(firstnum)
        percent_active = False

    elif not exponentiation and mathsign == '*' or '/' and percent_active:
        clear()

    mathsign = ""
    current = ""
    power = ""


def clear():
    global current, firstnum, secondnum, mathsign, power, exponentiation, percent_active

    screen.set(0)
    current = ""
    power = ""
    firstnum = ""
    secondnum = ""
    mathsign = ""
    exponentiation = False
    math_button_raised()
    percent_active = False


def percent():
    global firstnum, secondnum, current, percent_active

    current = str(is_int(secondnum)) + '%'
    screen.set(current)
    percent_active = True


# Widgets

calculation = Entry(root, textvariable=screen, font=("Verdana", 15,), bd=12,
                    insertwidth=4, width=14, justify=RIGHT)
calculation.grid(columnspan=4)
#   Numbers
button1 = Button(root, text='1', command=lambda: number_pressed(1), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button1.grid(row=2, column=0, sticky=W)
button2 = Button(root, text='2', command=lambda: number_pressed(2), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button2.grid(row=2, column=1, sticky=W)
button3 = Button(root, text='3', command=lambda: number_pressed(3), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button3.grid(row=2, column=2, sticky=W)
button4 = Button(root, text='4', command=lambda: number_pressed(4), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button4.grid(row=3, column=0, sticky=W)
button5 = Button(root, text='5', command=lambda: number_pressed(5), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button5.grid(row=3, column=1, sticky=W)
button6 = Button(root, text='6', command=lambda: number_pressed(6), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button6.grid(row=3, column=2, sticky=W)
button7 = Button(root, text='7', command=lambda: number_pressed(7), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button7.grid(row=4, column=0, sticky=W)
button8 = Button(root, text='8', command=lambda: number_pressed(8), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button8.grid(row=4, column=1, sticky=W)
button9 = Button(root, text='9', command=lambda: number_pressed(9), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button9.grid(row=4, column=2, sticky=W)
button0 = Button(root, text='0', command=lambda: number_pressed(0), bg="gainsboro",
                 bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button0.grid(row=5, column=0, sticky=W)
button_float = Button(root, text='.', command=lambda: number_pressed('.'), bg="gainsboro",
                      bd=3, padx=15, pady=5, font=("Helvetica", 14, "bold"))
button_float.grid(row=5, column=1)

#   Math signs
button_plus = Button(root, text='+', command=lambda: math_pressed('+'), bg="gray70",
                     bd=3, padx=11, pady=5, font=("Helvetica", 14, "bold"))
button_plus.grid(row=2, column=3, sticky=W)
button_minus = Button(root, text='-', command=lambda: math_pressed('-'), bg="gray70",
                      bd=3, padx=11, pady=4, font=("Verdana", 14, "bold"))
button_minus.grid(row=3, column=3, sticky=W)
button_multiply = Button(root, text='*', command=lambda: math_pressed('*'), bg="gray70",
                         bd=3, padx=13, pady=5, font=("Helvetica", 14, "bold"))
button_multiply.grid(row=4, column=3, )
button_division = Button(root, text='/', command=lambda: math_pressed('/'), bg="gray70",
                         bd=3, padx=14, pady=5, font=("Helvetica", 14, "bold"))
button_division.grid(row=5, column=3, )
button_equal = Button(root, text='=', command=lambda: result(), bg='orange',
                      bd=3, padx=12, pady=5, font=("Arial", 14))
button_equal.grid(row=5, column=2, )

button_percent = Button(root, text='%', command=lambda: percent(), bg="gray70",
                        bd=3, padx=8, pady=5, font=("Helvetica", 14, "bold"))
button_percent.grid(row=1, column=3, )

button_clear = Button(root, text='C', command=lambda: clear(), bg='gray70',
                      bd=3, padx=11, pady=5, font=("Helvetica", 14))
button_clear.grid(row=1, column=0)
button_sqrt = Button(root, text='√', command=lambda: squareroot(), bg="gray70",
                     bd=3, padx=12, pady=5, font=("Helvetica", 14, "bold"))
button_sqrt.grid(row=1, column=1, sticky=W)
button_x = Button(root, text='x^y', command=lambda: x(), bg="gray70",
                  bd=3, padx=6, pady=5, font=("Helvetica", 14))
button_x.grid(row=1, column=2, sticky=W)

root.mainloop()

18. Интересная шкала

from tkinter import *
import ttkbootstrap as tb


root = tb.Window(themename="superhero")

#root = Tk()
root.title("TTK Bootstrap! Meter!")
#root.iconbitmap('images/codemy.ico')
root.geometry('500x650')


def up():
    my_meter.step(10)

def down():
    my_meter.step(-10)


global counter
counter=20

def clicker():
    global counter
    if counter <= 100:
        my_meter.configure(amountused=counter)
        counter += 5
        my_button.configure(text=f'Нажми меня {my_meter.amountusedvar.get()}')

my_meter = tb.Meter(root, bootstyle="danger", 
    subtext="Умный Tkinter",
    interactive=True,
    textright="%",
    #textleft="$"
    metertype="full", # Can be semi
    stripethickness=10,
    metersize=200,
    padding=50,
    amountused=0,
    amounttotal=100,
    subtextstyle="light"
    )
my_meter.pack(pady=50)

my_button = tb.Button(root, text="Нажми меня 5", command=clicker)
my_button.pack(pady=20)

my_button2 = tb.Button(root, text="Шаг вверх", command=up)
my_button2.pack(pady=20)

my_button3 = tb.Button(root, text="Шаг вниз", command=down)
my_button3.pack(pady=20)



root.mainloop()

19. Интересный календарь

Модуль ttkbootstrap. Расширение темы для tkinter, которое позволяет создавать по запросу темы в современном плоском стиле, вдохновленные Bootstrap.

from tkinter import *
import ttkbootstrap as tb
from datetime import date
from ttkbootstrap.dialogs import Querybox

root = tb.Window(themename="superhero")

#root = Tk()
root.title("TTK Bootstrap! Ввод даты")
#root.iconbitmap('images/codemy.ico')
root.geometry('500x350')


def datey():
	# Grab The Date
	my_label.config(text=f"Ты выбрал: {my_date.entry.get()}")

def thing():
	cal = Querybox()
	my_label.config(text=f"Ты выбрал: {cal.get_date()}")


my_date = tb.DateEntry(root, bootstyle="danger", firstweekday=0, startdate=date(2023, 2, 14))
my_date.pack(pady=50)

my_button = tb.Button(root, text='Получить дату', bootstyle="danger outline", command=datey)
my_button.pack(pady=20)

my_button2 = tb.Button(root, text='Получить календарь', bootstyle="success outline", command=thing)
my_button2.pack(pady=20)


my_label = tb.Label(root, text="Ты выбрал: ")
my_label.pack(pady=20)

root.mainloop()

20. Слайдер

Сами выставляем размер окна

from tkinter import *


main = Tk()
main.geometry('720x360')

vertical = Scale(main, from_=180, to=360)
vertical.pack()

horizontal = Scale(main, from_=360, to=720, orient=HORIZONTAL)
horizontal.pack()


def clicked():  # one use!
    main.geometry(f'{horizontal.get()}x{vertical.get()}')


Button(main, text='Изменить размер окна', command=clicked).pack()

main.mainloop()

21. Цифровые часы

import sys
from  tkinter import *
import time 

def times():
	current_time=time.strftime("%H:%M:%S") 
	clock.config(text=current_time)
	clock.after(200,times)


root=Tk()
root.geometry("450x250")
clock=Label(root,font=("times",50,"bold"),bg="white")
clock.grid(row=2,column=2,pady=25,padx=100)
times()

digi=Label(root,text="Цифровые часы",font="times 24 bold")
digi.grid(row=0,column=2)

nota=Label(root,text="часы      минуты     секунды   ",font="times 15 bold")
nota.grid(row=3,column=2)

root.mainloop()

22. Система управления библиотекой

Проект GUI системы управления библиотеками на Python с использованием Tkinter и SQL Ссылка

Перед использованием установите следующие пакеты в cmd.

pip install python-tk
pip install pillow
  • запустить trinity .py
  • имя пользователя = Prakarsha, пароль = root

23. Симпатичный блокнот

Симпатичный блокнот с очисткой, удалением и сохранением.

Создает текстовый файл checklist (там же и сохраняет), в том же месте где и файл питон. Ссылка

Папка: 5_simple_checklist

#Simple Checklist
import tkinter
from tkinter import END, ANCHOR

#Define window
root = tkinter.Tk()
root.title('Простой список')
root.iconbitmap('check.ico')
root.geometry('400x400')
root.resizable(0,0)

#Define fonts and colors
my_font = ('Times New Roman', 12)
root_color = '#6c1cbc'
button_color = '#e2cff4'
root.config(bg=root_color)

#Define functions
def add_item():
    """Add an individual item to the listbox"""
    my_listbox.insert(END, list_entry.get())
    list_entry.delete(0, END)


def remove_item():
    """Remove the selected (ANCHOR) item from the listbox"""
    my_listbox.delete(ANCHOR)


def clear_list():
    """Delete all items from the listbox"""
    my_listbox.delete(0, END)


def save_list():
    """Save the list to a simple txt file"""
    with open('checklist.txt', 'w') as f:
        #listbox.get() returns a tuple....
        list_tuple = my_listbox.get(0, END)
        for item in list_tuple:
            #Take proper precautions to include only one \n for formatting purposes
            if item.endswith('\n'):
                f.write(item)
            else:
                f.write(item + "\n")


def open_list():
    """Open the list upon starting the program if there is one"""
    try:
        with open('checklist.txt', 'r') as f:
            for line in f:
                my_listbox.insert(END, line)
    except:
        return


#Define layout
#Create frames
input_frame = tkinter.Frame(root, bg=root_color)
output_frame = tkinter.Frame(root, bg=root_color)
button_frame = tkinter.Frame(root, bg=root_color)
input_frame.pack()
output_frame.pack()
button_frame.pack()

#Input frame layout
list_entry = tkinter.Entry(input_frame, width=35, borderwidth=3, font=my_font)
list_add_button = tkinter.Button(input_frame, text="Добавить", borderwidth=2, font=my_font, bg=button_color, command=add_item)
list_entry.grid(row=0, column=0, padx=5, pady=5)
list_add_button.grid(row=0, column=1, padx=5, pady=5, ipadx=5)

#Output frame layout
my_scrollbar = tkinter.Scrollbar(output_frame)
my_listbox = tkinter.Listbox(output_frame, height=15, width=45, borderwidth=3, font=my_font, yscrollcommand=my_scrollbar.set)
#Link scrollbar to listbox
my_scrollbar.config(command=my_listbox.yview)
my_listbox.grid(row=0, column=0)
my_scrollbar.grid(row=0, column=1, sticky="NS")

#Button Frame layout
list_remove_button = tkinter.Button(button_frame, text="Удалить", borderwidth=2, font=my_font, bg=button_color, command=remove_item)
list_clear_button = tkinter.Button(button_frame, text='Очистить', borderwidth=2, font=my_font, bg=button_color, command=clear_list)
save_button = tkinter.Button(button_frame, text='Сохранить', borderwidth=2, font=my_font, bg=button_color, command=save_list)
quit_button = tkinter.Button(button_frame, text='Выйти', borderwidth=2, font=my_font, bg=button_color, command=root.destroy)
list_remove_button.grid(row=0, column=0, padx=2, pady=10)
list_clear_button.grid(row=0, column=1, padx=2, pady=10, ipadx=10)
save_button.grid(row=0, column=2, padx=2, pady=10, ipadx=10)
quit_button.grid(row=0, column=3, padx=2, pady=10, ipadx=25)

#Open the previous list if available
open_list()

#Run the root window's main loop
root.mainloop()

24. Приложение в Tkinter и Pyserial для управления 4 контактами Arduino Ссылка

25. Управление светодиодом

Tkinter и Pyserial (Ардуино)

Ссылка

26. Сценарий ком порта

Резюме проекта

Этот проект включает в себя разработку сценария Python для создания терминала последовательного порта на основе графического интерфейса пользователя в Windows. Основной вариант использования — преобразование USB в TTL. Ссылка

27. Изменение шрифта

#tkinter for Python 3.x
#Tkinter for Python 2.x

import tkinter

def quit():
    global tkTop
    tkTop.destroy()

def setTextSize(ev=None):
    global tkLabel
    global tkScale
    tkLabel.config(font="Helvetica -%d bold" %tkScale.get())

tkTop = tkinter.Tk()
tkTop.geometry('300x200')

tkButtonQuit = tkinter.Button(tkTop, text="Quit", command=quit)
tkButtonQuit.pack()

tkLabel = tkinter.Label(text="Hello Python")
tkLabel.pack()

tkScale = tkinter.Scale(tkTop, from_=1, to=40, orient=tkinter.HORIZONTAL, command=setTextSize)
tkScale.set(18)
tkScale.pack(anchor=tkinter.CENTER)

tkinter.mainloop()

28. Выпадающий список

Если вы хотите создать раскрывающийся список элементов и разрешить пользователю выбирать элементы списка, вы можете использовать виджет Combobox. Виджет Combobox позволяет создать выпадающий список, в котором можно мгновенно выбрать список элементов. Однако, если вы хотите получить индекс выбранных элементов в виджете со списком, вы можете использовать метод get()Метод get() возвращает целое число выбранного элемента, известное как индекс элемента.

Пример

Давайте возьмем пример, чтобы увидеть, как это работает. В этом примере мы создали список дней недели в раскрывающемся списке, и всякий раз, когда пользователь выбирает день из раскрывающегося списка, он будет печатать и отображать индекс выбранного элемента в виджете «Label». Чтобы напечатать индекс, мы можем объединить строку, приведя данный индекс к строке.

from tkinter import *
from tkinter import ttk

# Создайте экземпляр фрейма или окна tkinter
window = Tk()

# Установить размер окна
window.geometry("700x350")

# Создайте функцию для очистки поля со списком
def clear_combobox():
  combobox.set('')

# Определить кортеж дней
days= ('Понедельник','Вторник','Среда','Четверг','Пятница','Суббота','Воскресенье')

# Функция для печати индекса выбранной опции в Combobox
def callback(*arg):
  Label(window, text = 'Индекс равен' + str(combobox.current()) + ' для ' + ' ' + str(var.get()), font = ('Helvetica 12') ).pack()


# Создайте виджет со списком
var = StringVar()
combobox = ttk.Combobox(window, textvariable = var)
combobox['values'] = days
combobox['state'] = 'readonly'
combobox.pack(fill='x',padx= 5, pady=5)

# Установите трассировку для данной переменной
var.trace('w', callback)


# Создайте кнопку, чтобы очистить выбранное текстовое значение поля со списком
button = Button(window, text = 'очистить', command = clear_combobox)
button.pack()


window.mainloop()

Выполнение приведенного выше кода отобразит виджет со списком дней. Всякий раз, когда вы выбираете день из списка, он будет печатать индекс и соответствующий элемент в виджете метки.

29. Форма для ввода пароля (без логики)

# импортируем библиотеку tkinter всю сразу
from tkinter import *
from tkinter import messagebox

# главное окно приложения
window = Tk()
# заголовок окна
window.title('Авторизация')
# размер окна
window.geometry('450x230')
# можно ли изменять размер окна - нет
window.resizable(False, False)

# кортежи и словари, содержащие настройки шрифтов и отступов
font_header = ('Arial', 15)
font_entry = ('Arial', 12)
label_font = ('Arial', 11)
base_padding = {'padx': 10, 'pady': 8}
header_padding = {'padx': 10, 'pady': 12}


# обработчик нажатия на клавишу 'Войти'
def clicked():

    # получаем имя пользователя и пароль
    username = username_entry.get()
    password = password_entry.get()

    # выводим в диалоговое окно введенные пользователем данные
    messagebox.showinfo('Заголовок', '{username}, {password}'.format(username=username, password=password))


# заголовок формы: настроены шрифт (font), отцентрирован (justify), добавлены отступы для заголовка
# для всех остальных виджетов настройки делаются также
main_label = Label(window, text='Авторизация', font=font_header, justify=CENTER, **header_padding)
# помещаем виджет в окно по принципу один виджет под другим
main_label.pack()

# метка для поля ввода имени
username_label = Label(window, text='Имя пользователя', font=label_font , **base_padding)
username_label.pack()

# поле ввода имени
username_entry = Entry(window, bg='#fff', fg='#444', font=font_entry)
username_entry.pack()

# метка для поля ввода пароля
password_label = Label(window, text='Пароль', font=label_font , **base_padding)
password_label.pack()

# поле ввода пароля
password_entry = Entry(window, bg='#fff', fg='#444', font=font_entry)
password_entry.pack()

# кнопка отправки формы
send_btn = Button(window, text='Войти', command=clicked)
send_btn.pack(**base_padding)


# запускаем главный цикл окна
window.mainloop()

30. Проект реализован на PyQt5

Игра . Тетрис.

Эту игру знают все! Главная задача игрока не дать разным, геометрическим фигурам достигнуть “ФИНИША”.

import sys, random
from PyQt5.QtWidgets import QMainWindow, QFrame, QDesktopWidget, QApplication
from PyQt5.QtCore import Qt, QBasicTimer, pyqtSignal
from PyQt5.QtGui import QPainter, QColor

Вы видите библиотеки, которые будут использоваться при создании данной игры, всех их нужно загрузить через командную строку вашего компьютера.

После того как установили нужные нам библиотеки, создаём класс с нашими переменными. класс назовём Tetris и будем использовать свойства отцовского класса, чтобы каждый раз не прописывать все переменные заново для каждого последующего класса.

class Tetris(QMainWindow):

    def __init__(self):
        super().__init__()

        self.initUI()


    def initUI(self):

        self.tboard = Board(self)
        self.setCentralWidget(self.tboard)

        self.statusbar = self.statusBar()
        self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage)

        self.tboard.start()

        self.resize(180, 380)
        self.center()
        self.setWindowTitle('Tetris')
        self.show()


    def center(self):

        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2,
            (screen.height()-size.height())/2)

После создания отцовского класса Tetris, создаём все остальные классы и переменные для уже других функций.

class Board(QFrame):

    msg2Statusbar = pyqtSignal(str)

    BoardWidth = 10
    BoardHeight = 22
    Speed = 300

    def __init__(self, parent):
        super().__init__(parent)

        self.initBoard()


    def initBoard(self):

        self.timer = QBasicTimer()
        self.isWaitingAfterLine = False

        self.curX = 0
        self.curY = 0
        self.numLinesRemoved = 0
        self.board = []

        self.setFocusPolicy(Qt.StrongFocus)
        self.isStarted = False
        self.isPaused = False
        self.clearBoard()


    def shapeAt(self, x, y):
        return self.board[(y * Board.BoardWidth) + x]


    def setShapeAt(self, x, y, shape):
        self.board[(y * Board.BoardWidth) + x] = shape


    def squareWidth(self):
        return self.contentsRect().width() // Board.BoardWidth


    def squareHeight(self):
        return self.contentsRect().height() // Board.BoardHeight


    def start(self):

        if self.isPaused:
            return

        self.isStarted = True
        self.isWaitingAfterLine = False
        self.numLinesRemoved = 0
        self.clearBoard()

        self.msg2Statusbar.emit(str(self.numLinesRemoved))

        self.newPiece()
        self.timer.start(Board.Speed, self)


    def pause(self):

        if not self.isStarted:
            return

        self.isPaused = not self.isPaused

        if self.isPaused:
            self.timer.stop()
            self.msg2Statusbar.emit("paused")

        else:
            self.timer.start(Board.Speed, self)
            self.msg2Statusbar.emit(str(self.numLinesRemoved))

        self.update()


    def paintEvent(self, event):

        painter = QPainter(self)
        rect = self.contentsRect()

        boardTop = rect.bottom() - Board.BoardHeight * self.squareHeight()

        for i in range(Board.BoardHeight):
            for j in range(Board.BoardWidth):
                shape = self.shapeAt(j, Board.BoardHeight - i - 1)

                if shape != Tetrominoe.NoShape:
                    self.drawSquare(painter,
                        rect.left() + j * self.squareWidth(),
                        boardTop + i * self.squareHeight(), shape)

        if self.curPiece.shape() != Tetrominoe.NoShape:

            for i in range(4):

                x = self.curX + self.curPiece.x(i)
                y = self.curY - self.curPiece.y(i)
                self.drawSquare(painter, rect.left() + x * self.squareWidth(),
                    boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(),
                    self.curPiece.shape())


    def keyPressEvent(self, event):

        if not self.isStarted or self.curPiece.shape() == Tetrominoe.NoShape:
            super(Board, self).keyPressEvent(event)
            return

        key = event.key()

        if key == Qt.Key_P:
            self.pause()
            return

        if self.isPaused:
            return

        elif key == Qt.Key_Left:
            self.tryMove(self.curPiece, self.curX - 1, self.curY)

        elif key == Qt.Key_Right:
            self.tryMove(self.curPiece, self.curX + 1, self.curY)

        elif key == Qt.Key_Down:
            self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY)

        elif key == Qt.Key_Up:
            self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY)

        elif key == Qt.Key_Space:
            self.dropDown()

        elif key == Qt.Key_D:
            self.oneLineDown()

        else:
            super(Board, self).keyPressEvent(event)


    def timerEvent(self, event):

        if event.timerId() == self.timer.timerId():

            if self.isWaitingAfterLine:
                self.isWaitingAfterLine = False
                self.newPiece()
            else:
                self.oneLineDown()

        else:
            super(Board, self).timerEvent(event)


    def clearBoard(self):

        for i in range(Board.BoardHeight * Board.BoardWidth):
            self.board.append(Tetrominoe.NoShape)


    def dropDown(self):

        newY = self.curY

        while newY > 0:

            if not self.tryMove(self.curPiece, self.curX, newY - 1):
                break

            newY -= 1

        self.pieceDropped()


    def oneLineDown(self):

        if not self.tryMove(self.curPiece, self.curX, self.curY - 1):
            self.pieceDropped()


    def pieceDropped(self):

        for i in range(4):

            x = self.curX + self.curPiece.x(i)
            y = self.curY - self.curPiece.y(i)
            self.setShapeAt(x, y, self.curPiece.shape())

        self.removeFullLines()

        if not self.isWaitingAfterLine:
            self.newPiece()




    def removeFullLines(self):

        numFullLines = 0
        rowsToRemove = []

        for i in range(Board.BoardHeight):

            n = 0
            for j in range(Board.BoardWidth):
                if not self.shapeAt(j, i) == Tetrominoe.NoShape:
                    n = n + 1

            if n == 10:
                rowsToRemove.append(i)

        rowsToRemove.reverse()


        for m in rowsToRemove:

            for k in range(m, Board.BoardHeight):
                for l in range(Board.BoardWidth):
                        self.setShapeAt(l, k, self.shapeAt(l, k + 1))

        numFullLines = numFullLines + len(rowsToRemove)

        if numFullLines > 0:

            self.numLinesRemoved = self.numLinesRemoved + numFullLines
            self.msg2Statusbar.emit(str(self.numLinesRemoved))

            self.isWaitingAfterLine = True
            self.curPiece.setShape(Tetrominoe.NoShape)
            self.update()


    def newPiece(self):

        self.curPiece = Shape()
        self.curPiece.setRandomShape()
        self.curX = Board.BoardWidth // 2 + 1
        self.curY = Board.BoardHeight - 1 + self.curPiece.minY()

        if not self.tryMove(self.curPiece, self.curX, self.curY):

            self.curPiece.setShape(Tetrominoe.NoShape)
            self.timer.stop()
            self.isStarted = False
            self.msg2Statusbar.emit("Game over")



    def tryMove(self, newPiece, newX, newY):

        for i in range(4):

            x = newX + newPiece.x(i)
            y = newY - newPiece.y(i)

            if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
                return False

            if self.shapeAt(x, y) != Tetrominoe.NoShape:
                return False

        self.curPiece = newPiece
        self.curX = newX
        self.curY = newY
        self.update()

        return True


    def drawSquare(self, painter, x, y, shape):

        colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC,
                      0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00]

        color = QColor(colorTable[shape])
        painter.fillRect(x + 1, y + 1, self.squareWidth() - 2,
            self.squareHeight() - 2, color)

        painter.setPen(color.lighter())
        painter.drawLine(x, y + self.squareHeight() - 1, x, y)
        painter.drawLine(x, y, x + self.squareWidth() - 1, y)

        painter.setPen(color.darker())
        painter.drawLine(x + 1, y + self.squareHeight() - 1,
            x + self.squareWidth() - 1, y + self.squareHeight() - 1)
        painter.drawLine(x + self.squareWidth() - 1,
            y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)

После создаём класс уже для самих объектов( фигур), назовём его Tetrominoe.

class Tetrominoe(object):

    NoShape = 0
    ZShape = 1
    SShape = 2
    LineShape = 3
    TShape = 4
    SquareShape = 5
    LShape = 6
    MirroredLShape = 7

И ещё один класс, но уже будем задавать координаты фигурам.

class Shape(object):

    coordsTable = (
        ((0, 0),     (0, 0),     (0, 0),     (0, 0)),
        ((0, -1),    (0, 0),     (-1, 0),    (-1, 1)),
        ((0, -1),    (0, 0),     (1, 0),     (1, 1)),
        ((0, -1),    (0, 0),     (0, 1),     (0, 2)),
        ((-1, 0),    (0, 0),     (1, 0),     (0, 1)),
        ((0, 0),     (1, 0),     (0, 1),     (1, 1)),
        ((-1, -1),   (0, -1),    (0, 0),     (0, 1)),
        ((1, -1),    (0, -1),    (0, 0),     (0, 1))
    )

    def __init__(self):

        self.coords = [[0,0] for i in range(4)]
        self.pieceShape = Tetrominoe.NoShape

        self.setShape(Tetrominoe.NoShape)


    def shape(self):
        return self.pieceShape


    def setShape(self, shape):

        table = Shape.coordsTable[shape]

        for i in range(4):
            for j in range(2):
                self.coords[i][j] = table[i][j]

        self.pieceShape = shape


    def setRandomShape(self):
        self.setShape(random.randint(1, 7))


    def x(self, index):
        return self.coords[index][0]


    def y(self, index):
        return self.coords[index][1]


    def setX(self, index, x):
        self.coords[index][0] = x


    def setY(self, index, y):
        self.coords[index][1] = y


    def minX(self):

        m = self.coords[0][0]
        for i in range(4):
            m = min(m, self.coords[i][0])

        return m

И завершаем наш код

    def maxX(self):

        m = self.coords[0][0]
        for i in range(4):
            m = max(m, self.coords[i][0])

        return m


    def minY(self):

        m = self.coords[0][1]
        for i in range(4):
            m = min(m, self.coords[i][1])

        return m


    def maxY(self):

        m = self.coords[0][1]
        for i in range(4):
            m = max(m, self.coords[i][1])

        return m


    def rotateLeft(self):

        if self.pieceShape == Tetrominoe.SquareShape:
            return self

        result = Shape()
        result.pieceShape = self.pieceShape

        for i in range(4):

            result.setX(i, self.y(i))
            result.setY(i, -self.x(i))

        return result


    def rotateRight(self):

        if self.pieceShape == Tetrominoe.SquareShape:
            return self

        result = Shape()
        result.pieceShape = self.pieceShape

        for i in range(4):

            result.setX(i, -self.y(i))
            result.setY(i, self.x(i))

        return result


if __name__ == '__main__':

    app = QApplication([])
    tetris = Tetris()
    sys.exit(app.exec_())    

Полный код:

import sys, random
from PyQt5.QtWidgets import QMainWindow, QFrame, QDesktopWidget, QApplication
from PyQt5.QtCore import Qt, QBasicTimer, pyqtSignal
from PyQt5.QtGui import QPainter, QColor

class Tetris(QMainWindow):

    def __init__(self):
        super().__init__()

        self.initUI()


    def initUI(self):

        self.tboard = Board(self)
        self.setCentralWidget(self.tboard)

        self.statusbar = self.statusBar()
        self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage)

        self.tboard.start()

        self.resize(180, 380)
        self.center()
        self.setWindowTitle('Tetris')
        self.show()


    def center(self):

        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2,
            (screen.height()-size.height())/2)


        
class Board(QFrame):

    msg2Statusbar = pyqtSignal(str)

    BoardWidth = 10
    BoardHeight = 22
    Speed = 300

    def __init__(self, parent):
        super().__init__(parent)

        self.initBoard()


    def initBoard(self):

        self.timer = QBasicTimer()
        self.isWaitingAfterLine = False

        self.curX = 0
        self.curY = 0
        self.numLinesRemoved = 0
        self.board = []

        self.setFocusPolicy(Qt.StrongFocus)
        self.isStarted = False
        self.isPaused = False
        self.clearBoard()


    def shapeAt(self, x, y):
        return self.board[(y * Board.BoardWidth) + x]


    def setShapeAt(self, x, y, shape):
        self.board[(y * Board.BoardWidth) + x] = shape


    def squareWidth(self):
        return self.contentsRect().width() // Board.BoardWidth


    def squareHeight(self):
        return self.contentsRect().height() // Board.BoardHeight


    def start(self):

        if self.isPaused:
            return

        self.isStarted = True
        self.isWaitingAfterLine = False
        self.numLinesRemoved = 0
        self.clearBoard()

        self.msg2Statusbar.emit(str(self.numLinesRemoved))

        self.newPiece()
        self.timer.start(Board.Speed, self)


    def pause(self):

        if not self.isStarted:
            return

        self.isPaused = not self.isPaused

        if self.isPaused:
            self.timer.stop()
            self.msg2Statusbar.emit("paused")

        else:
            self.timer.start(Board.Speed, self)
            self.msg2Statusbar.emit(str(self.numLinesRemoved))

        self.update()


    def paintEvent(self, event):

        painter = QPainter(self)
        rect = self.contentsRect()

        boardTop = rect.bottom() - Board.BoardHeight * self.squareHeight()

        for i in range(Board.BoardHeight):
            for j in range(Board.BoardWidth):
                shape = self.shapeAt(j, Board.BoardHeight - i - 1)

                if shape != Tetrominoe.NoShape:
                    self.drawSquare(painter,
                        rect.left() + j * self.squareWidth(),
                        boardTop + i * self.squareHeight(), shape)

        if self.curPiece.shape() != Tetrominoe.NoShape:

            for i in range(4):

                x = self.curX + self.curPiece.x(i)
                y = self.curY - self.curPiece.y(i)
                self.drawSquare(painter, rect.left() + x * self.squareWidth(),
                    boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(),
                    self.curPiece.shape())


    def keyPressEvent(self, event):

        if not self.isStarted or self.curPiece.shape() == Tetrominoe.NoShape:
            super(Board, self).keyPressEvent(event)
            return

        key = event.key()

        if key == Qt.Key_P:
            self.pause()
            return

        if self.isPaused:
            return

        elif key == Qt.Key_Left:
            self.tryMove(self.curPiece, self.curX - 1, self.curY)

        elif key == Qt.Key_Right:
            self.tryMove(self.curPiece, self.curX + 1, self.curY)

        elif key == Qt.Key_Down:
            self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY)

        elif key == Qt.Key_Up:
            self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY)

        elif key == Qt.Key_Space:
            self.dropDown()

        elif key == Qt.Key_D:
            self.oneLineDown()

        else:
            super(Board, self).keyPressEvent(event)


    def timerEvent(self, event):

        if event.timerId() == self.timer.timerId():

            if self.isWaitingAfterLine:
                self.isWaitingAfterLine = False
                self.newPiece()
            else:
                self.oneLineDown()

        else:
            super(Board, self).timerEvent(event)


    def clearBoard(self):

        for i in range(Board.BoardHeight * Board.BoardWidth):
            self.board.append(Tetrominoe.NoShape)


    def dropDown(self):

        newY = self.curY

        while newY > 0:

            if not self.tryMove(self.curPiece, self.curX, newY - 1):
                break

            newY -= 1

        self.pieceDropped()


    def oneLineDown(self):

        if not self.tryMove(self.curPiece, self.curX, self.curY - 1):
            self.pieceDropped()


    def pieceDropped(self):

        for i in range(4):

            x = self.curX + self.curPiece.x(i)
            y = self.curY - self.curPiece.y(i)
            self.setShapeAt(x, y, self.curPiece.shape())

        self.removeFullLines()

        if not self.isWaitingAfterLine:
            self.newPiece()




    def removeFullLines(self):

        numFullLines = 0
        rowsToRemove = []

        for i in range(Board.BoardHeight):

            n = 0
            for j in range(Board.BoardWidth):
                if not self.shapeAt(j, i) == Tetrominoe.NoShape:
                    n = n + 1

            if n == 10:
                rowsToRemove.append(i)

        rowsToRemove.reverse()


        for m in rowsToRemove:

            for k in range(m, Board.BoardHeight):
                for l in range(Board.BoardWidth):
                        self.setShapeAt(l, k, self.shapeAt(l, k + 1))

        numFullLines = numFullLines + len(rowsToRemove)

        if numFullLines > 0:

            self.numLinesRemoved = self.numLinesRemoved + numFullLines
            self.msg2Statusbar.emit(str(self.numLinesRemoved))

            self.isWaitingAfterLine = True
            self.curPiece.setShape(Tetrominoe.NoShape)
            self.update()


    def newPiece(self):

        self.curPiece = Shape()
        self.curPiece.setRandomShape()
        self.curX = Board.BoardWidth // 2 + 1
        self.curY = Board.BoardHeight - 1 + self.curPiece.minY()

        if not self.tryMove(self.curPiece, self.curX, self.curY):

            self.curPiece.setShape(Tetrominoe.NoShape)
            self.timer.stop()
            self.isStarted = False
            self.msg2Statusbar.emit("Game over")



    def tryMove(self, newPiece, newX, newY):

        for i in range(4):

            x = newX + newPiece.x(i)
            y = newY - newPiece.y(i)

            if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
                return False

            if self.shapeAt(x, y) != Tetrominoe.NoShape:
                return False

        self.curPiece = newPiece
        self.curX = newX
        self.curY = newY
        self.update()

        return True


    def drawSquare(self, painter, x, y, shape):

        colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC,
                      0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00]

        color = QColor(colorTable[shape])
        painter.fillRect(x + 1, y + 1, self.squareWidth() - 2,
            self.squareHeight() - 2, color)

        painter.setPen(color.lighter())
        painter.drawLine(x, y + self.squareHeight() - 1, x, y)
        painter.drawLine(x, y, x + self.squareWidth() - 1, y)

        painter.setPen(color.darker())
        painter.drawLine(x + 1, y + self.squareHeight() - 1,
            x + self.squareWidth() - 1, y + self.squareHeight() - 1)
        painter.drawLine(x + self.squareWidth() - 1,
            y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)


class Tetrominoe(object):

    NoShape = 0
    ZShape = 1
    SShape = 2
    LineShape = 3
    TShape = 4
    SquareShape = 5
    LShape = 6
    MirroredLShape = 7


class Shape(object):

    coordsTable = (
        ((0, 0),     (0, 0),     (0, 0),     (0, 0)),
        ((0, -1),    (0, 0),     (-1, 0),    (-1, 1)),
        ((0, -1),    (0, 0),     (1, 0),     (1, 1)),
        ((0, -1),    (0, 0),     (0, 1),     (0, 2)),
        ((-1, 0),    (0, 0),     (1, 0),     (0, 1)),
        ((0, 0),     (1, 0),     (0, 1),     (1, 1)),
        ((-1, -1),   (0, -1),    (0, 0),     (0, 1)),
        ((1, -1),    (0, -1),    (0, 0),     (0, 1))
    )

    def __init__(self):

        self.coords = [[0,0] for i in range(4)]
        self.pieceShape = Tetrominoe.NoShape

        self.setShape(Tetrominoe.NoShape)


    def shape(self):
        return self.pieceShape


    def setShape(self, shape):

        table = Shape.coordsTable[shape]

        for i in range(4):
            for j in range(2):
                self.coords[i][j] = table[i][j]

        self.pieceShape = shape


    def setRandomShape(self):
        self.setShape(random.randint(1, 7))


    def x(self, index):
        return self.coords[index][0]


    def y(self, index):
        return self.coords[index][1]


    def setX(self, index, x):
        self.coords[index][0] = x


    def setY(self, index, y):
        self.coords[index][1] = y


    def minX(self):

        m = self.coords[0][0]
        for i in range(4):
            m = min(m, self.coords[i][0])

        return m



    def maxX(self):

        m = self.coords[0][0]
        for i in range(4):
            m = max(m, self.coords[i][0])

        return m


    def minY(self):

        m = self.coords[0][1]
        for i in range(4):
            m = min(m, self.coords[i][1])

        return m


    def maxY(self):

        m = self.coords[0][1]
        for i in range(4):
            m = max(m, self.coords[i][1])

        return m


    def rotateLeft(self):

        if self.pieceShape == Tetrominoe.SquareShape:
            return self

        result = Shape()
        result.pieceShape = self.pieceShape

        for i in range(4):

            result.setX(i, self.y(i))
            result.setY(i, -self.x(i))

        return result


    def rotateRight(self):

        if self.pieceShape == Tetrominoe.SquareShape:
            return self

        result = Shape()
        result.pieceShape = self.pieceShape

        for i in range(4):

            result.setX(i, -self.y(i))
            result.setY(i, self.x(i))

        return result


if __name__ == '__main__':

    app = QApplication([])
    tetris = Tetris()
    sys.exit(app.exec_())    

Что такое Tkinter