TKInter - Запутались фреймы и скроллинг - PullRequest
0 голосов
/ 17 июня 2020

Я пытаюсь закодировать приложение tkinter с тремя фреймами - верхний фрейм, где пользователь вводит некоторый текст, динамически построенный средний раздел, в котором выполняется предварительный анализ текста, и нижний фрейм, в котором один раз пользователь выбрал, какой вариант он хочет в средней части, вывод будет произведен.

Проблема в том, что, в зависимости от ввода, может быть около 10-20 (а в худшем случае 30) отображаются линии, и на маленьком мониторе вывод исчезнет с экрана.

Я бы хотел, чтобы верхний (входной) и нижний (выходной) кадры были видны независимо от размера экрана , и чтобы средняя часть прокручивалась (при необходимости) и по-прежнему позволяла пользователю выбирать свой выбор.

Я не понимаю, как изменить размер средней части при изменении размера экрана, показать полосу прокрутки если требуется, и все же разрешить доступ ко всему контенту.

Я создал здесь урезанную версию (для простота, я удалил методы обработки и вместо этого создал какой-то поддельный вывод в al oop, который напоминает то, как будет выглядеть фактическая средняя часть).

Пожалуйста, игнорируйте ужасную цветовую схему - я просто пытался чтобы понять, какой фрейм куда пошел (я уберу цвета, как только смогу!)

Спасибо за любые предложения ...

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 голосов
/ 19 июня 2020

Я понимаю, что вы не можете смешивать сетку и геометрию упаковки в одном контейнере, и что полоса прокрутки должна быть прикреплена к холсту, а объекты, которые должны быть размещены на этом холсте, должны, следовательно, находиться в еще одном контейнере, поэтому, пытаясь Следуя примеру Брайана, я создал минимальную версию того, что хочу - окно с тремя секциями - верхней, средней и нижней. Верхняя и нижняя секции будут содержать простое текстовое поле, средняя часть будет содержать динамическое c содержимое и должна иметь возможность прокрутки по мере необходимости.


enter image description here

Импорт :

  • ScrollbarFrame
    Расширяет класс tk.Frame для поддержки прокручиваемого фрейма]
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()
...