首页 > 解决方案 > 如何在 Python tkinter 中使问卷可滚动?

问题描述

我是 Python 新手,一直在做一个学校项目。我们的想法是参加酒精使用障碍识别测试 (AUDIT),让用户知道他是否应该寻求专业帮助(如果他的分数超过 14 分)。我今天卡住了。我正在使用 tkinter,以及一组带有单选框的 10 个问题。但是,我无法继续,因为屏幕上不适合这些问题,而且看在上帝的份上,我无法使其可滚动。我已经尝试了我能找到的所有东西,设置课程,尝试使用框架或画布等。问题如下所示:

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

标签: pythontkinterscrollbar

解决方案


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

我也可以给你一些建议:
1) 最好使用 OOP 作为 GUI。对于小型应用程序,这可能不是问题,但如果您的应用程序更复杂和更大,那么使用 OOP 代码会比使用程序代码更容易。
2)您是否注意到您的代码有很多相似的部分?请记住:几乎在所有情况下,都不需要手动创建很多类似的变量(这也称为DRY 原则(不要重复自己)。您可以使用循环自动生成所有内容。有时您需要使用enumerate来自的函数Python内置。如果你不会使用DRY原则,你将花费更多的时间进行开发
。3)最好避免通过导入另一个模块来覆盖已经导入的东西。在您的代码中,

from tkinter import *
from tkinter.ttk import *

这两个模块都包含Button, Entry,ScrollbarRadiobutton。所以你可能会把所有东西都搞混了。最好这样做:

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

推荐阅读