This is the full code thus far of something I am working on right now.
Would love a critique and suggestions for improvements.
Been attempting to learn as I go using only free materials, and I am very new to programming.
Using Python 3.6.7 ([edit] on Ubuntu 18.04):
Would love a critique and suggestions for improvements.
Been attempting to learn as I go using only free materials, and I am very new to programming.
Using Python 3.6.7 ([edit] on Ubuntu 18.04):
import tkinter as tk import tkinter.ttk as ttk import time class _Documentation(): ''' Separation of functions: Functions that work with data input from the GUI will have their own class. GUI elements will contain their own logic for GUI operations. Entering information by the end-user through the GUI should not be manipulated by the GUI classes/elements logic, only checked and sent. When an end-user clicks on buttons which modify the GUI, _that_logic_ should be contained within the part of the GUI that controls its functionality. ''' pass class LogicHandler(object): ''' _This_ will parse the information that is extracted from the GUI. Such as: + When exiting the app; opens a pop-up window to verify choice, closes all connections and saves all data. + At some point, perhaps provide some kind of logging functions, just in case... + We use static methods, so they can't indirectly change data. (Correct?) ''' def __init__(self, parent): super().__init__ self.parent = parent @staticmethod def clock_ping(): return (time.strftime('%H%M')) @staticmethod def date_ping(): return time.strftime('%d%b%Y').upper() class Brass_IO(tk.Tk): ''' Main body of the GUI to which all other objects are attached. ''' def __init__(self): # testing: parent=None super().__init__() # parent self.title = self.winfo_toplevel().title( \ "<=| Access-Control Tracker |=>") # top-level item self.menu_bar = tk.Menu(self) self.config(menu=self.menu_bar) self.options_menu = tk.Menu(self.menu_bar, tearoff=0) self.menu_bar.add_cascade(label="Options", menu=self.options_menu) self.options_menu.add_command(label="Quit", command=self.destroy) # self.main_frame = tk.Frame(self) self.main_frame.grid() # self.nb = ttk.Notebook(self.main_frame) self.nb.grid(padx=(24,0), pady=(24,0), sticky='n,e,s,w') self.tab_one = tk.Frame(self.nb) self.nb.add(self.tab_one, text='Brass I/O') self.tab_two = tk.Frame(self.nb) self.nb.add(self.tab_two, text='Edit I/O') self.tab_three = tk.Frame(self.nb) self.nb.add(self.tab_three, text='Companies') self.tab_four = tk.Frame(self.nb) self.nb.add(self.tab_four, text='Contractors') self.tab_five = tk.Frame(self.nb) self.nb.add(self.tab_five, text='Reports') class TabOne(tk.Frame): ''' Intent: This tab will be labeled "Brass I/O". It will contain several widgets, which will log #'s in and out by time and date. Below it, a brief "history" frame of the last x-number of entries. The back-end to this UI element should therefore send the info to a scheduler which puts it all into a database. Entry widgets will need to have certain inputs be rejected to prevent errors. This helps keep the database intact, and the program running as smoothly as possible. Python's logic and branching make rejecting the input from the entry label easy, and a popup window can be implemented to let the user know what the desired input should be. Possibly even a few examples. Also, a quick listing of statistics in a frame to the right of the "entries" section of this tab should yield some useful information to the users. A question often asked is, "How many contractors are in right now?" ''' def __init__(self, parent): super().__init__(parent) self.grid(sticky='n,e,s,w') self.parent = parent self.tab_one_entries = ttk.LabelFrame(self, text="Entries") self.tab_one_entries.grid(column=0, row=0, padx=7, pady=7, ipadx=7, ipady=7) ## frame for brass num (entry), brass in & brass out buttons. self.tab1_main_top = tk.Frame(self.tab_one_entries) self.tab1_main_top.grid(column=0, row=0, sticky="n,e,s,w", padx=5, pady=5, ipadx=6, ipady=6) self.tab1_main_top.grid_columnconfigure(0, weight=1) # contents self.tab1_box = ttk.Entry(self.tab1_main_top, width=10, justify='center') self.tab1_box.grid(column=0, row=0, sticky="n,e,s,w") self.tab1_button1 = ttk.Button(self.tab1_main_top, text="Brass In") self.tab1_button1.grid(column=1, row=0, sticky="e,w") self.tab1_button2 = ttk.Button(self.tab1_main_top, text="Brass Out") self.tab1_button2.grid(column=2, row=0, sticky="e,w") ## frame for current time self.tab1_main_mid = ttk.LabelFrame(self.tab_one_entries, text="Format: HHMM -------------- \ Enter a time:") self.tab1_main_mid.grid(row=1, sticky="e, w", ipadx=6, ipady=6, padx=5, pady=5) self.tab1_main_mid.grid_columnconfigure(0, weight=0) self.tab1_main_mid.grid_columnconfigure(1, weight=0) self.tab1_main_mid.grid_columnconfigure(2, weight=0) self.tab1_main_mid.grid_columnconfigure(3, weight=1) # contents self.timeVar = tk.IntVar() self.timeVar.set(1) self.tab1_ctime = ttk.Radiobutton(self.tab1_main_mid, variable=self.timeVar, value=1, command=self.set_current_time) self.tab1_ctime.grid(row=1, column=0, sticky='e') self.tab1_ct_label = ttk.Label(self.tab1_main_mid, text="Current Time") self.tab1_ct_label.grid(row=1, column=1, padx=(0, 8), sticky="e") self.tab1_stime = ttk.Radiobutton(self.tab1_main_mid, variable=self.timeVar, value=2, command=self.set_time_entry) self.tab1_stime.grid(row=1, column=2, padx=(14, 0), sticky="e") self.tab1_stime_entry = ttk.Entry(self.tab1_main_mid, width=10, justify='center') self.tab1_stime_entry.grid(row=1, column=3, padx=(0, 2), sticky="n,e,s,w") self.tab1_stime_entry.grid_remove() self.tab1_stime_var = tk.StringVar() self.tab1_ct_label = tk.Label(self.tab1_main_mid, textvariable=self.tab1_stime_var, justify='center') self.tab1_ct_label.grid(row=1, column=3, padx=(0, 2), sticky="w,e") ## frame for current date self.tab1_main_bot = ttk.LabelFrame(self.tab_one_entries, text="Format: DDMONYYYY ----- \ Enter a date:") self.tab1_main_bot.grid(row=2, sticky="n,e,s,w", ipadx=6, ipady=6, padx=5, pady=5) self.tab1_main_bot.grid_columnconfigure(0, weight=0) self.tab1_main_bot.grid_columnconfigure(1, weight=0) self.tab1_main_bot.grid_columnconfigure(2, weight=0) self.tab1_main_bot.grid_columnconfigure(3, weight=1) # contents self.dateVar = tk.IntVar() self.dateVar.set(1) self.tab1_cdate = ttk.Radiobutton(self.tab1_main_bot, variable=self.dateVar, value=1, command=self.set_current_date) self.tab1_cdate.grid(row=2, sticky="e") self.tab1_cd_label = ttk.Label(self.tab1_main_bot, text="Current Date") self.tab1_cd_label.grid(row=2, column=1, padx=(0, 8), sticky="e") self.tab1_sdate = ttk.Radiobutton(self.tab1_main_bot, variable=self.dateVar, value=2, command=self.set_date_entry) self.tab1_sdate.grid(row=2, column=2, padx=(14, 0), sticky='e') self.tab1_sdate_entry = ttk.Entry(self.tab1_main_bot, width=10, justify='center') self.tab1_sdate_entry.grid(row=2, column=3, padx=(0, 2), sticky='n,e,s,w') self.tab1_sdate_entry.grid_remove() self.tab1_sdate_var = tk.StringVar() self.tab1_sdate_label = tk.Label(self.tab1_main_bot, textvariable=self.tab1_sdate_var, justify='center') self.tab1_sdate_label.grid(row=2, column=3, padx=(0, 2), sticky='w,e') ## Quick View frame (top right) of Tab 1 self.tab1_qv = ttk.LabelFrame(self, text="Quick View") self.tab1_qv.grid(column=1, row=0, sticky='n,e,s,w', padx=7, pady=7, ipadx=7, ipady=7) # contents self.tab1_qv_label = tk.Label(self.tab1_qv, text="Number of people in right now...\n\ Do tk labels display multi lines?\n\ Yes they do!\n\ But they look like poop in the code lol.") self.tab1_qv_label.grid() ## History frame (bottom) of Tab 1 self.tab1_history = tk.LabelFrame(self, text="History") self.tab1_history.grid(column=0, row=1, columnspan=2, sticky='n,e,s,w', padx=7, pady=(0, 7), ipadx=7, ipady=7) # contents self.tab1_history_label = tk.Label(self.tab1_history, text="It works.") self.tab1_history_label.grid() # finally, update time and date for labels self.set_time() self.set_date() def set_time(self): self.tab1_stime_var.set(LogicHandler.clock_ping()) self.parent.after(1000, self.set_time) def set_date(self): self.tab1_sdate_var.set(LogicHandler.date_ping()) self.parent.after(1000, self.set_date) def set_current_time(self): self.tab1_stime_entry.grid_remove() self.tab1_ct_label.grid() def set_time_entry(self): self.tab1_ct_label.grid_remove() self.tab1_stime_entry.grid() def set_current_date(self): self.tab1_sdate_entry.grid_remove() self.tab1_sdate_label.grid() def set_date_entry(self): self.tab1_sdate_label.grid_remove() self.tab1_sdate_entry.grid() class HistoryFrame(tk.Frame): ''' Intent: The "History" Frame (LabelFrame) of TabOne. The idea being, this frame displays a list of widgets which are each themselves generated by each entry that gets added to the list of Brass In and Brass Out button clicks. Important so that when we implement the logic for the Brass In and Brass Out buttons, it sends a signal to _this_ frame that updates the list. We'll make it a tk.StringVar() so Tkinter can automatically update it. A label widget's "textvariable=" attribute updates, while the "text=" option is a static value, set once at creation. ''' def __init__(self, parent=None): super().__init__(parent) self.grid(sticky='n,e,s,w') self.parent = parent class TabTwo(tk.Frame): ''' Intent: This tab will be labeled "Edit I/O" for the express purpose of interacting with the current-day's brass database (a literal piece of brass with a number on it), to keep track of "employees" who are currently on-site. Every day will have its own separate database that gets saved into a folder of the current date in the format "MON YYYY", ie, "JUL 2019". The database itself will be saved with the file name of the full current date in the format "DDMONYYYY" to prevent ambiguity, ie, "04JUL2019". The database should save an empty copy of itself with a message to indicate that this is not an error, and that no contractors were in for that day, in the event that there really were no contractors in that day. ''' pass class TabThree(tk.Frame): ''' Intent: This tab will be labeled "Companies" with similar functionality and layout of the second tab, and it will have its own database of companies. It will be for the collection of relevant information, for example contact information of safety officers and the overnight crew foreman for emergencies. ''' pass class TabFour(tk.Frame): ''' Intent: This tab will be labeled "Contractors" with similar functionality and layout of the previous tab, and is tied into the previous database of companies. This way the program can quickly grab information about the brass # they have, if they're in, what times, company they work for, etc.. ''' pass class TabFive(tk.Frame): ''' Intent: This tab will be labeled "Reports", and will have various buttons or check boxes to toggle options that display in HTML the requested information by the users for easy printing. A possiblity (requested in the past) could be what contractors for x company were in on some day last week. Payroll doesn't want to pay contractors for time they shouldn't be paid for, if those people were in fact not there that day. ''' pass def run_main(): brass_io = Brass_IO() handler = LogicHandler(brass_io) tab1 = TabOne(brass_io.tab_one) brass_io.mainloop() if __name__ == '__main__': run_main()Thank you.