Как сделать тест на python tkinter

Добавил пользователь Morpheus
Обновлено: 10.09.2024

Ниже приведена общая структура моей типичной программы Python tkinter.

funA funB и funC вызовет другие Toplevel окна с виджетами, когда пользователь нажмет кнопку 1, 2, 3.

Мне интересно, если это правильный способ написания программы Python Tkinter? Конечно, это сработает, даже если я напишу так, но лучше ли? Звучит глупо, но когда я вижу коды, написанные другими людьми, их код не перепутается с кучей функций, и в основном у них есть классы.

Есть ли какая-то конкретная структура, которой мы должны следовать в качестве хорошей практики? Как я должен планировать, прежде чем начать писать программу на Python?

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

Я защищаю объектно-ориентированный подход. Это шаблон, с которого я начинаю:

Важные вещи, на которые стоит обратить внимание:

Основное приложение - это класс . Это дает вам личное пространство имен для всех ваших обратных вызовов и частных функций, и, как правило, упрощает организацию вашего кода. В процедурном стиле вы должны кодировать сверху вниз, определять функции перед их использованием и т. Д. С помощью этого метода вы этого не делаете, поскольку вы фактически не создаете главное окно до самого последнего шага. Я предпочитаю наследовать tk.Frame только потому, что обычно начинаю с создания фрейма, но это ни в коем случае не является необходимым.

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

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

  • Open with Desktop
  • View raw
  • Copy raw contents Copy raw contents

Copy raw contents

Copy raw contents

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

Первый модуль Python window_01.py создает пустое окно 200x150 с названием "myWindow", расположенное в центре экрана.

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

Tk() - это функция Tkinter, открывающая главное окно любого приложения. Здесь мы создаем экземпляр с именем root. Это общая черта всех классов Tkinter - они должны быть присвоены какой-либо переменной. В следующих двух командах задаются некоторые свойства root, определяющие заголовок и размеры окна. Это другой общий факт - взаимодействие с объектами Tkinter происходит через задание свойств [и вызов методов]. '200x150+300+225' означает [ширина x высота + координата_x_верхнего_левого_угла + координата_y_верхнего_левого_угла].

Наконец, в этой строке происходит вызов метода Tk() под названием mainloop(), который держит окно раскрытым, пока оно не будет закрыто нажатием кнопки [x] на окне или вызовом метода Tk() destroy().

Довольно просто, не так ли? Понадобилось всего шесть строчек кода. Запустите Python; загрузите модуль Tkinter; присвойте какой-либо переменной значение Tk(); затем настройте три метода Tk() для этой переменной. Итак, запускаем window_01.py. Voila! Вы создали окно - фундаментальный элемент любого графического интерфейса пользователя Tkinter.

Создание "дочернего" окна

Следующий модуль Python - window_02.py помещает на экран еще одно пустое "дочернее" окно 200x150. В большинстве графических интерфейсов для организации диалога используют всплывающие окна. "Дочернее" окно исчезает при закрытии основного окна.

Toplevel() - это класс Tkinter, с помощью которого можно создавать любое окно кроме главного. Он также присваивается переменной child. Toplevel(root) означает дочернее окно child, относящееся и зависящее от родительского окна root. Следующие две команды формируют заголовок и размеры дочернего окна аналогично случаю родительского окна. Коду дочернего окна не нужен свой метод mainloop(). Он запускается из родительского окна.

Снова довольно просто. Потребовалось лишь три дополнительные строчки кода. Присвойте Toplevel() новой переменной; свяжите его с корневым окном root с помощью Toplevel(root); затем задайте значения пары свойств Toplevel(root). Наконец, запустите window_02.py. Мы движемся быстро. Мы умеем создавать родительское окно и любое число дочерних окон. Закрытие родительского окна вызывает закрытие и окна дочернего, но не наоборот.

Уже похоже на интерфейс.

Работа с классами

Python - это объектно-ориентированный язык программирования. Tk() и Toplevel() являются классами Tkinter, принимающими форму объектов для создания на экране графических окон. Программирование на Tkinter подразумевает комбинирование и преобразование встроенных классов Tkinter в новые классы с индивидуальными свойствами и методами.

Следующей задачей данного руководства будет воспроизведение визуального эффекта, достигнутого в последнем примере window_02.py, объектно-ориентированными средствами, заложенными в Python, т.е. путем создания классов. Приведенный выше код объявляет и определяет класс. Объект - это экземпляр класса. В данном случае мы собираемся создать простые классы родительских и дочерних окон. Позже мы будем формировать классы с их собственными (добавленными) свойствами и методами. Модуль, который рассматривается в этой части руководства, находится по ссылке window_03.py.

Вот обобщенная форма для создания классов. Замечание: отступы обязательны!

Здесь указывается, что будет создан класс с именем имя-класса со следующими определениями [def]. Команду __init__(self) проще показать в действии, чем объяснить. __init__() - это конструктор объектов, позволяющий создавать экземпляр объекта во время исполнения программы. self - это метка экземпляра, необходимая для привязки переменных класса к данному объекту. Таким образом инструкция self.master = root создает переменную master и присваивает ей глобальное значение root [пока еще не определенное]. В оставшейся части кода вы увидите, как теперь определяется то же самое окно внутри класса main. Итак, что же такое child()?

child() - это вызов другого класса, определенного в модуле. Так класс main генерирует экземпляр дочернего окна.

При запуске модуля на выполнение происходит вызов Python, загрузка Tkinter и сохранение определений классов main и child. Команды, приведенные выше, сначала задают значение переменной root, чтобы создать экземпляр Tk(), затем открывают окно, активируя main [который, в свою очередь, активирует child]. Обратите внимание, что mainloop() расположен "внутри" класса main. Запустите window_03.py. Он должен сделать то же самое, что и предыдущий пример.

Если этот пример - ваша первая встреча с классами, объектами и т.п., в голову вполне может прийти мысль: "К чему такие сложности?" Но стоит нам перейти к более сложным примерам, как тотчас станет очевидно, что инкапсуляция кода внутрь классов - это отличный способ писать лаконичные, пригодные для многократного использования программы на Python. Потерпите немного. Некоторые из нас помнят, как учились составлять "макаронные" программы ['spaghetti' coding - слабо структурированные программы с большим размером процедур и интенсивным использованием оператора goto; трудны для изучения и модификаций], а потом изучали "структурное" программирование. Так что "объектно-ориентированное" программирование - это еще одна новинка.

Классы и элементы управления

Запустите следующий модуль, что б ознакомится с элементами управления window_04.py.

Оставим на время разработку дочернего окна, чтобы сосредоточить все внимание на классах. Рассмотрим, как передавать классу информацию, и добавим к классу элемент управления [в данном случае кнопку (Button)], [и объект и окно].

В последнем примере window_03.py вас, возможно, удивило, что класс main содержит ссылку на переменную root, которая в программе еще не создана. Я сделал это специально, чтобы продемонстрировать, что классы ничего не делают, пока на их базе не будут созданы экземпляры объектов. Но есть лучший путь достичь того же самого. Объекту можно передать глобальную переменную root, и именно так сделано в нашем коде. Благодаря вызову main(root) параметр root передается переменной master класса main. В последующих примерах подобным же образом мы будем передавать классам множество различных параметров.

Ну, наконец и элемент управления. В Tkinter имеется определенное число графических элементов управления, которые можно размещать в нашем окне. В данном случае это будет кнопка (Button). Мы уже пользовались двумя элементами управления - Tk() и Toplevel(). Код self.button = Button(self.master, text = 'myButton') связывает элемент управления Button() с классом main [все элементы управления кроме Tk() кому-нибудь "принадлежат"], а text = 'myButton' задает значение свойства text [текст, который отобразится на кнопке во время исполнения программы]. Строка self.button.pack(side = BOTTOM) определяет, в какой части окна появится наша кнопка. Позже мы рассмотрим pack подробнее.

Между прочим, эта кнопка пока ничего не делает. Итак, запускаем window_04.py и нажимаем бесполезную кнопку.

Любая кнопка должна что-нибудь делать. В данном случае мы свяжем событие "нажатие кнопки" с открытием дочернего окна из одного из прошлых примеров. Для этого в класс main вводится метод openDialog, который создает экземпляр объекта child.

Для определения метода openDialog не нужна функция __init__(). Не создается экземпляра метода, - но метод создает экземпляр объекта child. Метод - это то, что класс main делает, а не то, чем класс main является.

Обращение к openDialog содержит вездесущее self. Это означает, что метод openDialog является внутренним по отношению к main.

Toplevel() из класса child узнает о том, что относится к дочернему классу класса main, довольно мучительным путем. Tk(), связанный с root, передается классу main через параметр master [в main], а затем пересылается другому параметру master [в child]. Всякий класс имеет свою переменную master, локальную по отношению к данному классу. Их имена могут быть различными. Ага! Метод. Запускаем window_05.py и испытываем работающую кнопку.

Модальное дочернее окно

В некоторых программах требуется для вывода информации создать дочернее окно, продолжая в тоже время использовать главное. При этом часто бывает нужно, чтобы все процессы, происходящие в дочернем окне, завершились до того, как вы продолжите работу. Такое окно называют модальным. Это значит, что оно будет удерживать фокус пока не будет закрыто. В Python дочернее окно можно превратить в модальное с помощью трех методов Toplevel():

child перехватывает все события, происходящие в приложении.

child захватывает фокус.

child ждет, когда будет уничтожен текущий объект, не возобновляя работы [но и не оказывая влияния на основной цикл].

Итак, рецепт. Если нужно создать модальное окно, воспользуйтесь этими тремя методами. Как говорится, "Просто сделай это!" window_06.py

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

Стоит создать один элемент управления, как все остальное становится ясно. Единственно стоит отметить, что элемент управления text имеет свойство background (фон) со значением 'white' (белый) и что пришло время поговорить о pack. Метод pack() размещает в окне элемент управления. Итак: side (сторона) определяет, какой стороны окна будет "держаться" элемент управления варианты: TOP (сверху) RIGHT (справа) LEFT (слева) BOTTOM (снизу) по умолчанию: NONE (никак) fill (заполнение) показывает, заполнит элемент доступное пространство или нет. варианты: X Y BOTH (X Y оба) по умолчанию: NONE (никак) expand (растяжение) указывает, будет ли элемент управления менять свой размер при изменении размеров окна. варианты: YES (да) по умолчанию: 0

В метод openDialog() мы ввели инструкцию self.text.get('0.0', END), которая является методом элемента управления Text. Она собирает все содержимое текстового окна от строки 0 символа 0 и до конца, чтобы передать его классу/окну child [как myText].

Как работает текстовый элемент управления child интуитивно ясно. Он заполняется текстом из главного окна посредством def __init__(self, master, myText = ''). Информация из myText вставляется в элемент управления text с помощью метода self.text.insert('0.0', myText), который помещает ее, начиная со строки 0 символа 0. Испытайте window_07.py, напечатав в нем какой-нибудь текст и отослав его.

Общение - хорошая штука, но оно должно быть улицей с двухсторонним движением.

Сначала посмотрите на код window_08.py.

Мы хотим, чтобы информация шла от родительского окна к дочернему И от дочернего к родительскому. Последнего можно добиться, добавив к дочернему окну кнопку accept и метод для регистрации всех изменений, произведенных в передаваемом тексте; также введем метод go как для создания экземпляра дочернего окна, так и для управления процессом обмена информацией. Такое применение методов [go] для открытия дочерних окон - полезный инстру. мент, который приобретет особую важность, когда мы будем иметь дело с более сложными операциями в последующих руководствах. Сейчас же он создает пустую переменную newValue, в которую будет записан измененный текст [если он был изменен].

При вызове дочернего метода go введенный текст вставляется в дочернее текстовое окно. Если текст редактировался и пользователь нажимает кнопку accept, исправленный текст возвращается как newValue. Если дочернее окно просто закрывается, newValue возвращается с пустым значением.

При возврате метод openDialog класса main осуществляет проверку. Если возвращаемая строка не пустая, возвращаемый текст будет вставлен в текстовое окно main.

Запускаем window_08.py. Убедитесь, что вы "уловили", как работает go. Нам придется еще довольно много иметь дело с этим методом.

Мы приближаемся к концу начала. Рассмотрим еще несколько приемов, которые будут использоваться позднее в "реальном" приложении: кнопки принятия (accept) и отмены (cancel), а также "перехват" закрытия основного окна с соответствующим диалогом.

Пока все просто. Размещение в дочерних диалоговых окнах кнопки отмены (cancel) - довольно стандартный прием. При этом происходит уничтожение дочернего окна без изменения newValue.

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

Запустите window_09.py, чтобы увидеть нашу программу в действии.

Наша программа растет. У нас получается. И что еще более важно, ее части возможно использовать повторно. Класс yesno может быть применен еще раз в этом же приложении или даже в будущих приложениях. Итак, в коде, приводимом ниже, мы разбиваем программу на три отдельных модуля, которые будут храниться в трех отдельных автономных файлах. Основной файл myWindow.py использует классы dialog и yesno так же, как и раньше, но, вместо того чтобы включить их в код, они импортируются из других файлов - myDialog.py и myBoolean.py.

Просмотрите завершающие части файлов myDialog.py и myBoolean.py. Там есть тестовая команда. Включать подобную команду в конец любого файла, который не выполняется напрямую, - стандартное правило. С помощью оператора if __name__ == '__main__': она проверяет, запущен файл из другой программы или сам по себе. В последнем случае открывается пустое окно, которое затем убирается с экрана командой root.withdraw(). Но именно к этому фиктивному окну привязывается рабочий код, позволяющий запускать данный файл. Это очень полезный инструмент для отладки. Использование тестов приводит к тому, что все модули становятся "исполняемыми".

Итак, запустим все три файла - myWindow.py, myDialog.py, myBoolean.py - и посмотрим, что произойдет.

Мини-руководство по Tkinter

Программа, которую мы составили, не сильно впечатляет - что-то вроде импровизации на тему "Hello World!". Предыдущая страница была названа "святым граалем" по двум причинам. Прежде всего, Python никак не связан со змеей. Это название взято из известного сериала Monty Python and the Quest for the Holy Grail. Кроме того, в легенде о Граале рассказывается о том, как нечто искали повсюду, и, когда, наконец, оно было найдено, оказалось, что ищущий обладал им с самого начала. Это учебное руководство было написано пять или шесть лет тому назад. Тогда оно не было опубликовано, поскольку я посчитал его слишком примитивным. Позднее это руководство выручило меня самого, облегчив вспоминание Tkinter. Сейчас я сознаю, что оно уже содержало все необходимые идеи, чтобы начать использовать Tkinter для интересующих меня задач. Если вы похожи на меня, то будете применять Python для написания различных утилит, которые часто бывают полезны в повседневной жизни. Это превосходный язык для таких целей [а Tkinter - почти совершенный GUI]. Но для создания коммерческих мегапрограмм, чтобы заработать много денег, ни Python, ни Tkinter не годятся. [Как, впрочем, и само программирование в целом. Лучше идите учиться на менеджера!].

Перечислим элементы управления, с которыми мы уже успели познакомиться, вместе с их свойствами и методами, использованными в примерах. Общий стиль Tkinter - это размещение свойств внутри круглых скобок: Имя_класса(свойство1 = значение1, свойство2 = значение2) и использование методов в роли особых "точечных" команд: Имя_класса.метод(параметры)

У меня есть проект питон и мне его надо перебросить в Qt Designer.

Как и каким интерфейсом это сделать?

Так-же какие блоки использовать в Qt Designer для создания именно такого опросника так сказать?

Мой Код питон 3.7.4


2 ответа 2

Этого материала по созданию простого приложения с использованием qt-designer'а более чем достаточно. Во всяком случае, ваш проект легко переносится на форму.

Если хотите автоматизировать такие процессы в дальнейшем нарабатывайте собственную библиотеку шаблонов.

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

PyQt — набор привязок графического фреймворка Qt для языка программирования Python, выполненный в виде расширения Python.

После инсталляции PyQt5, копируете модули main_survey.py , survey_ui.py и survey_ui.ui в какой-нибудь каталог.

Запускаем с консоли:

Для получения результатов опросника нажимаем на кнопку Опубликовать результат опроса .

main_survey.py - основной модуль приложения, содержит импорт класса Ui_Form из модуля survey_ui.py и логику программы.

survey_ui.py - модуль содержащий дизайн приложения, который был получен путем конвертации модуля survey_ui.ui в модуль survey_ui.py .

survey_ui.ui - модуль, который мы создали в Qt Designer.

Запустите Qt Designer и посмотрите как выглядит созданная форма:

введите сюда описание изображения

Вам придется самостоятельно найти Книги и учебные ресурсы по PyQt5 и Qt Designer если вам это будет интересно.

Все виджеты в Tkinter обладают некоторыми общими методами. В этой статье мы познакомимся с такими методами. Список всех виджетов можно изучить в статье “Библиотека Tkinter: Виджеты“.

1. configure

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

Для этого используется метод configure (или его синоним config). Также можно использовать квадратные скобки (widget[‘option’] = new_value).

Пример, программа выводит текущее время, после клика по кнопке:

В этом коде функция button_clicked вызывается каждый раз, когда пользователь “кликает” по кнопке.

2. cget

Метод cget является обратным к методу configure. Он предназначен для получения информации о конфигурации виджета. Здесь как и в случае с configure можно использовать квадратные скобки (value = widget[‘option’]).

В данном примере программа после “клика” на кнопку программа показывает цвет кнопки и меняет его на другой.

3. destroy

Метод destroy() уничтожает виджет и всех его потомков. Рассмотрим пример:

В данном примере мы создаем две кнопки и к одной кнопке даём команду: “При нажатии на кнопку уничтожать виджет в виде первой кнопки” с помощью метода destroy().

Главное окно программы не будет закрыто, но “Кнопка 1” будет удалена с главного окна.

Если необходимо только на время спрятать какой-либо виджет, то лучше пользоваться упаковщиком grid и методом grid_remove:

Использование grid_remove позволяет сохранять взаимное расположение виджетов.

4. quit

Метод quit() не уничтожает виджеты, но выходит из интерпретатора tcl/tk, то есть останавливает mainloop(). Пример:

5. grab_

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

  • grab_set – передать поток данному виджету;
  • grab_set_global – передать глобальный поток данному виджету. В этом случае все события на дисплее будут передаваться этому виджету. Следует пользоваться очень осторожно, т.к. остальные виджеты всех приложений не будут получать события;
  • grab_release – освободить поток;
  • grab_status – узнать текущий статус потока событий для виджета. Возможные значения: None, “local” или “global”;
  • grab_current – получить виджет, который получает поток.

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

6. focus_

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

  • focus (синоним focus_set) – передать фокус виджету;
  • focus_force – передать фокус, даже если приложение не имеет фокуса;
  • focus_get – возвращает виджет, на который направлен фокус, либо None, если такой отсутствует;
  • focus_displayof – возвращает виджет, на который направлен фокус на том дисплее, на котором размещён виджет, либо None, если такой отсутствует;
  • focus_lastfor – возвращает виджет, на который будет направлен фокус, когда окно с этим виджетом получит фокус;
  • tk_focusNext – возвращает виджет, который получит фокус следующим (обычно смена фокуса происходит при нажатии клавиши Tab). Порядок следования определяется последовательностью упаковки виджетов;
  • tk_focusPrev – то же, что и focusNext, но в обратном порядке;
  • tk_focusFollowsMouse – устанавливает, что виджет будет получать фокус при наведении на него мышью. Вернуть нормальное поведение достаточно сложно.

Перепишете код и запустите для проверки. В главном окне будет стоять кнопка и иметь фокус.

7. Системные методы

Системные методы не являются виджет-специфичными, т.е. хотя они являются методами виджетов они влияют на работу интерпретатора tcl/tk.

1. after, after_idle и after_cancel

Таймеры. С помощью этих методов вы можете отложить выполнение какого-нибудь кода на определённое время.

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

after_idle – принимает один аргумент – функцию. Эта функция будет выполнена после завершения всех отложенных операций (после того, как будут обработаны все события). Возвращает идентификатор, который может быть использован в after_cancel.

after_cancel – принимает один аргумент: идентификатор задачи, полученный предыдущими функциями, и отменяет это задание.

2. update и update_idletasks

Две функции, для работы с очередью задач. Их выполнение вызывает обработку отложенных задач.

update_idletasks выполняет задачи, обычно откладываемые “на потом”, когда приложение будет простаивать. Это приводит к прорисовке всех виджетов, расчёту их расположения и т.д.

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

update обрабатывает все задачи, стоящие в очереди. Обычно эта функция используется во время “тяжёлых” расчётов, когда необходимо чтобы приложение оставалось отзывчивым на действия пользователя.

3. eval и evalfile

Две недокументированные функции для выполнения кода на tcl.

eval позволяет выполнить строку на языке программирования tcl.

evalfile – выполнить код, записанный в файл.

В качестве аргументов принимают соответственно строку и путь к файлу. Данные функции полезны при использовании дополнительных модулей, написанных на tcl. Пример:

Читайте также: