преподаватель информатики (веб, Python, PHP, OC)
0,0
рейтинг
9 октября 2015 в 12:51

Разработка → Пишем графическую программу на Python с tkinter из песочницы

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

Поэтому предлагаю потренироваться в написании небольшой графической програмки на Python с использованием tkinter (кроссплатформенная библиотека для разработки графического интерфейса на языке Python).

Код в этой статье написан для Python 3.5.

Задание: написание программы для рисования на холсте произвольного размера кругов разных цветов.

Не сложно, возможно программа «детская», но я думаю, для яркой иллюстрации того, что может tkinter самое оно.

Хочу рассказать сначала о том, как указать цвет. Конечно удобным для компьютера способом. Для этого в tkinter есть специальный инструмент, который можно запустить таким образом:

from tkinter import *
window = Tk()
colorchooser.askcolor()

Пояснения к коду:

  • rom tkinter import * — импорт библиотеки, вернее всех ее методов, на что указывает звездочка (*);
  • window = Tk() — создание окна tkinter;
  • colorchooser.askcolor() — открывает окно выбора цвета и возвращает кортеж из двух значений: кортеж из трех элементов, интенсивность каждой RGB цвета, и строка. цвет в шестнадцатиричной системе.

askcolor

Можно для определения цвета рисования использовать английские название цветов. Здесь хочу заметить, что не все они поддерживаются. Тут говорится, что без проблем вы можете использовать цвета «white», «black», «red», «green», «blue», «cyan», «yellow», «magenta». Но я все таки поэкспериментировала, и вы увидите дальше, что из этого вышло.

Для того, чтобы рисовать в Python необходимо создать холст. Для рисования используется система координат х и у, где точка (0, 0) находится в верхнем левом углу.

В общем хватит вступлений — начнем.

from random import *
from tkinter import *

size = 600
root = Tk()
canvas = Canvas(root, width=size, height=size)
canvas.pack()
diapason = 0

Пояснения к коду:

  • from random import * — импорт всех методов модуля random;
  • from tkinter import * — это вы уже знаете;
  • переменная size понадобиться потом;
  • root = Tk() — создаем окно;
  • canvas = Canvas(root, width=size, height=size) — создаем холст, используя значение переменной size (вот она и понадобилась);
  • canvas.pack() — указание расположить холст внутри окна;
  • переменная diapason понадобиться потом для использования в условии цикла.

Дальше создаем цикл:

while diapason < 1000:
    colors = choice(['aqua', 'blue', 'fuchsia', 'green', 'maroon', 'orange',
                  'pink', 'purple', 'red','yellow', 'violet', 'indigo', 'chartreuse', 'lime', ''#f55c4b''])
    x0 = randint(0, size)
    y0 = randint(0, size)
    d = randint(0, size/5)
    canvas.create_oval(x0, y0, x0+d, y0+d, fill=colors)
    root.update()
    diapason += 1

Пояснения к коду:
  • while diapason < 1000: — с предусловием, которое говорит о том, что цикл будет повторятся пока переменная diapason не дойдет до 1000.

colors = choice(['aqua', 'blue', 'fuchsia', 'green', 'maroon', 'orange',
                  'pink', 'purple', 'red','yellow', 'violet', 'indigo', 'chartreuse', 'lime', ''#f55c4b''])

Создаем список для якобы случайного выбора цвета кругов. Заметьте, что один из цветов написан в формате ''#f55c4b'' — код цвета в шестнадцатиричной системе.

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

x0 = randint(0, size) и y0 = randint(0, size) — случайный выбор координат х и у в рамках холста размером size.
d randint(0, size/5) — произвольный выбор размера круга, ограниченный size/5.

canvas.create_oval(x0, y0, x0+d, y0+d, fill=colors) — собственно говоря рисуем круги, в точках с координатами x0 и y0, размерами по вертикали и горизонтали x0+d и y0+d, заливкой цветом, который выбирается случайным образом из списка colors.

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

Без этого в итоге отобразятся круги, но процесс их появления будет вам не виден. А именно это придает шарм этой програмке.

diapason += 1 — шаг цикла, счетчик.

В результате получается такая картинка:

image

Мне не понравилось, что справа и вверху какие-то пустые места образовываются, поэтому я немного изменила условие цикла while diapason < 2000 или 3000. Так холст получился более заполненным.

Также можно сделать цикл бесконечным:

while True:
    colors = choicecolors = choice(['aqua', 'blue', 'fuchsia', 'green', 'maroon', 'orange',
                  'pink', 'purple', 'red','yellow', 'violet', 'indigo', 'chartreuse', 'lime'])
    x0 = randint(0, size)
    y0 = randint(0, size)
    d = randint(0, size/5)
    canvas.create_oval(x0, y0, x0+d, y0+d, fill=colors )
    root.update()

Вот как-то так оно происходит: instagram.com/p/8fcGynPlEc

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

Студенты еще спросили, а можно ли запускать это как заставку на рабочем столе Windows? Пока не нашла как это можно было бы сделать.

Источники:
Документация по python http://www.ilnurgi1.ru/docs/python/modules/tkinter/colorchooser.html
Курс по библиотеке Tkinter языка Python

Помощники:
Введение в Tkinter http://habrahabr.ru/post/133337
Создание GUI на Python с помощью библиотеки Tkinter. Программирование для начинающих http://younglinux.info/book/export/html/48
Таблица названий цветов в английском языке http://www.falsefriends.ru/english-colors.htm
Екатерина @ketrin7
карма
13,0
рейтинг 0,0
преподаватель информатики (веб, Python, PHP, OC)
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (25)

  • +4
    Студенты еще спросили, а можно ли запускать это как заставку на рабочем столе Windows? Пока не нашла как это можно было бы сделать.

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

    from Tkinter import *
    
    root=Tk()
    root.overrideredirect(1) # убираем заголовок окна
    root.state('zoomed')  # разворачиваем на весь экран
    
    def exit(event):root.destroy()
    
    Label(root,text='Hello world').place(relx=0.5,rely=0.5,anchor=CENTER)
    
    
    root.bind('<Button-1>',exit) # сюда еще можно добавить события нажатия на клавиши
    
    root.mainloop()
    
    
    


    Остается собрать с помощью py2exe и поменять расширение с EXE на SCR
    • 0
      kAIST Спасибо за совет и код. Надо будет попробовать.
  • 0
    Изменить строчки выбора позиции круга.

    x0 = randint(-size/10, size)
    y0 = randint(-size/10, size)

    Таким образом круги будут вылезать слева и сверху. И пустоты не будет оставаться.
    • 0
      art1415926535 отлично. Спасибо за идею. Я пробовала вместо 0 написать -3 — особо разницы не увидела, потому отказалась от этого. А до -size/10 не додумалась ;)
      • +1
        А еще лучше координаты круга указать так:
        canvas.create_oval(x-d/2, y-d/2, x+d/2, y+d/2, fill=colors)

        canvas.create_oval(...) овал рисует по координатам левого верхнего и правого нижнего угла описанного прямоугольника
        image
        http://www.python-course.eu/tkinter_canvas.php

        P.S. и для d = randint(0, size/5) ноль лучше на какое-то число запустить (иначе получим круг нулевого диаметра)
        • 0
          P.S. и для d = randint(0, size/5) ноль лучше на какое-то число запустить (иначе получим круг нулевого диаметра)

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


    У меня примерно так было.
    Когда долгое время перед глазами графические интерфейсы, а сам не представляешь себе их внутреннего устройства, они кажутся магией. Открывая своё первое окно с помощью какого-нибудь API, будто посвящаешься в тайну, которая раньше тебе была недоступна. Отчего-то приложение с окном кажется более «реальным», чем прочие. Вероятно, это следствие повсеместного распространения Windows и невозможности представить себе какие-то иные приложения/программы. Консольные helloworld'ы кажутся непонятными и странными поделками.

    Успехов в начинаниях! Попробуйте посмотреть PyGame и PyGame Zero — обычно, создание игрушек ещё больше увлекает.
    www.pygame.org/docs/tut/newbieguide.html
    pygame-zero.readthedocs.org/en/latest
    • 0
      JIghtuse Про PyGame чиала, но пока не вникала, а про PyGame Zero и не слышала. Спасибо, покопаюсь.
  • –1
    На одной конференции писали ради забавы похожий код(код потерялся вместе с буком).
    image
    Из интересного цвета можно выбирать из палитры, а палитру взять уже готовую, тогда картинка будет смотреться целостнее, что ли (например flat ui).
    • 0
      ice2heart тоже думала о том, что можно не только кружочки рисовать. На счет flat ui нашла такое flatuicolors.com. Оно?
      • +1
        Да оно, там просто все цвета между собой сочетаются. Можно оттуда взять значение цветов, сложить в лист и брать случайный элемент.
  • 0
    Небольшое замечание к первому примеру. Вот сдесь пропущен импорт:
    from tkinter import *
    window = Tk()
    colorchooser.askcolor()
    


    Нужно добавить:
    from tkinter import colorchooser
    


    • 0
      Зачем? Мне кажется, что звездочки вполне достаточно, ведь нужен не только colorchooser, а и другие команды
      • +1
        Звездочка импортирует не все:
        In [1]: from tkinter import *
        
        In [2]: colorchooser.askcolor()                                                                     
        ---------------------------------------------------------------------------
        NameError                                 Traceback (most recent call last)
        <ipython-input-2-f2db2b9f793a> in <module>()
        ----> 1 colorchooser.askcolor()
        
        NameError: name 'colorchooser' is not defined
        
        In [3]: from tkinter import colorchooser
        
        In [4]: colorchooser.askcolor()
        Out[4]: (None, None)
        


        Почему так?
        Код
        from tkinter import *
        

        импортирует классы, заданные в
        /usr/lib/python3.4/tkinter/__init__.py


        Tk там есть, а colorchooser — нет. Отсюда и ошибка.
        • 0
          Понятно, спасибо. Отвечу как двоечник — но работает же :) И у меня такой ошибки не возникает
          • 0
            Вот у меня возникла, поэтому и разобрался. Возможно, он был импортирован где-то ранее в коде, вот и работало. Я тестировал в интерактивной консоли Python 3.4 и 3.5.
            • 0
              Возможно, он был импортирован где-то ранее в коде, вот и работало

              нет, не был
              Я делала в IDLE Python 3.5.

              В общем понятно, что нюанс такой может быть…
              У меня, кстати, получались ошибки, если я писала просто — import tkinter
              • 0
                Если просто import tkinter, то в консоли появлялся объект-модуль «tkinter», и обращаться к его содержимому (к объявленным там классам, функциям и переменным) нужно с префиксом: window = tkinter.Tk(). Но colorchooser всё равно придётся импортировать отдельно: import tkinter.colorchooser и потом tkinter.colorchooser.askcolor() и так далее. А поскольку window вы таким образом объявляете уже в своём модуле, у него префикса не будет, его методы будут доступны непосредственно — например, window.state('zoomed') для разворачивания окна.

                Если написать from tkinter import *, colorchooser не импортируется — посмотрите сами, dir() его не покажет.
              • +1
                О, а ведь и верно, если использовать idle, после from tkinter import * мы видим, что colorchooser в dir() есть.

                В любом случае, не рассчитывайте на это поведение. Это вероятнее всего баг idle, а не фича. В скриптах, запускаемых не через idle (c «шабангом» первой строкой вида #!/usr/bin/env python3, либо командой python script.py) это работать не будет.

                И не стоит писать «from XXX import *» — это дурной тон. Можно нарваться на одинаковые идентификаторы в нескольких модулях. Лучше импортировать либо только то, что вы действительно будете использовать — в данном случае, примерно так: from tkinter import colorchooser, Tk
                • 0
                  В любом случае, не рассчитывайте на это поведение. Это вероятнее всего баг idle, а не фича.

                  :))
                  А где лучше тогда проверять правильность кода?
                  • +2
                    Пишете в командной строке python или запускаете python.exe без параметров. Открывается интерактивная консоль, наподобие той, что в idle, но без всяких обрамлений. Вот поскольку непосредственно этот интерпретатор (python или python.exe) и будет выполнять вашу программу в подавляющем большинстве случаев, на её поведение можно ориентироваться.

                    А готовый скрипт запускать так: python(.exe) путь-к-скрипту.py
                    • 0
                      Собственно, так софт на python и работает, не через idle же запускается.

                      Как вариант для обучения/разработки — использовать ipython. У него удобные «консоли» и «ноутбуки», вроде этого. Не встречал в нём какого-то особого поведения, как в idle.
                      • 0
                        Собственно, так софт на python и работает, не через idle же запускается.

                        Я сказал «в подавляющем большинстве», потому, что иногда интерпретатор — всё же не /usr/bin/python, а встроен в приложение-хост. Например, в виде плагина uwsgi, или плагина xchat, и так далее.
                    • 0
                      Таки думала, что вы это скажете :)
                      Ясно. Но не очень удобно, зато надежно.
              • +1
                На счет ошибки — вероятно, еще одна особенность IDLE (в дополнение к тому, что описал merlin-vrn в своих комментариях). В обычной консоли все отлично, модуль импортируется:
                $ python3.5
                Python 3.5.0 (default, Nov  1 2015, 16:18:53) 
                [GCC 4.9.3] on linux
                Type "help", "copyright", "credits" or "license" for more information.
                >>> import tkinter
                >>> tkinter
                <module 'tkinter' from '/usr/lib64/python3.5/tkinter/__init__.py'>
                >>> 
                

                Осталось только обращаться к содержимому правильно :)

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