【问题标题】:python tkinter passing dataframes between widgetspython tkinter 在小部件之间传递数据帧
【发布时间】:2017-12-30 09:09:06
【问题描述】:

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

【问题讨论】:

  • 如果你使用self.p3 = PyDataTest1(self).grid(),那么你会在self.p3 中得到None,因为grid() 返回None。如果您需要self.p3,那么您必须分两行完成self.p3 = PyDataTest1(self)self.p3.grid()
  • 在小部件 p3 中,我已经可以访问保存在小部件 p1 中的数据框。在小部件 p2 和 p4 中我没有。但我会按照你的建议写。如何将信息从 p1 传递到 p2 ?
  • 而不是使用globals() 创建变量,您应该使用全局字典glb = {},然后在类glb[var] = 中不使用globals()
  • myabe 您可以访问,因为您使用globals() - 但不是首选。 Python 使用字典以字符串为键来保存数据。
  • 如果PyDataTest2PyDataTest2 有相同的代码,那么如果可以使用PyDataTest1,为什么要使用PyDataTest2

标签: python tkinter parameter-passing


【解决方案1】:

问题是你在模块中有代码并且你使用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)    

【讨论】:

  • 非常感谢您解决了我的问题。它完美地工作。 Dziękuje bardzo !
猜你喜欢
  • 1970-01-01
  • 2012-03-06
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 2018-10-09
  • 1970-01-01
  • 2020-05-18
  • 1970-01-01
相关资源
最近更新 更多