【问题标题】:tkinter gui which loads a flie and can print out the file nametkinter gui,它加载文件并可以打印出文件名
【发布时间】:2018-05-20 21:53:10
【问题描述】:

我从 python 开始,我已经用matplotlib 创建了一个很好的绘图函数。现在我想使用 tkinter 将该函数插入到 GUI 中。 正如我从 youtube 和这个论坛中了解到的那样,我应该使用课程。 不幸的是,我对此有一些问题。到目前为止我所拥有的(我没有详细了解所有内容)是:

import tkinter as tk
from tkinter import filedialog

LARGE_FONT=('Verdana',12)


class XPSPlotApp(tk.Tk):

    def __init__(self, *args,**kwargs):
        tk.Tk.__init__(self, *args,**kwargs)
        container=tk.Frame(self)

        container.pack(side='top',fill='both',expand=True)
        container.grid_rowconfigure(0,weight=1)#0 is min size
        container.grid_columnconfigure(0,weight=1)


        #adding a menubar#
        self.menuBar = tk.Menu(master=self)
        self.filemenu = tk.Menu(self.menuBar, tearoff=0)
        self.filemenu.add_command(label="Open", command=self.browse_file)
        self.filemenu.add_command(label="Quit!", command=self.quit)
        self.menuBar.add_cascade(label="File", menu=self.filemenu)
        self.config(menu=self.menuBar)

        self.frames={}

        for F in (HRXPSPlotter, SurveyXPSPlotter):

            frame=F(container,self)

            self.frames[F]=frame

            frame.grid(row=0,column=1,sticky='nsew')

        self.show_frame(HRXPSPlotter)

    def show_frame(self, cont):
        frame=self.frames[cont]
        frame.tkraise()

    #Question if it should be here because maybe overwrites the filename   form other window?
    def browse_file(self):
        self.filename =  filedialog.askopenfilename(initialdir = "E:/Images",title = "choose your file",filetypes = (("txt files","*.txt"),("all files","*.*")))
        print(self.filename)
    def printFN(self):
        print(self.filename)


class HRXPSPlotter(tk.Frame):

    def __init__(self,parent, controller):
        tk.Frame.__init__(self,parent)
        lable=tk.Label(self,text='Sart Page',font=LARGE_FONT)
        lable.pack(pady=10,padx=10)
        #button to go to another page
        button1=tk.Button(self, text='Visit Page 1',command=lambda:controller.show_frame(SurveyXPSPlotter))
        button1.pack()

class SurveyXPSPlotter(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        lable=tk.Label(self,text='Page One',font=LARGE_FONT)
        lable.pack(pady=10,padx=10)
        button1=tk.Button(self, text='Back to Page 1',command=lambda:controller.show_frame(HRXPSPlotter))
        button1.pack()

app=XPSPlotApp()
app.mainloop()

该程序有两个页面(因为我想使用不同的绘图仪)和一个可以从目录中打开文件的菜单。

  1. 现在我想实现一个函数,当我点击一个按钮时,它会绘制filename+filepath,但我没有得到它的工作?问题很简单,我真的不知道我必须在哪里定义函数——在__init__ 中还是在子类中?还有...
  2. command=lambda:controller 是如何工作的,它对我来说仍然很神奇!
  3. 为什么tk.Frame 而不是tk.Tk 的子类(例如pageOne)方法与__init__ 不同?

【问题讨论】:

  • command=lambda:controller.show_frame(SurveyXPSPlotter) 就像def command(): return controller.show_frame(SurveyXPSPlotter)

标签: python class user-interface tkinter


【解决方案1】:

我不会直接解决您的所有三个子问题,因为它最终会成为tkinter 上的完整迷你教程。但是,我可以向您展示如何添加 Button 来进行绘图。请特别注意带有注释 # ADDED 的行。

在您的代码的修改版本下面添加了一些内容,显示了可以放置绘图函数的位置和方式。我还更改了编码样式,使其更接近 PEP 8 - Style Guide for Python Code 并且是更具可读性。

在几个地方,我还更改了变量的名称,以便更清楚地了解这种基于 tkinter 的 gui 架构是如何运行的。

import tkinter as tk
from tkinter import filedialog
LARGE_FONT=('Verdana', 12)


class XPSPlotApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        container = tk.Frame(self)
        container.pack(side='top', fill='both', expand=True)
        container.grid_rowconfigure(0, weight=1)  # 0 is min size
        container.grid_columnconfigure(0, weight=1)

        # Add menubar and subcommands.
        self.menuBar = tk.Menu(master=self)
        self.filemenu = tk.Menu(self.menuBar, tearoff=0)
        self.filemenu.add_command(label="Open", command=self.browse_file)
        self.filemenu.add_command(label="Plot", command=self.plot_file)  # ADDED
        self.filemenu.add_command(label="Quit!", command=self.quit)
        self.menuBar.add_cascade(label="File", menu=self.filemenu)
        self.config(menu=self.menuBar)

        self.frames={}

        for FrameSubclass in (HRXPSPlotter, SurveyXPSPlotter):
            frame = FrameSubclass(container, self)  # create class instance.
            self.frames[FrameSubclass] = frame
            frame.grid(row=0, column=1, sticky='nsew')

        self.show_frame(HRXPSPlotter)

    def show_frame(self, subclass):
        frame = self.frames[subclass]
        frame.tkraise()

    def browse_file(self):
        self.filename = filedialog.askopenfilename(
            initialdir="E:/Images", title="Choose your file",
            filetypes=(("text files", "*.txt"), ("all files", "*.*"))
        )
        print(self.filename)

    def plot_file(self):  # ADDED
        try:
            print('Plotting:', self.filename)
        except AttributeError:
            print('No filename has been selected to plot!')


class HRXPSPlotter(tk.Frame):
    def __init__(self, parent, controller):
        super().__init__(parent)
        label = tk.Label(self, text='Start Page', font=LARGE_FONT)
        label.pack(pady=10, padx=10)
        # Button to go to another page.
        button1 = tk.Button(self, text='Visit Page 1',
                        command=lambda: controller.show_frame(SurveyXPSPlotter))
        button1.pack()


class SurveyXPSPlotter(tk.Frame):
    def __init__(self, parent, controller):
        super().__init__(parent)
        label = tk.Label(self, text='Page One', font=LARGE_FONT)
        label.pack(pady=10, padx=10)
        # Button to go to another page.
        button1 = tk.Button(self, text='Back to Page 1',
                        command=lambda: controller.show_frame(HRXPSPlotter))
        button1.pack()


app=XPSPlotApp()
app.mainloop()

用于构造tk.Buttonscommand=lambda: controller.show_frame(<tk.Frame subclass>) 参数创建了一个匿名函数,该函数在按下相应按钮时调用controller.show_frame(<tk.Frame subclass>)(而不是在创建Button 本身时发生)。

show_frame() 函数在self.frames 字典中查找Frame 子类instance,该字典是在XPSPlotApp__init__() 方法中创建的,并“引发”它,使其变为显示为最顶部的框架(有效地隐藏了所有其余大小相同且位置相同但现在“低于”它的框架)。

【讨论】:

  • 谢谢。答案!我的问题并不正确。所以我想要的是使用存储在其他类中 self.filename 中的路径+文件名来在每个窗口中加载数据,并使用存储在另一个 py 文件中的函数来绘制它们。问题是我不知道如何在“子类”中使用 self.filename(例如 HRXPSPlotter)?谢谢。
  • MatthiasK:我的示例代码显示在添加的XPSPlotApp.plot_file() 方法中使用self.filename。你还想要什么?在另一个类中“使用”它的例子是什么?还有什么课?每个tk.Frame 子类在构造时都会收到一个controller 参数。该对象是XPSPlotApp 的一个实例,一旦"Open" 菜单项运行browse_file() 方法,就会有一个filename 属性。
  • 什么其他类:正如我所说,例如HRXSPlotter 的子类。我在 HRXPSPlotter $ f=compxpsplot(data='c:/data/file_name.txt'.sizef=15) $ 中有这个函数现在我想用存储的变量替换 $'c:/data/file_name.txt'$在超类中的 self.filename 中。如果我在超类中定义一个返回 self.filename 的方法,controller.filename 也不起作用,它总是返回:$AttributeError: '_tkinter.tkapp' object has no attribute 'filename'$?
  • HRXPSPlottertk.Frame 的子类 not XPSPlotApp,因此它永远不会有 self.filename 属性。您的代码将其分配给名为 appXPSPlotApp instance,它是在代码的倒数第二行创建的,并且仅在调用其 browse_file() 方法时才会这样做.如果要在tk.Frame 子类方法之一中引用此属性,则需要保存传递​​给每个__init__() 函数的controller 参数。换句话说,属性是controller.filename
  • 正如我所说,controller.filename 不起作用--> 输出是 '_tkinter.tkapp' 对象没有属性 'filename' ...,顺便说一下为什么 str() 在班级?我认为标准库。工作吗?
猜你喜欢
  • 2022-08-02
  • 2021-12-27
  • 1970-01-01
  • 2010-09-20
  • 2013-07-07
  • 1970-01-01
  • 1970-01-01
  • 2015-08-12
  • 1970-01-01
相关资源
最近更新 更多