На главную страницу | Новости  |  Ссылки | Контакты

Spyphy Farnsworth
Квантовая реальность. Кибернетика. Искусственный интеллект


GUI на Python (Tkinter)

#!/bin/python

Библиотека Tk


Самый простой способ создания GUI-приложение на python - использование модуля tkinter, который по сути является надстройкой над библиотекой Tk.

Простой пример GUI-программы на python, созданный с помощью Tkinter


Рассмотрим минимальный пример:

from tkinter import Tk, Label
root = Tk()
label = Label(root, text='Hello') 
label.pack()
root.mainloop()

Создание GUI с помощью Tk включает в себя следующие основные шаги:


1) Импорт классов виджета из библиотеки:

from tkinter import Tk, Label

или

from tkinter import *

2) Создание главного окна:

root = Tk()

3) Создание виджетов и установка их свойств:

label = Label(root, text='Hello') 

либо

label = Label(root) 
label['text'] = 'Hello'

4) Определение событий и определение обработчиков событий (при необходимости) посредством метода bind или установки параметра command (для кнопки и меню);

5) Расположение (упаковка) виджетов на родительском окне:

label.pack()

6) Отображение главного окна и запуск цикла событий:

root.mainloop()

----------

Замечания:


Шаг 4 не обязателен в случае размещения пассивных элементов (таких как метки Label), но нужен, если мы хотим обрабатывать нажатие кнопок и т.п.

На самом деле создавать родительское окно (root) было тоже не обязательно, если виджет всего один. Так что этот пример с меткой можно было сократь до

from tkinter import Label
label = Label(None, text='Hello')
label.pack()
label.mainloop()

----------

Функция mainloop() запускает цикл обработки событий (посредством "обработного вызова"). Соответственно, чтобы происходили какие-то действия, необходимо зарегистрировать обработчики событий. Есть несколько способов как это сделать.

Обработка нажатий кнопок мыши и клавиш на клавиатуре


Способ 1 - cвойство command


import sys
from tkinter import *

def quit():
	sys.exit()

root = Tk()
but = Button(root, text="Press me to exit", command=quit) 
but.pack()
root.mainloop()

Здесь в качестве параметра мы передает ссылку на функцию (метод), а не результат выполнения функции. Поэтому скобки после quit ставить не нужно(!).

Конечно, здесь можно было и сразу написать


command = sys.exit

Также здесь можно было использовать анонимные функции (т.е. лямбда-выражения):


command = (lambda: sys.exit())

В этом случае скобки после метода уже нужны, что позволяет передавать туда аргументы при необходимости. Однако здесь, как и выше, вызов sys.exit() происходит не в момент создания кнопки, т.е. при выполнения инструкции

but = Button(root, text="Press me", command=(lambda: sys.exit()))

а в момент нажатия кнопки. Это так называемый отложенный вызов функции, который достигается за счет использования лямбда-выражений.

Способ 2 - метод bind


Рассмотрим пример:

import sys
from tkinter import *

def quit(event):
	sys.exit()

root = Tk()
but = Button(root, text="Press me", width=30, height=5, bg="white",fg="blue")
but.bind('', quit)
but.pack()
root.mainloop()

Здесь:

'<Button-1>' - низкоуровневый обработчик событий;

Метод bind связывает между собой 3 базовые компонента событийного программирования: виджет, событие и функцию. Таким образом, общая форма метода bind следующая:


виджет.bind(событие, функция)

При возникновении события будет вызывать соответствующая функция (обработчик события). В отличие от прежнего способа, здесь функция имеет один параметр event - событие.

Вообще, с помощью bind мы можем привязать к виджету не одно событие, а сразу несколько. Например,

but.bind('< Button-1 >', quit)
but.bind('< Double-1 >', somefunc)

Некоторые стандартные события, производимые мышью:


- < Button-1 > - щелчок левой кнопкой мыши

- < Button-2 > - щелчок средней кнопкой мыши

- < Button-3 > - щелчок правой кнопкой мыши

- < Double-Button-1 > - двойной клик левой кнопкой мыши

- < Motion > - движение мыши

События, производимые с помощью клавиатуры


- Буквенные клавиши (например, '< Q >' или просто 'Q').

- Для неалфавитных клавиш существуют специальные зарезервированные слова:

* < Return > - нажатие клавиши Enter;

* < space > - пробел;

- Сочетания клавиш пишутся через тире:

* < Control-Shift > - одновременное нажатие клавиш Ctrl и Shift.

Они устанавливаются для виджета, на котором в данный момент находится фокус:

root.bind('< Return >', quit)

Описание некоторых виджетов


Виджет Text


Пример:

text = Text(root, font=('times',12), width=50, height=15, wrap=WORD)
text.bind('Q', quit)
text.pack()

Рисование


виджет Canvas


Пример:

canv = Canvas(root, width=300, height=200, bg="white", cursor="pencil")
canv.pack()
canv.create_line(20,0,100,50, width=1, fill="green")
canv.create_line(0,0,100,100, width=2, fill="blue", arrow=LAST) 

Tk + PIL


Для работы с файлами JPG понадобятся следующие библиотеки:

$ sudo apt-get install python-imaging-tk

$ sudo apt-get install python3-pil.imagetk

затем коде делаем

import PIL
from PIL.ImageTk import PhotoImage

============================

Практический пример. Рисование с помощью tkinter графика функции, вычисление значений которой занимает много времени


Часто возникает необходимость запустить какой-то долго длящийся процесс вычислений, но так, чтобы само окно при этом не зависало и кнопки реагировали на нажатия, и при этом результат вычислений выводился в процессе работы программы, чтобы не возникало чувства, что программа зависла. Кроме того, может возникнуть необходимость остановить процесс вычислений при необходимости.

В этом случае проще всего (а возможно и единственный вариант) - запустить отдельный поток, используя модуль _thread либо threading. Следующий пример это демонстрирует (будет работать на python3). Эта программа состоит из двух частей (модулей).

Основной модуль graphic.py (для вывода графика на canvas):

import sys
from tkinter import *
import _thread
from calc import func

class Control:
	bool_stop = False

class Graphic:
	x0 = 0
	y0 = 0
	def next_point(self, y1):
		x1 = self.x0 + 2
		canv.create_line(self.x0, self.y0, x1, y1, width=2, fill="red")
		#canv.update() # not nesessary
		self.x0 = x1
		self.y0 = y1

def add_point_on_graphic(x):
	gr.next_point(x)

def quit(event):
	sys.exit()

def start_calc():
	Control.bool_stop = False
	_thread.start_new_thread(func, (add_point_on_graphic, Control))

def method_stop():
	Control.bool_stop = True

root = Tk()
canv = Canvas(root, width=600, height=200, bg="white", cursor="pencil")

but = Button(root, text="Draw", width=30, height=2, bg="white",fg="blue")
but['command'] = (lambda: start_calc())

but_stop = Button(root, text="Control", width=30, height=2, bg="white",fg="blue")
but_stop['command'] = (lambda: method_stop())

but_quit = Button(root, text="Quit", width=30, height=2, bg="white",fg="blue")
but_quit['command'] = (lambda: sys.exit())

canv.create_line(0,100,200,100, width=2, fill="blue", arrow=LAST)

gr = Graphic()

canv.pack()
but.pack()
but_stop.pack()
but_quit.pack()
root.mainloop()

Модуль calc.py для вычисления значения функции func. Эта функция будет запущена в отдельном потоке. При создании потока мы передаем в функцию func ссылку на метод add_point_on_graphic, который добавляет точку на график.

import math
import time
def func(func_add_point_on_graphic, Control):	
	for i in range(0, 2000):		
		if Control.bool_stop: break
		func_add_point_on_graphic(math.sin(i/4.0)*20+20)
		time.sleep(0.05)

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

Конечно, вместо передачи ссылки на функцию func_add_point_on_graphic можно было передать в funш ссылку на экземпляр класса Graphic и через него вызывать метод next_point(x), но здесь продемонстрировал еще один пример.

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

Библиотека PyQt


PyQt - это набор Python библиотек для создания графического интерфейса на базе платформы Qt от компании Digia.

В настоящий момент (под Python 3) доступна вервия PyQt5.

Установка:

$ sudo apt-get install python3-pyqt5 pyqt5-dev-tools

Минимальный пример:

 #!/usr/bin/python3
 import sys
 from PyQt5.QtWidgets import QApplication, QWidget
 if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = QWidget()
    w.resize(250, 150)
    w.move(300, 300)
    w.setWindowTitle('Simple')
    w.show()
    sys.exit(app.exec_())

Источники


http://younglinux.info/tkinter/tkinter.php

https://pythonworld.ru/gui/pyqt5-firstprograms.html

- Лутц М., том 1.




Платы ARDUINO


arduino NANO купить дешево arduino UNO купить дешево arduino UNO R3 ORIG купить дешево arduino MEGA купить дешево arduino DUE купить дешево



Now 19.09.21 22:56:10, Your IP: 34.239.177.24; spyphy.zl3p.com/python/gui_tk