Search code examples
pythonclassvalidationmessagebox

Python - Show messagebox if entry fields are empty


I've got this problem where i want my program to show a messageebox if an entry field is empty. There's function that runs when a button is clicked, it will get all the data from the entry fields in the frame class and place them into a spreadsheet file. All the entry fields are stored in another function. I also have another class called emailframe. This is the code for the button function:

def getVal(self):
    try:
        path = str(tm.strftime("%d-%m-%Y")) + ' - ' + str(tm.strftime("%A")) + '.xlsx'

        wb = xl.load_workbook(path)
        ws = wb.active

        entry_list = [child for child in root.winfo_children()
                      if isinstance(child, tk.Entry)]

        for entry in entry_list:
            if not entry.get():
                msgbox.showinfo('Daily Accounts', 'Enter in to entry fields.')
            else:
                ws['B3'] = float(self.entryBags.get())
                ws['B4'] = float(self.entryNotes.get())
                ws['B5'] = float(self.entry2pound.get())
                ws['B6'] = float(self.entry1pound.get())
                ws['B7'] = float(self.entry50p.get())
                ws['B8'] = float(self.entry20p.get())
                ws['B9'] = float(self.entry10p.get())
                ws['B10'] = float(self.entry5p.get())
                ws['B11'] = float(self.entry2p.get())
                ws['B12'] = float(self.entry1p.get())
                ws['B14'] = float(self.entryPrevTill.get())
                ws['B16'] = float(self.entryCard.get())
                ws['B17'] = float(self.entryCash.get())

        wb.save(path)

        app = xw.App(visible = False)
        book = xw.Book(path)
        ws2 = book.sheets[0]

        total_till = str(ws2.range('B13').value)
        till = str(ws2.range('B15').value)
        day_total = str(ws2.range('B18').value)

        self.lblTotalTillDisplay.configure(text = '£' + total_till) 
        self.lblLeftTillDisplay.configure(text = '£' + till)
        self.lbldaytotal2.configure(text = '£' + day_total)

        msgbox.showinfo('', 'Data Submitted.')

        book.close()
        app.kill()

    except IOError:
        msgbox.showinfo('Daily Accounts', 'New Day has not been created.')

I tried to use the winfo_children function to get all the entry fields but im not sure if it worked since i have other entryfields in another class which i dont want to retrieve.

This is the main part of the rest of my code:

class frame(tk.Frame):
def __init__(self, master):
    self.frame = ttk.Frame(master)
    self.frame.pack(fill="both", expand = True)

    self.entryfields()
    self.buttons()

def entryfields(self):  

    vcmd = (self.frame.register(self.validate),     
            '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')

    self.entryBags = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd) 
    self.entryBags.place(x = 100, y = 40)        
    self.entryNotes = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entryNotes.place(x = 100, y = 60)
    self.entry2pound = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entry2pound.place(x = 100, y = 80)
    self.entry1pound = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entry1pound.place(x = 100, y = 100)
    self.entry50p = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entry50p.place(x = 100, y = 120)
    self.entry20p = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entry20p.place(x = 100, y = 140)
    self.entry10p = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entry10p.place(x = 100, y = 160)
    self.entry5p = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entry5p.place(x = 100, y = 180)
    self.entry2p = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entry2p.place(x = 100, y = 200)
    self.entry1p = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entry1p.place(x = 100, y = 220)
    self.entryPrevTill = tk.Entry(self.frame)
    self.entryPrevTill.place(x = 100, y = 260)
    self.entryPrevTill.insert(0, 100)           
    self.entryCard = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)       
    self.entryCard.place(x = 100, y = 300)
    self.entryCash = tk.Entry(self.frame, validate = 'key', validatecommand = vcmd)
    self.entryCash.place(x = 100, y = 320)

def validate(self, action, index, value_if_allowed,
    prior_value, text, validation_type, trigger_type, widget_name):
    if(action=='1'):
        if text in '0123456789.':
            try:
                float(value_if_allowed)
                return True
            except ValueError:
                return False
        else:
            return False
    else:
        return True

def buttons(self):
    self.btnSub = tk.Button(self.frame, text = 'Submit', width = 30, command = self.getVal)
    self.btnSub.place(x = 20, y = 340)

def getVal(self):
    try:
        path = str(tm.strftime("%d-%m-%Y")) + ' - ' + str(tm.strftime("%A")) + '.xlsx'

        wb = xl.load_workbook(path)
        ws = wb.active

        entry_list = [child for child in root.winfo_children()
                      if isinstance(child, tk.Entry)]

        for entry in entry_list:
            if not entry.get():
                msgbox.showinfo('Daily Accounts', 'New Day has not been created.')
            else:
                ws['B3'] = float(self.entryBags.get())
                ws['B4'] = float(self.entryNotes.get())
                ws['B5'] = float(self.entry2pound.get())
                ws['B6'] = float(self.entry1pound.get())
                ws['B7'] = float(self.entry50p.get())
                ws['B8'] = float(self.entry20p.get())
                ws['B9'] = float(self.entry10p.get())
                ws['B10'] = float(self.entry5p.get())
                ws['B11'] = float(self.entry2p.get())
                ws['B12'] = float(self.entry1p.get())
                ws['B14'] = float(self.entryPrevTill.get())
                ws['B16'] = float(self.entryCard.get())
                ws['B17'] = float(self.entryCash.get())

        wb.save(path)

        app = xw.App(visible = False)
        book = xw.Book(path)
        ws2 = book.sheets[0]

        total_till = str(ws2.range('B13').value)
        till = str(ws2.range('B15').value)
        day_total = str(ws2.range('B18').value)

        self.lblTotalTillDisplay.configure(text = '£' + total_till) 
        self.lblLeftTillDisplay.configure(text = '£' + till)
        self.lbldaytotal2.configure(text = '£' + day_total)

        msgbox.showinfo('', 'Data Submitted.')

        book.close()
        app.kill()

    except IOError:
        msgbox.showinfo('Daily Accounts', 'New Day has not been created.')

def email(self):
    self.frame.destroy()
    app = emailFrame(root)

class emailFrame(tk.Frame):
def __init__(self, master):
    self.eframe = ttk.Frame(master)
    self.eframe.pack(fill="both", expand = True)

    self.entry()

def entry(self):

    self.entryemail = tk.Entry(self.eframe, width = 40)
    self.entryemail.place(x = 180, y = 20)

if __name__ == "__main__":
root = tk.Tk()
root.geometry("480x480")
root.title("Daily Accounts")
root.resizable(0,0)
app = frame(root)   
root.mainloop()

Sorry for the long code, trying to get as much information out as possible.


Solution

  • This would be an ideal place to use a custom Entry widget and a class method. The custom widget would inherit from tk.Entry so it would have all the attributes of a normal Entry widget:

    class Ashki(tk.Entry):
        elements = []
        def __init__(self, master=None, **kwargs):
            tk.Entry.__init__(self, master, **kwargs)
            self.elements.append(self)
    
        @classmethod
        def all_filled(cls):
            return all(entry.get() for entry in cls.elements)
    

    Now, in every place that you want to include in the check, use Ashki instead of tk.Entry.

    self.entryBags = Ashki(self.frame, validate = 'key', validatecommand = vcmd) 
    self.entryBags.place(x = 100, y = 40)  
    

    Then in your check method you can use this code:

    if not Ashki.all_filled():
        msgbox.showinfo('Daily Accounts', 'Enter in to entry fields.')
        return # abort this method