Python TKinter 在小部件之间传递数据帧



我的Python tkinter程序有几个小部件。在 1 个小部件(例如 PyDataTest1(中创建的数据帧,其名称由用户选择,也应该在其他小部件中可用。但如果小部件有另一个类,情况似乎并非如此。我写了3个python模块:PyDataTestMain,PyDataTest1和PyDataTest2。为了保持示例简单,PyDataTest2 的代码与 PyDataTest1 的代码相同(我只用 PyDataTest2 替换了 PyDataTest1(。如果我将数据帧保存在小部件 p1 中,我可以在小部件 p3 中检索它,但不能在小部件 p2 和 p4 中检索它。我需要更改什么才能在那里使用它?

'''
    PyDataTestMain.py
'''
#%% Import libraries
import tkinter as tk
import tkinter.ttk as ttk
from PyDataTest1 import PyDataTest1
from PyDataTest2 import PyDataTest2
#%% Main class
class PyDataTestMain(ttk.Frame):
    def __init__(self, master = None):
        # Construct the Frame object.
        ttk.Frame.__init__(self, master)
        self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
        self.createWidgets()
    #%% Create widgets
    def createWidgets(self):
        # Get top window 
        self.top = self.winfo_toplevel()
        # Make it stretchable         
        self.top.rowconfigure(0, weight=1)
        self.top.columnconfigure(0, weight=1)
        # Add several PyDataTest widgets
        self.p1 = PyDataTest1(self).grid(row = 0, column = 0, sticky = tk.W, padx =5, pady=5)
        self.p2 = PyDataTest2(self).grid(row = 1, column = 0, sticky = tk.W, padx =5, pady=5)
        self.p3 = PyDataTest1(self).grid(row = 2, column = 0, sticky = tk.W, padx =5, pady=5)
        self.p4 = PyDataTest2(self).grid(row = 3, column = 0, sticky = tk.W, padx =5, pady=5)
#%% Allow the class to run stand-alone.
if __name__ == "__main__":
    PyDataTestMain().mainloop()

'''
    PyDataTest1.py
'''
#%% Import libraries
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
import pandas as pd
#%% Main class
class PyDataTest1(ttk.Frame):
    def __init__(self, master = None):
        # Construct the Frame object.
        ttk.Frame.__init__(self, master)
        self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
        self.createWidgets()
    def save(self):
        var = self.pythonVar.get()
        global glb
        glb = globals()
        glb[var] = pd.DataFrame({'AAA' : [1., 2., 3., 4.], 'BBB' : [43., 32., 21., 10.]})
        messagebox.showinfo("Info","pandas dataframe saved as " + var)
    def listVars(self):
        variables= [var for var in globals() if isinstance(eval(var), pd.core.frame.DataFrame)]
        self.comboboxDataframes['values'] = variables
    #%% Create widgets
    def createWidgets(self):
        # Get top window 
        self.top = self.winfo_toplevel()
        # Make it stretchable         
        self.top.rowconfigure(0, weight=1)
        self.top.columnconfigure(0, weight=1)
        # Allow to enter a name and save the data in the base workspace
        ttk.Label(self, text = "Variable").grid(row = 0, column = 0, sticky = tk.W, padx =5, pady=5)
        self.pythonVar = tk.StringVar()
        self.pythonVar.set('d')
        ttk.Entry(self, textvariable=self.pythonVar).grid(row = 0, column = 1, sticky = tk.W, padx =5, pady=5)
        # Save button
        ttk.Button(self, text = "Save", command=self.save).grid(row = 0, column = 2, sticky = tk.W, padx =5, pady=5)
        # Combobox showing dataframes stored
        ttk.Label(self, text = "Dataframes").grid(row = 1, column = 0, sticky = tk.W, padx =5, pady=5)
        self.comboboxDataframes = ttk.Combobox(self, postcommand=self.listVars)
        self.comboboxDataframes.grid(row = 1, column = 1, sticky = tk.W, padx =5, pady=5)    
#%% Allow the class to run stand-alone.
if __name__ == "__main__":
    PyDataTest1().mainloop()

我调整了代码并将所有内容放在一个文件中。

'''
    PyDataTestMain.py
'''
#%% Import libraries
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
import pandas as pd
#%% Main class
class PyDataTestMain(ttk.Frame):
    def __init__(self, master = None):
        # Construct the Frame object.
        ttk.Frame.__init__(self, master)
        self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
        self.createWidgets()
    #%% Create widgets
    def createWidgets(self):
        # Get top window 
        self.top = self.winfo_toplevel()
        # Make it stretchable         
        self.top.rowconfigure(0, weight=1)
        self.top.columnconfigure(0, weight=1)
        # Add several PyDataTest widgets
        self.p1 = PyDataTest1(self)
        self.p1.grid(row = 0, column = 0, sticky = tk.W, padx =5, pady=5)
        self.p2 = PyDataTest2(self)
        self.p2.grid(row = 1, column = 0, sticky = tk.W, padx =5, pady=5)
        self.p3 = PyDataTest1(self)
        self.p3.grid(row = 2, column = 0, sticky = tk.W, padx =5, pady=5)
        self.p4 = PyDataTest2(self)
        self.p4.grid(row = 3, column = 0, sticky = tk.W, padx =5, pady=5)
class PyDataTest1(ttk.Frame):
    def __init__(self, master = None):
        # Construct the Frame object.
        ttk.Frame.__init__(self, master)
        self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
        self.createWidgets()
    def save(self):
        var = self.pythonVar.get()
        #global glb
        #glb = globals()
        self.glb = {}
        self.glb[var] = pd.DataFrame({'AAA' : [1., 2., 3., 4.], 'BBB' : [43., 32., 21., 10.]})
        messagebox.showinfo("Info","pandas dataframe saved as " + var)
    def listVars(self):
        #variables= [var for var in globals() if isinstance(eval(var), pd.core.frame.DataFrame)]
        variables= [var for var in self.glb() if isinstance(eval(var), pd.core.frame.DataFrame)]
        self.comboboxDataframes['values'] = variables
    #%% Create widgets
    def createWidgets(self):
        # Get top window 
        self.top = self.winfo_toplevel()
        # Make it stretchable         
        self.top.rowconfigure(0, weight=1)
        self.top.columnconfigure(0, weight=1)
        # Allow to enter a name and save the data in the base workspace
        ttk.Label(self, text = "Variable").grid(row = 0, column = 0, sticky = tk.W, padx =5, pady=5)
        self.pythonVar = tk.StringVar()
        self.pythonVar.set('d')
        ttk.Entry(self, textvariable=self.pythonVar).grid(row = 0, column = 1, sticky = tk.W, padx =5, pady=5)
        # Save button
        ttk.Button(self, text = "Save", command=self.save).grid(row = 0, column = 2, sticky = tk.W, padx =5, pady=5)
        # Combobox showing dataframes stored
        ttk.Label(self, text = "Dataframes").grid(row = 1, column = 0, sticky = tk.W, padx =5, pady=5)
        self.comboboxDataframes = ttk.Combobox(self, postcommand=self.listVars)
        self.comboboxDataframes.grid(row = 1, column = 1, sticky = tk.W, padx =5, pady=5)    
class PyDataTest2(ttk.Frame):
    def __init__(self, master = None):
        # Construct the Frame object.
        ttk.Frame.__init__(self, master)
        self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
        self.createWidgets()
    def save(self):
        var = self.pythonVar.get()
        #global glb
        #glb = globals()
        glb = {}
        glb[var] = pd.DataFrame({'AAA' : [1., 2., 3., 4.], 'BBB' : [43., 32., 21., 10.]})
        messagebox.showinfo("Info","pandas dataframe saved as " + var)
    def listVars(self):
        variables= [var for var in globals() if isinstance(eval(var), pd.core.frame.DataFrame)]
        self.comboboxDataframes['values'] = variables
    #%% Create widgets
    def createWidgets(self):
        # Get top window 
        self.top = self.winfo_toplevel()
        # Make it stretchable         
        self.top.rowconfigure(0, weight=1)
        self.top.columnconfigure(0, weight=1)
        # Allow to enter a name and save the data in the base workspace
        ttk.Label(self, text = "Variable").grid(row = 0, column = 0, sticky = tk.W, padx =5, pady=5)
        self.pythonVar = tk.StringVar()
        self.pythonVar.set('d')
        ttk.Entry(self, textvariable=self.pythonVar).grid(row = 0, column = 1, sticky = tk.W, padx =5, pady=5)
        # Save button
        ttk.Button(self, text = "Save", command=self.save).grid(row = 0, column = 2, sticky = tk.W, padx =5, pady=5)
        # Combobox showing dataframes stored
        ttk.Label(self, text = "Dataframes").grid(row = 1, column = 0, sticky = tk.W, padx =5, pady=5)
        self.comboboxDataframes = ttk.Combobox(self, postcommand=self.listVars)
        self.comboboxDataframes.grid(row = 1, column = 1, sticky = tk.W, padx =5, pady=5)    

#%% Allow the class to run stand-alone.
if __name__ == "__main__":
    PyDataTestMain().mainloop()

问题是你在模块中有代码并且你使用globals()

但是globals()在模块内给出全局变量,而不是在完整程序中。


在主文件中使用字典来保存数据 - 它可以是全局字典或主类中的字典

 self.all_dfs = {}

并将此字典作为参数发送到其他类

self.p1 = PyDataTest1(self, self.all_dfs)
self.p2 = PyDataTest2(self, self.all_dfs)

main.py

import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
import pandas as pd
from PyDataTest1 import PyDataTest1
from PyDataTest2 import PyDataTest2
class PyDataTestMain(ttk.Frame):
    def __init__(self, master=None):
        # Construct the Frame object.
        ttk.Frame.__init__(self, master)
        self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
        self.all_dfs = {
            # example dataframe at start
            #'a': pd.DataFrame(),
            #'b': pd.DataFrame(),
        }
        self.createWidgets()
    #%% Create widgets
    def createWidgets(self):
        # Get top window 
        self.top = self.winfo_toplevel()
        # Make it stretchable         
        self.top.rowconfigure(0, weight=1)
        self.top.columnconfigure(0, weight=1)
        # Add several PyDataTest widgets
        self.p1 = PyDataTest1(self, self.all_dfs)
        self.p1.grid(row=0, column=0, sticky=tk.W, padx=5, pady=5)
        self.p2 = PyDataTest2(self, self.all_dfs)
        self.p2.grid(row=1, column=0, sticky=tk.W, padx=5, pady=5)
        self.p3 = PyDataTest1(self, self.all_dfs)
        self.p3.grid(row=2, column=0, sticky=tk.W, padx=5, pady=5)
        self.p4 = PyDataTest2(self, self.all_dfs)
        self.p4.grid(row=3, column=0, sticky=tk.W, padx=5, pady=5)
#---
PyDataTestMain().mainloop()

PyDataTest1.py

import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
import pandas as pd
class PyDataTest1(ttk.Frame):
    def __init__(self, master=None, dfs=None):
        # Construct the Frame object.
        ttk.Frame.__init__(self, master)
        self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
        self.createWidgets()
        self.dfs = dfs
        if self.dfs is None:
            raise("Need DataFrames dictionary")
    def save(self):
        var = self.pythonVar.get()
        self.dfs[var] = pd.DataFrame({'AAA' : [1., 2., 3., 4.], 'BBB' : [43., 32., 21., 10.]})
        messagebox.showinfo("Info","pandas dataframe saved as " + var)
    def listVars(self):
        self.comboboxDataframes['values'] = list(self.dfs.keys())
    #%% Create widgets
    def createWidgets(self):
        # Get top window 
        self.top = self.winfo_toplevel()
        # Make it stretchable         
        self.top.rowconfigure(0, weight=1)
        self.top.columnconfigure(0, weight=1)
        # Allow to enter a name and save the data in the base workspace
        ttk.Label(self, text = "Variable").grid(row = 0, column = 0, sticky = tk.W, padx =5, pady=5)
        self.pythonVar = tk.StringVar()
        self.pythonVar.set('d')
        ttk.Entry(self, textvariable=self.pythonVar).grid(row = 0, column = 1, sticky = tk.W, padx =5, pady=5)
        # Save button
        ttk.Button(self, text = "Save", command=self.save).grid(row = 0, column = 2, sticky = tk.W, padx =5, pady=5)
        # Combobox showing dataframes stored
        ttk.Label(self, text = "Dataframes").grid(row = 1, column = 0, sticky = tk.W, padx =5, pady=5)
        self.comboboxDataframes = ttk.Combobox(self, postcommand=self.listVars)
        self.comboboxDataframes.grid(row=1, column=1, sticky=tk.W, padx=5, pady=5)    

最新更新