Skip to main content
 首页 » 编程设计

Python之在类中初始化 tkinter,当在另一个类中需要另一个 gui 时会发生什么

2025年01月19日30jiqing9006

我正在尝试创建一个“从 csv 文件读取”类。这个类应该读取一个 csv 文件并将结果作为列表返回。到目前为止 - 即使对于像我这样的新手来说也很简单。

但是-我需要一些更复杂的东西:

1) 如果没有给出文件名(作为类的参数)——弹出一个文件选择对话框来选择一个。

2) 可选:使用 CSVGui 类(使用方法 self.out_in_gui)在 GUI 中显示文件内容。

由于 ReadCSV 不是基于 GUI 的类,GUI 仅在需要启动 askopenfilename 时初始化。使用 widtdraw() 是为了不显示额外的空白 GUI。

问题是:当我尝试读取一个文件时,没有指定一个文件,弹出一个文件选择对话框,加上调用方法self.out_in_gui来执行CSVGui 类 - 文件内容不显示在 GUI 中(条目留空)。

TRIES:当我指定要加载的文件作为参数时,一切运行正常。我的猜测 - 它与使用 ReadFile 中的 GUI 加载文件选择 GUI 有关。

谢谢 J

import csv 
import tkinter as tk 
from tkinter import ttk 
from tkinter.filedialog import askopenfilename 
 
 
class ReadFile: 
    """This class reads CSV w/out header line, and returen it as a list""" 
 
    def __init__(self, fname='', path='', **kwargs): 
        if fname == '' and path == '': 
            tk.Tk().withdraw() 
            self.filename = askopenfilename(title='Select CSV file', filetypes=[('CommaSeperatedFile', '*.csv')]) 
        else: 
            if path != '': 
                self.filename = path + '/' + fname 
            else: 
                self.filename = fname 
        self.file_content = [] 
        self.read_file(kwargs) 
        self.out_in_gui() 
 
    def read_file(self, kwargs): 
        with open(self.filename, newline='', **kwargs) as csvfile: 
            file_obj = csv.reader(csvfile) 
            for i in file_obj: 
                self.file_content.append(i) 
            print("file %s was read successfully, containing %d lines" % (self.filename, len(self.file_content))) 
 
    def out_in_gui(self): 
        print("send data to CSVGui") 
        CSVGui(self, data=self.file_content) 
 
    def file_contents(self): 
        return self.file_content 
 
 
class CSVGui(ttk.Frame): 
    def __init__(self, master=None, data=[]): 
        ttk.Frame.__init__(self, master) 
        self.master = master 
        # csvroot = tk.Tk() 
        fname = 'No file loaded' 
        # if data is not None and master is not None: 
        #     fname = self.master.filename 
        # csvroot.title("CSVGui - " + fname) 
        self.frame = ttk.LabelFrame(self, text='Data set', padding=10) 
        self.frame.grid(row=0, column=0, padx=5, pady=5) 
        self.widgets_frame = ttk.Frame(self) 
        self.widgets_frame.grid(row=1, column=0) 
 
        self.m, self.row_vars = [], [] 
        self.exec_gui(data) 
        print(data) 
        # self.read_from_gui() 
        # csvroot.mainloop() 
 
    def exec_gui(self, data): 
        # populted and create GUI with data 
        for r in range(len(data)): 
            self.m = [] 
            self.ent = '' 
            for col in range(len(max(data))): 
                self.m.append(tk.StringVar()) 
                self.ent = ttk.Entry(self.frame, textvariable=self.m[-1], state=tk.NORMAL) 
                self.ent.grid(row=r, column=col) 
                try: 
                    self.m[-1].set(data[r][col]) 
                    print("IN") 
                except IndexError: 
                    self.m[-1].set('') 
                    print("OUT") 
            # create structured vector of var for use in save mode 
            self.row_vars.append(self.m) 
 
        self.create_widgets() 
        print("CSVGui - Created") 
 
    def create_widgets(self): 
        self.save_button = ttk.Button(self.widgets_frame, text='Save', command=self.save2file) 
        self.save_button.grid(row=0, column=0) 
        self.exit_button = ttk.Button(self.widgets_frame, text='Exit')  # , command=print('Exit')) 
        self.exit_button.grid(row=0, column=1) 
        tk.Spinbox(self.widgets_frame, width=5, from_=0, to=20).grid() 
 
    def read_from_gui(self): 
        data_list = [] 
        for r, rows in enumerate(self.row_vars): 
            c_data = [] 
            for c, cols in enumerate(rows): 
                if cols.get() != '': 
                    c_data.append(cols.get()) 
            data_list.append(c_data) 
 
        return data_list 
 
    def save2file(self): 
        WriteFile('w', self.master.filename, data=self.read_from_gui()) 

请您参考如下方法:

我试过你的代码,但它对我不起作用,因为问题是 master

在 ReadFile 中运行 CSVGui(self, ...) 并且 self 表示 ReadFile。在 CSVGui 中,您将此 ReadFile 分配给 master 并在 ttk.Frame.__init__(self, master) 中使用 -但 master 必须是任何 tkinter 的 小部件,而不是 ReadFile。

我修改了两个地方

首先:在 ReadFile 中,我创建了 Tk() 窗口,在 askopenfilename 之后,我销毁了它。这样,如果我运行 ReadFile() 或 ReadFile(filename.csv) 我总是会在没有 master 的情况下运行 CSVGui在计算机内存中。

   if fname == '' and path == '': 
        master = tk.Tk() 
        master.withdraw() 
        self.filename = askopenfilename(title='Select CSV file', filetypes=[('CommaSeperatedFile', '*.csv')]) 
        master.destroy() 

第二:CSVGui 不需要 master 作为第二个参数,因为我在 CSVGui 中创建了它

class CSVGui(ttk.Frame): 
    def __init__(self, data=[]): 
        master = tk.Tk() 
        ttk.Frame.__init__(self, master) 

它还需要 self.pack() 把 class CSVGui(ttk.Frame) 放在这个 master 里面,和 master.mainloop() 使其保持打开状态。


import csv 
import tkinter as tk 
from tkinter import ttk 
from tkinter.filedialog import askopenfilename 
 
 
class ReadFile: 
    """This class reads CSV w/out header line, and returen it as a list""" 
 
    def __init__(self, fname='', path='', **kwargs): 
        if fname == '' and path == '': # <--- changes 
            master = tk.Tk() 
            master.withdraw() 
            self.filename = askopenfilename(title='Select CSV file', filetypes=[('CommaSeperatedFile', '*.csv')]) 
            master.destroy() 
        else: 
            if path != '': 
                self.filename = path + '/' + fname 
            else: 
                self.filename = fname 
        self.file_content = [] 
        self.read_file(kwargs) 
        self.out_in_gui() 
 
    def read_file(self, kwargs): 
        with open(self.filename, newline='', **kwargs) as csvfile: 
            file_obj = csv.reader(csvfile) 
            for i in file_obj: 
                self.file_content.append(i) 
            print("file %s was read successfully, containing %d lines" % (self.filename, len(self.file_content))) 
 
    def out_in_gui(self): 
        print("send data to CSVGui") 
        CSVGui(self.filename, data=self.file_content) # <--- changes 
 
    def file_contents(self): 
        return self.file_content 
 
 
class CSVGui(ttk.Frame): 
    def __init__(self, filename, data=[]): # <--- changes 
        self.filename = filename # <--- changes 
 
        master = tk.Tk() # <--- changes 
        ttk.Frame.__init__(self, master) 
        self.grid() # <--- changes (updated. was `pack` before) 
 
        # csvroot = tk.Tk() 
        fname = 'No file loaded' 
        # if data is not None and master is not None: 
        #     fname = self.master.filename 
        # csvroot.title("CSVGui - " + fname) 
        self.frame = ttk.LabelFrame(self, text='Data set', padding=10) 
        self.frame.grid(row=0, column=0, padx=5, pady=5) 
        self.widgets_frame = ttk.Frame(self) 
        self.widgets_frame.grid(row=1, column=0) 
 
        self.m, self.row_vars = [], [] 
        self.exec_gui(data) 
        print(data) 
        # self.read_from_gui() 
        # csvroot.mainloop() 
        master.mainloop() # <--- changes 
 
    def exec_gui(self, data): 
        # populted and create GUI with data 
        for r in range(len(data)): 
            self.m = [] 
            self.ent = '' 
            for col in range(len(max(data))): 
                self.m.append(tk.StringVar()) 
                self.ent = ttk.Entry(self.frame, textvariable=self.m[-1], state=tk.NORMAL) 
                self.ent.grid(row=r, column=col) 
                try: 
                    self.m[-1].set(data[r][col]) 
                    print("IN") 
                except IndexError: 
                    self.m[-1].set('') 
                    print("OUT") 
            # create structured vector of var for use in save mode 
            self.row_vars.append(self.m) 
 
        self.create_widgets() 
        print("CSVGui - Created") 
 
    def create_widgets(self): 
        self.save_button = ttk.Button(self.widgets_frame, text='Save', command=self.save2file) 
        self.save_button.grid(row=0, column=0) 
        self.exit_button = ttk.Button(self.widgets_frame, text='Exit')  # , command=print('Exit')) 
        self.exit_button.grid(row=0, column=1) 
        tk.Spinbox(self.widgets_frame, width=5, from_=0, to=20).grid() 
 
    def read_from_gui(self): 
        data_list = [] 
        for r, rows in enumerate(self.row_vars): 
            c_data = [] 
            for c, cols in enumerate(rows): 
                if cols.get() != '': 
                    c_data.append(cols.get()) 
            data_list.append(c_data) 
 
        return data_list 
 
    def save2file(self): 
        WriteFile('w', self.filename, data=self.read_from_gui()) # <--- changed 
 
ReadFile() 

编辑:我将 filename 添加到 CSVGui(self.filename, data=self.file_content)