Что такое mainloop в python
Перейти к содержимому

Что такое mainloop в python

  • автор:

Как в python запустить паралельно две функции mainloop и socket

мне надо запустить одновременно две функции window.mainloop (модуль tkinter) и функцию с сервером socket. Как это сделать?

Отслеживать
задан 8 ноя 2022 в 17:33
349 2 2 серебряных знака 13 13 бронзовых знаков

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

У Питона с коробки есть модуль threading . Он позволяет выполнять функции паралелно.

from threading import * t1 = Thread(target='функция 1') t2 = Thread(target='функция 2') t1.start() t2.start() 

Повторюсь, они запускаются паралельно, то есть вторая не ждет окончае первой

Tkinter: кратко для начинающих

Python — один из самых лёгких и популярных языков программирования. С помощью python решается достаточно много проблем — он сможет помочь в почти любой ситуации. Сегодня речь пойдёт о встроенной библиотеке tkinter. С помощью tkinter создаётся уникальный графический интерфейс для приложения на python.

  1. Загрузка
  2. Синтаксис
  3. Компиляция

Tkinter вы можете скачать на официальном сайте или PyPi.

Загрузка

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

Загрузка для windows:

pip install tkinter pip install --update tkinter

либо на всё том же PyPi выбираете tkinter для Windows, macOS или Linux.

Синтаксис

Теперь надо разобраться с синтаксисом tkinter. Сначала импортируем:

from tkinter import *

Теперь наша задача — сделать окно приложения. Для этого выберем название приложения (у меня это My App). Запишем

from tkinter import * #исходный код if __name__ == '__main__': #выполнение кода до загрузки root = Tk() root.title('My App') #заголовок root.mainloop() #отображение окна

пояснение

Сначала мы импортировали tkinter. После него идёт исходный код — виджеты, текст и тд. После if name == ‘main’ в отступах идёт код, который выполняется до загрузки, тоесть первее чем код в начале (не считая импорт). Сам код, который будет дальше, пишите до. .mainloop() отвечает за отображение окна — оно обязательно должно быть в конце кода. Если вы редактируете 2 окна, нужно ставить не в конец, а в начало кода второго окна (да я «очень хорошо» объясняю)

виджеты и текст

Теперь наша задача — ввести текст. Наше окно пока что пустое. Выглядит оно так:

P.S. картинка с интернета

Чтобы добавить и редактировать текст, нужно использовать виджет Label. Давайте попробуем записать

lbl1 = Label(root, text='Привет') lbl1.grid(column=0, row=0)

Виджет Label

Row отвечает за строку, а column за столбец. Правда, у некоторых могут возникнуть проблемы в том, что вторая строка сдвинута. Для этого изменим grid на place

lbl1.place(x=10,y=10)

Нужно всего лишь указать место по x и y. Для удобства можете задать отдельный класс для управления переменными

class wid_prm(): #класс управления переменными x = 10 y1 = 10 y2 = 30 y3 = 50 x_y_z = 410 #. lbl1 = Label(root, text='. ') lbl2 = Label(root, text='. ') #плейсы lbl1.place(x=x,y=y1) lbl2.place(x=x,y=y2)

Думаю, тут всё понятно. Местоположение по x нужно использовать одно, если вы хотите использовать один столбец. Думаю, не стоит тратить время, нужно автоматизировать управление переменными x, y

for auto_prm in range(5): y1 = 10 y1 += 20 y1 -= 10 y1 -= 10 if y1 == 30: #останавливаем процесс y1 = 30 else: y2 = y1 + 20 y3 = y1 + 40 y4 = y1 + 60 y5,y6,y7,y8 = y1 * 2 + (y1 * 4) y990 = 4 if y990 > 1: x = 10 else: x = 5

А для чего это? Это для того, чтобы задать переменные автоматически. Просто скопируйте и вставьте эту часть кода в свой код.

Давайте теперь сделаем шрифт жирным в Label

lbl1 = Label(root,text='. ',font=("Times New Roman",21,"bold"))

Вы, наверное, уже поняли, что за шрифт отвечает функция font. «bold» можете убрать, если вы не хотите жирный шрифт текста. 21 — размер текста в пикселях/мм.

Теперь попробуем использовать виджет Button — добавим кнопку

btn1 = Button(root, text='Не нажимай', command=clicked) btn1.place(x=x_x,y=y1_y) def clicked(): print('Я же сказал. ')

При нажатии на кнопку будет писать определённый текст по команде clicked. Вы можете дать любое название и любое содержимое команды.

Получается, что полный код пока-что выглядит так:

from tkinter import * #импорт #исходный код class wid_prm(): #класс управления переменными x = 10 y1 = 10 y2 = 30 y3 = 50 x_y_z = 410 for auto_prm in range(5): y1 = 10 y1 += 20 y1 -= 10 y1 -= 10 if y1 == 30: #останавливаем процесс y1 = 30 else: y2 = y1 + 20 y3 = y1 + 40 y4 = y1 + 60 y5,y6,y7,y8 = y1 * 2 + (y1 * 4) y990 = 4 if y990 > 1: x = 10 else: x = 5 class prm_x_y(): x_x = 10 y1_y = 50 lbl1 = Label(root, text='. ') btn1 = Label(root, text='Не нажимай', command=clicked) def clicked(): print('Я же сказал. ') #плейсы lbl1.place(x=x,y=y1) btn1.place(x=x_x,y=y1_y) if __name__ == '__main__': root = Tk() root.title('My App') root.geometry('400x400') root.mainloop()

Виджет messagebox

Виджет messagebox позволяет создать отдельное окно с информацией. Давайте попробуем

from tkinter import * from tkinter import messagebox messagebox.showinfo('Заголовок', 'текст')

Это довольно круто для дополнительных виджетов.

Я, наверное, с синтаксисом закончу.

Компиляция

Первым делом нужно установить приложение auto-py-to-exe. Вы его можете установить либо с того же PyPi, либо через командную строку:

pip install auto-py-to-exe pip install --update auto-py-to-exe

Вы скачаете приложение auto-py-to-exe от python. Вот как оно выглядит:

auto-py-to-exe

В script location указываете путь к файлу. Вот небольшой пример:

>Path to file: >\Users\username\Desktop\file.py

Дальше всё просто. Укажите One File, если не хотите, чтобы файлы приложения засоряли ваш пк. Если хотите скрыть консоль (и оставить только окно tkinter), выберите Window Based.

Загрузите иконку приложения в Icon. И наконец-то нажимаете CONVERT .PY TO .EXE. Думаю, с последующим вы сами справитесь — в консоль будет выводиться всякая всячина, и в итоге вы успешно сконвертируете приложение на tkinter.

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

Что такое Tkinter

Tkinter – это пакет для Python, предназначенный для работы с библиотекой Tk. Библиотека Tk содержит компоненты графического интерфейса пользователя (graphical user interface – GUI). Эта библиотека написана на языке программирования Tcl.

Под графическим интерфейсом пользователя (GUI) подразумеваются все те окна, кнопки, текстовые поля для ввода, скроллеры, списки, радиокнопки, флажки и другие элементы, которые вы видите на экране, открывая то или иное приложение. Через них вы взаимодействуете с программой и управляете ею. Все эти элементы интерфейса будем называть виджетами (widgets – штуковины).

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

Существует множество библиотек GUI, среди которых Tk не самый популярный инструмент, хотя с его помощью написано немало проектов. Он был выбран для Python по-умолчанию. Установочный файл интерпретатора Питона обычно уже включает пакет tkinter в составе стандартной библиотеки.

Tkinter можно представить как переводчик с языка Python на язык Tcl. Вы пишете программу на Python, а код модуля tkinter переводит ваши инструкции на язык Tcl, который понимает библиотека Tk.

Программы с графическим интерфейсом пользователя событийно-ориентированные. Вы уже должны иметь представление о структурном и желательно объектно-ориентированном программировании. Событийно-ориентированное ориентировано на события. То есть та или иная часть программного кода начинает выполняться лишь тогда, когда случается то или иное событие.

Событийно-ориентированное программирование базируется на объектно-ориентированном. Даже если мы не будем разрабатывать собственные классы, мы обязательно будем пользоваться теми, что есть в tkinter . Все виджеты – это объекты-экземпляры, создаваемые от встроенных классов.

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

Tkinter импортируется стандартно для модуля Python любым из способов:

  • import tkinter
  • from tkinter import *
  • import tkinter as tk

Можно импортировать отдельные классы, что делается редко. В данном курсе мы будем использовать выражение from tkinter import * .

Если необходимо, узнать установленную версию Tk можно через константу TkVersion:

>>> from tkinter import * >>> TkVersion 8.6

Чтобы написать GUI-программу, надо выполнить приблизительно следующее:

  1. Создать главное окно.
  2. Создать виджеты и выполнить конфигурацию их свойств (опций).
  3. Определить события, то есть то, на что будет реагировать программа.
  4. Описать обработчики событий, то есть то, как будет реагировать программа.
  5. Расположить виджеты в главном окне.
  6. Запустить цикл обработки событий.

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

В современных операционных системах любое пользовательское приложение заключено в окно, которое можно назвать главным, так как в нем располагаются все остальные виджеты. Объект окна верхнего уровня создается от класса Tk модуля tkinter . Переменную, связываемую с объектом, часто называют root (корень):

root = Tk()

Пусть в окне приложения располагаются текстовое поле, метка и кнопка. Данные объекты создаются от классов Entry , Label и Button модуля tkinter . Сразу выполним конфигурацию некоторые их свойства с помощью передачи аргументов конструкторам этих классов:

ent = Entry(root, width=20) but = Button(root, text="Преобразовать") lab = Label(root, width=20, bg='black', fg='white')

Устанавливать свойства объектов не обязательно при их создании. Существуют еще пара способов, с помощью которых это можно сделать после.

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

ent = Entry(width=20) but = Button(text="Преобразовать") lab = Label(width=20, bg='black', fg='white')

Однако виджеты не обязательно располагаются на root ‘е. Они могут находиться на других виджетах, и тогда указывать «мастера» необходимо.

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

def str_to_sort_list(event): s = ent.get() s = s.split() s.sort() lab['text'] = ' '.join(s)

У функций, которые вызываются при наступлении события с помощью метода bind , должен быть один параметр. Обычно его называют event , то есть «событие».

В нашей функции с помощью метода get из поля забирается текст, представляющий собой строку. Она преобразуется в список слов с помощью метода split . Потом список сортируется. В конце изменяется свойство text метки. Ему присваивается строка, полученная из списка с помощью строкового метода join .

Теперь необходимо связать вызов функции с событием:

but.bind('', str_to_sort_list)

В данном случае это делается с помощью метода bind . Ему передается событие и функция-обработчик. Событие будет передано в функцию и присвоено параметру event . Здесь событием является щелчок левой кнопкой мыши, что обозначается строкой » .

В любом приложении виджеты не разбросаны по окну как попало, а организованы, интерфейс продуман до мелочей и обычно подчинен определенным стандартам. Пока расположим элементы друг под другом с помощью наиболее простого менеджера геометрии tkinter – метода pack :

ent.pack() but.pack() lab.pack()

Метод mainloop экземпляра Tk запускает главный цикл обработки событий, что в том числе приводит к отображению главного окна со всеми «упакованными» на нем виджетами:

root.mainloop()

Полный код программы:

from tkinter import * def str_to_sort_list(event): s = ent.get() s = s.split() s.sort() lab['text'] = ' '.join(s) root = Tk() ent = Entry(width=20) but = Button(text="Преобразовать") lab = Label(width=20, bg='black', fg='white') but.bind('', str_to_sort_list) ent.pack() but.pack() lab.pack() root.mainloop() 

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

Пример программы на Python, написанной с помощью tkinter

Попробуем теперь реализовать в нашей программе объектно-ориентированный подход. Это необязательно, но позволяет связать/объединить вместе (вспомните про инкапсуляцию в ООП) виджет и функции, которые обрабатывают связанные с ним события, что концептуально более верно. В этом случае функции становятся методами.

Пусть группа из метки, кнопки и поля представляет собой один объект, порождаемый от класса Block . Тогда в основной ветке программы будет главное окно, объект типа Block и запуск окна. Поскольку блок должен быть привязан к главному окну, то неплохо бы передать в конструктор класса окно-родитель:

from tkinter import * root = Tk() first_block = Block(root) root.mainloop()

Теперь напишем сам класс Block :

class Block: def __init__(self, master): self.ent = Entry(master, width=20) self.but = Button(master, text="Преобразовать") self.lab = Label(master, width=20, bg='black', fg='white') self.but['command'] = self.str_to_sort self.ent.pack() self.but.pack() self.lab.pack() def str_to_sort(self): s = self.ent.get().split() s.sort() self.lab['text'] = ' '.join(s)

Здесь виджеты являются значениями полей объекта типа Block , функция-обработчик события нажатия на кнопку устанавливается не с помощью метода bind , а с помощью свойства кнопки command . В этом случае в вызываемой функции не требуется параметр event . В метод мы передаем только сам объект.

Больший смысл в определении собственного класса появляется, когда требуется несколько или множество похожих объектов-блоков. Допустим, нам нужно несколько блоков, состоящих из метки, кнопки, поля. Причем у кнопки каждой группы будет своя функция-обработчик клика.

Тогда можно передавать значения для свойства command в конструктор. Значение будет представлять собой привязываемую к кнопке функцию-обработчик события. Полный код программы:

from tkinter import * class Block: def __init__(self, master, func): self.ent = Entry(master, width=20) self.but = Button(master, text="Преобразовать") self.lab = Label(master, width=20, bg='black', fg='white') # self.but['command'] = eval('self.' + func) self.but['command'] = getattr(self, func) self.ent.pack() self.but.pack() self.lab.pack() def str_to_sort(self): s = self.ent.get().split() s.sort() self.lab['text'] = ' '.join(s) def str_reverse(self): s = self.ent.get().split() s.reverse() self.lab['text'] = ' '.join(s) root = Tk() first_block = Block(root, 'str_to_sort') second_block = Block(root, 'str_reverse') root.mainloop() 

Выражение getattr(self, func) , где вместо func подставляется строка ‘str_to_sort’ или ‘str_reverse’, преобразуется в выражение self.str_to_sort или self.str_reverse .

При выполнения этого кода в окне будут выведены два однотипных блока, кнопки которых выполняют разные действия.

Окно с двумя блоками кнопки, метки и текстового поля

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

Практическая работа

Напишите простейший калькулятор, состоящий из двух текстовых полей, куда пользователь вводит числа, и четырех кнопок «+», «-«, «*», «/». Результат вычисления должен отображаться в метке. Если арифметическое действие выполнить невозможно (например, если были введены буквы, а не числа), то в метке должно появляться слово «ошибка».

Курс с примерами решений практических работ: pdf-версия

X Скрыть Наверх

Tkinter. Программирование GUI на Python

Введение в Tkinter

image

Tkinter – это кроссплатформенная библиотека для разработки графического интерфейса на языке Python (начиная с Python 3.0 переименована в tkinter). Tkinter расшифровывается как Tk interface, и является интерфейсом к Tcl/Tk.
Tkinter входит в стандартный дистрибутив Python.

Весь код в этой статье написан для Python 2.x.
Чтобы убедиться, что Tkinter установлен и работает, воспользуемся стандартной функцией Tkinter _test():

import Tkinter Tkinter._test()

После выполнения данного кода должно появиться следующее окно:

Отлично, теперь можно приступать к написанию нескольких простых программ для демонстрации основных принципов Tkinter.

Hello world

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

from Tkinter import * root = Tk()

Да-да, всего одна строка, это вам не WinAPI (=. Теперь создадим кнопку, при нажатии на которую будет выводиться текст в консоль:

def Hello(event): print "Yet another hello world" btn = Button(root, #родительское окно text="Click me", #надпись на кнопке width=30,height=5, #ширина и высота bg="white",fg="black") #цвет фона и надписи btn.bind("", Hello) #при нажатии ЛКМ на кнопку вызывается функция Hello btn.pack() #расположить кнопку на главном окне root.mainloop()

Всё просто, не так ли? Создаём экземпляр класса Button, указываем родителя и при желании список параметров. Есть еще немало параметров, таких как шрифт, толщина рамки и т.д.
Затем привязываем к нажатию на кнопку событие (можно привязать несколько разных событий в зависимости, например, от того, какой кнопкой мыши был нажат наш btn.
mainloop() запускает цикл обработки событий; пока мы не вызовем эту функцию, наше окно не будет реагировать на внешние раздражители.

Упаковщики

Функция pack() — это так называемый упаковщик, или менеджер расположения. Он отвечает за то, как виджеты будут располагаться на главном окне. Для каждого виджета нужно вызвать метод упаковщика, иначе он не будет отображён. Всего упаковщиков три:

pack(). Автоматически размещает виджеты в родительском окне. Имеет параметры side, fill, expand. Пример:

from Tkinter import * root = Tk() Button(root, text = '1').pack(side = 'left') Button(root, text = '2').pack(side = 'top') Button(root, text = '3').pack(side = 'right') Button(root, text = '4').pack(side = 'bottom') Button(root, text = '5').pack(fill = 'both') root.mainloop()

grid(). Размещает виджеты на сетке. Основные параметры: row/column – строка/столбец в сетке, rowspan/columnspan – сколько строк/столбцов занимает виджет. Пример:

from Tkinter import * root = Tk() Button(root, text = '1').grid(row = 1, column = 1) Button(root, text = '2').grid(row = 1, column = 2) Button(root, text = '__3__').grid(row = 2, column = 1, columnspan = 2) root.mainloop()

place(). Позволяет размещать виджеты в указанных координатах с указанными размерами.
Основные параметры: x, y, width, height. Пример:

from Tkinter import * root = Tk() Button(root, text = '1').place(x = 10, y = 10, width = 30) Button(root, text = '2').place(x = 45, y = 20, height = 15) Button(root, text = '__3__').place(x = 20, y = 40) root.mainloop()

Теперь для демонстрации других возможностей Tkinter, напишем простейший

Текстовый редактор

Без лишних слов приведу код:

from Tkinter import * import tkFileDialog def Quit(ev): global root root.destroy() def LoadFile(ev): fn = tkFileDialog.Open(root, filetypes = [('*.txt files', '.txt')]).show() if fn == '': return textbox.delete('1.0', 'end') textbox.insert('1.0', open(fn, 'rt').read()) def SaveFile(ev): fn = tkFileDialog.SaveAs(root, filetypes = [('*.txt files', '.txt')]).show() if fn == '': return if not fn.endswith(".txt"): fn+=".txt" open(fn, 'wt').write(textbox.get('1.0', 'end')) root = Tk() panelFrame = Frame(root, height = 60, bg = 'gray') textFrame = Frame(root, height = 340, width = 600) panelFrame.pack(side = 'top', fill = 'x') textFrame.pack(side = 'bottom', fill = 'both', expand = 1) textbox = Text(textFrame, font='Arial 14', wrap='word') scrollbar = Scrollbar(textFrame) scrollbar['command'] = textbox.yview textbox['yscrollcommand'] = scrollbar.set textbox.pack(side = 'left', fill = 'both', expand = 1) scrollbar.pack(side = 'right', fill = 'y') loadBtn = Button(panelFrame, text = 'Load') saveBtn = Button(panelFrame, text = 'Save') quitBtn = Button(panelFrame, text = 'Quit') loadBtn.bind("", LoadFile) saveBtn.bind("", SaveFile) quitBtn.bind("", Quit) loadBtn.place(x = 10, y = 10, width = 40, height = 40) saveBtn.place(x = 60, y = 10, width = 40, height = 40) quitBtn.place(x = 110, y = 10, width = 40, height = 40) root.mainloop()

Здесь есть несколько новых моментов.

Во-первых, мы подключили модуль tkFileDialog для диалогов открытия/закрытия файла. Использовать их просто: нужно создать объект типа Open или SaveAs, при желании задав параметр filetypes, и вызвать его метод show(). Метод вернёт строку с именем файла или пустую строку, если пользователь просто закрыл диалог.

Во-вторых, мы создали два фрейма. Фрейм предназначен для группировки других виджетов. Один содержит управляющие кнопки, а другой — поле для ввода текста и полосу прокрутки.
Это сделано, чтобы textbox не налезал на кнопки и всегда был максимального размера.

В-третьих, появился виджет Text. Мы его создали с параметром wrap=’word’, чтобы текст переносился по словам. Основные методы Text: get, insert, delete. Get и delete принимают начальный и конечный индексы. Индекс — это строка вида ‘x.y’, где x — номер символа в строке, а y — номер строки, причём символы нумеруются с 1, а строки — с 0. То есть на самое начала текста указывает индекс ‘1.0’. Для обозначения конца текста есть индекс ‘end’. Также допустимы конструкции вида ‘1.end’.

B в-четвёртых, мы создали полосу прокрутки (Scrollbar). После создания её нужно связать с нужным виджетом, в данном случае, с textbox. Связывание двустороннее:

scrollbar['command'] = textbox.yview textbox['yscrollcommand'] = scrollbar.set

Вот и всё. Tkinter – это, безусловно, мощная и удобная библиотека. Мы осветили не все её возможности, остальные — тема дальнейших статей.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *