python - 如何在 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。我知道这可能不是最有效的方法,但这是我编写的第一个代码。如何添加滚动条以使所有问题可见?谢谢你,祝你有美好的一天。
解决方案
您需要:
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
,Scrollbar
等Radiobutton
。所以你可能会把所有东西都搞混了。最好这样做:
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