tkinter:如何在一个框架中使用不同框架中的按钮从 ComboBox 获取价值

tkinter: How to get value from ComboBox in one frame with button in different frame

目标是允许用户从组合框下拉列表中 select,然后单击 Select 文件按钮。该按钮将获取产品类型(组合框中的值),并将根据组合框中的选择打开正确的目录。问题是,我似乎无法获得此值,因为按钮和组合框位于不同的框架中。我觉得我在这里缺少一些基本的东西。

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()

您可以在创建产品类型变量时将其传递给 ButtonFrame,因为您在创建 InputFrame 之后创建了 ButtonFrame。这是代码,相应地标记了更改和添加的行:

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初始化时才创建。在上面的行中,您引用了 class 本身,而不是 class 的 实例 ,因此它没有被初始化。因此,未定义在 InputFrame.__init__() 中创建的任何内容,因为未调用 __init__()