Quiz - Викторина

Quiz - викторина или тест, программа с тестовыми вопросами.

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

Для выполнения цели: нужно уметь разбивать задачу на шаги и выполнять их в дальнейшем.

Будем придумывать, записывать и выполнять шаги по мере решения.😉

Step 1 - Шаг 1: приветствие

Создадим окно приветствия.

Для подключения библиотек tkinter используем рекомендованный формат подключения:

from tkinter import *
from tkinter.ttk import *
1
2

Создадим пустое окно с названием «My quiz».

quiz_01

Создадим рамку - LabelFrame, с названием «Generate screen» для наглядной визуализации. Далее все элементы будут создаваться в этой рамке:

frm = LabelFrame(text="Generate screen")
frm.pack()
1
2

Виджеты первого окна приветствия создадим отдельной функцией с параметром, в котором будет передаваться сам фрейм. В Label добавим текст приветствия: «Welcome to my quiz!n Press start to continue…». Последовательность символов n - означает, что следующий текст будет выводиться с новой строки. Добавив метку - Label и кнопку. Для которых укажем родительский элемент, переданный в функцию параметром el:

def first_screen(el):
    Label(el, text='Welcome to my quiz!\n Press "Start" to continue...').pack()
    Button(el, text="Start", command=lambda e=el: ask_question(e)).pack()
1
2
3

Для вызова функции поле создания окна и фрейма в вызовем функцию командой:

first_screen(frm)
1

Результат выполнения:

quiz_02

Step 2 - Шаг 2: меняем содержание фрейма

Теперь создадим функцию с параметром, которая будет отображать вопросы с вариантами ответов. Вызываться эта функция будет кнопкой в которой задана команда: command=lambda e=el: ask_question(e). Имя функции будет соответственно: ask_question(el):

def ask_question(el):
    for widget in el.winfo_children():
        widget.destroy()
    Label(el, text="Здесь могла быть Ваша реклама! \n Или вопрос с вариантами ответов.").pack()
1
2
3
4

При вызове этой функции происходит следующее:

  • функция принимает аргумент, которым является основной виждет LabelFrame;
  • функция for перебирает все вложенные элементы в этот фрейм ранее и удаляет их;
  • далее создаем новые элемент метку - Label(text=»Здесь могла быть Ваша реклама! n Или вопрос с вариантами ответов.»)

Результат выполнения, после нажатия кнопки:

quiz_03

Step 3 - Шаг 3: вопрос с ответами

Предположим первый вопрос с вариантами ответов: Вопрос:

Какие виждеты используют для вывода текста с возможностью его редактирования? Which widgets using to display text with the ability to edit it?

Ответы:

  • Canvas
  • Listbox
  • Entry
  • Text
  • Label

Для сохранения результата наших ответов, после строк импорта создадим переменную с пустым массивом (листом), в котором будем сохранять ответы:

from tkinter import *
from tkinter.ttk import *

answers = []
...
1
2
3
4
5

Внесем изменения в функцию def ask_question(el): Для вопроса будем использовать виджет метку - Label():

def ask_question(el):
    for widget in el.winfo_children():
        widget.destroy()

    question = Label(el, text="Which widgets using to display text with the ability to edit it?").pack()
1
2
3
4
5

А для вариантов ответа используем флажки - Checkbutton(), и у каждого флажка должна быть своя переменная. Выберем для неё тип переменной BooleanVar(), и хранить её будем в массиве answer. Чтобы добавить переменную в массив будем использовать метод .append(…) с параметром задающим тип переменной BooleanVar():

answers.append(BooleanVar())
ch_1 = Checkbutton(el, text="Canvas", variable=answers[0], onvalue=1, offvalue=0).pack(anchor=W)
1
2

Остальные варианты ответа добавьте самостоятельно, используя копировать-вставить (copy-paste). Привязка новых элементов обязательно должна быть к передаваемому фрейм элементу el. Результат выполнения:

quiz_04

Step 4 - Шаг 4: проверка ответов

Создадим функцию проверки ответов check(), после объявленной переменной answer, которая будет перебирать массив (лист) answer:

...
answers = []

def check():
    for i in answers:
        print(i.get())
...
1
2
3
4
5
6
7

В конце функции def ask_question(el): создадим кнопку «Next >>», которая вызывает функцию проверки:

button_next = Button(el, text="Next >>", command=check).pack()
1

quiz_05

Пример результата вывода в консоль, который только отражает какие флажки были выбраны:

False
True
False
True
False
1
2
3
4
5

Для сохранения итоговых баллов создадим переменную points и переменную true_answers в которой будет храниться строка, состоящая из 0 и 1 (пример: 000110, где длинна это количество предлагаемых ответов, а 1 обозначают какие ответы правильные):

...
answer = []
points = 0
true_answers = "10110"
...
1
2
3
4
5

Для проверки выбранных ответов с правильными изменим check() функцию. Для одновременного перебора двух списков параллельно можно воспользоваться функцией zip():

...
for t, a in zip(true_answers, answers):
    print(bool(t), a.get())
...
1
2
3
4

Переменная t будет перебирать список true_answers, переменная a - answers. После преобразования bool(int(t)) в булевый тип, пример вывода в консоль:

True False
False False
True True
True True
False False
1
2
3
4
5

Осталось вписать условие сравнения для подсчета результата. За каждый правильный ответ будем увеличивать баллы на 1 в результате неправильного уменьшать на 1, если вариант ответа не выбран, то баллы не изменяются:

def check(el):
    global points
    for t, a in zip(true_answers, answers):
        if bool(int(t)) and bool(int(t)) == a.get():
            points += 1
        elif bool(int(t)) != a.get():
            points -= 1
    print(points)
    points = 0      # для обнуления результата при пересчете
1
2
3
4
5
6
7
8
9

Пример вывода в консоль:

-5
1

Step 5 - Шаг 5: вывод баллов в окно

Для вывода результата в окно продолжим изменять функцию check(), она должна принимать параметр, а именно фрейм в который выводится результат:

...
def check(el):
...
1
2
3

А также нужно изменить кнопку «Next >>»:

button_next = Button(el, text="Next >>", command=lambda e=el: check(e)).pack()
1

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

Теперь вместо строки print(points) пишем код очищающий фрейм:

for widget in el.winfo_children():
    widget.destroy()
1
2

А затем добавляем метку - Label() который выводит, например: «Ваш результат: -4 балла», количество баллов соответствует подсчету после ответа.

quiz_06

Упражнения

  1. Добавьте на последней форме кнопку «Try again», которая будет предлагать выполнение программы сначала.

  2. Создайте переменную типа лист, в которой последовательно хранятся вопрос, ответы и правильная вариация ответов:

q1 = ["Which widgets using to display text with the ability to edit it?",
    "Canvas",
    "Listbox",
    "Entry",
    "Text",
    "Label",
    "10110"]
1
2
3
4
5
6
7
  1. Измените программу так, чтобы данные для генерации вопросов брались из этой переменной. Желательно использовать срезы и перебор циклом.

  2. Добавьте переменную с вопросом и ответами, с использованием дополнительного символа перед строкой:

    «?» - означает вопрос, «+» - означает правильный ответ, «-» - означает неправильный ответ, «10110» - последовательность правильных вариантов вычеркиваем.

q2 = [«?What widgets using for positioning other widgets?»,
«-Button», «-Radiobutton», «+Frame», «-Text», «+LabelFrame»]
1
2

Добавьте этот вопрос в форму, с последующим отображением и подсчетом общего результата.

  1. Добавьте любой вопрос с ответами, с последующим отображением и подсчетом результатов.