TKInter-对帧和滚动感到困惑

时间:2020-06-17 19:39:21

标签: python-3.x tkinter canvas tkinter-canvas frames

我正在尝试编写一个具有三个框架的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()

1 个答案:

答案 0 :(得分:0)

我了解到您不能在同一容器中混合使用网格和打包几何图形,并且必须将滚动条附加到画布上,因此要放置在画布上的对象必须在另一个容器中,因此尝试按照Bryan的示例,我创建了所需的最低版本-窗口分为三部分-顶部,中间和底部。顶部和底部将包含一个简单的文本字段,中间部分将包含动态内容,并且必须能够按要求滚动。


enter image description here

进口

import tkinter as tk

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("A simple GUI")

        # Top frame
        self.top_frame = tk.Frame(self, bg="LIGHT GREEN")
        self.top_frame.pack(fill=tk.X)
        tk.Label(self.top_frame, bg=self.top_frame.cget('bg'),
                 text="This is a label on the top frame")\
            .grid(row=0, columnspan=3, sticky=tk.NSEW)

        # Middle Frame
        # Import from https://stackoverflow.com/a/62446457/7414759
        # and don't change anything
        sbf = ScrollbarFrame(self, bg="LIGHT BLUE")
        sbf.pack(fill=tk.X, expand=True)

        # self.middle_frame = tk.Frame(self, bg="LIGHT BLUE")
        self.middle_frame = sbf.scrolled_frame

        # Force scrolling by adding multiple Label
        for _ in range(25):
            tk.Label(self.middle_frame, bg=self.middle_frame.cget('bg'),
                     text="This is a label on the dynamic (middle) section")\
                .grid()

        # Bottom Frame
        self.bottom_frame = tk.Frame(self, bg="WHITE")
        self.bottom_frame.pack(fill=tk.X)
        tk.Label(self.bottom_frame, bg=self.bottom_frame.cget('bg'),
                 text="This is a label on the bottom section")\
            .grid(row=0, columnspan=3, sticky=tk.NSEW)


if __name__ == '__main__':
    App().mainloop()
相关问题