【发布时间】:2020-06-17 19:39:21
【问题描述】:
我正在尝试编写一个具有三个框架的 tkinter 应用程序 - 一个顶部框架,用户在其中输入一些文本,一个动态构造的中间部分,其中对文本进行一些预分析,以及一个底部框架,其中一次用户在中间部分选择了他们想要的选项,将产生输出。
问题在于,根据输入,可能会显示大约 10-20 行(最坏的情况下是 30 行),而在小型监视器上,输出会从屏幕上消失。
我希望无论屏幕如何调整大小,顶部(输入)和底部(输出)框架都可见,并且中间部分滚动(如果需要)并且仍然允许用户选择他们的选择。
我很困惑如何在调整屏幕大小时调整中间部分的大小,如果需要显示滚动条,并且仍然允许访问所有内容。
我在这里创建了一个缩减版(为简单起见,我删除了处理方法,而是在一个类似于实际中间部分的循环中创建了一些假输出)。
请忽略可怕的配色方案 - 我只是想了解哪个框架去了哪里(我会尽快删除颜色!)
感谢您的任何建议...
import tkinter as tk
from tkinter import scrolledtext
class MyApp(tk.Tk):
def __init__(self, title="Sample App", *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title(title)
self.configure(background="Gray")
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
# Create the overall frame:
master_frame = tk.Frame(self, bg="Light Blue", bd=3, relief=tk.RIDGE)
master_frame.grid(sticky=tk.NSEW)
master_frame.rowconfigure([0, 2], minsize=90) # Set min size for top and bottom
master_frame.rowconfigure(1, weight=1) # Row 1 should adjust to window size
master_frame.columnconfigure(0, weight=1) # Column 0 should adjust to window size
# Create the frame to hold the input field and action button:
input_frame = tk.LabelFrame(master_frame, text="Input Section", bg="Green", bd=2, relief=tk.GROOVE)
input_frame.grid(row=0, column=0, padx = 5, pady = 5, sticky=tk.NSEW)
input_frame.columnconfigure(0, weight=1)
input_frame.rowconfigure(0, weight=1)
# Create a frame for the middle (processing) section.
middle_frame = tk.LabelFrame(master_frame, text = "Processing Section")
middle_frame.grid(row=1, column=0, padx=5, pady=5, sticky=tk.NSEW)
# Create the frame to hold the output:
output_frame = tk.LabelFrame(master_frame, text="Output Section", bg="Blue", bd=2, relief=tk.GROOVE)
output_frame.grid(row=2, column=0, columnspan=3, padx=5, pady=5, sticky=tk.NSEW)
output_frame.columnconfigure(0, weight=1)
output_frame.rowconfigure(0, weight=1)
# Add a canvas in the middle frame.
self.canvas = tk.Canvas(middle_frame, bg="Yellow")
self.canvas.grid(row=0, column=0)
# Create a vertical scrollbar linked to the canvas.
vsbar = tk.Scrollbar(middle_frame, orient=tk.VERTICAL, command=self.canvas.yview)
vsbar.grid(row=0, column=1, sticky=tk.NS)
self.canvas.configure(yscrollcommand=vsbar.set)
# Content for the input frame, (one label, one input box and one button).
tk.Label(input_frame,
text="Please type, or paste, the text to be analysed into this box:").grid(row=0, columnspan = 3, sticky=tk.NSEW)
self.input_box = scrolledtext.ScrolledText(input_frame, height=5, wrap=tk.WORD)
self.input_box.columnconfigure(0, weight=1)
self.input_box.grid(row=1, column=0, columnspan = 3, sticky=tk.NSEW)
tk.Button(input_frame,
text="Do it!",
command=self.draw_choices).grid(row=2, column=2, sticky=tk.E)
# Content for the output frame, (one text box only).
self.output_box = scrolledtext.ScrolledText(output_frame, width=40, height=5, wrap=tk.WORD)
self.output_box.grid(row=0, column=0, columnspan=3, sticky=tk.NSEW)
def draw_choices(self):
""" This method will dynamically create the content for the middle frame"""
self.option = tk.IntVar() # Variable used to hold user's choice
self.get_input_text()
for i in range(30):
tk.Radiobutton(self.canvas,
text=f"Option {i + 1}: ", variable=self.option,
value=i,
command=self.do_analysis
).grid(row=i, column=0, sticky=tk.W)
tk.Label(self.canvas,
text=f"If you pick Option {i + 1}, the output will look like this: {self.shortText}.",
anchor=tk.W
).grid(row=i, column=1, sticky=tk.W)
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def get_input_text(self):
""" Will get the text from the input box and also create a shortened version to display on one line"""
screenWidth = 78
self.input_text = self.input_box.get(0.0, tk.END)
if len(self.input_text) > screenWidth:
self.shortText = self.input_text[:screenWidth]
else:
self.shortText = self.input_text[:]
self.shortText = self.shortText.replace('\n', ' ') # strip out carriage returns just in case
def do_analysis(self):
"""This will ultimately process and display the results"""
option = self.option.get() # Get option from radio button press
output_txt = f"You picked option {option + 1} and here is the output: \n{self.input_text}"
self.output_box.delete(0.0, tk.END)
self.output_box.insert(0.0, output_txt)
if __name__ == "__main__":
app = MyApp("My Simple Text Analysis Program")
app.mainloop()
【问题讨论】:
-
是的 - 谢谢!我认为这两个链接中的第二个正是我正在寻找的(我一定在我所有的谷歌搜索中都错过了它)。但是,Bryan Oakley 出色的解决方案混合了包和网格几何,并且不会(按原样)在我的代码上工作,因为我的根窗口顶部有一个主框架。然而,无论如何我都会重构我的代码并摆脱主框架(因为我意识到我不再需要那个设置)并遵循 Bryan 的结构。我需要一段时间才能完成,但我会回来报告...谢谢!
-
仍在苦苦挣扎...关注 @ bryan Oakley 的优秀帖子:使用 this answer 重试,滚动部分 独立于要滚动的小部件。也去掉你的例子并展示你的尝试。
-
@stovfl 这真是太棒了!非常感谢!这正是我一直在尝试(并且失败)实现的目标。我还处于与 tkinter 的学习之旅的早期阶段,这对我帮助很大。再次感谢您。
标签: python-3.x tkinter canvas tkinter-canvas frames