How do i get numberOfItemsHired to only accept 1-500 if it is outside those values error message should be displayed

Joined
Jul 5, 2024
Messages
4
Reaction score
0
how do i get numberOfItemsHired to only accept 1-500 if it is outside those values error message should be displayed. Checking if the input contains string works well, as well as checking if user has entered anything in the entry box and it has not been left blank. I have tried:
if len(range(int(entry_numberOfItemshired.get()))) in range (1,500
but this does not work because len function does not work properly with integers. I have also tried:
numberOfItens= int(entry_numberOfItemsHired.get())
if not (1 <= (numberOfItems)<= 500):
but this does not work as well and I have no idea why as no error message is being delievered.
This is my code:
from tkinter import*
import tkinter as tk

def quit():
main_window.destroy()

def print_details():
global counter
counter= 0
Label(main_window, text= "Row").grid(column= 0, row= 7)
Label(main_window, text= "Customer Name").grid(column= 1, row= 7)
Label(main_window, text= "Receipt Number").grid(column= 2, row= 7)
Label(main_window, text= "Item Hired").grid(column= 3, row= 7)
Label(main_window, text= "Number of Item Hired").grid(column= 4, row= 7)
ROWS_ABOVE= 8

while counter < number['total_entries']:
Label(main_window, text= counter).grid(column= 0, row= counter + ROWS_ABOVE)
Label(main_window, text= (hireDetails[counter][0])).grid(column= 1, row= counter + ROWS_ABOVE)
Label(main_window, text= (hireDetails[counter][1])).grid(column= 2, row= counter + ROWS_ABOVE)
Label(main_window, text= (hireDetails[counter][2])).grid(column= 3, row= counter + ROWS_ABOVE)
Label(main_window, text= (hireDetails[counter][3])).grid(column= 4, row= counter + ROWS_ABOVE)
counter += 1
number['counter']= counter



def check_validity():
global items
if (entry_customer_name.get().isalpha()) and (entry_numberOfItemsHired.get().isnumeric())and int(entry_receipt_number.get().isnumeric()) != 0:
if(range(int(entry_receipt_number.get()))) in range (1,99999999):
numberOfItems= int(entry_numberOfItemsHired.get())
minimum_item= 1
maximum_item= 500
if(minimum_item <= (numberOfItems)<= maximum_item) == True:
items= ["Spoons", "Forks" , "Knives" , "Tables" , "Chairs" , "Cater Dishes"]
if (entry_itemHired.get()) in items:
return True
append_details ()
Label(main_window, text= "Customer Name: ").grid(column= 0, row= 1)
Label(main_window, text= "Receipt No.: ").grid(column= 0, row= 2)
Label(main_window, text= "Item Hired: ").grid(column= 0, row= 3)
Label(main_window, text= "No. of Items Hired: ").grid(column= 0, row= 4)
Label(main_window, text= " ").grid(column= 2, row= 1, sticky= "W")
Label(main_window, text= " ").grid(column= 2, row= 2, sticky= "W")
Label(main_window, text= " ").grid(column= 2, row= 3, sticky= "W")
Label(main_window, text= " ").grid(column= 2, row= 4, sticky= "W")

else:
if len(entry_customer_name.get()) == 0:
Label(main_window, text= "Enter Customer Name. No numbers allowed.", bg= 'red').grid(column= 2, row= 1, sticky= "W")
else:
Label(main_window, text= " ").grid(column= 2, row= 1, sticky= "W")
if not(entry_customer_name.get().isalpha()):
Label(main_window, text= "No numbers allowed.", bg= 'red').grid(column= 2, row= 1, sticky= "W")

if len(entry_receipt_number.get()) == 0:
Label(main_window, text= "Receipt Number is invalid.", bg= 'red').grid(column= 2, row= 2, sticky= "W")
else:
Label(main_window, text= " ").grid(column= 2, row= 2, sticky= "W")
if not(entry_receipt_number.get().isnumeric()):
Label(main_window, text= "Receipt Number is invalid. Use digits.", bg= 'red').grid(column= 2, row= 2, sticky= "W")
elif len(range(int(entry_receipt_number.get()))) not in range (1,99999999):
Label(main_window, text= "Receipt Number is invalid. Only 8 digits needed.", bg= 'red').grid(column= 2, row= 2, sticky= "W")

if len(entry_itemHired.get()) == 0:
items= ["Spoons", "Forks" , "Knives" , "Tables" , "Chairs" , "Cater Dishes"]
Label(main_window, text= "Choose Item Hired: Spoons, Forks, Knives, Tables, Chairs, Cater Dishes.", bg= 'red').grid(column= 2, row= 3, sticky= "W")
else:
Label(main_window, text= " ").grid(column= 2, row= 3, sticky= "W")
if (entry_itemHired.get()) not in items:
Label(main_window, text= "Choose Item Hired: Spoons, Forks, Knives, Tables, Chairs, Cater Dishes.", bg= 'red').grid(column= 2, row= 3, sticky= "W")

if len(entry_numberOfItemsHired.get()) == 0:
Label(main_window, text= "Only 1-500 items allowed to be hired.", bg= 'red').grid(column= 2, row= 4, sticky= "W")
return False

if (entry_numberOfItemsHired.get().isalpha()):
Label(main_window, text= "Use Numbers. Only 1-500 items allowed to be hired.", bg= 'red').grid(column= 2, row= 4, sticky= "W")
return False

numberOfItems= int(entry_numberOfItemsHired.get())
minimum_item= 1
maximum_item= 500
if not (minimum_item<= (numberOfItems)<= maximum_item):
Label(main_window, text= "Only 1-500 items allowed to be hired.", bg= 'red').grid(column= 2, row= 4, sticky= "W")
return False
else:
Label(main_window, text= " ").grid(column= 2, row= 4, sticky= "W")
return True


def append_details():
hireDetails.append([entry_customer_name.get(),entry_receipt_number.get(),entry_itemHired.get(),entry_numberOfItemsHired.get()])
entry_customer_name.delete(0,'end')
entry_receipt_number.delete(0,'end')
entry_itemHired.delete(0,'end')
entry_numberOfItemsHired.delete(0,'end')
number ['total_entries'] += 1

def delete_row():
del hireDetails [int(delete_details.get())-0]
counter= number['counter']
number['total_entries']-=1
delete_details.delete(0,'end')
Label(main_window, text= " ").grid(column= 0, row= counter + 7)
Label(main_window, text= " ").grid(column= 1, row= counter + 7)
Label(main_window, text= " ").grid(column= 2, row= counter + 7)
Label(main_window, text= " ").grid(column= 3, row= counter + 7)
Label(main_window, text= " ").grid(column= 4, row= counter + 7)
print_details()

def main():
Button(main_window, text= "Quit", command= quit).grid(column= 4, row= 1)
Button(main_window, text= "Print Details", command= print_details).grid(column= 4, row= 2)
Button(main_window, text= "Append Details", command= check_validity).grid(column= 3, row= 2)
Button(main_window, text= "Delete ", command= delete_row).grid(column= 4, row= 5)
Label(main_window, text= "Customer Name: ").grid(column= 0, row= 1)
Label(main_window, text= "Receipt No.: ").grid(column= 0, row= 2)
Label(main_window, text= "Item Hired: ").grid(column= 0, row= 3)
Label(main_window, text= "No. Of Items Hired: ").grid(column= 0, row= 4)
Label(main_window, text= "Row No. : ").grid(column= 2 , row= 5)

main_window.wm_title("Party Hire Shop - Julies")

main_window.mainloop()


number= {'total_entries':0,'counter':0}
hireDetails= []
main_window= tk.Tk()
entry_customer_name= Entry(main_window)
entry_customer_name.grid(column= 1, row= 1)
entry_receipt_number= Entry(main_window)
entry_receipt_number.grid(column= 1, row= 2)
entry_itemHired= Entry(main_window)
entry_itemHired.grid(column= 1, row= 3)
entry_numberOfItemsHired= Entry(main_window)
entry_numberOfItemsHired.grid(column= 1, row=4)
delete_details= Entry(main_window)
delete_details.grid(column= 3, row= 5)


main()
 
Joined
Jul 4, 2023
Messages
463
Reaction score
56
if len(range(int(entry_numberOfItemshired.get()))) in range (1,500
IMO in this line is not necessary: len and range
Python:
if int(entry_numberOfItemshired.get()) in range (1, 500 + 1):
cos Entry will return always value type of String

numberOfItens= int(entry_numberOfItemsHired.get())
if not (1 <= (numberOfItems)<= 500):
just write down
Python:
numberOfItens = int(entry_numberOfItemsHired.get())
if not (minimum_item <= numberOfItems <= maximum_item):
or
Python:
numberOfItens = int(entry_numberOfItemsHired.get())
if not numberOfItems in range(minimum_item, maximum_item + 1):
 
Last edited:
Joined
Jul 4, 2023
Messages
463
Reaction score
56
BTW,
Importing everything from tkinter using
Python:
from tkinter import *
is generally considered bad practice for several reasons:
  • Namespace Pollution: It imports all names (functions, classes, constants) into your current namespace. This can lead to name clashes if you have functions or classes with the same name in your code. For example, if you have a function named Button in your code, it will conflict with tkinter.Button.
  • Readability Concerns: It makes your code less readable because readers (including you in the future) won't immediately know which functions or classes are from tkinter and which are defined in your code.
  • Explicit Imports are Clearer: Explicitly importing what you need (Entry, Button, Label, etc.) makes it clear to anyone reading your code which tkinter components your code is using. This improves readability and helps in maintaining your code in the long term.
  • Avoids Unintended Side Effects: Importing everything using * can lead to unintended side effects if tkinter adds new names in future releases that conflict with names in your code.
On the other hand, importing specific components like Entry, Button, and Label from tkinter
Python:
from tkinter import Entry, Button, Label
is generally preferred because:
  • Clarity: It explicitly states which components you are using from tkinter, making your code easier to understand at a glance.
  • Namespace Control: It avoids polluting your namespace with unnecessary names from tkinter that you might not use.
  • Avoids Conflicts: It reduces the risk of name clashes with your own code or with other libraries that you may be using.
 
Joined
Dec 10, 2022
Messages
91
Reaction score
25
I took an interest in your project. You should learn about classes as they will help a lot in the long run.
I would also recommend using some type of data storage like sqlite, mysql, or json.
Well anyhow here is what I came up with. Hope it helps

Python:
import tkinter as tk
from tkinter.messagebox import showerror
from tkinter import ttk

class Data:
    ''' Data class handles the insert and delete of self.data items '''
    def __init__(self):
        self.data = []


    def _add(self, data):
        ''' Method for adding to list '''
        self.data.append(data)

    def _delete(self, row):
        ''' Method for removing items from list '''
        for index, item in enumerate(self.data):
            if row == item[0]:
                self.data.pop(index)


class Window:
    ''' Window class is for presentation '''
    def __init__(self, parent):
        self.parent = parent
        parent.columnconfigure(0, weight=1)
        parent.rowconfigure(0, weight=1)
        
        # Container for holding widgets
        container = tk.Frame(parent)
        container.grid(column=0, row=0, sticky='news')
        container.grid_columnconfigure(0, weight=3, uniform='columns')
        container.grid_columnconfigure(1, weight=3, uniform='columns')

        # container for hold the widgets on the left
        left = tk.Frame(container)
        left['highlightbackground'] = '#999999'
        left['highlightcolor'] = '#999999'
        left['highlightthickness'] = 1
        left.grid(column=0, row=0, sticky='new', padx=4, pady=4)
        left.grid_columnconfigure(1, weight=3)

        # Container for holding widgets on the right
        right = tk.Frame(container)
        right['highlightbackground'] = '#999999'
        right['highlightcolor'] = '#999999'
        right['highlightthickness'] = 1
        right.grid(column=1, row=0, sticky='new')
        right.grid_columnconfigure(0, weight=3)

        # Items for the labels
        items = ('Customer Name', 'Receipt No.:', 'Item:', 'Amount:')

        # Create the labels
        for index, item in enumerate(items):
            label = tk.Label(left, text=item, font=(None, 11, 'bold'), anchor='w')
            label.grid(column=0, row=index, sticky='new', padx=4, pady=4)

        # Create the entry fields
        self.entries = []
        for index, entry in enumerate(items):
            self.entries.append(tk.Entry(left))
            self.entries[index].grid(column=1, row=index, sticky='new', padx=4, pady=4)

        # Create a treeview
        columns = ('Row', 'Customer', 'Receipt No.', 'Item', 'Amount')
        self.tree = ttk.Treeview(right, columns=columns, show='headings', selectmode='browse')
        for column in columns:
            self.tree.heading(column, text=column)

        for column in columns:
            self.tree.column(column, stretch='no', width=130)
        self.tree.grid(column=0, row=0, sticky='news', padx=4, pady=4)

        # Container for the buttons
        btnframe = tk.Frame(container)
        btnframe['highlightbackground'] = '#999999'
        btnframe['highlightcolor'] = '#999999'
        btnframe['highlightthickness'] = 1
        btnframe.grid(column=0, columnspan=2, row=5, sticky='new', padx=4, pady=8)
        btnframe.grid_columnconfigure(1, weight=3)
        
        # Create the buttons
        self.addbtn = tk.Button(btnframe, text='Add', bg='skyblue', cursor='hand2', )
        self.addbtn.grid(column=0, row=0, sticky='news', padx=4, pady=4)
        self.addbtn.bind('<Enter>', self.e_add)

        self.delbtn = tk.Button(btnframe, text='Delete', bg='orange', cursor='hand2')
        self.delbtn.grid(column=1, row=0, sticky='e', padx=4, pady=4)
        self.delbtn.bind('<Enter>', self.e_del)

        self.exitbtn = tk.Button(btnframe, text='Exit', bg='tomato', cursor='hand2', command=parent.destroy)
        self.exitbtn.grid(column=2, row=0, sticky='e', padx=4,pady=4)
        self.exitbtn.bind('<Enter>', self.e_enter)

    # Methods for giving a hover effect
    def e_enter(self, event):
        self.exitbtn.configure(activebackground='red')

    def e_del(self, event):
        self.delbtn.configure(activebackground='orangered')

    def e_add(self, event):
        self.addbtn.configure(activebackground='powderblue')
        

class Controller:
    ''' Controller class handles communications between window and data class '''
    def __init__(self, data, window):
        self.data = data
        self.window = window

        # Button commands
        self.window.addbtn.configure(command=self._add)
        self.window.delbtn.configure(command=self._delete)

        # So the treeview is loaded with data if any
        self.refresh()

    def _delete(self):
        ''' Method for deleting items from list '''
        try:
            item = self.window.tree.focus()
            row = self.window.tree.item(item)['values'][0]
            self.data._delete(int(row))
            self.refresh()
        except:
            pass

    def _add(self):
        ''' Method for adding items to the list '''
        entries = self.window.entries
        
        customer = entries[0].get()
        receipt = entries[1].get()
        item = entries[2].get()
        amount = entries[3].get()

        # A little error checking
        error = 0
        messages = []

        items = ['spoons', 'forks', 'knives', 'tables', 'chairs', 'cater dishes']

        if not customer:
            messages.append('customer name is required.')
            error += 1

        if not receipt.isnumeric():
            messages.append('receipt no. needs to be digits')
            error += 1

        if item.lower() not in items:
            messages.append(f'Item has to be one of: {", ".join(items)}')
            error += 1


        if not amount.isnumeric():
            messages.append('Amount must be digits')
            error += 1

        elif int(amount) < 1 or int(amount) > 500:
            messages.append('Amount needs to be between 1 and 500')
            error += 1

        # If there are errors display using messagebox
        if error > 0:
            field = 'These fields need' if error > 1 else 'This field needs'
            showerror('Error!', f'{field} to be corrected:\n{"\n".join(messages)}')
            
        # Everything is ok add data to the list
        else:
            row = len(self.data.data)+1
            self.data._add((row, customer, receipt, item, amount))
            
            for index, field in enumerate(self.window.entries):
                self.window.entries[index].delete(0, tk.END)

            self.refresh()
        

    def refresh(self):
        ''' Method for refreshing treeview '''
        for row in self.window.tree.get_children():
            self.window.tree.delete(row)

        # Add data to tree
        for items in self.data.data:
            self.window.tree.insert('', tk.END, values=items)

if __name__ == '__main__':
    root = tk.Tk()
    controller = Controller(Data(), Window(root))
    root.mainloop()
 
Joined
Jul 5, 2024
Messages
4
Reaction score
0
I took an interest in your project. You should learn about classes as they will help a lot in the long run.
I would also recommend using some type of data storage like sqlite, mysql, or json.
Well anyhow here is what I came up with. Hope it helps

Python:
import tkinter as tk
from tkinter.messagebox import showerror
from tkinter import ttk

class Data:
    ''' Data class handles the insert and delete of self.data items '''
    def __init__(self):
        self.data = []


    def _add(self, data):
        ''' Method for adding to list '''
        self.data.append(data)

    def _delete(self, row):
        ''' Method for removing items from list '''
        for index, item in enumerate(self.data):
            if row == item[0]:
                self.data.pop(index)


class Window:
    ''' Window class is for presentation '''
    def __init__(self, parent):
        self.parent = parent
        parent.columnconfigure(0, weight=1)
        parent.rowconfigure(0, weight=1)
       
        # Container for holding widgets
        container = tk.Frame(parent)
        container.grid(column=0, row=0, sticky='news')
        container.grid_columnconfigure(0, weight=3, uniform='columns')
        container.grid_columnconfigure(1, weight=3, uniform='columns')

        # container for hold the widgets on the left
        left = tk.Frame(container)
        left['highlightbackground'] = '#999999'
        left['highlightcolor'] = '#999999'
        left['highlightthickness'] = 1
        left.grid(column=0, row=0, sticky='new', padx=4, pady=4)
        left.grid_columnconfigure(1, weight=3)

        # Container for holding widgets on the right
        right = tk.Frame(container)
        right['highlightbackground'] = '#999999'
        right['highlightcolor'] = '#999999'
        right['highlightthickness'] = 1
        right.grid(column=1, row=0, sticky='new')
        right.grid_columnconfigure(0, weight=3)

        # Items for the labels
        items = ('Customer Name', 'Receipt No.:', 'Item:', 'Amount:')

        # Create the labels
        for index, item in enumerate(items):
            label = tk.Label(left, text=item, font=(None, 11, 'bold'), anchor='w')
            label.grid(column=0, row=index, sticky='new', padx=4, pady=4)

        # Create the entry fields
        self.entries = []
        for index, entry in enumerate(items):
            self.entries.append(tk.Entry(left))
            self.entries[index].grid(column=1, row=index, sticky='new', padx=4, pady=4)

        # Create a treeview
        columns = ('Row', 'Customer', 'Receipt No.', 'Item', 'Amount')
        self.tree = ttk.Treeview(right, columns=columns, show='headings', selectmode='browse')
        for column in columns:
            self.tree.heading(column, text=column)

        for column in columns:
            self.tree.column(column, stretch='no', width=130)
        self.tree.grid(column=0, row=0, sticky='news', padx=4, pady=4)

        # Container for the buttons
        btnframe = tk.Frame(container)
        btnframe['highlightbackground'] = '#999999'
        btnframe['highlightcolor'] = '#999999'
        btnframe['highlightthickness'] = 1
        btnframe.grid(column=0, columnspan=2, row=5, sticky='new', padx=4, pady=8)
        btnframe.grid_columnconfigure(1, weight=3)
       
        # Create the buttons
        self.addbtn = tk.Button(btnframe, text='Add', bg='skyblue', cursor='hand2', )
        self.addbtn.grid(column=0, row=0, sticky='news', padx=4, pady=4)
        self.addbtn.bind('<Enter>', self.e_add)

        self.delbtn = tk.Button(btnframe, text='Delete', bg='orange', cursor='hand2')
        self.delbtn.grid(column=1, row=0, sticky='e', padx=4, pady=4)
        self.delbtn.bind('<Enter>', self.e_del)

        self.exitbtn = tk.Button(btnframe, text='Exit', bg='tomato', cursor='hand2', command=parent.destroy)
        self.exitbtn.grid(column=2, row=0, sticky='e', padx=4,pady=4)
        self.exitbtn.bind('<Enter>', self.e_enter)

    # Methods for giving a hover effect
    def e_enter(self, event):
        self.exitbtn.configure(activebackground='red')

    def e_del(self, event):
        self.delbtn.configure(activebackground='orangered')

    def e_add(self, event):
        self.addbtn.configure(activebackground='powderblue')
       

class Controller:
    ''' Controller class handles communications between window and data class '''
    def __init__(self, data, window):
        self.data = data
        self.window = window

        # Button commands
        self.window.addbtn.configure(command=self._add)
        self.window.delbtn.configure(command=self._delete)

        # So the treeview is loaded with data if any
        self.refresh()

    def _delete(self):
        ''' Method for deleting items from list '''
        try:
            item = self.window.tree.focus()
            row = self.window.tree.item(item)['values'][0]
            self.data._delete(int(row))
            self.refresh()
        except:
            pass

    def _add(self):
        ''' Method for adding items to the list '''
        entries = self.window.entries
       
        customer = entries[0].get()
        receipt = entries[1].get()
        item = entries[2].get()
        amount = entries[3].get()

        # A little error checking
        error = 0
        messages = []

        items = ['spoons', 'forks', 'knives', 'tables', 'chairs', 'cater dishes']

        if not customer:
            messages.append('customer name is required.')
            error += 1

        if not receipt.isnumeric():
            messages.append('receipt no. needs to be digits')
            error += 1

        if item.lower() not in items:
            messages.append(f'Item has to be one of: {", ".join(items)}')
            error += 1


        if not amount.isnumeric():
            messages.append('Amount must be digits')
            error += 1

        elif int(amount) < 1 or int(amount) > 500:
            messages.append('Amount needs to be between 1 and 500')
            error += 1

        # If there are errors display using messagebox
        if error > 0:
            field = 'These fields need' if error > 1 else 'This field needs'
            showerror('Error!', f'{field} to be corrected:\n{"\n".join(messages)}')
           
        # Everything is ok add data to the list
        else:
            row = len(self.data.data)+1
            self.data._add((row, customer, receipt, item, amount))
           
            for index, field in enumerate(self.window.entries):
                self.window.entries[index].delete(0, tk.END)

            self.refresh()
       

    def refresh(self):
        ''' Method for refreshing treeview '''
        for row in self.window.tree.get_children():
            self.window.tree.delete(row)

        # Add data to tree
        for items in self.data.data:
            self.window.tree.insert('', tk.END, values=items)

if __name__ == '__main__':
    root = tk.Tk()
    controller = Controller(Data(), Window(root))
    root.mainloop()
could you explain the use of classes pls? im new to python so im unsure of what their purpose are
 
Joined
Jul 5, 2024
Messages
4
Reaction score
0
IMO in this line is not necessary: len and range
Python:
if int(entry_numberOfItemshired.get()) in range (1, 500 + 1):
cos Entry will return always value type of String


just write down
Python:
numberOfItens = int(entry_numberOfItemsHired.get())
if not (minimum_item <= numberOfItems <= maximum_item):
or
Python:
numberOfItens = int(entry_numberOfItemsHired.get())
if not numberOfItems in range(minimum_item, maximum_item + 1):
thank you, will give it a go
 
Joined
Jul 5, 2024
Messages
4
Reaction score
0
Unfortunately, I do not have enough time to change much of my program and I am still having trouble with it. The user input input is not being converted into an integer on numberOfItems= int(entry_numberOfItemsHired.get()) so the program is not checking if the user input is in range of (1,501). I don't how to implement a solution.

Code:
def check_validity():  #make it so numberOfItemsHired is converted into string
    global items
    items= ["Spoons", "Forks" , "Knives" , "Tables" , "Chairs" , "Cater Dishes"]
    valid= 0

    if(entry_customer_name.get().isalpha()) and (entry_receipt_number.get().isnumeric()) and (entry_itemHired.get()) and (entry_numberOfItemsHired.get().isdigit()) != 0:
        if (int(entry_receipt_number.get())) in range (1,99999999):
            valid= 1
        else:
           Label(main_window, text= "Receipt Number is invalid. Only 8 digits needed.", bg= 'red').grid(column= 2, row= 2, sticky= "W")
           if (entry_itemHired.get()) in items:
               valid= 1
           else:
               Label(main_window, text= "Choose Item Hired: Spoons, Forks, Knives, Tables, Chairs, Cater Dishes.", bg= 'red').grid(column= 2, row= 3, sticky= "W")

               if (entry_numberOfItemsHired.get().isdigit()) == True:
                   numberOfItems= int(entry_numberOfItemsHired.get())
                   if numberOfItems in range (1,501) == True:
                       valid= 1


    else:
        if len(entry_customer_name.get()) == 0:
            Label(main_window, text= "Enter Customer Name. No numbers allowed.", bg= 'red').grid(column= 2, row= 1, sticky= "W")
        else:
            Label(main_window, text= "                                                           ").grid(column= 2, row= 1, sticky= "W")                                       
            if not(entry_customer_name.get().isalpha()):
                Label(main_window, text= "No numbers allowed.", bg= 'red').grid(column= 2, row= 1, sticky= "W")

            
        if len(entry_receipt_number.get()) == 0:
            Label(main_window, text= "Receipt Number is invalid. Use digits.", bg= 'red').grid(column= 2, row= 2, sticky= "W")
        else:
            Label(main_window, text= "                                                           ").grid(column= 2, row= 2, sticky= "W")
            if not(entry_receipt_number.get().isnumeric()):
                Label(main_window, text= "Receipt Number is invalid. Use digits.", bg= 'red').grid(column= 2, row= 2, sticky= "W")
            elif (int(entry_receipt_number.get())) not in range (1,99999999):#works but needs enhancement
                Label(main_window, text= "Receipt Number is invalid. Only 8 digits needed.", bg= 'red').grid(column= 2, row= 2, sticky= "W")

            
        if len(entry_itemHired.get()) == 0:
            Label(main_window, text= "Choose Item Hired: Spoons, Forks, Knives, Tables, Chairs, Cater Dishes.", bg= 'red').grid(column= 2, row= 3, sticky= "W")
        else:
            Label(main_window, text= "                                                           ").grid(column= 2, row= 3, sticky= "W")
            if (entry_itemHired.get()) not in items:
                Label(main_window, text= "Choose Item Hired: Spoons, Forks, Knives, Tables, Chairs, Cater Dishes.", bg= 'red').grid(column= 2, row= 3, sticky= "W")

        
        if (entry_numberOfItemsHired.get().isdigit()) == False:
            Label(main_window, text= "Only 1-500 items allowed to be hired. Use Digits", bg= 'red').grid(column= 2, row= 4, sticky= "W")
        else:
            Label(main_window, text= "                                                           ").grid(column= 2, row= 4, sticky= "W")
            numberOfItems= int(entry_numberOfItemsHired.get())#code skips to this line/not transforming this into integer
            if numberOfItems in range (1,501) == False:
                Label(main_window, text= "Only 1-500 items allowed to be hired.", bg= 'red').grid(column= 2, row= 4, sticky= "W")
                valid= 0
            else:
                Label(main_window, text= "                                                           ").grid(column= 2, row= 4, sticky= "W")
            valid= 0
    print(type(entry_numberOfItemsHired.get()))
    print(type(entry_receipt_number.get()))

    if valid == 1:
        append_details()
        Label(main_window, text= "Customer Name: ").grid(column= 0, row= 1)
        Label(main_window, text= "Receipt No.: ").grid(column= 0, row= 2)
        Label(main_window, text= "Item Hired: ").grid(column= 0, row= 3)
        Label(main_window, text= "No. of Items Hired: ").grid(column= 0, row= 4)
        Label(main_window, text= "                                                                      ").grid(column= 2, row= 1, sticky= "W")
        Label(main_window, text= "                                                                      ").grid(column= 2, row= 2, sticky= "W")
        Label(main_window, text= "                                                                      ").grid(column= 2, row= 3, sticky= "W")
        Label(main_window, text= "                                                                      ").grid(column= 2, row= 4, sticky= "W")
 
Joined
Dec 10, 2022
Messages
91
Reaction score
25
You are creating new label every time. That is not a very good way. You should just create one label and change the text as needed. Also instead of doing Label().grid() will cause problems. Should be something like
some_label = Label()
some_label.grid()
That is just some of the things I noticed at a glance. Here is the final code I came up with.
Using sqlite3 as a data storage

Python:
import tkinter as tk
from tkinter.messagebox import showerror
from tkinter import ttk
import os
from PIL import Image, ImageTk
import sqlite3 as sq


class Data:
    ''' Data class handles the database queries '''
    def __init__(self):
        path = os.path.realpath(os.path.dirname(__file__))
        self.connect = sq.connect(f'{path}/test.db')
        self.cursor = self.connect.cursor()

    def create(self):
        query = '''
            create table if not exists mytable (
            id integer primary key,
            customer text not null,
            receipt integer,
            item text not null,
            amount integer not null
            )
        '''
        self.connect.execute(query)
        self.connect.commit()


    def getdata(self):
        query = 'select * from mytable order by id desc'
        return self.cursor.execute(query).fetchall()

    def getreceipt(self):
        query = 'select receipt from mytable order by receipt desc limit 1'
        res = self.cursor.execute(query).fetchone()
        return res

    def _add(self, data):
        ''' Method for adding to list '''
        query = '''insert into mytable (customer, item, amount)
                    values (?,?,?)'''
        self.cursor.execute(query, data)
        self.connect.commit()

        query = 'update mytable set receipt = id'
        self.cursor.execute(query)
        self.connect.commit()

    def _delete(self, receipt):
        ''' Method for removing items from list '''
        query = f'delete from mytable where receipt = {receipt}'
        self.cursor.execute(query)
        self.connect.commit()


class Window:
    ''' Window class is for presentation '''
    def __init__(self, parent):
        self.parent = parent
        parent.columnconfigure(0, weight=1)
        parent.rowconfigure(0, weight=1)
       
        # Container for holding widgets
        container = tk.Frame(parent)
        container.grid(column=0, row=0, sticky='news')
        container.grid_columnconfigure(0, weight=3, uniform='columns')
        container.grid_columnconfigure(1, weight=3, uniform='columns')

        header = tk.Frame(container)
        header['bg'] = 'slateblue'
        header['highlightbackground'] = '#999999'
        header['highlightcolor'] = '#999999'
        header['highlightthickness'] = 1
        header.grid(column=0, columnspan=2, row=0, sticky='news', padx=4, pady=(2,4))
        header.grid_columnconfigure(0, weight=3)


        self.text = 'Party Hire Shop'
       
        self.canvas = tk.Canvas(header, bg='#D7D2CB', height=80)
        self.canvas.grid(column=0, row=0, sticky='news')
        self.shadow = self.canvas.create_text((0,0), text=self.text, \
            font=('comic sans ms', 35, 'bold'), fill='#333333')

        self._text = self.canvas.create_text((0,0), text=self.text, \
            font=('comic sans ms', 35, 'bold'), fill='#FFAA00')        
       
        # container for hold the widgets on the left
        left = tk.Frame(container)
        left['highlightbackground'] = '#999999'
        left['highlightcolor'] = '#999999'
        left['highlightthickness'] = 1
        left.grid(column=0, row=1, sticky='news', padx=4, pady=(2,4))
        left.grid_columnconfigure(1, weight=3)

        # Container for holding widgets on the right
        right = tk.Frame(container)
        right['highlightbackground'] = '#999999'
        right['highlightcolor'] = '#999999'
        right['highlightthickness'] = 1
        right.grid(column=1, row=1, rowspan=2, sticky='news', pady=(2,4))
        right.grid_columnconfigure(0, weight=3)

        # Items for the labels
        items = ('Customer Name', 'Receipt No.:', 'Item:', 'Amount:')

        # Create the labels
        for index, item in enumerate(items):
            label = tk.Label(left, text=item, font=(None, 11, 'bold'), anchor='w')
            label.grid(column=0, row=index, sticky='new', padx=4, pady=4)

        # Create the entry fields
        self.entries = []
        for index, entry in enumerate(items):
            self.entries.append(tk.Entry(left))
            self.entries[index].grid(column=1, row=index, sticky='new', padx=4, pady=4)

        # Create a container to hold the logos
        self.logoframe = tk.Frame(container, pady=8)
        self.logoframe['highlightbackground'] = '#999999'
        self.logoframe['highlightcolor'] = '#999999'
        self.logoframe['highlightthickness'] = 1
        self.logoframe.grid(column=0, row=2, sticky='news', padx=4, pady=4)
        self.logoframe.grid_rowconfigure(0, weight=3)
               
        # Add the powered by text
        label = tk.Label(self.logoframe, text='Powered By:', font=(None, 14, 'bold'))
        label.grid(column=0, row=0, sticky='news', padx=8, pady=8)

        # Create a treeview
        style = ttk.Style()
        style.configure('Treeview', rowheight=25, font=(None, 10, 'normal'))
        columns = ('Customer', 'Receipt No.', 'Item', 'Amount')
        self.tree = ttk.Treeview(right, columns=columns, show='headings', selectmode='browse')
        for column in columns:
            self.tree.heading(column, text=column)

        for column in columns:
            self.tree.column(column, stretch='yes', width=130)
        self.tree.grid(column=0, row=0, rowspan=2, sticky='news', padx=4, pady=4)

        # Create a scrollbar
        self.scrollbar = ttk.Scrollbar(right, orient='vertical', command=self.tree.yview)
        self.scrollbar.grid(column=1, row=0, rowspan=2, sticky='ns', padx=2, pady=4)
        self.tree.configure(yscrollcommand=self.scrollbar.set)


        # Container for the buttons
        btnframe = tk.Frame(container)
        btnframe['highlightbackground'] = '#999999'
        btnframe['highlightcolor'] = '#999999'
        btnframe['highlightthickness'] = 1
        btnframe.grid(column=0, columnspan=2, row=53, sticky='new', padx=4, pady=8)
        btnframe.grid_columnconfigure(1, weight=3)
       
        # Create the buttons
        self.addbtn = tk.Button(btnframe, text='Add', bg='skyblue', cursor='hand2', )
        self.addbtn.grid(column=0, row=0, sticky='news', padx=4, pady=4)
        self.addbtn.bind('<Enter>', self.e_add)

        self.delbtn = tk.Button(btnframe, text='Delete', bg='orange', cursor='hand2')
        self.delbtn.grid(column=1, row=0, sticky='e', padx=4, pady=4)
        self.delbtn.bind('<Enter>', self.e_del)

        self.exitbtn = tk.Button(btnframe, text='Exit', bg='tomato', cursor='hand2', command=parent.destroy)
        self.exitbtn.grid(column=2, row=0, sticky='e', padx=4,pady=4)
        self.exitbtn.bind('<Enter>', self.e_enter)

        # Display the logos
        self.get_images()

        self.parent.update()

        self.header_text()

    def header_text(self):
        x = self.canvas.winfo_width()/2
        y = self.canvas.winfo_height()/2

        self.canvas.move(self.shadow, x ,y-2)
        self.canvas.move(self._text, x-2, y-4)    

    # Methods for giving a hover effect and adding the logos
    def e_enter(self, event):
        self.exitbtn.configure(activebackground='red')

    def e_del(self, event):
        self.delbtn.configure(activebackground='orangered')

    def e_add(self, event):
        self.addbtn.configure(activebackground='powderblue')

    def get_images(self):
        ''' Method grabs the logos '''
        # Images that are not wanted in the powered by group
        unwanted = ('plate.jpg')
       
        path = f'{os.path.realpath(os.path.dirname(__file__))}/images'
        logos = os.listdir(path)
        for index, logo in enumerate(logos):
            if logo not in unwanted:
                image = Image.open(f'{path}/{logo}')
                image = image.resize((80,30))
                image = ImageTk.PhotoImage(image)
                label = tk.Label(self.logoframe, image=image)
                label.grid(column=index+1, row=0, sticky='news',padx=8, pady=8)
                label.image = image
       

class Controller:
    ''' Controller class handles communications between window and data class '''
    def __init__(self, data, window):

        # Make the Data and Window classes available for Controller class
        self.data = data
        self.window = window

        # Create the database if not exist
        self.data.create()

        # Set disabled colors for receipt entry field
        self.window.entries[1].configure(disabledbackground='white', disabledforeground='black')

        # Button commands
        self.window.addbtn.configure(command=self._add)
        self.window.delbtn.configure(command=self._delete)

        # Load treeview with data if any
        self.refresh()

    def _delete(self):
        ''' Method for deleting items from database '''

        # Set the state of receipt field to normal and clear all fields
        self.window.entries[1]['state'] = 'normal'
        for entry in self.window.entries:
            entry.delete(0, tk.END)

        # Try block for getting selected item then delete from database
        try:          
            item = self.window.tree.focus()
            receipt = self.window.tree.item(item)['values'][1]
            self.data._delete(receipt)

            # Refresh treeview
            self.refresh()
        except:
            pass

    def _add(self):
        ''' Method for adding items to the list '''

        # Get the form fields
        entries = self.window.entries
       
        # seperate for easier handling
        customer = entries[0].get()
        item = entries[2].get()
        amount = entries[3].get()

        # A little error checking
        error = 0
        messages = []

        # Available items
        items = ['spoons', 'forks', 'knives', 'tables', 'chairs', 'cater dishes']

        # Customer name required
        if not customer:
            messages.append('Customer name is required.')
            error += 1

        # Item must be in the available items list
        if item.lower() not in items:
            messages.append(f'Item has to be one of: {", ".join(items)}')
            error += 1

        # Try block for checking for positive numbers and within 1 - 500
        try:
            amount = int(amount)
            if amount < 0:
                messages.append('Amount can not be a negative number')
                error += 1
            if amount < 1 or amount > 500:
                messages.append('Amount must be between 1 and 500')
                error += 1
        except ValueError:
            messages.append('Amount must be a whole number')
            error += 1

        # If there are errors display using messagebox
        if error > 0:
            field = 'These fields need' if error > 1 else 'This field needs'
            showerror('Error!', f'{field} to be corrected:\n{"\n".join(messages)}')
           
        # Everything is ok add data to the database
        else:
            # Clear all form fields
            self.window.entries[1]['state'] = 'normal'
            for entry in self.window.entries:
                entry.delete(0, tk.END)

            # Add data to database
            self.data._add((customer,item,amount))

            # Refresh the treeview
            self.refresh()

    def refresh(self):
        ''' Method for refreshing treeview '''

        # Set the receipt field to normal
        self.window.entries[1]['state'] = 'normal'

        # Clear the treeview
        for row in self.window.tree.get_children():
            self.window.tree.delete(row)

        # self.window.tree.tag_configure('odd', background='lightyellow')
        self.window.tree.tag_configure('even', background='#DBD7D2')

        # Repopulate treeview with current data
        for index, items in enumerate(self.data.getdata()):
            data = (items[1].title(), f'{items[2]:09}',
                    items[3], items[4])
            if index % 2 == 0:
                self.window.tree.insert('', tk.END, values=data, tags=('even',))
            else:
                self.window.tree.insert('', tk.END, values=data)

        # This is used to increase receipt value in form
        # Format to have leading zeros
        # Disable the field so it can't be changed
        receipt = 1 if self.data.getreceipt() == None else self.data.getreceipt()[0]+1
        self.window.entries[1].insert(tk.END, f'{receipt:09}')
        self.window.entries[1]['state'] = 'disabled'


if __name__ == '__main__':
    root = tk.Tk()

    path = f'{os.path.realpath(os.path.dirname(__file__))}/images'
    icon = Image.open(f'{path}/plate.jpg')
    # icon = icon.resize((64,64))
    icon = ImageTk.PhotoImage(icon)
    root.iconphoto(False, icon)

    root.title('Party Hire Shop')
    root.resizable(False, False)
    controller = Controller(Data(), Window(root))
    root.mainloop()
 

Attachments

  • Kazam_screenshot_00000.png
    Kazam_screenshot_00000.png
    52.3 KB · Views: 12
Joined
Jul 4, 2023
Messages
463
Reaction score
56
Little bit different GUI layout based on code from @menator01 ;)
Python:
import tkinter as tk
from tkinter import ttk

class Data:
    ''' Data class handles the insert and delete of self.data items '''
    def __init__(self):
        self.data = []

    def _add(self, data):
        ''' Method for adding to list '''
        if self.data: # Get the largest id from existing rows
            id = max(item[0] for item in self.data) + 1
        else: # If the list is empty, start numbering from 1
            id = 1
        self.data.append((id, ) + data)

    def _delete(self, row):
        ''' Method for removing items from list '''
        for index, item in enumerate(self.data):
            if row == item[0]:
                self.data.pop(index)
                break  # Exit the loop after removing the item


class Window:
    ''' Window class is for presentation '''
    def __init__(self, parent):
        self.parent = parent
        parent.columnconfigure(0, weight=1)
        parent.rowconfigure(0, weight=1)

        self.parent.wm_title('Party Hire Shop - Julies')      
        self.parent.resizable(False, False) # Make the window non-resizable

        # Constans for gui belowe ;-)
        CONTAINER_COUNT = 4
        FRAME_PAD       = 5
        ENTRY_WIDTH     = 40
        SHOWERROR_WIDTH = 30
        BUTTON_WIDTH    = 10
        BUTTON_R_PAD    = (0, (FRAME_PAD * 2))

        # Container for holding widgets
        container = tk.Frame(parent)
        container.grid(column=0, row=0, sticky='news')
        for row in range(CONTAINER_COUNT):
            container.grid_rowconfigure(row, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = []
        for index in range(CONTAINER_COUNT):
            frame = tk.Frame(container)
            frame['highlightbackground'] = '#999999'
            frame['highlightcolor'] = '#999999'
            frame['highlightthickness'] = 0
            frame.grid(column=0, row=index, sticky='new', padx=FRAME_PAD, pady=FRAME_PAD)
            frame.grid_rowconfigure(0, weight=1)
            frame.grid_columnconfigure(0, weight=1)
            self.frames.append(frame)

        self.frames[0]['highlightthickness'] = 1 # Visible border for the entries frame
        self.frames[2]['highlightthickness'] = 1 # Visible border for the treeview frame

        # Text for the labels
        labels = ( 'Customer name', 'Receipt no.', 'Item', 'Amount' )
        # Create the Labels
        for index, text in enumerate(labels):
            label = tk.Label(self.frames[0], text=(text + ':'), font=(None, 10, 'bold'))
            label.grid(column=0, row=index, sticky='e', padx=FRAME_PAD, pady=FRAME_PAD)

        # Create the Entry fields
        self.entries = []
        for index, entry in enumerate(labels):
            entry = tk.Entry(self.frames[0], width=ENTRY_WIDTH)
            entry.grid(column=1, row=index, sticky='ew', padx=FRAME_PAD, pady=FRAME_PAD)
            self.entries.append(entry)
           
        # Create the Labels for error(s) message(s)
        self.showerror = []
        for index, label in enumerate(labels):
            label = tk.Label(self.frames[0], text='', fg='orangered', width=SHOWERROR_WIDTH, anchor='w')
            label['font'] = (None, 10, 'normal')
            label.grid(column=2, row=index, sticky='e', padx=FRAME_PAD, pady=FRAME_PAD)
            self.showerror.append(label)

        # Create a combobox (dropdown menu)
        items = [ 'Spoons', 'Forks', 'Knives', 'Tables', 'Chairs', 'Cater Dishes' ] # The Items should be loaded, e.g., from a file or database    
        self.combo = ttk.Combobox(self.frames[0], values=items)
        self.combo.grid(column=1, row=2, sticky='ew', padx=FRAME_PAD, pady=FRAME_PAD)
        self.combo.bind('<<ComboboxSelected>>', lambda e: self.combo__onSelect(e))

        # Create the buttons
        self.button_add = tk.Button(self.frames[1], text='Add', width=BUTTON_WIDTH, bg='skyblue', cursor='hand2', )
        self.button_add.grid(column=0, row=0, sticky='e', padx=BUTTON_R_PAD, pady=0)
        self.button_add.bind('<Enter>', lambda e: self.button__hover(e, 'powderblue'))
       
        self.button_clear = tk.Button(self.frames[1], text='Clear', width=BUTTON_WIDTH, bg='orange', cursor='hand2', )
        self.button_clear.grid(column=1, row=0, sticky='e', padx=0, pady=0)
        self.button_clear.bind('<Enter>', lambda e: self.button__hover(e, 'orangered'))

        self.button_delete = tk.Button(self.frames[3], text='Delete', width=BUTTON_WIDTH, bg='orange', cursor='hand2', )
        self.button_delete.grid(column=0, row=0, sticky='e', padx=BUTTON_R_PAD, pady=0)
        self.button_delete.bind('<Enter>', lambda e: self.button__hover(e, 'orangered'))

        self.button_exit = tk.Button(self.frames[3], text='Exit', width=BUTTON_WIDTH, bg='tomato', cursor='hand2')
        self.button_exit.grid(column=2, row=0, sticky='e', padx=0,pady=0)
        self.button_exit.bind('<Enter>', lambda e: self.button__hover(e, 'red'))          

        # Create a treeview
        columns = ( 'Id', ) + labels
        self.tree = ttk.Treeview(self.frames[2], columns=columns, show='headings', selectmode='browse')
       
        for column in columns:
            self.tree.heading(column, anchor='center', text=column)
            self.tree.column(column, stretch='no', anchor='center', width=130)
        self.tree.grid(column=0, row=0, sticky='we', padx=0, pady=0)
        self.tree.tag_configure('even_row', background='#DDDDDD') # Alternate color for every even row

        # Create a vertical scrollbar
        vertical_scrollbar = ttk.Scrollbar(self.frames[2], orient="vertical", command=self.tree.yview)
        vertical_scrollbar.grid(column=1, row=0, sticky='ns')
        self.tree.configure(yscrollcommand=vertical_scrollbar.set)

        # Set focus to the first entry field
        if self.entries[0]:
            self.entry__focus(self.entries[0])

    # Method for giving a hover effect
    def button__hover(self, event, color):
        event.widget.configure(activebackground=color)

    # Set focus to the specified entry field
    def entry__focus(self, entry):
        entry.focus_set()

    def combo__onSelect(self, event):
        self.entries[2].delete(0, tk.END) # Item entry
        self.entries[2].insert(0, event.widget.get()) # From Item combo to Item entry
        self.entry__focus(self.entries[3]) # Set focus to the Amount entry


class Controller:
    ''' Controller class handles communications between window and data class '''
    def __init__(self, data, window):
        self.data = data
        self.window = window
       
        # Button commands
        self.window.button_add.configure(command=self._add)
        self.window.button_clear.configure(command=self._clear)
        self.window.button_delete.configure(command=self._delete)
        self.window.button_exit.configure(command=self._exit)

        self.tree__refresh() # So the treeview is loaded with data if any

    def _add(self): # Method for adding items to the list
        entries = self.window.entries

        customer = self.clean_entry(entries[0].get())
        receipt  = self.clean_entry(entries[1].get())
        item     = entries[2].get()
        amount   = self.clean_entry(entries[3].get())
       
        MIN_AMOUNT = 1
        MAX_AMOUNT = 500
        LEADING    = 8 # Constant for leading zeros
        error = False
        self.showerror__refresh()

        if not customer:
            self.window.showerror[0]['text'] = 'Customer name is required.'
            error = True
        if not receipt.isnumeric():
            self.window.showerror[1]['text'] = 'Receipt no. needs to be digits'
            error = True
        if not item:
            self.window.showerror[2]['text'] = 'Item is required.'
            error = True
        if not amount.isnumeric():
            self.window.showerror[3]['text'] = 'Amount needs to be digit(s)'
            error = True
        elif not int(amount) in range(MIN_AMOUNT, MAX_AMOUNT + 1):
            self.window.showerror[3]['text'] = f'Amount needs to be between {MIN_AMOUNT} and {MAX_AMOUNT}'
            error = True

        if not error: # Everything is ok add data to the list
            self.data._add((customer, f'{receipt:0>{LEADING}}', item, amount))
            self.tree__refresh()          

    def _clear(self):
        entries = self.window.entries      
        for index in range(len(entries)):
            entries[index].delete(0, tk.END)
           
        self.window.combo.set('') # Reset the Item combobox
        self.showerror__refresh()
        self.window.entry__focus(entries[0]) # Set focus to the first entry field

    def _delete(self): # Method for deleting items from list
        try:
            row = self.window.tree.focus()
            index = self.window.tree.item(row)['values'][0]
            self.data._delete(int(index))
            self.tree__refresh()
        except:
            pass

    def _exit(self):
        self.window.parent.destroy()

    def clean_entry(self, value):
        return value.strip(' \n\t\r_')

    def showerror__refresh(self):
        for row in range(len(self.window.entries)):
            self.window.showerror[row]['text'] = ''      

    def tree__refresh(self): # Method for refreshing treeview      
        for row in self.window.tree.get_children():
            self.window.tree.delete(row)
        for index, item in enumerate(self.data.data): # Add data to tree
            if index % 2 == 0:
                self.window.tree.insert('', tk.END, values=item, tags=('even_row',))
            else:
                self.window.tree.insert('', tk.END, values=item)


if __name__ == '__main__':
    root = tk.Tk()
    controller = Controller(Data(), Window(root))
    root.mainloop()

1720830537617.png


You can compare both codes and learn how to make changes to the code to get a different effect for GUI.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,922
Messages
2,570,047
Members
46,475
Latest member
RacheleGri

Latest Threads

Top