tkinter: Как получить значение из комбинации в одном кадре с помощью кнопки в другом кадре

#python #tkinter #combobox

Вопрос:

Цель состоит в том, чтобы позволить пользователю выбрать из выпадающего списка выпадающих окон, а затем нажать кнопку «Выбрать файлы». Кнопка получит тип продукта (значение из списка) и откроет правильный каталог, основанный на том, что выбрано в списке. Проблема в том, что я, похоже, не могу получить это значение, так как кнопка и выпадающий список находятся в разных кадрах. Я чувствую, что упускаю здесь что-то основное.

 import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd


def select_files(prod_type):
    path = f"\\10.10.3.7\Production\Test_Folder\{prod_type}"
    filetypes = (
        ('PDF Files', '*.pdf'),
    )

    filenames = fd.askopenfilenames(
        title='Open files',
        initialdir=path,
        filetypes=filetypes)

    for file in filenames:
        print(file)


class InputFrame(ttk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        # setup the grid layout manager
        self.columnconfigure(0, weight=1)
        self.columnconfigure(0, weight=3)
        self.__create_widgets()

    def __create_widgets(self):
        # Product
        ttk.Label(self, text='Product:').grid(column=0, row=0, sticky=tk.W)
        self.product_type = tk.StringVar()
        self.product_combo = ttk.Combobox(self, width=30, textvariable=self.product_type)
        self.product_combo['values'] = ('Notepad', 'Flat Notecard', 'Folded Notecard', 'Journal')
        self.product_combo.set('Notepad')
        self.product_combo['state'] = 'readonly'
        self.product_combo.grid(column=1, row=0, sticky=tk.W)

        # Algorithm:
        ttk.Label(self, text='Algorithm:').grid(column=0, row=1, sticky=tk.W)
        algo_var = tk.StringVar()
        algo_combo = ttk.Combobox(self, width=30)
        algo_combo['values'] = ('panel', 'fuzzy')
        algo_combo.set('panel')
        algo_combo.grid(column=1, row=1, sticky=tk.W)

        # Orientation:
        ttk.Label(self, text='Orientation:').grid(column=0, row=2, sticky=tk.W)
        orientation_var = tk.StringVar()
        orientation_combo = ttk.Combobox(self, width=30, textvariable=orientation_var)
        orientation_combo['values'] = ('auto', 'portrait', 'landscape')
        orientation_combo.set('auto')
        orientation_combo.grid(column=1, row=2, sticky=tk.W)

        # Margin:
        ttk.Label(self, text='Margin:').grid(column=0, row=3, sticky=tk.W)
        margin = ttk.Entry(self, width=30)
        margin.grid(column=1, row=3, sticky=tk.W)

        # Gap:
        ttk.Label(self, text='Gap:').grid(column=0, row=4, sticky=tk.W)
        gap = ttk.Entry(self, width=30)
        gap.grid(column=1, row=4, sticky=tk.W)

        # Repeat:
        ttk.Label(self, text='Repeat:').grid(column=0, row=5, sticky=tk.W)
        repeat_number = tk.StringVar()
        repeat = ttk.Spinbox(self, from_=1, to=10, width=30, textvariable=repeat_number)
        repeat.set(1)
        repeat.grid(column=1, row=5, sticky=tk.W)

        for widget in self.winfo_children():
            widget.grid(padx=0, pady=5)


class ButtonFrame(ttk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        # setup the grid layout manager
        self.columnconfigure(0, weight=1)

        self.__create_widgets()

    def __create_widgets(self):
        ttk.Button(self, text='Select Files', command=self.on_go_pressed).grid(column=0, row=0)
        ttk.Button(self, text='Generate PDF').grid(column=0, row=1)

        for widget in self.winfo_children():
            widget.grid(padx=0, pady=3)

    def on_go_pressed(self):
        select_files(InputFrame.product_type.get())


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("PDF n-up")
        self.eval('tk::PlaceWindow . center')
        self.geometry('400x200')
        self.resizable(0, 0)
        self.attributes('-toolwindow', True)

        # layout on the root window
        self.columnconfigure(0, weight=4)
        self.columnconfigure(1, weight=1)

        self.__create_widgets()

    def __create_widgets(self):
        # create the input frame
        input_frame = InputFrame(self)
        input_frame.grid(column=0, row=0)

        # create the button frame
        button_frame = ButtonFrame(self)
        button_frame.grid(column=1, row=0)


if __name__ == '__main__':
    app = App()
    app.mainloop()
 

Ответ №1:

Вы можете передать переменную типа продукта ButtonFrame при ее создании, так как вы создаете ее ButtonFrame после создания InputFrame . Вот код, с измененными и добавленными строками, отмеченными соответствующим образом:

 import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd


def select_files(prod_type):
    path = f"/home/sam/Pictures/Test/{prod_type}"
    filetypes = (
        ('PDF Files', '*.pdf'),
    )

    filenames = fd.askopenfilenames(
        title='Open files',
        initialdir=path,
        filetypes=filetypes)

    for file in filenames:
        print(file)


class InputFrame(ttk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        # setup the grid layout manager
        self.columnconfigure(0, weight=1)
        self.columnconfigure(0, weight=3)
        self.__create_widgets()

    def __create_widgets(self):
        # Product
        ttk.Label(self, text='Product:').grid(column=0, row=0, sticky=tk.W)
        self.product_type = tk.StringVar()
        self.product_combo = ttk.Combobox(self, width=30, textvariable=self.product_type)
        self.product_combo['values'] = ('Notepad', 'Flat Notecard', 'Folded Notecard', 'Journal')
        self.product_combo.set('Notepad')
        self.product_combo['state'] = 'readonly'
        self.product_combo.grid(column=1, row=0, sticky=tk.W)

        # Algorithm:
        ttk.Label(self, text='Algorithm:').grid(column=0, row=1, sticky=tk.W)
        algo_var = tk.StringVar()
        algo_combo = ttk.Combobox(self, width=30)
        algo_combo['values'] = ('panel', 'fuzzy')
        algo_combo.set('panel')
        algo_combo.grid(column=1, row=1, sticky=tk.W)

        # Orientation:
        ttk.Label(self, text='Orientation:').grid(column=0, row=2, sticky=tk.W)
        orientation_var = tk.StringVar()
        orientation_combo = ttk.Combobox(self, width=30, textvariable=orientation_var)
        orientation_combo['values'] = ('auto', 'portrait', 'landscape')
        orientation_combo.set('auto')
        orientation_combo.grid(column=1, row=2, sticky=tk.W)

        # Margin:
        ttk.Label(self, text='Margin:').grid(column=0, row=3, sticky=tk.W)
        margin = ttk.Entry(self, width=30)
        margin.grid(column=1, row=3, sticky=tk.W)

        # Gap:
        ttk.Label(self, text='Gap:').grid(column=0, row=4, sticky=tk.W)
        gap = ttk.Entry(self, width=30)
        gap.grid(column=1, row=4, sticky=tk.W)

        # Repeat:
        ttk.Label(self, text='Repeat:').grid(column=0, row=5, sticky=tk.W)
        repeat_number = tk.StringVar()
        repeat = ttk.Spinbox(self, from_=1, to=10, width=30, textvariable=repeat_number)
        repeat.set(1)
        repeat.grid(column=1, row=5, sticky=tk.W)

        for widget in self.winfo_children():
            widget.grid(padx=0, pady=5)


class ButtonFrame(ttk.Frame):
    def __init__(self, parent, product_type): ### EDITED THIS LINE
        super().__init__(parent)
        # setup the grid layout manager
        self.columnconfigure(0, weight=1)

        self.product_type = product_type ### ADDED THIS LINE

        self.__create_widgets()

    def __create_widgets(self):
        ttk.Button(self, text='Select Files', command=self.on_go_pressed).grid(column=0, row=0)
        ttk.Button(self, text='Generate PDF').grid(column=0, row=1)

        for widget in self.winfo_children():
            widget.grid(padx=0, pady=3)

    def on_go_pressed(self):
        select_files(self.product_type.get()) ### EDITED THIS LINE


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("PDF n-up")
        self.eval('tk::PlaceWindow . center')
        self.geometry('400x200')
        self.resizable(0, 0)
        # self.attributes('-toolwindow', True)

        # layout on the root window
        self.columnconfigure(0, weight=4)
        self.columnconfigure(1, weight=1)

        self.__create_widgets()

    def __create_widgets(self):
        # create the input frame
        input_frame = InputFrame(self)
        input_frame.grid(column=0, row=0)

        # create the button frame
        button_frame = ButtonFrame(self, input_frame.product_type) ### EDITED THIS LINE
        button_frame.grid(column=1, row=0)


if __name__ == '__main__':
    app = App()
    app.mainloop()
 

Обратите внимание , как в строке button_frame = ButtonFrame(self, input_frame.product_type) я даю его input_frame.product_type в качестве аргумента, чтобы он мог получить к нему доступ в любое время, когда захочет.

Изменения ButtonFrame , необходимые для этого: я изменил __init__() метод, чтобы он мог получать другой аргумент. Затем он присваивает значение product_type аргумента переменной, чтобы она могла использовать его позже. Когда он звонит select_files() , он просто использует self.product_type .

Относительно того, почему вызов select_files(InputFrame.product_type.get()) не работает: product_type это переменная, которая создается только при InputFrame инициализации. В приведенной выше строке вы ссылаетесь на сам класс, а не на экземпляр класса, поэтому он не был инициализирован. Следовательно, все, что создано в InputFrame.__init__() , не определено, потому __init__() что не было вызвано.

Комментарии:

1. Очень признателен!!