- Вопрос или проблема
- Ответ или решение
- Использование PyQt для создания сложных GUI
- Ресурсы для изучения PyQt
- Углубление в Tkinter
- 1. Собственные классы для виджетов
- 2. Управление размещением виджетов
- 3. Управление жизненным циклом виджетов
- 4. Хранение вопросов и проверки ответов
- 5. Привязка событий
- Программные рекомендации
- Заключение
Вопрос или проблема
Мне сложно создать графический интерфейс пользователя (GUI) на Python (используя Tkinter), так как, насколько я знаю, в нём нет таких вещей, как переключатели. И я не нашёл хороших ресурсов по этой теме. (TKdocs довольно запутанный и трудно понимаемый) Я прочитал книгу “Современный Tkinter”, и из неё я узнал довольно много и могу использовать основные концепции Tkinter. Но некоторые вещи устарели. Многие найденные мною материалы по Python, на самом деле, такие. Например, “Учебник Python” и “Библия Python” не охватывают Match/Case. Я узнал о них только после того, как спросил здесь. Я также использую видео от Bro Codes по Python, в котором кажется есть информация о match case.
Я также не думаю, что tkinter может создавать более сложные виджеты. (по крайней мере, я не видел никаких указаний на это, укажите мне в этом направлении, если знаете хорошие ресурсы, это не так просто найти и sift через это)
Я слышал, что PyQt может это сделать. Но я тоже не знаю хороших ресурсов по этому поводу.
Я пытался создать программу викторины, но хотя я выяснил, как редактировать radiobuttonы с использованием textvariables, я не могу проверить, какую кнопку я выбрал. И затем решить, правильный ли это ответ. “Современный Tkinter” не углублялся в детали виджетов. В целом, программирование GUI на Python вызывает разочарование. Но это весело.
Моя проблема в том, что я не хочу создавать самый простой графический интерфейс. Я хочу делать с ним интересные вещи. Например, иметь виджеты карточек или хотя бы переключатель. В моей программе викторины есть кнопки “Далее” и “Назад”, которые переключаются между вопросами. Чем я горжусь. Это супер просто. Я не смог понять, как уничтожать виджеты. Поэтому мне пришлось сделать несколько обходных путей. И я получил общее представление о match/case.
В дополнение к комбобоксу, который показывает, на каком вопросе вы находитесь. (я ещё не выяснил, как его заставить менять вопрос) Я хотел бы хранить вопросы/ответы в другом файле (чтобы я мог переключаться между наборами вопросов и ответов через главное меню). Но “Современный Tkinter” не описал, как переключить страницу на другую. Наилучшее, что я могу придумать, это либо поэкспериментировать с виджетами notebook, либо попробовать заставить работать меню (но это также не слишком хорошо объяснено, и почему-то меню не работают, когда я пытаюсь их использовать, просто открывается отдельное пустое окно вместо панели с опциями.
Я хотел бы иметь возможность создать работающий GUI с довольно сложной структурой. Но у меня пока нет опыта и знаний, чтобы разобраться с этим самостоятельно, поэтому мне действительно нужны указания и советы по моему коду и где продолжать искать ответы на вопросы вроде этого.
Вот код:
from tkinter import *
from tkinter import ttk
import random
from time import *
root = Tk()
root.title("[Введите заголовок]")
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
frame = Frame(root)
frame.grid(column=0, row=0)
s = ttk.Style()
s.configure('a.TFrame', background=None, borderwidth=1,
relief=None)
quest = 0
class Questions:
a = """Каков результат 2 + 2? """
b = """Каков результат 3 умножить на 15? """
c = """Каков результат 21 разделить на 3?"""
d = """Каков результат 2 - 12 """
def assignprompt():
global quest
match quest:
case 1:
prompt.set(Questions.a)
root.update()
case 2:
prompt.set(Questions.b)
root.update()
case 3:
prompt.set(Questions.c)
root.update()
case 4:
prompt.set(Questions.d)
root.update()
def assignchoice():
global quest
match quest:
case 1:
num.set(1)
A.set("6")
B.set("43")
C.set("3")
D.set("4")
case 2:
num.set(2)
A.set("56")
B.set("45")
C.set("72")
D.set("32")
case 3:
num.set(3)
A.set("7")
B.set("64")
C.set("6")
D.set("12")
case 4:
num.set(4)
A.set("10")
B.set("3")
C.set("-10")
D.set("-2")
case 5:
num.set(5)
A.set("1")
B.set("4")
C.set("5")
D.set("9")
case 6:
num.set(6)
A.set("-12")
B.set("43")
C.set("-1")
D.set("2")
case 7:
num.set(7)
A.set("10")
B.set("6")
C.set("69")
D.set("12")
case 8:
num.set(8)
A.set("10")
B.set("3")
C.set("303")
D.set("2")
case 9:
num.set(9)
A.set("57")
B.set("64")
C.set("23")
D.set("14")
case 10:
num.set(10)
A.set("150")
B.set("35")
C.set("150")
D.set("-25")
A = StringVar()
B = StringVar()
C = StringVar()
D = StringVar()
ttk.Radiobutton(frame, textvariable=A, value=1).grid(column=0, row=1, sticky=W)
ttk.Radiobutton(frame,textvariable=B, value=2).grid(column=0, row=2, sticky=W)
ttk.Radiobutton(frame, textvariable=C, value=3).grid(column=0, row=3, sticky=W)
ttk.Radiobutton(frame, textvariable=D, value=4).grid(column=0, row=4, sticky=W)
def assign():
global quest
if quest > 10:
quest = 0
elif quest < 1:
quest = 10
assignprompt()
assignchoice()
def previous():
global quest
quest -= 1
assign()
def nextq():
global quest
quest += 1
assign()
num = IntVar()
prompt = StringVar()
check = StringVar()
Label(frame,
textvariable=prompt).grid(column=4, row=0, sticky=E)
Label(frame,
textvariable=check).grid(column=4, row=0, sticky=E)
Button(frame, text="Назад",
command=previous).grid(column=1, row=0, sticky=W)
Button(frame, text="Далее",
command=nextq).grid(column=3, row=0, sticky=W)
ttk.Combobox(frame, height=2, width=3, textvariable=num,
values=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
state="readonly").grid(column=0, row=0)
root.mainloop()
Это в процессе разработки. Я думаю, что использование переменной quest для переключения вопросов, вероятно, неэффективно и проблематично. Но я не понял, как уничтожать radiobuttons при переключении вопросов. (Я действительно смог заставить переключаться вопросы и создавать новые виджеты, я просто не знал, как уничтожать старые виджеты. Поэтому изменение текущих виджетов — это то, с чем я столкнулся).
Я также пытался сделать так, чтобы радиокнопки выбирались из диапазона случайных чисел, но я не знал, как избежать повторений и удостовериться, что хотя бы один из них является правильным ответом. Поэтому я просто ввёл заданные ответы вручную. И также мне нужно было убедиться, что ответы достаточно похожи, чтобы не было очевидно, какой из них правильный, поэтому я попытался выбрать из списка. Затем снова столкнулся с проблемой повторов и необходимости одной правильной ответы.
Я бы также хотел иметь возможность случайным образом назначать вопросы из пула. (Может быть, у меня будет словарь с вопросом в качестве ключа и ответом в качестве значения? Или может быть нет, потому что тогда я не смог бы использовать сам вопрос, да?)
Другие проблемы связаны с размещением виджетов. Кнопка "Далее" не останется на месте, если метка в той же колонке изменит ширину, возможно, я мог бы использовать place() для этого. Я думаю, что это недостаток менеджера grid(), если нет встроенного исправления.
Я также хотел сделать так, чтобы я мог привязать комбобокс к функции. (в основном, если значение комбобокса изменяется, тогда вопрос меняется), но я не смог понять, как привязывать виджеты.
У меня была проблема с проверкой, какая радиокнопка была выбрана. (например, я не мог просто вызвать get() на переменной и проверить, какое значение оно возвращает. Затем сказать: "О, они выбрали вариант 1, вариант 1 - это 2, и вопрос 2 - '2 + 2', Неверно".
Вот с какими проблемами я сталкиваюсь, помимо того, что не могу создать более сложные виджеты.
Ответ или решение
Создание более сложных графических интерфейсов (GUI) и виджетов с использованием Python - задача, требующая глубоких знаний и понимания библиотек, таких как Tkinter или PyQt. Вы уже сделали хороший шаг вперед, изучив базовые концепции Tkinter, но столкнулись с типичными ограничениями этой библиотеки. В этом ответе мы обсудим дополнительные подходы к разработке сложных GUI, включая использование более мощных инструментов, таких как PyQt, и методы, которые вы можете применять при работе с Tkinter.
Использование PyQt для создания сложных GUI
Если вы хотите создать более сложные пользовательские интерфейсы, я рекомендую рассмотреть возможность использования библиотеки PyQt или PySide, которые предоставляют больше возможностей для работы с современными интерфейсами и виджетами. PyQt имеет широкий спектр встроенных виджетов, таких как переключатели (switches), вкладки и сложные диалоговые окна.
Ресурсы для изучения PyQt
- Документация PyQt - Официальная документация является отличным ресурсом для изучения различных компонентов и механизмов.
- Книга "Rapid GUI Programming with Python and Qt" - Эта книга помогает понять, как быстро разрабатывать приложения с использованием PyQt.
- Онлайн-курсы - Платформы, такие как Udemy или Coursera, предлагают курсы по PyQt.
Углубление в Tkinter
Если вы решите остаться с Tkinter, то вам следует использовать следующее:
1. Собственные классы для виджетов
Вы можете создать собственные виджеты, унаследовав классы Tkinter. Это позволит вам расширять функциональность базовых виджетов:
class CustomRadiobutton(ttk.Radiobutton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
2. Управление размещением виджетов
Используйте метод pack()
или place()
, если столкнулись с проблемами с grid()
. Например, в некоторых случаях pack()
может обеспечить более предсказуемое размещение.
3. Управление жизненным циклом виджетов
Чтобы удалить старые виджеты перед созданием новых, используйте метод destroy()
:
for widget in frame.winfo_children():
widget.destroy()
4. Хранение вопросов и проверки ответов
Вместо статического определения вопросов в коде, используйте словари или JSON-файлы для хранения вопросов и ответов. Это позволяет легко добавлять новые вопросы или изменять существующие:
questions = {
"What is 2 + 2?": ["3", "4", "5", "6"],
"What is the capital of France?": ["Berlin", "Madrid", "Paris", "Rome"]
}
Используйте метод random.choice()
, чтобы случайным образом выбирать вопросы.
5. Привязка событий
Чтобы связать изменение значения в Combobox
с определенной функцией, используйте метод bind()
:
def on_combobox_change(event):
selected_question = combobox.get()
# обновите вопрос в интерфейсе
combobox.bind("<<ComboboxSelected>>", on_combobox_change)
Программные рекомендации
Разработайте свой вопрос-ответный процесс, используя структурированный подход:
- Создайте класс, который управляет состоянием вопросов и ответов.
- Реализуйте логику избегания повторяющихся вопросов, храня answered questions в списке.
- Убедитесь, что интерфейс адаптивен, чтобы избежать проблем с размещением при изменении текста меток и кнопок.
Заключение
Создание сложных GUI требует времени и терпения, но, исследуя более мощные библиотеки, такие как PyQt, или углубляя свои знания в Tkinter, вы сможете создавать адаптивные и функциональные интерфейсы. Применяя методы управления виджетами и структурированное хранение данных, вы сможете справиться со всеми упомянутыми вами задачами и создать действительно уникальное приложение.
Если у вас есть дополнительные вопросы или вам нужна помощь по конкретным аспектам вашего проекта, пожалуйста, дайте знать!