Главная страница
Навигация по странице:

  • Глава Библиотека компонентов8

  • Глава Библиотека компонентов8 164 Рис.

  • Шуман Х. - Python для детей - 2019. # Startwerte festlegen Red (255,0,0)


    Скачать 5.95 Mb.
    Название# Startwerte festlegen Red (255,0,0)
    Дата10.03.2023
    Размер5.95 Mb.
    Формат файлаpdf
    Имя файлаШуман Х. - Python для детей - 2019.pdf
    ТипДокументы
    #977830
    страница11 из 22
    1   ...   7   8   9   10   11   12   13   14   ...   22
    Глава
    Библиотека компонентов
    8
    152
    Кнопки и ответы
    Ранее у нас было что-то подобное в игре-лотерее, где мы все включили в список. Сработает ли способ с компонента- ми? Попробуем, но давай сначала объявим пустой список.
    Knopka = []
    Я не использую в коде слово Button, потому что это имя класса. В цикле списка ты можешь теперь генерировать шесть таких «кнопок»:
    for Nr in range(0,6) :
    Knopka.append(Button(Window, text=Answer[Nr]))
    После создания каждая кнопка должна быть добавлена в список с помощью функции append(). Я просто добавил еще один список, который нам нужно сгенерировать в на- чале программы:
    Answer = ["Супер", "Хорошо", "Так себе", "Плохо", "Ужасно", \
    "Не скажу"]
    В другом цикле for мы организуем шесть кнопок (обе ин- струкции должны быть однострочными):
    for pos in range(0,3) :
    Knopka[pos].place(x=20, y=60+pos*40, width=120, height=30)
    Knopka[pos+3].place(x=160, y=60+pos*40, width=120, height=30)
    Это три строки, в каждой из которых есть пара кнопок. Зна- чения по оси x фиксированы, значения по оси y изменяют- ся в каждой строке. Поэтому счетчик pos учитывается, когда речь идет о вычислении позиции по оси y.
    На данный момент я не включил функции события, потому что это не так просто. Ты можешь оставить все как есть, на- значить функцию
    Knopka[0].config(command=buttonClick)
    и продублировать ее шесть раз (с параметром от 0 до 5).
    Я поместил параметр command в метод config, что вполне себе работает. Но здесь я бы предпочел цикл.
    Однако тогда нам сначала нужно сделать одну функцию для многих кнопок. Для этого нам нужен еще один список:

    Кнопки и ответы
    153
    Diagnose = ["Это здорово!", "Это радует!", "Все возможно.", \
    "Это огорчает!", "Это плохо!", \
    "Раз ты так думаешь..."]
    Здесь и в других похожих ситуациях ты можешь использовать символ \, чтобы разбить длинную инструкцию на две и более строк.
    Функция события выглядит следующим образом:
    def buttonClick(Nr) :
    Display.config(text=Diagnose[Nr])
    И вот уже у нас возникла проблема. Сообщение об ошибке не появится, если мы расширим блок инструкций первого цикла for следующим образом:
    Knopka[Nr].config(command=buttonClick(Nr))
    Однако начало программы вызывает разочарование: не- зависимо от того, какую кнопку я нажимаю, не появляется ответ. На самом деле мы не должны передавать какие-либо параметры функции buttonClick, но компьютер не ругается, а лишь игнорирует параметр.
    Как же использовать функцию buttonClick(), которая на- столько красива, с короткими параметрами? Ключевое сло- во lambda поможет нам в этом. Используется оно так:
    Knopka[Nr].config(command=lambda: buttonClick(Nr))
    Если ты применишь его в первом цикле for, исходный код будет выглядеть так:
    for Nr in range(0,6) :
    Knopka.append(Button(Window, text=Answer[Nr]))
    Knopka[Nr].config(command=lambda: buttonClick(Nr))
    Но даже это не приносит желаемого эффекта. Ты увидишь текст, когда нажмешь кнопку, но только последний вариант ответа: «Раз ты так думаешь...».
    Каждому параметру command нужен уникальный номер, по- этому у нас нет выбора, кроме как обойтись без цикла и на- значить определенное число каждой из шести кнопок:

    Глава
    Библиотека компонентов
    8
    154
    Knopka[0].config(command=lambda: buttonClick(0))
    Knopka[1].config(command=lambda: buttonClick(1))
    Knopka[2].config(command=lambda: buttonClick(2))
    Knopka[3].config(command=lambda: buttonClick(3))
    Knopka[4].config(command=lambda: buttonClick(4))
    Knopka[5].config(command=lambda: buttonClick(5))
    В конце концов, мы смогли избежать проблем. Теперь я приведу исходный код целиком (⇒ hello4.py):
    # Приветствие с кнопками from tkinter import *
    # Константы текста
    Answer = ["Супер", "Хорошо", "Так себе", "Плохо", "Ужасно", \
    "Не скажу"]
    Diagnose = ["Это здорово!", "Это радует!", "Все возможно.", \
    "Это огорчает!", "Это плохо!", \
    "Раз ты так думаешь..."]
    # Функция события def buttonClick(Nr) :
    Display.config(text=Diagnose[Nr])
    # Основная программа
    Window = Tk()
    Window.title("Привет!")
    Window.config(width=300, height=190)
    Display = Label(Window, text="Как это сделать?")
    Display.place(x=80, y=10, width=160, height=30)
    # Кнопки
    Knopka = []
    for Nr in range(0,6) :
    Knopka.append(Button(Window, text=Answer[Nr]))
    for pos in range(0,3) :
    Knopka[pos].place(x=20, y=60+pos*40, width=120, height=30)
    Knopka[pos+3].place(x=160, y=60+pos*40, width=120, height=30)
    # Индивидуальная настройка событий
    Knopka[0].config(command=lambda: buttonClick(0))
    Knopka[1].config(command=lambda: buttonClick(1))
    Knopka[2].config(command=lambda: buttonClick(2))
    Knopka[3].config(command=lambda: buttonClick(3))
    Knopka[4].config(command=lambda: buttonClick(4))
    Knopka[5].config(command=lambda: buttonClick(5))
    # Цикл событий
    Window.mainloop()

    Списки выбора
    155
    ¾
    Лучше создай новый файл. Или сохрани изменения в файл под новым именем. Введи указанный исходный код и протестируй программу. Если хочешь, можешь по- пробовать реализовать такой функционал с помощью метода config в цикле.
    Списки выбора
    В поисках альтернативы кнопкам мы теперь немного поко- паемся в коллекции компонентов модуля tkinter. Без кно- пок наша программа может работать, если мы создадим список со всеми ответами, которые раньше были на кноп- ках. И тогда нам больше не понадобятся кнопки. Поэтому тебе нужно их удалить, либо ты можешь создать совершен- но новый файл и скопировать туда необходимые строки ис- ходного кода.
    Теперь мы имеем дело только с одним компонентом, кото- рый нам нужно создать:
    Box = Listbox(Window)
    Разумеется, сейчас этот список пуст, поэтому мы заполним его текстом:
    for Nr in range(0,6) :
    Box.insert(Nr, Answer[Nr])
    Метод insert() принимает в качестве параметра сначала номер записи, затем текст ответа. Наконец, мы помещаем блок компонента и указываем его размеры:
    Box.place(x=30,y=50, width=200, height=150)
    (Тебе может понадобиться настроить высоту и ширину, осо- бенно если ты используешь другие, более длинные строки ответов.)
    Как связать список с функцией события? Здесь речь идет не о нажатии на кнопку, а о том, какой элемент был выбран.
    Поэтому мы используем совершенно другой метод:
    Box.bind("<>", listboxSelect)
    Инструкция bind() привязывает событие к функции (или методу). Первый параметр определяет событие, которое не

    Глава
    Библиотека компонентов
    8
    156
    только заключается в кавычки, но и оборачивается в двой- ные угловые скобки.
    Я переименовал функцию события: listboxSelect() (имя button­Click()
    больше не подходит). И вот как выглядит эта функция сейчас:
    def listboxSelect(event) :
    Select = Box.curselection()
    Nr = Select[0]
    Display.config(text=Diagnose[Nr])
    Здесь необходим параметр, который принимает событие
    (английское слово event). Сначала функция определяет, ка- кая запись была выбрана (отмечена или нажата):
    Select = Box.curselection()
    Результат – это не число, а выражение, из которого число сначала должно быть «выделено». Мы делаем это следую- щим образом:
    Nr = Select[0]
    Теперь можно отобразить соответствующий текст ответа.
    Давай рассмотрим исходный код целиком (⇒ hello5.py):
    from tkinter import *
    # Константы текста
    Answer = ["Супер", "Хорошо", "Так себе", "Плохо", "Ужасно", \
    "Не скажу"]
    Diagnose = ["Это здорово!", "Это радует!", "Все возможно.", \
    "Это огорчает!", "Это плохо!", \
    "Раз ты так думаешь..."]
    # Функция события def listboxSelect(event) :
    Select = Box.curselection()
    Nr = Select[0]
    Display.config(text=Diagnose[Nr])
    # Основная программа
    Window = Tk()
    Window.title("Привет!")
    Window.config(width=260, height=230)
    Display = Label(Window, text="Как это сделать?")

    О переключателях...
    157
    Display.place(x=20, y=10, width=160, height=30)
    # Список
    Box = Listbox(Window)
    for Nr in range(0,6) :
    Box.insert(Nr, Answer[Nr])
    Box.bind("<>", listboxSelect)
    Box.place(x=30,y=50, width=200, height=150)
    # Цикл событий
    Window.mainloop()
    ¾
    Введи этот исходный код и запусти программу (рис. 8.2).
    Выбери каждую запись один раз.
    Рис. 8.2.Результат работы программы со списком
    О переключателях...
    Существует еще один способ визуализировать твое на- строение. Для этого ты можешь взять свой старый проект, работающий с помощью кнопок. В принципе, компоненты могут быть изменены непосредственно там.
    Изучаемый компонент носит имя Radiobutton и называется
    переключателем. Такой объект содержит текст, отображае- мый справа от кружочка. Если в кружочке установлена точ- ка – переключатель считается установленным.
    Как и в случае с кнопками, нам нужны шесть компонентов, которые мы создаем в виде пустого списка:
    Option = []

    Глава
    Библиотека компонентов
    8
    158
    Затем мы создаем шесть элементов, список параметров ко- торых будет немного отличаться от кнопок:
    for Nr in range(0,6) :
    Option.append(Radiobutton(Window, variable=Number, value=Nr, \ text=Answer[Nr]))
    Здесь создается позиция переключателя с определенным текстом. Пока это похоже на работу с кнопками. Но есть два новых параметра:
    – variable – вставляет дополнительную переменную, ко- торая делит переключатель с другими позициями. Они образуют группу, в которой можно активировать толь- ко один параметр. У нас это номер выбранного эле- мента;
    – value получает последовательный номер соответствую- щей позиции в группе.
    Теперь число не является обычной численной перемен- ной так, как это было ранее в классическом Python. Модуль tkinter использует свой собственный тип, который описы- вается следующим образом:
    Number = IntVar()
    Number.set(-1)
    Этой переменной присваивается значение с помощью ме- тода set(). Это не может быть число из списка с номерами позиций (от 0 до 5). В противном случае соответствующий компонент будет считаться активированным и переключа- тель будет установлен в соответствующую позицию при за- пуске программы. Тем не менее должен отмечаться только тот вариант, который мы выбираем.
    Функция IntVar() так же, как, например, StringVar(), – это соб- ственное творение модуля tkinter для работы с целыми чис- лами и строками. Это методы, которые создают «обычную» пе- ременную, нужную для работы программы. Важно, чтобы такая переменная не создавалась, пока не появится окно как экземп- ляр Tk()!
    Функция события не нуждается в параметре, потому что значение переменной Number глобально. Однако ты получа- ешь ее значение только с помощью метода get():

    О переключателях...
    159
    def buttonClick() :
    Display.config(text=Diagnose[Number.get()])
    Используя дополнительные переменные, многое можно упростить, как показывает следующий полный листинг (⇒
    hello6.py):
    from tkinter import *
    # Константы текста
    Answer = ["Супер", "Хорошо", "Так себе", "Плохо", "Ужасно", \
    "Не скажу"]
    Diagnose = ["Это здорово!", "Это радует!", "Все возможно.", \
    "Это огорчает!", "Это плохо!", \
    "Раз ты так думаешь..."]
    # Функция события def buttonClick() :
    Display.config(text=Diagnose[Number.get()])
    # Основная программа
    Window = Tk()
    Window.title("Привет!")
    Window.minsize(width=260, height=260)
    Display = Label(Window, text="Как это сделать?")
    Display.pack()
    # Вспомогательная переменная
    Number = IntVar()
    Number.set(-1)
    # Опции
    Option = []
    for Nr in range(0,6) :
    Option.append(Radiobutton(Window, variable=Number, value=Nr, \ text=Answer[Nr]))
    Option[Nr].config(command=buttonClick)
    Option[Nr].pack(anchor="w")
    # Цикл событий
    Window.mainloop()
    На этот раз я выбрал вариант pack(), который показался мне проще. Тем не менее пришлось помешать окну стать слишком маленьким. Вот почему я определил минимально допустимые размеры и использовал метод minsize() вместо config()
    :
    Window.minsize(width=260, height=260)

    Глава
    Библиотека компонентов
    8
    160
    Кроме того, нам нужен параметр anchor="w", позволяющий убедиться, что кружочки позиций переключателя выровне- ны должным образом. (Вариант anchor="e" тоже подойдет.)
    ¾
    Введи показанный код и запусти программу. Щелкни по каждому положению переключателя один раз.
    Рис. 8.3.Результат работы версии программы с переключателем
    ...и флажках
    Современная медицина уже признала, что помимо физи- ческого есть еще моральные и духовные аспекты состояния человека. Поэтому давай применим новейшие продвиже- ния в науке в нашем текущем проекте.
    Для этого мы используем новый объект типа Checkbutton, также называемый флажком. Этот компонент отображает квадратик слева от текста. Если в нем установлен флажок
    (галочка), запись считается отмеченной (рис. 8.4).
    Рис. 8.4.Сгруппированные переключатель и флажки
    Чтобы охватить все аспекты состояния человека, мы допол- ним нашу программу тремя флажками:

    ...и флажках
    161
    Choice = []
    for Nr in range(0,3) :
    Choice.append(Checkbutton(Window, variable=Number, \ text=State[Nr]))
    Нам также нужен еще один список строк:
    State = ["Духовно", "Морально", "Физически"]
    Похоже на переключатели, но здесь нам нужен лишь па- раметр variable, и мы можем избавиться от переменной value
    . Однако мы не можем использовать одну и ту же пе- ременную здесь, если она уже используется в коде пере- ключателей. По этой причине я ее переименовал и кое-что дополнил:
    ChkNum = [0,0,0]
    OptNum = IntVar()
    OptNum.set(-1)
    В то время как элемент теперь назван OptNum, у меня есть пе- ременная ChkNum, которая сразу становится списком из трех элементов. Почему? В то время как переключатель может быть установлен только в одну позицию, флажков можно установить любое количество (даже все). Поэтому каждый элемент Checkbutton нуждается в собственной переменной.
    Затем мы создаем их в цикле for:
    for Nr in range(0,3) :
    ChkNum[Nr] = IntVar()
    Choice.append(Checkbutton(Window, variable=ChkNum[Nr], \ text= State [Nr]))
    Теперь что-то должно произойти, если установить фла- жок. Например, соответствующая «строка ответа» появится в строке заголовка окна.
    Для этого нам нужен другой метод событий, который я на- зову checkClick():
    def checkClick() :
    Text = "Привет! "
    for Nr in range (0,3) :
    if ChkNum[Nr].get() == 1 :
    Text = Text + State[Nr] + " ";
    Window.title(Text)

    Глава
    Библиотека компонентов
    8
    162
    Сначала мы создаем строку с содержимым «Привет!», кото- рое изначально присутствовало в заголовке окна. Затем эта строка проверяется в цикле, в котором установлен флажок.
    Так происходит, если связанный элемент ChkNum имеет зна- чение 1:
    if ChkNum[Nr].get() == 1 :
    Если это так, то добавляется соответствующий текст («Духов- но», «Морально», «Физически») (с пробелами между ними):
    Text = Text + State[Nr] + " ";
    Наконец, у нас есть полноценный заголовок окна:
    Window.title(Text)
    ¾
    Теперь у нас есть все необходимое, чтобы собрать ис- ходный код программы воедино (⇒ hello7.py):
    from tkinter import *
    # Константы текста
    Answer = ["Супер", "Хорошо", "Так себе", "Плохо", "Ужасно", \
    "Не скажу"]
    State = ["Духовно", "Морально", "Физически"]
    Diagnose = ["Это здорово!", "Это радует!", "Все возможно.", \
    "Это огорчает!", "Это плохо!", \
    "Раз ты так думаешь..."]
    # Функция для события def buttonClick() :
    Display.config(text=Diagnose[OptNum.get()])
    def checkClick() :
    Text = "Привет! "
    for Nr in range (0,3) :
    if ChkNum[Nr].get() == 1 :
    Text = Text + State[Nr] + " ";
    Window.title(Text)
    # Основная программа
    Window = Tk()
    Window.title("Привет!")
    Window.minsize(width=420, height=260)
    Display = Label(Window, text="Как дела?")
    Display.grid(row=0, column=1)

    ...и флажках
    163
    # Вспомогательные переменные
    ChkNum = [0,0,0]
    OptNum = IntVar()
    OptNum.set(-1)
    # Опции
    Option = []
    for Nr in range(0,6) :
    Option.append(Radiobutton(Window, variable=OptNum, value=Nr, \ text=Answer[Nr]))
    Option[Nr].config(command=buttonClick)
    Option[Nr].grid(row=Nr+1, column=0, sticky="w")
    # Управление
    Choice = []
    for Nr in range(0,3) :
    ChkNum[Nr] = IntVar()
    Choice.append(Checkbutton(Window, variable=ChkNum[Nr], \ text= State [Nr]))
    Choice[Nr].config(command=checkClick)
    Choice[Nr].grid(row=Nr+1, column=2, sticky="w")
    # Цикл событий
    Window.mainloop()
    Опять же, я немного экспериментировал с дизайном, а за- тем решил использовать для разметки сетку. Сначала поле отображается в первой строке, но во втором столбце:
    Display.grid(row=0, column=1)
    Я расположил позиции переключателя в первом столбце, строка меняется в соответствии с нумерацией отдельных элементов:
    Option[Nr].grid(row=Nr+1, column=0, sticky="w")
    Флажки попадают в столбец 3:
    Choice[Nr].grid(row=Nr+1, column=2, sticky="w")
    Ключевое слово sticky гарантирует, что все пункты вырав- ниваются по левому краю.
    ¾
    Запусти программу и протестируй все переключатели и галочки (рис. 8.5).

    Глава
    Библиотека компонентов
    8
    164
    Рис. 8.5.Версия программы с флажками и переключателем
    Декорирование приложения
    Все эти пункты с возможностью выбора с их точками и флажками кажутся какими-то блеклыми. Посмотрим, удастся ли нам немного доработать внешний вид програм- мы. Для этого я использую два других компонента того же типа, с которыми я хотел бы визуально совместить две группы элементов управления – переключателя и флажков:
    Links = Frame(Window, borderwidth=2, relief="sunken")
    Links.place(x=20, y=50, width=180, height=220)
    Rechts = Frame(Window, borderwidth=2, relief="raised")
    Rechts.place(x=220, y=50, width=180, height=110)
    Frame
    – это тип компонента, который прежде всего предна- значен для генерации красивой рамки. С помощью пара- метра relief я могу влиять на то, как выглядит внутренняя поверхность этого компонента, например утопленная или выступающая. А параметр borderwidth определяет толщину границы. Кроме того, с помощью функции place() можно тщательно позиционировать элементы управления.
    Окно будет состоять лишь из двух новых компонентов, по- казанных на рис. 8.6.

    Декорирование приложения
    165
    Рис. 8.6.Примеры рамок – утопленной и выступающей
    Теперь мы должны убедиться, что позиции переключателя и флажки попадают в нужные рамки. Поэтому мы сделаем
    Radiobuttons и Checkbuttons элементами рамки:
    Option.append(Radiobutton(Links, variable=OptNum, value=Nr, \ text=Answer[Nr]))

    Choice.append(Checkbutton(Rechts, variable=ChkNum[Nr], \ text= State [Nr]))
    И с этим мы приходим к полному исходному коду (⇒ hel­
    lo8.py):
    from tkinter import *
    # Константы текста
    Answer = ["Супер", "Хорошо", "Так себе", "Плохо", "Ужасно", \
    "Не скажу"]
    State = ["Духовно", "Морально", "Физически"]
    Diagnose = ["Это здорово!", "Это радует!", "Все возможно.", \
    "Это огорчает!", "Это плохо!", \
    "Раз ты так думаешь..."]
    # Функция для события def buttonClick() :
    Display.config(text=Diagnose[OptNum.get()])
    def checkClick() :
    Text = "Привет! "

    1   ...   7   8   9   10   11   12   13   14   ...   22


    написать администратору сайта