Home > Software design >  Tkinter delete not working on referenced entry when referenceing lenth of entry
Tkinter delete not working on referenced entry when referenceing lenth of entry

Time:11-17

I have a tkinter window class that I've made and my delete function is not working properly.

my_window = tk.Tk()

class QuoteForm():
    def __init__(self,master):
        self.file_data = ''
        self.master = master

        self.master.rowconfigure(0, weight=1)
        self.master.rowconfigure(1, weight= 1)
        self.master.rowconfigure(2, weight = 1)
        
        master.geometry('600x400')
        master.resizable(False,False)


        #create the frames
        self.directory_frm = tk.Frame(master=master)
        self.directory_frm.grid(row=0) #this is the frame for the directory
        self.add_on_frm = tk.Frame(master=master)
        self.add_on_frm.grid(row=1) #this is the frame for add-ons input
        self.button_frm = tk.Frame(master=master)
        self.button_frm.grid(row=2) #this is the frame for



        #creates buttons, entries, labels
        self.load_directory_frame() #creates and grids the directory button
        self.load_add_on_frame() #creates and grids the entry buttons and labels
        self.load_button_frame() #creates and grids the buttons

        my_window.mainloop()


     def load_add_on_frame(self):
        vcmd = (self.master.register(self.validate_ent), '%S')


        #create inputs and labels for add-ons
        self.trip_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd, name='trip_ent')
        self.trip_ent.grid(column= 1, row = 0)
        self.raw_cutouts_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.raw_cutouts_ent.grid(column= 3, row = 0)
        


    def clear_entries(self):
            entries = (self.trip_ent, self.raw_cutouts_ent) #list of entries to loop (there are a total of 12 in the actual code)
            for entry in entries:
                entry.delete(0,len(entry.get())) #this is where the trouble seems to happen

        


new_quote = QuoteForm(my_window)


My problem is that the on the second to last line of code (starting with 'entry.delete') Typically you would do 'entry.delete(0,END)' but because entry is a variable the code won't run with END. 'END' is an invalid index, and 'end' just does the same as pulling the length, and so i tried to make it dynamic by making the 'end' the length of whatever is in the entry. When i do that however, it deletes nothing [i also tried forcing it with int(len(entry.get()))]. If i manually enter an integer it will delete everything up to that integer, including if it's the same as the length of that entry, and I put breaks to confirm that i'm getting an int return and I am.

I realize i could just write a line of code to delete each entry individually, but there's a totaly of 12 and I would like to clean it up.

I'm adding the full code to be able to run below

import os
import re
import tkinter as tk
from tkinter import filedialog as fd
from tkinter import messagebox

import pandas as pd

my_window = tk.Tk()

class QuoteForm():
    def __init__(self,master):
        self.file_data = ''
        self.master = master

        self.master.rowconfigure(0, weight=1)
        self.master.rowconfigure(1, weight= 1)
        self.master.rowconfigure(2, weight = 1)
        
        master.geometry('600x400')
        master.resizable(False,False)



        self.directory_frm = tk.Frame(master=master)
        self.directory_frm.grid(row=0) #this is the frame for the directory
        self.add_on_frm = tk.Frame(master=master)
        self.add_on_frm.grid(row=1) #this is the frame for add-ons input
        self.button_frm = tk.Frame(master=master)
        self.button_frm.grid(row=2) #this is the frame for



        
        self.load_directory_frame()
        self.load_add_on_frame()
        self.load_button_frame()

        my_window.mainloop()


    @staticmethod
    def get_quote_data(filepath):
    #read csv to get job infomation for pricing
        try:
            if filepath:
                job_info = pd.read_csv(filepath, 
                        index_col=0, #set index column
                        skiprows=range(4), #skip first 4 rows
                        usecols=['Item','Quan'])
                job_info = job_info.drop(labels='Grand Total:', axis= 0)
                customer_info = pd.read_csv(filepath, header=None,
                        skiprows= lambda x: x not in range(2), #skip any row beyond first two rows
                        usecols=[0,1]) #use first two columns
                

                customer_info = {customer_info.at[0,0].replace(':',''): customer_info.at[0,1], ##formatting the data for legibility
                                customer_info.at[1,0].replace(':','') : customer_info.at[1,1]}
                return [customer_info, job_info]
        except:
            messagebox.showerror("Data Invalid", "Please make sure you select a valid estimate CSV file.")



    def sink_check(self):
        ####this is to be used at the submit buttons to confirm that there are not more sinks than cutouts
        cutouts = self.um_sink_inst_ent.get()
        sink_quan_list = (self.std_sink_ent.get(),self.upgrd_sink_ent.get(),self.van_sink_ent.get(),self.cust_sink_temp_ent.get())
        sinks = sum(sink_quan_list)
        if sinks > cutouts:
            return False
        ###check that the sinks included does not exceed the number of sinks charged for install
        return True

    def validate_ent(self,input):
        if not input:
            return True
        elif re.fullmatch(r'[0-9]',input):
            return True

        return False


    def open_file(self):
        file = fd.askopenfile(mode='r', filetypes=[('CSV Files', '*.csv')])
        if file:
            filepath = os.path.abspath(file.name)
            file_data = self.get_quote_data(filepath)
            cust_name = file_data[0]['Name']
            job_addr = file_data[0]['Addr']
        self.file_select_text['text'] = f"{job_addr} for {cust_name} is currently selected"
        
       
    def load_directory_frame(self):
        file_select_btn = tk.Button(master=self.directory_frm,text= "Select a file",command=self.open_file)
        file_select_btn.grid(column=0, row=0)
        self.file_select_text = tk.Label(master=self.directory_frm, text = "No File Selected")
        self.file_select_text.grid(column=1, row=0)

        
    def load_add_on_frame(self):
        vcmd = (self.master.register(self.validate_ent), '%S')


        #create inputs and labels for add-ons
        self.trip_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd, name='trip_ent')
        self.trip_ent.grid(column= 1, row = 0)
        self.raw_cutouts_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.raw_cutouts_ent.grid(column= 3, row = 0)
        self.radii_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.radii_ent.grid(column= 1, row = 1)
        self.arcs_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.arcs_ent.grid(column= 3, row = 1)
        self.splay_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.splay_ent.grid(column= 1, row = 2)
        self.wtrfall_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.wtrfall_ent.grid(column= 3, row = 2)
        self.um_sink_inst_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.um_sink_inst_ent.grid(column= 1, row = 3)
        self.farm_sink_co_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.farm_sink_co_ent.grid(column= 3, row = 3)
        self.std_sink_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.std_sink_ent.grid(column= 1, row = 4)
        self.upgrd_sink_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.upgrd_sink_ent.grid(column= 3, row = 4)
        self.van_sink_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.van_sink_ent.grid(column= 1, row = 5)
        self.cust_sink_temp_ent = tk.Entry(master=self.add_on_frm,validate = 'key', validatecommand = vcmd)
        self.cust_sink_temp_ent.grid(column= 3, row = 5)
        
        trip_lbl = tk.Label(master=self.add_on_frm,text = "Extra Trip(s)")
        trip_lbl.grid(column= 0, row = 0)
        raw_cutouts_lbl = tk.Label(master=self.add_on_frm,text = "Unpolished Cutout(s)")
        raw_cutouts_lbl.grid(column= 2, row = 0)
        radii_lbl = tk.Label(master=self.add_on_frm,text = "Radii")
        radii_lbl.grid(column= 0, row = 1)
        arcs_lbl = tk.Label(master=self.add_on_frm,text = "Arc(s)")
        arcs_lbl.grid(column= 2, row = 1)
        splay_lbl = tk.Label(master=self.add_on_frm,text = "Splay(s)")
        splay_lbl.grid(column= 0, row = 2)
        wtrfall_lbl = tk.Label(master=self.add_on_frm,text = "Waterfal Leg(s)")
        wtrfall_lbl.grid(column= 2, row = 2)
        um_sink_inst_lbl = tk.Label(master=self.add_on_frm,text = "Install of UM Sink(s)")
        um_sink_inst_lbl.grid(column= 0, row = 3)
        farm_sink_co_lbl = tk.Label(master=self.add_on_frm,text = "Farm Sink C/O")
        farm_sink_co_lbl.grid(column= 2, row = 3)
        std_sink_lbl = tk.Label(master=self.add_on_frm,text = "Standard 18ga Sink(s)")
        std_sink_lbl.grid(column= 0, row = 4)
        upgrd_sink_lbl = tk.Label(master=self.add_on_frm,text = "Upgrade 18ga Sink(s)")
        upgrd_sink_lbl.grid(column= 2, row = 4)
        van_sink_lbl = tk.Label(master=self.add_on_frm,text = "Vanity Sink(s)")
        van_sink_lbl.grid(column= 0, row = 5)
        cust_sink_temp_lbl = tk.Label(master=self.add_on_frm,text = "Customer Sink Template(s)")
        cust_sink_temp_lbl.grid(column= 2, row = 5)

    def load_button_frame(self):
        

        submit_btn = tk.Button(master=self.button_frm, text='Submit')
        submit_btn.grid(column=0,row=0)
        clear_btn = tk.Button(master=self.button_frm,text='Clear',command=self.clear_entries)
        clear_btn.grid(column=1, row=0)
        advanced_btn = tk.Button(master=self.button_frm,text='Advanced')
        advanced_btn.grid(column=2, row=0)


    def clear_entries(self):
            entries = (self.trip_ent, self.raw_cutouts_ent, self.radii_ent, self.arcs_ent, self.splay_ent, #list of entry boxes on the form
                    self.wtrfall_ent, self.um_sink_inst_ent, self.um_sink_inst_ent, self.farm_sink_co_ent, 
                    self.std_sink_ent, self.upgrd_sink_ent, self.van_sink_ent, self.cust_sink_temp_ent)
            for entry in entries:
                entry.delete(0,tk.END)

        


new_quote = QuoteForm(my_window)

CodePudding user response:

It's all about yourvalidate_ent function. Only when it returns true then your entry text can change. While typing tkinter just sent single chars like '1','2','a'. Even when you remove with backspace, this function gets the character you are trying to remove. However when you try to clear it function gets as an input whole string like '123543123'. This is not takes place inside r'[0-9]' reguler expression and you return false so tkinter denies removing it. There is two simple solution to fix this. First one add another condition for longer input like:

def validate_ent(self,input):
  if not input:
     return True
  elif re.fullmatch(r'[0-9]',input):
     return True
  if(len(input)>2):
     return True
  return False

However I do not recommend this one because if someone copy paste longer inputs then it can write letters inside entry boxes.

def validate_ent(self,input):
  if not input:
     return True
  elif re.fullmatch(r'[0-9]*',input):
     return True
  return False

In here we added a asteriks to reguler expression. Now it's accepting numbers bigger then 9. Now people can also paste numbers that fits into this rule. Also removing works as expected!

CodePudding user response:

You have a validation function that rejects the deletion if there's more than one digit in the input. Your function will work when there is a single digit in the input fields.

You can see this by adding a print statement inside validate_ent and then following the logic for what is in the input parameter.

  • Related