# tkinter GUI library import tkinter as tk from tkinter import font # date time library used for clock and time durations from datetime import datetime, timedelta # OS library for accessing os functions import os # Config global variables from lib import Config class UICommon(): # common images used with the application system_path = "" # Common functions related to the UI click_start_time = datetime.now() cursor_start_position = 0 root_frame = None numeric_keypad_frame = None numeric_keypad_value = "" numeric_keypad_display = None numeric_keypad_target = None def __init__(self, root = None): self.root_frame = root self.system_path = os.path.dirname(os.path.abspath(__file__)).replace("lib", "") + "graphics/" def clear_frame(self, frame): # # clears all of the children from a frame # for widget in frame.winfo_children(): widget.destroy() def table(self, master, title, content, target=None, backgroundcolour="White", foregroundcolour="black", bordercolour="grey", borderwidth=1, fontstyle="DejaVuSans 18 normal"): # creates a table from a 2 dimensional array. # master: = this represents the parent window # content: a 2 dimensional array containing the table contents # First column in the array must be the row id which is returned on a click event. This will not be displayed in the table index = 0 for i in range(len(content)): #Rows for j in range(len(content[i])): if j==0: index = content[i][j] else: b = tk.Label(master, text=str(content[i][j]), background=backgroundcolour, foreground=foregroundcolour,padx=5, pady=10, highlightthickness=borderwidth, highlightbackground=bordercolour, font=fontstyle) if (target is not None): b.bind('<ButtonPress-1>', self.__row_pressed) b.bind('<ButtonRelease-1>', lambda event, arg1=index, arg2=target: self.__row_released(event, arg1, arg2)) b.grid(row=i, column=j-1, sticky=tk.N+tk.S+tk.E+tk.W) return def __row_pressed(self, event): # # detects a press event by starting a timer and saving the current position # self.click_start_time = datetime.now() self.cursor_start_position = self.root_frame.winfo_pointery() def __row_released(self, event, index, target): # # check if the mouse has been moved more than 5 pixels # x = self.root_frame.winfo_pointery() - self.cursor_start_position if (x > -5) and (x < 5): # mouse has moved less than 5 pixels so detect it as a click # check the amount of time that has passed since the press started duration = datetime.now() - self.click_start_time if (duration < timedelta(seconds=1)): # less than 1 second has passed so detect as click instead of hold target(index) def table_column_weighs(self, target, columns, minsize=None): # # set the column weights and minimum size for a grid # for i in range(len(columns)): if (minsize == None): target.columnconfigure(i, weight= columns[i]) else: target.columnconfigure(i, weight= columns[i], minsize=minsize[i]) def table_cell(self, cellframe = None, celltext = None, image=None, wraplength=0, justify=tk.LEFT, row=0, column=0, rowspan=1, columnspan=1, sticky=tk.N+tk.S+tk.E+tk.W): # # create a table cell frame and label and add it to a grid # cell = tk.Frame(cellframe, bg=Config.style_row_background_colour, highlightthickness=Config.style_row_border_width, highlightbackground=Config.style_row_border_colour) label = tk.Label(cell, text=celltext,wraplength=wraplength, image=image, justify=justify,background=Config.style_row_background_colour, foreground=Config.style_row_foreground_colour, padx=5, pady=10, font=Config.style_row_font) label.pack(side=tk.LEFT, fill=tk.Y) cell.grid(row=row, column=column, sticky=sticky, rowspan=rowspan, columnspan=columnspan) return cell def table_title(self, cellframe, celltext, wraplength=0, justify=tk.LEFT, row=0, column=0, rowspan=1, columnspan=1, sticky=tk.N+tk.S+tk.E+tk.W): # # create a table title frame and label and add it to a grid # cell = tk.Frame(cellframe, bg=Config.style_header_background_colour, highlightthickness=Config.style_header_border_width, highlightbackground=Config.style_header_border_colour) label = tk.Label(cell, text=celltext,wraplength=wraplength, justify=justify,background=Config.style_header_background_colour, foreground=Config.style_header_foreground_colour, padx=5, pady=10, font=Config.style_row_font) label.pack(side=tk.LEFT, fill=tk.Y) cell.grid(row=row, column=column, sticky=sticky, rowspan=rowspan, columnspan=columnspan) return cell def bind_children(self, widget, event, callback, add=""): # # bind the event to a widget and all of its children # widget.bind(event, callback, add) for child in widget.children.values(): self.bind_children(child, event, callback) def barcode_type(self, barcode): # # parse the barcode to check whether it is an order, product or unknown part # if (str(barcode).startswith("99")): # barcode is an order return("order") elif (str(barcode).startswith("742678787")): # barcode is a product return("product") else: # barcode is not an internal code. return("unknown") def message_box(self, master, title, content, target=None): # # replaces the standard tkinter message box # box = tk.Frame(master, highlightbackground="grey", highlightcolor="grey", highlightthickness=1, background="#FFFFFF") tk.Label(box, text=title, font="DejaVuSans 22 bold", background="#FFFFFF", pady=20).pack() tk.Label(box, text=content, font="DejaVuSans 22 normal", background="#FFFFFF", pady=30).pack() tk.Button(box, text="Close", font="DejaVuSans 28 normal",pady=20, command=lambda arg1=box, arg2=target: self.__message_box_close(arg1, arg2)).pack(side = tk.BOTTOM, fill=tk.X) box.place(x = 20, y=100, width=280) def __message_box_close(self, master, target): # # Closes and destroys the message box frame and calls a target function if there is one # master.place_forget() master.destroy() if (target != None): target() def numeric_keypad(self, master=None, target=None, title="Quanitity", value=None): # # draws a numeric keypad on the display # # save the return target self.numeric_keypad_target = target if (value == None): self.numeric_keypad_value = "" else: self.numeric_keypad_value = str(value) # master frame self.numeric_keypad_frame = tk.Frame(master, width=320, height=480, background="#000000") self.numeric_keypad_frame.place(x=0, y=0, width=320, height=480) # title tk.Label(self.numeric_keypad_frame, text=title, font="DejaVuSans 22 normal", background="#000000", foreground="#FFFFFF", pady=5).pack(side = tk.TOP,fill=tk.X) # display label self.numeric_keypad_display = tk.Label(self.numeric_keypad_frame, text=self.numeric_keypad_value, font="DejaVuSans 50 normal", background="#FFFFFF", pady=10) self.numeric_keypad_display.pack(side = tk.TOP,fill=tk.X) # number grid numbergrid = tk.Frame(self.numeric_keypad_frame, width=320, height=320) x = 0 y = 0 for i in range(1, 10): label = tk.Label(numbergrid, text=str(10-i), font="DejaVuSans 50 normal", background="#333333", foreground="#FFFFFF", highlightthickness=1, highlightbackground="#000000", pady=20) self.bind_children(label, '<ButtonRelease-1>', lambda event, arg1=10-i: self.__numeric_keypad_update(arg1)) label.grid(row=y, column=x, sticky=tk.N+tk.S+tk.E+tk.W) x+=1 if (x >= 3): y+=1 x=0 number0 = tk.Label(numbergrid, text="0", font="DejaVuSans 50 normal", background="#333333", foreground="#FFFFFF", highlightthickness=1, highlightbackground="#000000") self.bind_children(number0, '<ButtonRelease-1>', lambda event, arg1=0: self.__numeric_keypad_update(arg1)) number0.grid(row=3, column=1, sticky=tk.N+tk.S+tk.E+tk.W) delete = tk.Label(numbergrid, text="<", font="DejaVuSans 50 normal", background="#333333", foreground="#FFFFFF", highlightthickness=1, highlightbackground="#000000", pady=20) self.bind_children(delete, '<ButtonRelease-1>', self.__numeric_keypad_delete) delete.grid(row=3, column=0, sticky=tk.N+tk.S+tk.E+tk.W) decimal = tk.Label(numbergrid, text=".", font="DejaVuSans 50 normal", background="#333333", foreground="#FFFFFF", highlightthickness=1, highlightbackground="#000000") self.bind_children(decimal, '<ButtonRelease-1>', lambda event, arg1=".": self.__numeric_keypad_update(arg1)) decimal.grid(row=3, column=2, sticky=tk.N+tk.S+tk.E+tk.W) save = tk.Label(numbergrid, text="Enter", font="DejaVuSans 20 normal", background="#29a329", foreground="#FFFFFF", highlightthickness=1, highlightbackground="#000000") self.bind_children(save, '<ButtonRelease-1>', lambda event, arg1=0: self.__numeric_keypad_save(arg1)) save.grid(row=1, column=3, sticky=tk.N+tk.S+tk.E+tk.W, rowspan=3) cancel = tk.Label(numbergrid, text="Cancel", font="DejaVuSans 20 normal", background="#b30000", foreground="#FFFFFF", highlightthickness=1, highlightbackground="#000000") self.bind_children(cancel, '<ButtonRelease-1>', lambda event, arg1=0: self.__numeric_keypad_cancel(arg1)) cancel.grid(row=0, column=3, sticky=tk.N+tk.S+tk.E+tk.W) numbergrid.place(x=0, y=110, width=320, height=370) self.table_column_weighs(numbergrid, [1,1,1,1], minsize=[78,78,78,78]) def __numeric_keypad_update(self, value): # # append the selelected number or character to the keypad string # if (value == "."): # check if a decimal point already exists before adding one if (self.numeric_keypad_value.find(".")==-1): self.numeric_keypad_value += "." else: if (self.numeric_keypad_value == ""): if (value > 0): self.numeric_keypad_value = str(value) else: self.numeric_keypad_value += str(value) self.numeric_keypad_display.configure(text=str(self.numeric_keypad_value)) def __numeric_keypad_delete(self, value): # # remove the last character from the keypad value # if (len(self.numeric_keypad_value) > 0): self.numeric_keypad_value = self.numeric_keypad_value[:-1] self.numeric_keypad_display.configure(text=str(self.numeric_keypad_value)) return def __numeric_keypad_save(self, value): # # call the target function and return the value in float or int depending on a decimal point # # clear the frame if (self.numeric_keypad_frame != None): self.numeric_keypad_frame.destroy() if (self.numeric_keypad_target != None): # convert into an int or float and return the value if (self.numeric_keypad_value.find(".")==-1): self.numeric_keypad_target(int(self.numeric_keypad_value)) else: self.numeric_keypad_target(float(self.numeric_keypad_value)) return def __numeric_keypad_cancel(self, value): # # clear the contents of numeric_keypad_value and remove the frame # self.numeric_keypad_value = "" if (self.numeric_keypad_frame != None): self.numeric_keypad_frame.destroy() if (self.numeric_keypad_target != None): self.numeric_keypad_target(None) return