tkinter, не может вызвать функцию из-за пределов своего класса - PullRequest
0 голосов
/ 08 мая 2020

Проще говоря, я не могу вызвать filterCBO из отмеченной проблемной области в моей программе. Он возвращает:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Anaconda\envs\SE_win64_py35\lib\tkinter\__init__.py", line 1550, in __call__
    return self.func(*args)
  File "<ipython-input-24-b9ade6a4c197>", line 116, in callFilters
    Root.filterCBOs(self)
  File "<ipython-input-24-b9ade6a4c197>", line 164, in filterCBOs
    startDate = dt.datetime(year=int(self.fromDate.get()[2]),month=int(self.fromDate.get()[0]),day=int(self.fromDate.get()[1]))
AttributeError: 'Event' object has no attribute 'fromDate'

Как видите, эта функция работает точно так же, как и должна, когда она вызывается в init , а также когда она вызывается путем выбора значения поля со списком. Однако он не работает, когда он вызывается путем привязки клавиши ввода к полям ввода в DateEntry. Я новичок в классах, поэтому я уверен, что это как-то связано с тем, что он вызывается из другого класса, но я не знаю, как перемещаться по нему.


    #================================================================================
    # Imports
    #================================================================================
    import os
    import pandas as pd
    import datetime as dt
    import tkinter as tk
    from tkinter import ttk
    startTimestamp=dt.datetime.now()
    print('Starting ' + str(startTimestamp))
    #================================================================================
    # User Changable Variables
    #================================================================================
    #signaturePath = r'T:\Process Data\EDM\Signature Files'
    #================================================================================
    # Functions (mostly used to cleanup variables)
    #================================================================================

    #commented out because i ran this section once and saved to csv. saves me from indexing
    #the directory during testing.   

    '''
    def indexDirectory():
        #filenames use the following format:
        # yyyy.mm.dd.hh.mm.tool.toolSN.feature.sfc.sig
        df = pd.DataFrame(columns=['FullPath', 'Timestamp', 'Feature', 'Machine', 'Tool'])
        for root, dirs, files in os.walk(signaturePath):
            for file in files:
                splitter = file.split('.')
                if len(splitter) != 10: #weird filename
                    continue #skip to next file
                date=dt.datetime.strptime(splitter[0]+'-'+splitter[1]+'-'+splitter[2]+' '+splitter[3]+':'+splitter[4],'%Y-%m-%d %H:%M')
                df = df.append({'FullPath' : os.path.join(root, file), \
                                'Timestamp' : date, \
                                'Feature' : splitter[7], \
                                'Machine' : os.path.basename(root), \
                                'Tool' : splitter[5] + '_' + splitter[6] \
                                }, ignore_index=True)
        return df

    with open(r'C:\Users\u1106710\Desktop\Index.csv', 'w+') as SaTemp:
        indexDirectory().to_csv(SaTemp, header=True, index=False)
    '''


    # Index available signature files to a dataframe
    #sigIndex=indexDirectory
    sigIndex=pd.read_csv(r'D:\Tibbert\4) Scripts\Signature Analysis\Temp\Index.csv')
    sigIndex['Timestamp'] = pd.to_datetime(sigIndex['Timestamp'])
    #================================================================================
    # Build GUI
    #================================================================================
    class DateEntry(tk.Frame):
        def __init__(self, master, frame_look={}, **look):
            args = dict(relief=tk.SUNKEN, border=1)
            args.update(frame_look)
            tk.Frame.__init__(self, master, **args)

            args = {'relief': tk.FLAT}
            args.update(look)

            self.entry_1 = tk.Entry(self, width=2, **args)
            self.label_1 = tk.Label(self, text='/', **args)
            self.entry_2 = tk.Entry(self, width=2, **args)
            self.label_2 = tk.Label(self, text='/', **args)
            self.entry_3 = tk.Entry(self, width=4, **args)

            self.entry_1.pack(side=tk.LEFT)
            self.label_1.pack(side=tk.LEFT)
            self.entry_2.pack(side=tk.LEFT)
            self.label_2.pack(side=tk.LEFT)
            self.entry_3.pack(side=tk.LEFT)

            self.entries = [self.entry_1, self.entry_2, self.entry_3]

            self.entry_1.bind('<KeyRelease>', lambda e: self._check(0, 2))
            self.entry_2.bind('<KeyRelease>', lambda e: self._check(1, 2))
            self.entry_3.bind('<KeyRelease>', lambda e: self._check(2, 4))

            #PROBLEM HERE!
            #self.entry_1.bind('<Return>', Root.filterCBOs)
            #self.entry_2.bind('<Return>', Root.filterCBOs)
            #self.entry_3.bind('<Return>', Root.filterCBOs)

        def _backspace(self, entry):
            cont = entry.get()
            entry.delete(0, tk.END)
            entry.insert(0, cont[:-1])

        def _check(self, index, size):
            entry = self.entries[index]
            next_index = index + 1
            next_entry = self.entries[next_index] if next_index < len(self.entries) else None
            data = entry.get()

            if len(data) > size or not data.isdigit():
                self._backspace(entry)
            if len(data) >= size and next_entry:
                next_entry.focus()

        def get(self):
            return [e.get() for e in self.entries]



    class Root(tk.Tk):
        def __init__(self):
            super(Root, self).__init__()
            self.title("Filmcool Siganture Analysis")
            self.minsize(width=800,height=600)

            self.InitUI()
            self.filterCBOs()

        def InitUI(self):
            #Setup Date Entry
            self.fromDateLBL = tk.Label(self, text='Date Range')
            self.fromDate = DateEntry(self)
            self.toDateLBL = tk.Label(self, text='To')
            self.toDate = DateEntry(self)

            #Set Date Defaults
            self.fromDate.entry_1.insert(0,'01')
            self.fromDate.entry_2.insert(0,'01')
            self.fromDate.entry_3.insert(0,'2014')
            self.toDate.entry_1.insert(0,dt.date.today().month)
            self.toDate.entry_2.insert(0,dt.date.today().day)
            self.toDate.entry_3.insert(0,dt.date.today().year)

            #Setup Feature Combobox
            self.featureLBL = tk.Label(self, text='Feature')
            self.featureCBO = ttk.Combobox(self, width=15)
            self.featureCBO.bind('<<ComboboxSelected>>', self.filterCBOs)

            #Setup Tool Combobox
            self.toolLBL = tk.Label(self, text='Tool')
            self.toolCBO = ttk.Combobox(self, width=15)
            self.toolCBO.bind('<<ComboboxSelected>>', self.filterCBOs)

            #Arrange UI Elements
            self.fromDateLBL.grid(column=0,row=4)
            self.fromDate.grid(column=1,row=4,sticky='e')
            self.toDateLBL.grid(column=2,row=4,sticky='e')
            self.toDate.grid(column=3,row=4)
            self.featureLBL.grid(column=0, row=0, sticky='w')
            self.featureCBO.grid(column=1, row=0)
            self.toolLBL.grid(column=0, row=1, sticky='w')
            self.toolCBO.grid(column=1, row=1)

        def filterCBOs(self, event=None):
            #Create and filter dataframe
            df=sigIndex
            #Filter by Date

    #THROWS ERROR ON NEXT LINE
            startDate = dt.datetime(year=int(self.fromDate.get()[2]),month=int(self.fromDate.get()[0]),day=int(self.fromDate.get()[1]))
            endDate = dt.datetime(year=int(self.toDate.get()[2]),month=int(self.toDate.get()[0]),day=int(self.toDate.get()[1]))
            print(startDate)
            print(endDate)
            df=df[(df['Timestamp'] >= startDate) & (df['Timestamp'] <= endDate)]
            #Filter by Feature
            if self.featureCBO.get() == "":
                pass
            else:
                df=df[df['Feature'] == self.featureCBO.get()]
            #Filter by Tool
            if self.toolCBO.get() == "":
                pass
            else:
                df=df[df['Tool'] == self.toolCBO.get()]

            #print(df)
            #Filter Feature CBO        
            self.featureCBO['values'] = df['Feature'].unique().tolist()
            self.featureCBO['values'] = (*self.featureCBO['values'], '') #add empty line to end
            #Filter Tool CBO 
            self.toolCBO['values'] = df['Tool'].unique().tolist()
            self.toolCBO['values'] = (*self.toolCBO['values'], '') #add empty line to end




    if __name__ == '__main__':
        window = Root()
        window.mainloop()

    print('done')

1 Ответ

1 голос
/ 08 мая 2020

Проблема заключается в попытке сослаться на функцию как Root .filterCBOs) . The function belongs to an instance of Root, so it needs to be master.filterCBOs since master` устанавливается в окно root.

self.entry_1.bind('<Return>', master.filterCBOs)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...