Как сделать опросник прокручиваемым в Python ткинтер? - PullRequest
2 голосов
/ 24 апреля 2020

Я новичок в Python и работаю над школьным проектом. Идея состоит в том, чтобы пройти тест на выявление расстройств, связанных с употреблением алкоголя (AUDIT), и сообщить пользователю, должен ли он обратиться за профессиональной помощью (если он набрал 14+). Я застрял сегодня. Я использую tkinter и набор из 10 вопросов с радиобоксами. Тем не менее, я не могу продолжить, так как вопросы не помещаются на экране, и ради любви к Богу я не могу сделать это прокручиваемым. Я перепробовал все, что смог найти, установив класс, пытаясь работать с рамкой или холстом и т. Д. c. Вопросы выглядят так:

"""imports"""
import tkinter as tk
app = tk.Tk()
app.title("AUDIT")
from tkinter import *
from tkinter import ttk

canvas = tk.Canvas(app)
scroll_y = tk.Scrollbar(app, orient="vertical", command=canvas.yview)

frame = tk.Frame(canvas)
# group of widgets
"""question 1"""
o1 = Text(app, height = 1, width =100)
o1.insert(INSERT, "Jak často pijete alkoholické nápoje (včetně piva)")
o1.insert(END, "?")
o1.pack()
OTAZKA1 = [
        ("Nikdy", "0"),
        ("Jednou za měsíc či méně často", "1"),
        ("2-4x za měsíc", "2"),
        ("2-3x týdně", "3"),
        ("4x nebo vícekrát týdně", "4"),
        ]
o1 = StringVar()
o1.set("0") #initialize

for text, mode in OTAZKA1:
    a = Radiobutton(app, text = text, variable = o1, value = mode)
    a.pack(anchor=W)

"""question 2"""
o2 = Text(app, height = 2, width =100)
o2.insert(INSERT, "Kolik standardních sklenic alkoholického nápoje vypijete během typického dne, kdy pijete")
o2.insert(END, "?")
o2.pack()
OTAZKA2 = [
        ("Nejvýše 1", "0"),
        ("1,5 až 2", "1"),
        ("2,5 až 3", "2"),
        ("3,5 až 5", "3"),
        ("5 a více", "4"),
        ]
o2 = StringVar()
o2.set("0") #initialize

for text, mode in OTAZKA2:
    b = Radiobutton(app, text = text, variable = o2, value = mode)
    b.pack(anchor=W)

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

1 Ответ

0 голосов
/ 26 апреля 2020

Вам необходимо:
1) использовать Canvas.create_window(x, y, window=widget) метод
2) установить для атрибута canvas scrollregion значение Canvas.bbox("all") (но перед обновлением окна, в противном случае вы получите неправильный результат "
3) правильно прикрепите полосу прокрутки к холсту (см. Код ниже)

Я также могу дать вам несколько советов:
1) Лучше использовать OOP для GUI. Для небольших приложений это может не быть проблемой, но если ваше приложение более сложное и большое, вам будет гораздо проще работать с кодом OOP, чем с процедурным.
2 ) Вы заметили, что в вашем коде много похожих частей? Помните: почти во всех случаях нет необходимости создавать множество похожих переменных вручную (это также называется принципом DRY (не повторяйте себя) ) . Вы можете генерировать все автоматически, используя циклы. Иногда вам нужно использовать функцию enumerate из встроенных Python. Если вы не будете использовать принцип DRY, вы потратит гораздо больше времени на разработку.
3) Это б etter, чтобы избежать переопределения уже импортированных вещей, импортируя другой модуль. В вашем коде вы делаете:

from tkinter import *
from tkinter.ttk import *

Оба из этих модулей содержат Button, Entry, Scrollbar, Radiobutton et c. Таким образом, вы можете все перепутать. Лучше сделать так:

from tkinter import *
from tkinter.ttk import only, what, you, need

или даже лучше:

import tkinter as tk
import tkinter.ttk as ttk  # or: from tkinter import ttk

4) Вы можете настроить размер всего в Canvas вручную и запретить изменение размера окна (либо по ширине и / или высоте).

Вот переписанный код:

from tkinter import *
from tkinter import messagebox
from tkinter.ttk import Button, Scrollbar, Radiobutton


# Create questions as a list of dictionaries
# The GUI will be generated automatically
questions = [
    {"question": "Jak často pijete alkoholické nápoje (včetně piva)?",
     "answers": ("Nikdy", "Jednou za měsíc či méně často",
                 "2-4x za měsíc", "2-3x týdně",
                 "4x nebo vícekrát týdně")},
    {"question": "Kolik standardních sklenic alkoholického nápoje vypijete během typického dne, kdy pijete?",
    "answers": ("Nejvýše 1", "1,5 až 2", "2,5 až 3", "3,5 až 5", "5 a více")},
    ]

class App(Tk):
    def __init__(self):
        super().__init__()

        self.title("AUDIT")  # set the window title
        self.resizable(False, True)  # make window unresizable by width

        canv_frame = Frame(self)  # create the canvas frame
        # create the Canvas widget
        # highlightthickness=0 removes the black border when the canvas gets focus
        self.canv = Canvas(canv_frame, highlightthickness=0, width=420)
        # add scrolling when mouse wheel is rotated
        self.canv.bind_all("<MouseWheel>",
                           lambda event: self.canv.yview_scroll(-1 * (event.delta // 120), "units"))
        self.canv.pack(fill=BOTH, expand=YES, side=LEFT)  # pack the Canvas

        # Create a scrollbar
        # command=self.canv.yview tells the scrollbar to change the canvas yview
        # and canvas's yscrollcommand=self.yscrollbar.set tells the canvas to update
        # the scrollbar if canvas's yview is changed without it.
        self.yscrollbar = Scrollbar(canv_frame, command=self.canv.yview)
        self.canv["yscrollcommand"] = self.yscrollbar.set
        self.yscrollbar.pack(fill=Y, side=LEFT)  # pack the Scrollbar

        for question_id, question in enumerate(questions, 1):
            qaframe = Frame(self.canv)  # create the question-answers (QA) frame
            text = Text(qaframe, width=50, height=3)  # create the Text widget for question
            text.insert(END, question["question"])  # insert the question text there
            text.pack(fill=X)  # pack the text widget
            aframe = Frame(qaframe)  # create the answers frame
            # Create the question variable and add it to the variables list
            question_var = IntVar(self)
            question["variable"] = question_var
            # create the radiobuttons 
            for answer_id, answer in enumerate(question["answers"]):
                Radiobutton(aframe, variable=question_var, text=answer, value=answer_id).pack()
            aframe.pack(fill=Y)  # pack the answers frame
            self.canv.create_window(210, question_id * 175, window=qaframe)  # insert the QA frame into the Canvas
        canv_frame.pack(fill=BOTH, expand=YES)  # pack the canvas frame
        Button(self, text="Submit", command=self.submit).pack(fill=X)  # create the "Submit" button
        self.update()  # update everything to get the right scrollregion.
        self.canv.configure(scrollregion=self.canv.bbox("all"))  # set the canvas scrollregion

    def submit(self):
        sum_ = 0  # initially, the sum_ equals 0
        for question in questions:
            sum_ += question["variable"].get()  # and then, we add all the questions answers
        messagebox.showinfo("Result", "Your result is %s!" % sum_)  # show the result in an info messagebox

if __name__ == "__main__":  # if the App is not imported from another module,
    App().mainloop()  # create it and start the mainloop
...