如何在Python tkinter中使问卷可滚动?

2024-04-29 08:48:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Python新手,一直在做一个学校项目。其想法是参加酒精使用障碍鉴定测试(审计),让用户知道他是否应该寻求专业帮助(如果他得分14+)。 我今天卡住了。我用的是tkinter,还有一套10个问题的RadioBox。然而,我不能继续,因为这些问题不适合在屏幕上显示,而且为了上帝的爱,我不能让它滚动。我尝试了我能找到的一切,设置一个类,尝试使用框架或画布,等等。 问题如下:

"""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。我知道这可能不是最有效的方法,但这是我写的第一个代码。 如何添加滚动条以显示所有问题? 谢谢,祝你今天愉快


Tags: textfromimportapptkintermodepacktk
1条回答
网友
1楼 · 发布于 2024-04-29 08:48:29

您需要:
1) 使用Canvas.create_window(x, y, window=widget)方法
2) 将canvas scrollregion属性设置为Canvas.bbox("all")(但在必须更新窗口之前,否则将得到错误的结果)
3) 以正确的方式将滚动条连接到画布(请参见下面的代码)

我也可以给你一些建议:
1) 最好在GUI中使用OOP。对于小应用程序,这可能不是问题,但如果你的应用程序更复杂、更大,那么使用OOP代码比使用过程代码容易得多。
2) 你注意到你的代码有很多相似的部分吗?记住:在几乎所有情况下,都不需要手动创建很多相似的变量(也称为DRY principle (don't repeat yourself)。你可以使用循环自动生成所有内容。有时你需要使用^{}如果你不使用DRY原则,你将花费更多的时间进行开发。
3) 最好通过导入另一个模块来避免覆盖已导入的内容。在代码中,您可以:

from tkinter import *
from tkinter.ttk import *

这两个模块都包含ButtonEntryScrollbarRadiobutton等。因此,您可能会把所有内容都搞混。最好这样做:

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)您可以手动调整画布中所有内容的大小,并拒绝调整窗口的大小(通过宽度和/或高度)

以下是重写的代码:

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

相关问题 更多 >