Visitors Details

Visitors Details

Above UI we are going to create by Tkinter for Entry/Exit Visitor Details in our Security management system desktop application. For that first we create a window and configure its title, size and color. Here we are creating a window at Top Level so we can add this window at the top of any other window.

    
    root = tk.Toplevel()
    root.title("Add Visitors")

    root.configure(bg="#585858")
    root.resizable(width=0, height=0)
    win_width = 1280
    print(1280 * 56.25 / 100)
    win_height = int(1280 * 52 / 100)
    root.geometry(str(win_width) + "x" + str(win_height))
    Util.center(root)
        
    # Get screen size
    screen_width = self.winfo_screenwidth()
    screen_height = self.winfo_screenheight()
    Util.set_font_size(screen_width, screen_height, win_width, win_height)

    self.width = win_width * 96 / 100
    self.height = win_height * 94 / 100
    

After creation of window, we will add a canvas background.

    
    bg_canvas = RoundBackgroundFrame(root, self.width, self.height, padding, cornerradius, color_2, "#585858")
    bg_canvas.place(width=self.width, height=self.height, x=win_width / 2 - self.width / 2,
                        y=win_height / 2 - self.height / 2)

class RoundBackgroundFrame(tk.Canvas):

    def __init__(self, parent, width, height, padding, cornerradius, color, bg):
        tk.Canvas.__init__(self, parent, borderwidth=0, relief="flat", highlightthickness=0, bg=bg)
        self.width = width
        self.height = height
        self.padding = padding
        self.cornerradius = cornerradius
        self.color = color

        original = Image.open("images/corner_green.png")
        resized = original.resize((int(40), int(40)), Image.ANTIALIAS)
        self.image_r_t = ImageTk.PhotoImage(resized)

        original = original.rotate(90, expand=0)
        resized = original.resize((int(40), int(40)), Image.ANTIALIAS)
        self.image_l_t = ImageTk.PhotoImage(resized)

        # original = Image.open("images/corner.png")
        original = original.rotate(90, expand=0)
        resized = original.resize((int(40), int(40)), Image.ANTIALIAS)
        self.image_l_b = ImageTk.PhotoImage(resized)

        original = original.rotate(90, expand=0)
        resized = original.resize((int(40), int(40)), Image.ANTIALIAS)
        self.image_r_b = ImageTk.PhotoImage(resized)

        self.shape(width, height, padding, cornerradius, color)
        (x0, y0, x1, y1) = self.bbox("all")
        width = (x1 - x0)
        height = (y1 - y0)
        self.configure(width=width, height=height)

    def shape(self, width, height, padding, cornerradius, color):
        self.create_polygon((padding, height - cornerradius - padding, padding, cornerradius + padding,
                            padding + cornerradius, padding, width - padding - cornerradius, padding,
                            width - padding, cornerradius + padding, width - padding,
                            height - cornerradius - padding, width - padding - cornerradius, height - padding,
                            padding + cornerradius, height - padding), fill=color, outline=color)

        self.create_image(width - self.image_r_t.width(), 0, image=self.image_r_t, anchor=NW)
        self.create_image(0, 0, image=self.image_l_t, anchor=NW)
        self.create_image(0, height - self.image_l_b.width(), image=self.image_l_b, anchor=NW)
        self.create_image(width - self.image_r_b.width(), height - self.image_r_b.width(), image=self.image_r_b,
                        anchor=NW)

    

Once your window is created with custom background, we will create a frame with some reduced dimensions.

    
    self.width = self.width * 98 / 100
    self.height = self.height * 96 / 100
    self.base_frame = Frame(root, width=self.width, height=self.height, bg=self.color)
    bg_canvas.create_window(self.width / 100, self.height * 2 / 100, anchor=NW, window=self.base_frame)


    # Add Heading Name
    add_heading_label(self.base_frame, self.color, AppConstant.FONT_SIZE, self.height, self.width)

    def add_heading_label(base_frame, color, font_size, height, width):
        label_heading = Label(base_frame, text="ENTRY / EXIT VISITOR", anchor=CENTER, bg=color,
                              font=("Lucida Grande", int(font_size * 120 / 100)))
        label_heading.place(width=width * 90 / 100, height=height * 7 / 100, x=width * 5 / 100, y=height * 1.5 / 100)

    # Add line
    add_line_border(self.base_frame, self.color, self.height, self.width)

    def add_line_border(base_frame, color, height, width):
        line_canvas = Canvas(base_frame, bg=color, borderwidth=0, relief="flat", highlightthickness=0)
        line_canvas.place(width=width - 4, height=5, x=2, y=height * 10 / 100)
        line_canvas.create_line(0, 0, width, 0, fill="#787878")


    action_frame = add_action_frame(self, self.base_frame, self.color, self.height, self.width)

    def add_action_frame(self, base_frame, color, height, width):
        afw = width * 95 / 100
        afh = height * 20 / 100
        button_font = ("Lucida Grande", AppConstant.FONT_SIZE - 6)
        label_frame_action = LabelFrame(base_frame, text="Actions", font=button_font, pady=afw * 2 / 100,
                                        padx=afw * 2 / 100, bg=color)
        label_frame_action.place(width=afw, height=afh, x=width * 2.5 / 100, y=height * 0.12)
        return label_frame_action

    self.search_frame = add_search_frame(self.base_frame, self.color, self.height, self.width)

    def add_search_frame(base_frame, color, height, width):
        sfw = width * 95 / 100
        sfh = height * 60 / 100
        button_font = ("Lucida Grande", AppConstant.FONT_SIZE - 6)
        label_frame_search = LabelFrame(base_frame, text="Search", font=button_font, pady=sfw * 2 / 100,
                                        padx=sfw * 2 / 100, bg=color)
        label_frame_search.place(width=sfw, height=sfh, x=width * 2.5 / 100, y=height * 0.12 + height * 22 / 100)
        
    

Now We create Add Visitor UI in Action Frame.

    
    self.visitor_name = CustomEntrySimple(action_frame, entry_width, entry_height, ("Lucida Grande", text_size),
                                          self.color,
                                          "Visitor Name")
    self.visitor_name.place(x=20, y=pos_y)
    self.visitor_contact_number = CustomEntrySimple(action_frame, entry_width, entry_height,
                                                    ("Lucida Grande", text_size), self.color,
                                                    "Visitor Contact Number")
    self.visitor_contact_number.place(x=entry_width * 3 / 2, y=pos_y)
    self.visiting_flat_no = CustomEntrySimple(action_frame, entry_width, entry_height, ("Lucida Grande", text_size),
                                              self.color,
                                              "Visiting Flat No")
    self.visiting_flat_no.place(x=2 * entry_width + entry_width * 90 / 100, y=pos_y)
    self.visiting_flat_no.entry.bind('', self.search_flat)
    self.show_add_visitor_button()
        
    

Here is our class CustomEntrySimple:

    
    class CustomEntrySimple(tk.Canvas):

        def __init__(self, parent, width, height, font, color, text):
            tk.Canvas.__init__(self, parent, borderwidth=0, relief="flat", highlightthickness=0, bg=color)

            self.width = width
            self.height = height
            self.color = color

            self.create_text(6, 6, anchor=W, font=font, text=text, fill="#000000")
            self.create_line(5, height - 8, width - 5, height - 8, fill="#808080")

            frame = Frame(parent, width=width * 95 / 100, height=height * 50 / 100)
            self.entry = Entry(frame, bg=color, bd=0, highlightthickness=0, font=font)

            self.entry.place(relwidth=1, relheight=1, x=0, y=0)

            self.create_window(6, height / 2 - (height * 50 / 100) / 2, anchor=NW, window=frame)
            self.update()

            (x0, y0, x1, y1) = self.bbox("all")
            width = (x1 - x0)
            height = (y1 - y0)
            self.configure(width=width, height=height)
    

Create a "ADD VISITOR" button in Action Frame.

    
    def show_add_visitor_button(self):
        self.add_button = RoundedButton(self.base_frame, self.width * 12 / 100, self.width * 3 / 100, self.color,
                                        "images/button3.png",
                                        "ADD VISITOR",
                                        font=("Lucida Grande", int(AppConstant.FONT_SIZE * 75 / 100)),
                                        command=self.add_visitor_click)
        self.add_button.place(x=self.width * 82 / 100, y=self.height * 20 / 100)

    class RoundedButton(tk.Canvas):

        def __init__(self, parent, width, height, bg, icon_path, text, font, command=None):
            tk.Canvas.__init__(self, parent, borderwidth=0, relief="flat", highlightthickness=0, bg=bg)
            self.command = command
            self.width = width
            self.height = height
            self.text = text
            self.font = font

            original = Image.open(icon_path)
            resized = original.resize((int(width), int(height)), Image.ANTIALIAS)
            self.image = ImageTk.PhotoImage(resized)

            self.shape(width, height)
            (x0, y0, x1, y1) = self.bbox("all")
            width = (x1 - x0)
            height = (y1 - y0)
            self.configure(width=width, height=height)
            self.bind("", self._on_press)
            self.bind("", self._on_release)

        def shape(self, width, height):
            self.create_image(0, 0, image=self.image, anchor=NW)
            self.create_text(width / 2, height / 2, anchor=CENTER, font=self.font, text=self.text, fill="#FFFFFF")

        def shape_press(self, width, height):
            self.create_image(0, 0, image=self.image, anchor=NW)
            self.create_text(width / 2, height / 2, anchor=CENTER, font=self.font, text=self.text, fill="#000000")

        def _on_press(self, event):
            self.configure(relief="sunken")
            self.delete("all")
            # self.update()
            self.shape_press(self.width, self.height)

        def _on_release(self, event):
            self.configure(relief="raised")
            self.delete("all")
            self.shape(self.width, self.height)
            if self.command is not None:
                self.command()

    

Now Create a Search UI for already added Visitors in database. First we create a entry box to search Visitor with Visitor Name & Contact no.

    
    self.ce_visitor_var = CustomEntry(self.base_frame, entry_width * 7 / 4, entry_height * 88 / 100, 10, 2, self.color,
                                       "Search Visitor",
                                       "images/ic_search.png")
    self.ce_visitor_var.place(x=self.width * 5 / 100, y=self.height * 38 / 100)
    self.ce_visitor_var.entry.bind('', self.search_visitor)
                    

Here's the logic to search data in table

    
    def search_visitor(self, *arg):

        if self.ce_book_var.entry.get() != "":
            self.tree.delete(*self.tree.get_children())
            conn = Util.connect_db()
            cursor = conn.cursor()
            # cursor.execute(
            #     'SELECT visitor_id, visitor_name, visitor_contact_no, visiting_flat_no, entry_time, exit_time, date FROM visitor_detail')

            cursor.execute(
                "SELECT visitor_id, visitor_name, visitor_contact_no, visiting_flat_no, entry_time, exit_time FROM `visitor_detail` WHERE `visitor_name` LIKE ? OR `visitor_contact_no` LIKE ?",
                ('%' + str(self.ce_visitor_var.entry.get()) + '%',
                 '%' + str(self.ce_visitor_var.entry.get()) + '%'))
            fetch = cursor.fetchall()
            count = 0
            for data in fetch:
                if count % 2 == 0:
                    self.tree.insert('', 'end', values=data, tags=('even',))
                else:
                    self.tree.insert('', 'end', values=data, tags=('odd',))
                count = count + 1
            cursor.close()
            conn.close()
        else:
            self.reset_visitor()

    def reset_visitor(self):
        self.tree.delete(*self.tree.get_children())
        self.update_table_data()
        

We have created a Database named "securitySystem.db", lets connect that database and put that code in seperate class "Util" because we are going to use it multiple time in our project.

    
    class Util:

        @staticmethod
        def connect_db():
            db = None
            try:
                db = sql.connect("securitySystem.db")
                return db
            except sql.Error as error:
                print("Failed to insert data into sqlite table", error)
        

Fetch data from database and show it in table form with the use of "Treeview" of Tkinter.

    
    
        style = ttk.Style()
        #  style.element_create("Custom.Treeheading.border", "from", "default")
        style.layout("Custom.Treeview.Heading", [
            ("Custom.Treeheading.cell", {'sticky': 'nswe'}),
            ("Custom.Treeheading.border", {'sticky': 'nswe', 'children': [
                ("Custom.Treeheading.padding", {'sticky': 'nswe', 'children': [
                    ("Custom.Treeheading.image", {'side': 'right', 'sticky': ''}),
                    ("Custom.Treeheading.text", {'sticky': 'we'})
                ]})
            ]}),
        ])
        #   style.configure("Custom.Treeview.Heading", background="blue", foreground="red", relief="flat")
        style.map("Custom.Treeview.Heading", relief=[('active', 'groove'), ('pressed', 'sunken')])
        style.configure("Custom.Treeview", highlightthickness=0, bd=0,
                        font=('Calibri', int(AppConstant.FONT_SIZE * 60 / 100)), rowheight=30)

        self.table_heading()

        # style.map('Custom.Treeview', background=[], foreground=[])

        list_box_width = self.width * 90 / 100
        heading_width = list_box_width / 8
        self.tree = ttk.Treeview(self.base_frame, height=8, show='tree', style="Custom.Treeview")
        self.tree.tag_configure('odd', background='#DFEBF6', foreground="#000000", )
        self.tree.tag_configure('even', background='#FFFFFF', foreground="#000000", )
        self.tree.place(x=self.width * 5 / 100, y=self.height * 52 / 100, width=list_box_width)
        self.tree["columns"] = "0", "1", "2", "3", "4", "5", "6"
        self.tree.column("#0", width=0)
        self.tree.column("#1", width=100)
        self.tree.column("#3", width=100)
        self.tree.column("#4", width=150)
        self.tree.column("#5", width=200)
        self.tree.column("#6", width=150)
        
        vsby = ttk.Scrollbar(self.base_frame, orient="vertical", command=self.tree.yview)
        vsby.place(x=self.width * 93.8 / 100, y=self.height * 53 / 100, height=self.height * 39.4 / 100)
        self.tree.configure(yscrollcommand=vsby.set)

        self.update_table_data()

        self.tree.column("#0", anchor=tk.CENTER)
        self.tree.column("#1", anchor=tk.CENTER)
        self.tree.column("#2", anchor=tk.CENTER)
        self.tree.column("#3", anchor=tk.CENTER)
        self.tree.column("#4", anchor=tk.CENTER)
        self.tree.column("#5", anchor=tk.CENTER)
        self.tree.column("#6", anchor=tk.CENTER)
        self.tree.column("#7", anchor=tk.CENTER)
        
        self.tree.bind('<>', self.exit_visitor_button())

        # Util.get_time(self)

        root.attributes('-alpha', 0.0)

        root.attributes('-alpha', 1.0)

        

We have created our own heading for table, lets configure it.

    
    def table_heading(self):

        heading_y = self.height * 47 / 100
        bg_color = "#5ad16a"
        text_color = "#ffffff"
        canvas_width = self.width * 90 / 100
        text_size = int(AppConstant.FONT_SIZE * 73 / 100)

        canvas = Canvas(self.base_frame, width=canvas_width, height=30)
        canvas.create_rectangle(0, 0, canvas_width, 30, fill=bg_color)
        canvas.place(x=self.width * 5 / 100, y=heading_y - 3)

        heading_width = canvas_width / 8

        visitor_id_label = Label(self.base_frame, text="Visitor's ID", font=('Calibri', text_size, 'bold'),
                              background=bg_color,
                              foreground=text_color)
        visitor_id_label.place(x=self.width * 6 / 100, y=heading_y, width=heading_width)
        visitor_id_label.configure(anchor="center")

        visitor_name_label = Label(self.base_frame, text="Visitor's Name", font=('Calibri', text_size, 'bold'),
                                background=bg_color,
                                foreground=text_color)
        visitor_name_label.place(x=heading_width + self.width * 6 / 100 + 5, y=heading_y, width=heading_width)
        visitor_name_label.configure(anchor="center")

        contact_label = Label(self.base_frame, text="Contact", font=('Calibri', text_size, 'bold'), background=bg_color,
                              foreground=text_color)
        contact_label.place(x=2 * heading_width + self.width * 8 / 100, y=heading_y, width=heading_width)
        contact_label.configure(anchor="center")
        #
        flat_number = Label(self.base_frame, text="Flat No", width=6, font=('Calibri', text_size, 'bold'),
                            background=bg_color,
                            foreground=text_color)
        flat_number.place(x=3 * heading_width + self.width * 7 / 100, y=heading_y, width=heading_width)
        flat_number.configure(anchor="center")

        entery_number = Label(self.base_frame, text="Entry Time", font=('Calibri', text_size, 'bold'),
                              background=bg_color,
                              foreground=text_color)
        entery_number.place(x=4 * heading_width + self.width * 10 / 100, y=heading_y, width=heading_width)
        entery_number.configure(anchor="center")

        exit_time = Label(self.base_frame, text="Exit Time", font=('Calibri', text_size, 'bold'), background=bg_color,
                          foreground=text_color)
        exit_time.place(x=5 * heading_width + self.width * 13 / 100, y=heading_y, width=heading_width)
        exit_time.configure(anchor="center")

        date_label = Label(self.base_frame, text="Status", font=('Calibri', text_size, 'bold'),
                           background=bg_color,
                           foreground=text_color)
        date_label.place(x=6 * heading_width + self.width * 15.7 / 100, y=heading_y, width=heading_width)
        date_label.configure(anchor="center")
        

UI part is completed, lets move to funtionality. First we need to add click on "ADD VISITOR" button.

    

    def add_visitor_click(self):

        var = ""
        visitor_name = ""
        visitor_contact = ""
        visiting_flat_no = ""
        is_name_entered = False
        is_contact_entered = False
        is_flat_no_entered = False
        status = "IN"

        if self.visiting_flat_no.entry.get() == "" or self.visiting_flat_no.entry.get() == " ":
            var += "Flat Should not be empty, "
        else:
            visiting_flat_no = self.visiting_flat_no.entry.get()
            is_flat_no_entered = True

        if self.visitor_name.entry.get() == "" or self.visitor_name.entry.get() == " ":
            var += "Visitor Name Should not be empty, "
        else:
            visitor_name = self.visitor_name.entry.get()
            is_name_entered = True

        if self.visitor_contact_number.entry.get() == "" or self.visitor_contact_number.entry.get() == " ":
            var += "Visitor Contact Should not be empty, "
        else:
            visitor_contact = self.visitor_contact_number.entry.get()
            is_contact_entered = True

        if is_name_entered and is_contact_entered and is_flat_no_entered:

            conn = Util.connect_db()
            cursor = conn.cursor()

            cursor.execute(
                'INSERT INTO visitor_detail(visitor_name, visitor_contact_no, visiting_flat_no, entry_time, exit_time, status) VALUES(?,?,?,?,?,?)',
                (visitor_name, visitor_contact, visiting_flat_no, str(Util.get_time(self)), "---", status))

            conn.commit()

            messagebox.showinfo("Success", "Visitor has been added successfully")
            self.visiting_flat_no.entry.delete(0, 'end')
            self.visitor_contact_number.entry.delete(0, 'end')
            self.visitor_name.entry.delete(0, 'end')

            self.visitor_name.entry.focus()
            (id_count, key,))
            self.tree.delete(*self.tree.get_children())
            self.update_table_data()

        else:
            messagebox.showerror("showerror", var)
            

When we click on "ADD VISITOR", data will be added to database, after that we need to update the data on UI.

    
    def update_table_data(self):
        conn = Util.connect_db()
        cursor = conn.cursor()
        # cursor.execute('SELECT visitor_id, visitor_name, visitor_contact_no, visiting_flat_no, entry_time, exit_time, date FROM visitor_detail WHERE IS_INSIDE = ? ORDER BY visitor_id DESC', (visitor_inside))
        cursor.execute(
            'SELECT visitor_id, visitor_name, visitor_contact_no, visiting_flat_no, entry_time, exit_time, status FROM visitor_detail ORDER BY visitor_id DESC')

        self.sql_output = cursor.fetchall()

        count = 0
        for data in self.sql_output:
            if count % 2 == 0:
                self.tree.insert('', 'end', values=data, tags=('even',))
            else:
                self.tree.insert('', 'end', values=data, tags=('odd',))
            count = count + 1

    

For Exit Visitor we need show a button "EXIT VISITOR".

    
    def exit_visitor_button(self, *args):
        self.delete_button = RoundedButton(self.base_frame, self.width * 12 / 100, self.width * 3 / 100, self.color,
                                           "images/button3.png",
                                           "EXIT VISITOR",
                                           font=("Lucida Grande", int(AppConstant.FONT_SIZE * 75 / 100)),
                                           command=self.exit_visitor)
        self.delete_button.place(x=self.width * 82 / 100, y=self.height * 38 / 100)
    

After EXIT Button UI completed move on it's click functionality

    
    def exit_visitor(self):

        cur_item = self.tree.focus()

        if self.tree.item(cur_item)["values"]:
            visitor_id = self.tree.item(cur_item)["values"][0]
            visitor_name = self.tree.item(cur_item)["values"][1]

            response = messagebox.askokcancel("Are you sure?", "Do you want to exit " + visitor_name + " ?")
            if response:
                status = "OUT"
                conn = Util.connect_db()
                cursor = conn.cursor()
                cursor.execute("UPDATE visitor_detail SET status = ?, exit_time = ?WHERE visitor_id = ?",
                               (status, str(Util.get_time(self)), visitor_id,))
                conn.commit()

                # conn = Util.connect_db()
                # cursor = conn.cursor()
                # cursor.execute("DELETE FROM visitor_detail WHERE visitor_id = ?", (visitor_id,))
                # conn.commit()

                self.tree.delete(*self.tree.get_children())
                self.update_table_data()

        else:
            messagebox.askokcancel("Error !", "Please Select a Visitor.")

    

At last we will manage closing of window

    
    def on_closing():
        root.destroy()
        if len(args) > 1:
            from dashboard.DashboardWindow import DashboardWindow
            DashboardWindow.add_desk_frame(args[1])
            args[0].deiconify()

    root.protocol("WM_DELETE_WINDOW", on_closing)
                       

Programmer Mirta is for learning and training. Projects might be simple to improve learning. Projects are constantly reviewed to avoid errors, but we cannot assure full correctness of all content. While using Programmer Mitra, you agree to have read and accepted our terms of use, cookie and privacy policy.

Copyright 2021 by Programmer Mitra. All Rights Reserved.