def right_frame(parent): rf_width = 300 rf_height = 360 # right side frame frame_right = LabelFrame( parent.building_pos_window, text="Building Position", width=rf_width - 10, height=rf_height - 10, ) frame_right.grid_rowconfigure(0, weight=1) frame_right.grid_columnconfigure(0, weight=1) frame_right.grid_propagate(False) canvas_right = Canvas(frame_right) canvas_right.grid(row=0, column=0, sticky=N + W) # Link a scrollbar to the canvas def on_mousewheel(event): canvas_right.yview_scroll(int(-1 * (event.delta / 120)), "units") def bound_to_mousewheel(event): canvas_right.bind_all("<MouseWheel>", on_mousewheel) def unbound_to_mousewheel(event): canvas_right.unbind_all("<MouseWheel>") y_scrollbar = Scrollbar(frame_right, orient="vertical", command=canvas_right.yview) y_scrollbar.grid(row=0, column=1, sticky='ns') canvas_right.configure(yscrollcommand=y_scrollbar.set) inner_frame_right = Frame(canvas_right) inner_frame_right.bind('<Enter>', bound_to_mousewheel) inner_frame_right.bind('<Leave>', unbound_to_mousewheel) canvas_right.create_window((0, 0), window=inner_frame_right, anchor='nw') idx = 0 for e_name in BuildingNames: building_name_xy_config_frame( inner_frame_right, idx, e_name.value, parent.bot_building_pos.get(e_name.value, [-1, -1]) if parent.bot_building_pos is not None else [-1, -1]) idx = idx + 1 inner_frame_right.update_idletasks() frame_right.config(width=rf_width - 10, height=360 - 10) canvas_right.config(width=rf_width - 10, height=360 - 10, scrollregion=canvas_right.bbox("all")) frame_right.grid(row=0, column=1, padx=5, pady=5, sticky=N + W) return inner_frame_right
def descrip_window(self): window = tk.Toplevel(self) #LabfelFrame for data file input. lbf1 = LabelFrame(window, text='Input file', padx=5, pady=5) lbf1.grid(row=0, padx=5, pady=5) ipte = Entry(lbf1).pack(side='left', padx=5, pady=5) iptb = Button(lbf1, text='...').pack(side='left', padx=5, pady=5) ipt_cal = Button(lbf1, text='Calculation').pack(side='left', padx=5, pady=5) ipt_corr = Button(lbf1, text="Person Corr").pack(side='left', padx=5, pady=5) ipt_show = Button(lbf1, text="Show Data").pack(side='left', padx=5, pady=5) #LabelFrame for selecting variables. lbf2 = LabelFrame(window, text='Select Variables', padx=5, pady=5) lbf2.grid(row=1, sticky='nsew', padx=5, pady=5) lbf2.grid_columnconfigure(0, weight=3) lbf2.grid_columnconfigure(1, weight=1) lbf2.grid_columnconfigure(2, weight=3) listframe1 = Frame(lbf2) listframe1.grid(row=0, column=0, sticky='nswe') #listframe1.place(rely=1.0, relx=1.0,anchor='w') scrollbar1 = Scrollbar(listframe1) listbox1 = Listbox(listframe1, yscrollcommand=scrollbar1.set) listbox1.pack(side='left', fill='both', expand=True) scrollbar1.pack(side='right', fill='both') button_frame = Frame(lbf2) button_frame.grid(row=0, column=1) selectbtn1 = Button(button_frame, text='>>').grid(row=0, padx=5, pady=5) selectbtn2 = Button(button_frame, text='>>>').grid(row=1, padx=5, pady=5) selectbtn3 = Button(button_frame, text='<<').grid(row=2, padx=5, pady=5) selectbtn4 = Button(button_frame, text='<<<').grid(row=3, padx=5, pady=5) listframe2 = Frame(lbf2) listframe2.grid(row=0, column=2, sticky='nswe') scrollbar2 = Scrollbar(listframe2) listbox2 = Listbox(listframe2, yscrollcommand=scrollbar2.set) listbox2.pack(side='left', fill='both', expand=True) scrollbar2.pack(side='right', fill='y') #LabelFrame for show calculation results. lbf3 = LabelFrame(window, text='Calculation Results', padx=5, pady=5) lbf3.grid(row=2, sticky='nswe') btn1 = Button(lbf3, text='Save to File') btn2 = Button(lbf3, text='Save to Clipboard') btn1.pack(side='left', padx=5, pady=5) btn2.pack(side='left', padx=5, pady=5)
def config_frame(self): frame_canvas = LabelFrame(self, text='Config', width=self.windows_size[0], height=self.windows_size[1] - 200 ) frame_canvas.grid_rowconfigure(0, weight=1) frame_canvas.grid_columnconfigure(0, weight=1) frame_canvas.grid_propagate(False) # Add a canvas in that frame canvas = Canvas(frame_canvas) canvas.grid(row=0, column=0, sticky=N+W) # Link a scrollbar to the canvas def on_mousewheel(event): canvas.yview_scroll(int(-1*(event.delta/120)), "units") def bound_to_mousewheel(event): canvas.bind_all("<MouseWheel>", on_mousewheel) def unbound_to_mousewheel(event): canvas.unbind_all("<MouseWheel>") y_scrollbar = Scrollbar(frame_canvas, orient="vertical", command=canvas.yview) y_scrollbar.grid(row=0, column=1, sticky='ns') canvas.configure(yscrollcommand=y_scrollbar.set) inner_frame = Frame(canvas) inner_frame.bind('<Enter>', bound_to_mousewheel) inner_frame.bind('<Leave>', unbound_to_mousewheel) canvas.create_window((0, 0), window=inner_frame, anchor='nw') for i in range(len(atf.bot_config_title_fns)): title_fns, sub_fns = atf.bot_config_title_fns[i] check = section_frame( self, inner_frame, title_fns, sub_fns ) check.grid(row=i, column=0, sticky=N + W) inner_frame.update_idletasks() frame_canvas.config(width=self.windows_size[0] - 20, height=self.windows_size[1] - 350) canvas.config(width=self.windows_size[0] - 20, height=self.windows_size[1] - 350, scrollregion=canvas.bbox("all")) return frame_canvas
class LoadGUI(Frame): """Loading frame which allows the users to pick quizzes. """ def __init__(self, master=None): Frame.__init__(self, master) self.grid(row=0, column=0, sticky="nsew") self.grid_columnconfigure(0, weight=1) self.cover_photo = PhotoImage(file="static/cover.png") self.cover_label = Label(self, image=self.cover_photo) self.cover_label.grid(row=0, column=0, padx=(20,20), pady=(20,10), sticky="ew") self.select_frame = LabelFrame(self, text="Select a quiz") self.select_frame.grid(row=1, column=0, padx=(20,20), pady=(10,20), sticky="ew") for i in range(0,4): self.select_frame.grid_rowconfigure(i, weight=1) self.select_frame.grid_columnconfigure(0, weight=4) self.select_frame.grid_columnconfigure(1, weight=1) self.quiz_list = Listbox(self.select_frame) self.quiz_list.grid(row=0, column=0, rowspan=4, padx=(10,10), pady=(10,10), sticky="ew") self.start_button = Button(self.select_frame, text="Start quiz", command=self.start_chosen) self.start_button.grid(row=0, column=1, padx=(0,10), pady=(10,5), sticky="nsew") self.refresh_button = Button(self.select_frame, text="Refresh list", command=self.refresh) self.refresh_button.grid(row=1, column=1, padx=(0,10), pady=(5,5), sticky="nsew") self.help_button = Button(self.select_frame, text="Help", command=var.HELP_URL) self.help_button.grid(row=2, column=1, padx=(0,10), pady=(5,5), sticky="nsew") self.quit_button = Button(self.select_frame, text="Quit", command=root.destroy) self.quit_button.grid(row=3, column=1, padx=(0,10), pady=(5,10), sticky="nsew") self.get_quizzes() def get_quizzes(self): """[summary] """ self.dir_list = sorted([i[:-5] for i in os.listdir() if i.endswith(".json") and "quiz" in i.lower()]) for f in self.dir_list: self.quiz_list.insert("end", f) def refresh(self): """[summary] """ self.quiz_list.delete(0, "end") self.get_quizzes() def start_chosen(self): """[summary] """ self.filename = self.quiz_list.get("active") + ".json" file_handler.parse_file(self.filename) file_handler.parse_leaderboard() quiz_gui.add_questions() quiz_gui.tkraise()
def __init__(self, thread_cls): super().__init__() self.window = self self.last_request = 0 self.running = False self.thread_cls = thread_cls self.img = None self.title("HomEMOstasis") # our ms azure api key :) self.ety_key = "eed879d931a146d1ac9992ce47e71342" self.grid() self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(1, weight=2) self.grid_rowconfigure(4, weight=1) self.vid = VideoCapture() # Create LabelFrames lf_request = LabelFrame(self, text="Control Panel") lf_request.grid(row=0, column=0, columnspan=1, sticky=W+E, padx=5, pady=3) lf_request.grid_columnconfigure(0, weight=1) lf_console = LabelFrame(self, text="Console") lf_console.grid(row=4, column=0, columnspan=1, sticky=N+S+W+E, padx=5, pady=3) lf_console.grid_columnconfigure(0, weight=1) lf_console.grid_rowconfigure(0, weight=1) lf_img = LabelFrame(self, text="Webcam View") lf_img.grid(row=0, column=1, rowspan=5, sticky=N+S+W+E) lf_img.grid_columnconfigure(0, weight=1) lf_img.grid_rowconfigure(0, weight=1) self.btn_start = Button(lf_request, text="Start Analysis", command=self.start_analysis, state='normal') self.btn_start.grid(sticky = 'nsew', row = 0, column = 0,) self.btn_stop = Button(lf_request, text="Stop Analysis", command=self.stop_analysis, state='disabled') self.btn_stop.grid(sticky = 'nsew', row = 0, column = 1) lf_request.grid_columnconfigure(0, weight=1, uniform="group1") lf_request.grid_columnconfigure(1, weight=1, uniform="group1") lf_request.grid_rowconfigure(0, weight=1) # Create Output Console self.console = ScrolledText( lf_console, state='disable', width=60, bg='gray20', fg='white') self.console.grid(sticky=N+S+W+E) # Create Output Image self.plot = ResultImg(lf_img) self.plot.grid(sticky=N+S+W+E) self.update()
class cFrame(Frame): """Basic structure for frames inside the notebook's tabs""" def __init__(self, parent, pos, name, spring=None): self.parent = parent self.spring = spring super().__init__(parent) self.frame = LabelFrame(self.parent, text=name) self.frame.grid(column=pos[0], row=pos[1], columnspan=pos[2], sticky='nsew', padx=5, pady=5) for i in range(pos[2]): self.frame.grid_columnconfigure(i, weight=1) self.parent.bind('<<solved>>', self.enaButtons, add='+') self.parent.bind('<<unsolved>>', self.disButtons, add='+') self.entries = OrderedDict() def createButtons(self, tup1, tup2): rstButton = Button(self.frame, text='Borrar', command=self.rst) rstButton.grid(row=tup1[1], column=tup1[0], columnspan=tup1[2], sticky='w', padx=5, pady=4) solveButton = Button(self.frame, text='Resolver', command=self.solve) solveButton.grid(row=tup2[1], column=tup2[0], columnspan=tup2[2], sticky='e', padx=5, pady=4) def cleanEntries(self): for k in self.entries.keys(): self.entries[k]['entry'].configure(bg='white') self.entries[k]['entry'].delete(0, 'end') def enaButtons(self, event): for k in self.entries.keys(): self.entries[k]['entry']['state'] = 'normal' def disButtons(self, event): for k in self.entries.keys(): self.entries[k]['entry']['state'] = 'disabled'
def __init__(self, modelProc, tick): self.modelProc = modelProc self.tick = tick self.queue = modelProc.getQueue() # ----------------- Model parameters ----------------- # Waiting time between two events self.refreshRate = DEFAULT_REFRESH_RATE # Elapsed time (in number of ticks) self.count = 0 # ------------------------ GUI ----------------------- # Main window self.window = Tk() self.window.title("Model Rendering") self.window.configure(bg=BG_COLOR) self.window.protocol("WM_DELETE_WINDOW", self.onClosing) # Main pane mainPane = PanedWindow(self.window, orient=HORIZONTAL, bg=BG_COLOR) mainPane.pack(side=TOP, expand=Y, fill=BOTH, pady=5, padx=5) # Canvas frame canvasFrame = LabelFrame(mainPane, text="Rendering", padx=10, pady=10, bg=BG_COLOR) mainPane.add(canvasFrame) self.canvas = Canvas(canvasFrame, width=CANVAS_X, height=CANVAS_Y, background="white") self.canvas.pack() # Parameters frame paramFrame = LabelFrame(mainPane, text="Simulation parameters",\ padx=20, pady=20, bg=BG_COLOR) mainPane.add(paramFrame) # ===> Refresh rate slider self.stepVar = DoubleVar(paramFrame, value=DEFAULT_REFRESH_RATE) slider = Scale(paramFrame, from_=0, to_=0.5, resolution=0.001, length=350, orient=VERTICAL,\ variable=self.stepVar, label="# Refresh rate", bg=BG_COLOR, bd=1) slider.bind("<ButtonRelease-1>", self.updateRate) slider.grid(row=1, column=1) # ===> Elapsed time self.timeLabel = Label(paramFrame, text="# Elapsed time (hours) :\n0", bg=BG_COLOR) self.timeLabel.grid(row=3, column=1) # Rows and columns configuration paramFrame.grid_columnconfigure(0, weight=1) paramFrame.grid_columnconfigure(1, weight=2) paramFrame.grid_columnconfigure(2, weight=1) paramFrame.grid_rowconfigure(0, weight=1) paramFrame.grid_rowconfigure(2, weight=2) paramFrame.grid_rowconfigure(4, weight=2)
def _setup_widgets(self): container = LabelFrame(text=" Output Text ", bg="black", fg='white') container.pack(expand=1, fill="both", padx=5, pady=5) # create a treeview with dual scrollbars ttk.Style().configure("Treeview", background="black", foreground="white", fieldbackground="black") self.tree = ttk.Treeview(columns=self.list_header, show="headings") self.tree.column('Port', width=0) self.tree.column('Status', width=40) self.tree.grid(column=0, row=0, sticky='nsew', in_=container, padx=5, pady=5) container.grid_columnconfigure(0, weight=1) container.grid_rowconfigure(0, weight=1)
def displayDriverSettings (self): SettingFrame=LabelFrame(self.settingWindow, text= 'Driver Settings ') SettingFrame.grid(column=0, row=0, padx=5, pady=5, sticky= 'nsew') SettingFrame.grid_columnconfigure(1, weight=1) chromePathVar=Tkinter.StringVar() chromePathVar.trace( 'w',lambda name, index, mode, sv=chromePathVar: self.updateConfigFromEntry(sv, 'chrome_driver')) IEPathVar=Tkinter.StringVar() IEPathVar.trace('w',lambda name, index, mode, sv=IEPathVar: self.updateConfigFromEntry(sv,'ie_driver')) EdgePathVar=Tkinter.StringVar() EdgePathVar.trace('w',lambda name, index, mode, sv=EdgePathVar: self.updateConfigFromEntry(sv,'edge_driver')) FFPathVar=Tkinter.StringVar() FFPathVar.trace('w',lambda name, index, mode, sv=FFPathVar: self.updateConfigFromEntry(sv, 'firefox_driver')) Label(SettingFrame, text= 'Chrome Driver ').grid(column=0, row=0, sticky= '', padx=5, pady=5) ChromeDriverPath = Entry(SettingFrame, textvariable=chromePathVar) ChromeDriverPath.grid(row=0, column=1, padx=5, sticky= 'we',pady=5 ) ChromeDriverPath.insert(0, self.config['Driver']['chrome_driver']) ChromebrowseButton=ttk.Button(SettingFrame, text= 'Browse', command= lambda: self.getDriverPath(ChromeDriverPath)) ChromebrowseButton.grid(row=0, column=2, padx=5, pady=5) Label(SettingFrame, text='IE Driver'). grid(column=0, row=1, sticky= 'we', padx=5, pady=5) IEDriverPath = Entry(SettingFrame, textvariable=IEPathVar) IEDriverPath.grid(row=1, column=1, padx=5, sticky='we', pady=5) IEDriverPath.insert(0, self.config[ 'Driver']['ie_driver']) IEbrowseButton=ttk.Button(SettingFrame, text= 'Browser', command= lambda: self.getDriverPath(IEDriverPath)) IEbrowseButton.grid(row=1, column=2, padx=5, pady=5) Label(SettingFrame, text='Edge Driver').grid(column=0, row=2, sticky='we', padx=5, pady=5) EdgeDriverPath = Entry(SettingFrame, textvariable=EdgePathVar) EdgeDriverPath.grid(row=2, column=1, padx=5, sticky="we", pady=5) EdgeDriverPath.insert(0,self.config['Driver']['edge_driver']) EdgebrowseButton=ttk.Button (SettingFrame, text="Browse", command= lambda: self.getDriverPath(EdgeDriverPath)) EdgebrowseButton.grid(row=2, column=2, padx=5,pady=5) Label(SettingFrame, text='Firefox Driver').grid(column=0, row=3, sticky='we', padx=5, pady=5) FireFoxDriverPath = Entry(SettingFrame, textvariable=FFPathVar) FireFoxDriverPath.grid(row=3, column=1, padx=5, sticky="we", pady=5) FireFoxDriverPath.insert(0,self.config['Driver']['firefox_driver']) FireFoxbrowseButton=ttk.Button (SettingFrame, text="Browse", command= lambda: self.getDriverPath(FireFoxDriverPath)) FireFoxbrowseButton.grid(row=3, column=2, padx=5,pady=5)
class ResultGUI(Toplevel): """Initializes and hides the result window. """ def __init__(self, master=None): Toplevel.__init__(self, master) self.title("Result") self.resizable(False, False) self.final_time = StringVar() # Final displayed time. self.final_score = StringVar() # Final displayed score. self.final_msg = StringVar() # Message displayed based on scores. # List with the format (lower boundary, upper boundary, message) to display a message based on the correct percentage. self.msg_list = [ (0, 20, "Are you even trying?"), (20, 40, "Try harder!"), (40, 60, "Keep trying!"), (60, 80, "You're getting there!"), (80, 100, "Almost there!"), (100, 100, "Perfect score!") ] self.grid_columnconfigure(0, weight=1, uniform="col") self.grid_columnconfigure(1, weight=1, uniform="col") self.stat_frame = LabelFrame(self, text="Final results:") self.stat_frame.grid(column=0, row=0, padx=(20,20), pady=(20,0), sticky="ew", columnspan=2) self.stat_frame.grid_columnconfigure(0, weight=1) self.info_frame = Frame(self.stat_frame) self.info_frame.grid(column=0, row=0, sticky="ew") self.info_frame.grid_columnconfigure(0, weight=1) self.info_frame.grid_columnconfigure(1, weight=1) self.timer_label = Label(self.info_frame, text="Time:") self.timer_label.grid(column=0, row=0, padx=(0,0), pady=(10,0), sticky="ew") self.timer = Label(self.info_frame, textvariable=self.final_time, justify="center") self.timer.grid(column=1, row=0, padx=(0,0), pady=(10,0), sticky="ew") self.score_label = Label(self.info_frame, text="Correct:") self.score_label.grid(column=0, row=1, padx=(0,0), pady=(0,10), sticky="ew") self.score = Label(self.info_frame, textvariable=self.final_score, justify="center") self.score.grid(column=1, row=1, padx=(0,0), pady=(0,10), sticky="ew") self.msg = Label(self.info_frame, textvariable=self.final_msg) self.msg.grid(column=0, row=2, padx=(0,0), pady=(0,10), columnspan=2) self.ok_button = Button(self, text="OK", command=self.hide) self.ok_button.grid(column=0, row=1, padx=(20,10), pady=(10,20), ipadx=10, ipady=5, sticky="ew") self.board_button = Button(self, text="Leaderboard", command=leader_gui.show) self.board_button.grid(column=1, row=1, padx=(0,20), pady=(10,20), ipadx=10, ipady=5, sticky="ew") self.hide() # Set the results label, calculate percentage and set the message label. def get_results(self): self.final_time.set(var.time_text.get()) self.final_score.set(var.correct_text.get()) self.percentage = (handler.correct_int / len(var.questions["questions"])) * 100 for i in self.msg_list: if i[0] <= self.percentage < i[1]: self.final_msg.set(i[2]) def show(self): self.get_results() self.deiconify() self.lift() def hide(self): self.withdraw()
trackFaces = tk.Button(frame_track, text="Track Faces", command=TrackImages, font=('times', 15, ' bold ')) trackFaces.grid(row=0, column=0) takeAttendance = tk.Button(frame_track, text="Take Attendance", command=takeAttendance, font=('times', 15, ' bold ')) takeAttendance.grid(row=0, column=1) frame_track.grid(row=0, ipady=10, ipadx=10) # Center buttons in frame frame_track.grid_rowconfigure(0, weight=1) frame_track.grid_columnconfigure(0, weight=1) frame_track.grid_columnconfigure(1, weight=1) # frame_mainContent ROW 1 frame_addUser = LabelFrame(frame_mainContent, text="Add User") frame_enterData = Frame(frame_addUser) # frame_enterData ROW 0 lbl_enterID = tk.Label(frame_enterData, text="Enter ID", font=('times', 15, ' bold ')) lbl_enterID.grid(row=0, column=0, sticky="W") txt_enterID = tk.Entry(frame_enterData, font=('times', 15, ' bold ')) txt_enterID.grid(row=0, column=1) clearButton_enterID = tk.Button(frame_enterData, text="Clear",
class QuizGUI(Frame): """Initializes the GUI for the quiz, along with the implementation of dynamically-created widgets. """ def __init__(self, master=None): self.widget_list = [] # List to store dynamic widgets. self.image_list = [] # list to store image objects. self.button_list = [] # List to store answer buttons. Frame.__init__(self, master) self.style_manager = ttk.Style() self.style_manager.layout("TNotebook.Tab", []) self.master.title("Quiz Framework") self.master.resizable(False, False) self.grid(column=0, row=0, padx=(20,20), pady=(10,20)) self.menubar = Menu(self) self.filemenu = Menu(self.menubar, tearoff=0) self.filemenu.add_command(label="Load quiz", command=self.raise_load) self.filemenu.add_command(label="Leaderboard", command=leader_gui.show) self.filemenu.add_command(label="Exit", command=root.destroy) self.menubar.add_cascade(label="Quiz", menu=self.filemenu) self.helpmenu = Menu(self.menubar, tearoff=0) self.helpmenu.add_command(label="About", command=var.HELP_URL) self.menubar.add_cascade(label="Help", menu=self.helpmenu) self.master.config(menu=self.menubar) self.info_frame = LabelFrame(self, text="Current quiz:") self.info_frame.grid(column=0, row=0, padx=(0,10), sticky="nsew") self.quiz_name_label = Label(self.info_frame, text="Name:") self.quiz_name_label.grid(column=0, row=0, padx=(10,0), pady=(10,0), sticky="w") self.quiz_name = Label(self.info_frame, textvariable=var.name) self.quiz_name.grid(column=1, row=0, padx=(0,10), pady=(10,0), sticky="w") self.quiz_desc_label = Label(self.info_frame, text="Description:") self.quiz_desc_label.grid(column=0, row=1, padx=(10,0), pady=(0,10), sticky="nw") self.quiz_desc = Label(self.info_frame, textvariable=var.desc, justify="left") self.quiz_desc.grid(column=1, row=1, padx=(0,10), pady=(0,10), sticky="w") self.stat_frame = LabelFrame(self, text="Statistics:") self.stat_frame.grid(column=1, row=0, sticky="nsew", padx=(10,0)) self.timer_label = Label(self.stat_frame, text="Time:") self.timer_label.grid(column=0, row=0, padx=(10,0), pady=(10,0), sticky="w") self.timer = Label(self.stat_frame, textvariable=var.time_text) self.timer.grid(column=1, row=0, padx=(0,10), pady=(10,0), sticky="w") self.score_label = Label(self.stat_frame, text="Correct:") self.score_label.grid(column=0, row=1, padx=(10,0), pady=(0,10), sticky="w") self.score = Label(self.stat_frame, textvariable=var.correct_text) self.score.grid(column=1, row=1, padx=(0,10), pady=(0,10), sticky="w") self.quiz_frame = LabelFrame(self, text="Quiz:") self.quiz_frame.grid(column=0, row=1, pady=(10,10), columnspan=2, sticky="ew") self.quiz_frame.grid_columnconfigure(0, weight=1) self.quiz_frame.grid_rowconfigure(0, weight=1) self.quiz_notebook = ttk.Notebook(self.quiz_frame) self.quiz_notebook.grid(column=0, row=1, padx=(10,10), pady=(10,10), sticky="ew") self.add_questions() self.options_frame = Frame(self) self.options_frame.grid(column=0, row=2, columnspan=2, sticky="ew") for i in range(0,3): self.options_frame.grid_columnconfigure(i, weight=1) self.start_button = Button(self.options_frame, text="Start", command=handler.start_quiz) self.start_button.grid(column=0, row=0, ipadx=20, ipady=5, padx=(0,10), sticky="ew") self.reset_button = Button(self.options_frame, text="Reset", state="disabled", command=handler.reset_quiz) self.reset_button.grid(column=1, row=0, ipadx=20, ipady=5, padx=(0,10), sticky="ew") self.skip_button = Button(self.options_frame, text="Skip", command=self.skip) self.skip_button.grid(column=2, row=0, ipadx=20, ipady=5, padx=(0,10), sticky="ew") self.load_button = Button(self.options_frame, text="Load quiz", command=self.raise_load) self.load_button.grid(column=3, row=0, ipadx=20, ipady=5, padx=(0,0), sticky="ew") def add_questions(self): """Dynamically create widgets based on pre-defined data. """ random.shuffle(var.questions["questions"]) # Shuffling questions self.image_list = [] for q in range(0, len(var.questions["questions"])): # Iterate through the pre-defined list of questions random.shuffle(var.questions["questions"][q]["answers"]) self.question_num = "Question " + str(q+1) + ": " # Question number self.current_question = self.question_num + var.questions["questions"][q]["question"] self.current_image = var.questions["questions"][q]["image"] self.answer_list = var.questions["questions"][q]["answers"] self.question_frame = Frame(self.quiz_notebook) self.question_frame.grid_columnconfigure(0, weight=1) self.quiz_notebook.add(self.question_frame, text=self.question_num, sticky="nsew") self.question_label = Label(self.question_frame, text=self.current_question, wraplength=350) self.question_label.grid(column=0, row=0, padx=(10,10), pady=(10,10), sticky="ew") if self.current_image != "": self.image_obj = PhotoImage(file=self.current_image) else: self.image_obj = PhotoImage(file="static/blank.png") self.image_list.append(self.image_obj) self.question_image = Label(self.question_frame, image=self.image_list[q], relief="ridge") self.question_image.image = self.image_obj self.question_image.grid(column=0, row=1, padx=(10,10), pady=(0,10), sticky="ew") for i in enumerate(self.answer_list, 1): # Refrain from using lambda to attach a function without initially triggering it, # as the argument doesn't get passed until the very last iteration of the for loop. self.quiz_answer = Button(self.question_frame, text=i[1]["text"], command=functools.partial(self.ans_check, answer_arg=i[1]["key"], question_idx=q)) self.button_list.append(self.quiz_answer) # Check if the current answer is the last in the list. if i[0] % 4 != 0: self.quiz_answer.grid(column=0, row=2+i[0], padx=(10,10), ipady=10, sticky="ew") else: self.quiz_answer.grid(column=0, row=2+i[0], padx=(10,10), pady=(0,10), ipady=10, sticky="ew") def kill_questions(self): """Kill all notebook frames. """ for frame in quiz_gui.quiz_notebook.winfo_children(): for wdg in frame.winfo_children(): wdg.destroy() def raise_load(self): """Raise the loading frame. """ self.load_confirm = simpledialog.messagebox.askyesno("Warning", "Your current progress will not be saved. Do you wish to continue?") if self.load_confirm: handler.reset_quiz() self.kill_questions() load_gui.tkraise() def ans_check(self, answer_arg:str, question_idx:int): """Check the answer by comparing it to the dictionary's answer key. """ handler.check_answers(answer_arg, question_idx) def skip(self): """Skips the current question """ pass
def __init__(self, master, cnf={}, **kw): super().__init__(master, cnf, **kw) self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1) self.grid_columnconfigure(2, weight=1) system_info_frame = LabelFrame(self, text="System Information", pady=5, font=load_font(RelativeSize.normal)) system_info_frame.grid_rowconfigure(0, weight=1) system_info_frame.grid_columnconfigure(0, weight=1) system_info_frame.grid(row=0, column=0, sticky="nsew") self.system_info_tree = AutosizeTreeview(system_info_frame, columns="value") self.system_info_tree.heading("#0", text="command") self.system_info_tree.column("#0", stretch=True, width=50) self.system_info_tree.heading("#1", text="result") self.system_info_tree.column("#1", stretch=True, width=50) self.system_info_tree.grid(row=0, column=0, sticky="nsew") system_info_xscroll = Scrollbar(system_info_frame, orient="horizontal", command=self.system_info_tree.xview) system_info_yscroll = Scrollbar(system_info_frame, orient="vertical", command=self.system_info_tree.yview) system_info_xscroll.grid(row=1, column=0, sticky="nsew") system_info_yscroll.grid(row=0, column=1, sticky="nsew") self.system_info_tree.configure(xscroll=system_info_xscroll.set, yscroll=system_info_yscroll.set) connection_status_frame = LabelFrame(self, text="Connection Status", font=load_font( RelativeSize.normal)) connection_status_frame.grid_rowconfigure(0, weight=1) connection_status_frame.grid_rowconfigure(1, weight=1) connection_status_frame.grid_rowconfigure(2, weight=1) connection_status_frame.grid_columnconfigure(0, weight=1) connection_status_frame.grid_columnconfigure(1, weight=1) connection_status_frame.grid_columnconfigure(2, weight=1) connection_status_frame.grid(row=0, column=1, sticky="nsew") self.signal_status_bar = Progressbar(connection_status_frame, orient="vertical", mode="determinate") self.signal_status_bar.grid(row=1, column=1, sticky="nsew") self.signal_status_text = Label(connection_status_frame) self.signal_status_text.grid(row=1, column=1) battery_status_frame = LabelFrame(self, text="Battery Status", font=load_font(RelativeSize.normal)) battery_status_frame.grid_rowconfigure(0, weight=1) battery_status_frame.grid_rowconfigure(1, weight=1) battery_status_frame.grid_rowconfigure(2, weight=1) battery_status_frame.grid_columnconfigure(0, weight=1) battery_status_frame.grid_columnconfigure(1, weight=1) battery_status_frame.grid_columnconfigure(2, weight=1) battery_status_frame.grid(row=0, column=2, sticky="nsew") self.battery_status_bar = Progressbar(battery_status_frame, orient="vertical", mode="determinate") self.battery_status_bar.grid(row=1, column=1, sticky="nsew") self.battery_status_text = Label(battery_status_frame) self.battery_status_text.grid(row=1, column=1)
def openaboutwindow(main_root_title): global about_window # Defines the path to config.ini and opens it for reading/writing config_file = 'Runtime/config.ini' # Creates (if doesn't exist) and defines location of config.ini config = ConfigParser() config.read(config_file) try: # If "About" window is already opened, display a message, then close the "About" window if about_window.winfo_exists(): messagebox.showinfo( title=f'"{about_window.wm_title()}" Info!', parent=about_window, message= f'"{about_window.wm_title()}" is already opened, closing window instead' ) about_window.destroy() return except NameError: pass def about_exit_function(): # Exit function when hitting the 'X' button func_parser = ConfigParser() func_parser.read(config_file) if func_parser['save_window_locations'][ 'about'] == 'yes': # If auto save position on close is checked try: if func_parser['save_window_locations'][ 'about position'] != about_window.geometry(): func_parser.set('save_window_locations', 'about position', about_window.geometry()) with open(config_file, 'w') as configfile: func_parser.write(configfile) except (Exception, ): pass about_window.destroy() # Close window about_window = Toplevel() about_window.title('About') about_window.configure(background="#434547") if config['save_window_locations']['about position'] == '' or config[ 'save_window_locations']['about'] == 'no': window_height = 650 window_width = 720 screen_width = about_window.winfo_screenwidth() screen_height = about_window.winfo_screenheight() x_coordinate = int((screen_width / 2) - (window_width / 2)) y_coordinate = int((screen_height / 2) - (window_height / 2)) about_window.geometry("{}x{}+{}+{}".format(window_width, window_height, x_coordinate, y_coordinate)) elif config['save_window_locations']['about position'] != '' and config[ 'save_window_locations']['about'] == 'yes': about_window.geometry( config['save_window_locations']['about position']) about_window.resizable(False, False) about_window.protocol('WM_DELETE_WINDOW', about_exit_function) about_window.grid_columnconfigure(0, weight=1) detect_font = font.nametofont( "TkDefaultFont") # Get default font value into Font object set_font = detect_font.actual().get("family") about_information_frame = LabelFrame(about_window, text=' About ', labelanchor="nw") about_information_frame.grid(column=0, row=0, columnspan=1, padx=5, pady=(0, 3), sticky=N + S + E + W) about_information_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 10, "bold")) about_information_frame.grid_rowconfigure(0, weight=1) about_information_frame.grid_columnconfigure(0, weight=1) about_window_text = Text(about_information_frame, background="#434547", foreground="white", relief=FLAT, height=10) about_window_text.pack() about_window_text.insert(INSERT, f"{main_root_title}\n") about_window_text.insert(INSERT, "\n") about_window_text.insert( INSERT, "Development: jlw4049\n\nContributors: BassThatHertz, aaronrausch") about_window_text.insert(INSERT, "\n\n") about_window_text.insert( INSERT, "Power audio encoding GUI, that mostly uses FFMPEG at the heart. \n") about_window_text.configure(state=DISABLED) about_information_frame = LabelFrame(about_window, text=' License ', labelanchor="nw") about_information_frame.grid(column=0, row=1, columnspan=1, padx=5, pady=(0, 3), sticky=N + S + E + W) about_information_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 10, "bold")) about_information_frame.grid_rowconfigure(0, weight=1) about_information_frame.grid_columnconfigure(0, weight=1) license_text = """ Copyright (c) 2012-2022 Scott Chacon and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ about_window_license = Text(about_information_frame, background="#434547", foreground="white", relief=FLAT) about_window_license.pack(anchor='center') about_window_license.insert(INSERT, license_text) about_window_license.configure(state=DISABLED)
class BornDigitalGUI(Frame): def __init__(self, master): ##### Configure Canvas ##### Frame.__init__(self, master) self.master = master self.canvas = Canvas(master, borderwidth=0) self.frame = Frame(self.canvas) self.canvas.create_window((4,4), window=self.frame, anchor='nw', tags='self.frame') self.master.title('Born Digital Accessioner 1.0') self.initmenu() self.frame.config(bg='gainsboro', highlightthickness=0) self.canvas.config(bg='gainsboro', highlightthickness=0) self.canvas.grid_rowconfigure(0, weight=1) self.canvas.grid_columnconfigure(0, weight=1) self.frame.grid_rowconfigure(0, weight=1) self.frame.grid_columnconfigure(0, weight=1) self.master.grid_rowconfigure(0, weight=1) self.master.grid_columnconfigure(0, weight=1) self.canvas.grid(row=0, column=0, sticky="nsew") self.frame.grid(row=0, column=0, sticky="nsew") ##### Execute login process by pressing Enter #### self.master.bind('<Return>', self.asloginprocess) ########### Step 1: Login to ArchivesSpace API ########### ## Set Step 1 Variable Inputs ## self.authenticate = StringVar() self.api_url = StringVar() self.username = StringVar() self.password = StringVar() self.login_confirmed = StringVar() ## Create Step 1 Widgets ## self.login_labelframe = LabelFrame(self.frame, text='Step 1: Connect to ArchivesSpace', font=('Arial', 14), bg='gainsboro', padx=1, pady=1) self.api_url_label = Label(self.login_labelframe, text='ArchivesSpace URL: ', font=('Arial', 13), bg='gainsboro') self.username_label = Label(self.login_labelframe, text='ArchivesSpace Username: '******'Arial', 13), bg='gainsboro') self.password_label = Label(self.login_labelframe, text='ArchivesSpace Password: '******'Arial', 13), bg='gainsboro') self.api_url_entry = Entry(self.login_labelframe, width=32, textvariable=self.api_url, highlightthickness=0) self.username_entry = Entry(self.login_labelframe, width=32, textvariable=self.username, highlightthickness=0) self.password_entry =Entry(self.login_labelframe, width=32, textvariable=self.password, show='*', highlightthickness=0) self.login_confirmed_variable = Label(self.login_labelframe, textvariable=self.login_confirmed, width=25, font=('Arial', 13), bg='gainsboro', highlightthickness=0, anchor='e') self.connect_button = Button(self.login_labelframe, text='Connect!',command=self.asloginprocess, width=10, relief=RAISED, bd=1, padx=3, pady=3, highlightthickness=0, cursor="hand1") ## Set Set Step 1 Widget Layout ## self.login_labelframe.grid(column=0, columnspan=2, sticky="nsew", padx=5, pady=5) self.login_labelframe.grid_rowconfigure(0, weight=1) self.login_labelframe.grid_columnconfigure(0, weight=1) self.api_url_label.grid(column=0, row=2, sticky="nw") self.api_url_entry.grid(column=0, row=3, sticky="nw") self.username_label.grid(column=0, row=4, sticky="nw") self.username_entry.grid(column=0, row=5, sticky="nw") self.password_label.grid(column=0, row=6, sticky="nw") self.password_entry.grid(column=0, row=7, sticky="nw") self.login_confirmed_variable.grid(column=1, row=6, sticky="ns") self.connect_button.grid(column=1, row=7, sticky="ne") ########### Step 2: Select Input CSV ########### ## Set Step 2 Variable Inputs ## self.csv_filename = StringVar() ## Create Step 2 Widgets ## self.fileselect_labelframe = LabelFrame(self.frame, text='Step 2: Select Input CSV', font=('Arial', 14), bg='gainsboro', highlightthickness=0, padx=1, pady=1) self.file_selected_label = Label(self.fileselect_labelframe, text='Selection: ', font=('Arial', 13), anchor='w', bg='gainsboro', highlightthickness=0) self.selected_csv_variable = Label(self.fileselect_labelframe, textvariable=self.csv_filename, width=65, font=('Arial', 11), anchor='w', bg='gainsboro', highlightthickness=0) self.input_csv_button = Button(self.fileselect_labelframe, text='Select File', command=self.csvbutton, relief=RAISED, bd=1, padx=3, pady=3, highlightthickness=0, cursor="hand1") ## Set Step 2 Layout ## self.fileselect_labelframe.grid(column=0, columnspan=2, sticky="nsew", padx=5, pady=5) self.fileselect_labelframe.grid_rowconfigure(0, weight=1) self.fileselect_labelframe.grid_columnconfigure(0, weight=1) self.input_csv_button.grid(column=1, row=9, sticky='se') self.file_selected_label.grid(column=0, columnspan=1, row=10, sticky='w') self.selected_csv_variable.grid(column=0, row=11, columnspan=2, sticky='w') ## Set Step _ Variable Inputs ## self.csv_output = StringVar() ########### Step 3: Choose an Action ########### ## Create Step 3 Widgets ## self.action_labelframe = LabelFrame(self.frame, text='Step 3: Choose Action', font=('Arial', 14), bg='gainsboro', highlightthickness=0, padx=1, pady=1) self.create_components_button = Button(self.action_labelframe, text='Create records', width=30, command=self.run_create_script, relief=RAISED, bd=1, padx=3, pady=3, highlightthickness=0, cursor="hand1") self.update_components_button = Button(self.action_labelframe, text='Update records', width=30, command=self.run_update_script, relief=RAISED, bd=1, padx=3, pady=3, highlightthickness=0, cursor="hand1") ## Set Step 3 Layout ## self.action_labelframe.grid(column=0, columnspan=2, sticky="nsew", padx=5, pady=5) self.action_labelframe.grid_rowconfigure(0, weight=1) self.action_labelframe.grid_columnconfigure(0, weight=1) self.create_components_button.grid(row=12, columnspan=2) self.update_components_button.grid(row=13, columnspan=2) ########### Step 4: Review Output ########### ## Set Step 4 Variable Inputs ## self.update_attempts = StringVar() self.updates_success = StringVar() self.elapsed_time = StringVar() self.log_file = StringVar() self.error_dialog = StringVar() self.script_status = StringVar() self.parent_id = StringVar() self.resource_id = StringVar() self.repo_id_no = StringVar() ## Create Step 4 Widgets ## self.output_labelframe = LabelFrame(self.frame, text='Step 4: Review Output', font=('Arial', 14), bg='gainsboro', highlightthickness=0, padx=1, pady=1) self.script_status_variable = Label(self.output_labelframe, textvariable=self.script_status, font=('Arial', 13), anchor='e', bg='gainsboro', highlightthickness=0) self.record_updates_attempted_label = Label(self.output_labelframe, text='Record updates attempted: ', width=30, font=('Arial', 13), anchor='w', bg='gainsboro', highlightthickness=0) self.record_updates_attempted_variable = Label(self.output_labelframe, textvariable=self.update_attempts, width=30, font=('Arial', 13), anchor='w', bg='gainsboro', highlightthickness=0) self.records_updated_successsfully_label = Label(self.output_labelframe, text='Records updated successfully: ', width=30, font=('Arial', 13), anchor='w', bg='gainsboro', highlightthickness=0) self.records_updated_successsfully_variable = Label(self.output_labelframe, textvariable=self.updates_success, width=30, font=('Arial', 13), anchor='w', bg='gainsboro', highlightthickness=0) self.elapsed_time_label = Label(self.output_labelframe, text='Elapsed time: ', width=30, font=('Arial', 13), anchor='w', bg='gainsboro', highlightthickness=0) self.elapsed_time_variable = Label(self.output_labelframe, textvariable=self.elapsed_time, width=30, font=('Arial', 13), anchor='w', bg='gainsboro', highlightthickness=0) self.view_output_file_button = Button(self.output_labelframe, text='Open Output File', command=self.opencsvoutput, relief=RAISED, bd=1, padx=3, pady=3, highlightthickness=0, cursor="hand1") self.view_error_log_button = Button(self.output_labelframe, text='Open Log', command=self.openerrorlog, relief=RAISED, bd=1, padx=3, pady=3, highlightthickness=0, cursor="hand1") self.view_url_button = Button(self.output_labelframe, text='Open in ArchivesSpace', command=self.openparent_record, relief=RAISED, bd=1, padx=3, pady=3, highlightthickness=0, cursor="hand1") ## Set Step 5 Layout ## self.output_labelframe.grid(column=0, columnspan=2, sticky="nsew", padx=5, pady=5) self.output_labelframe.grid_rowconfigure(0, weight=1) self.output_labelframe.grid_columnconfigure(0, weight=1) self.script_status_variable.grid(column=1, row=14, sticky='e') self.record_updates_attempted_label.grid(column=0, row=15) self.records_updated_successsfully_label.grid(column=0, row=16) self.elapsed_time_label.grid(column=0, row=17) self.record_updates_attempted_variable.grid(column=1, row=15, sticky='w') self.records_updated_successsfully_variable.grid(column=1, row=16, sticky='w') self.elapsed_time_variable.grid(column=1, row=17, sticky='w') self.view_output_file_button.grid(column=1, row=18, sticky="ne") self.view_error_log_button.grid(column=1, row=19, sticky="ne") self.view_url_button.grid(column=1, row=20, sticky="ne") ## Clear Inputs, Help Buttons self.clear_labelframe = LabelFrame(self.frame, text=None, bg='gainsboro', highlightthickness=0, padx=1, pady=1) self.clear_labelframe.grid(column=0, columnspan=2, sticky="nsew", padx=5, pady=5) self.clear_labelframe.grid_rowconfigure(0, weight=1) self.clear_labelframe.grid_columnconfigure(0, weight=1) self.clear_all_inputs_button = Button(self.clear_labelframe, text='Clear Inputs', command=self.clear_inputs, relief=RAISED, bd=1, padx=5, pady=5, highlightthickness=0, cursor="hand1") self.clear_all_inputs_button.grid(column=0, row=21) #Initiates error logging self.error_log() ####### Functions ######### #initializes file menu - see https://stackoverflow.com/questions/34442626/why-is-the-menu-not-showing-on-my-tkinter-gui/34442773 def initmenu(self): menubar = Menu(self.master) self.master.config(menu=menubar) filemenu = Menu(menubar) filemenu.add_command(label='Help', command=self.new_window) filemenu.add_command(label='Template', command=self.open_template) filemenu.add_command(label="Exit", command=self.client_exit) menubar.add_cascade(label="File", menu=filemenu) #Opens the help file in a new window def new_window(self): self.newwindow = Toplevel(self.master) self.newwindow.title('Born-Digital Accessioner Help') f = open('./files/bd_accessioner_help.txt', 'r', encoding='utf-8') self.textbox = Text(self.newwindow, width=115) self.textbox.pack(side='top', fill='both', expand=True) self.textbox.insert(0.0, f.read()) self.textbox.config(state=DISABLED, wrap=WORD) self.textbox.grid_rowconfigure(0, weight=1) self.textbox.grid_columnconfigure(0, weight=1) #exits program def client_exit(self): self.quit() #opens the born-dig-accessioner template in the system's default program def open_template(self): #Open template file if sys.platform == "win32": os.startfile('./files/Template_Digital_Accessioning_Service_Metadata_102017.xlsx') else: opener = "open" if sys.platform == "darwin" else "xdg-open" subprocess.call([opener, './files/Template_Digital_Accessioning_Service_Metadata_102017.xlsx']) #logs in to ArchivesSpace API def asloginprocess(self, event=None): try: #basic/imperfect check for improperly formatted URLs urlcheck = re.compile( r'^https?://' r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' r'localhost|' r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' r'(?::\d+)?' r'(?:/?|[/?]\S+)$', re.IGNORECASE) #if URL field is empty; missing field error checks may be obsolete now but I'm leaving it in because the URL checks may not be perfect if self.api_url.get() == '': self.login_confirmed.set('Missing value, try again') #empty username field if self.username.get() == '': self.login_confirmed.set('Missing value, try again') #empty password field if self.password.get() == '': self.login_confirmed.set('Missing value, try again') #uses reg ex above to check formulation of URL; may not be perfect but anything it misses gets caught later if not re.match(urlcheck, self.api_url.get()): self.login_confirmed.set('Invalid URL, try again') else: if self.api_url.get().endswith('/'): self.api_url.set(self.api_url.get() + 'api') else: self.api_url.set(self.api_url.get() + '/api') #self.api_url.set(self.api_url.get()) auth = requests.post(self.api_url.get()+'/users/'+self.username.get()+'/login?password='******'error' in auth.keys(): self.login_confirmed.set('Login failed, try again') elif 'session' in auth.keys(): session = auth["session"] h = {'X-ArchivesSpace-Session':session, 'Content_Type': 'application/json'} self.login_confirmed.set('Login successful!') self.authenticate.set(h) return h #this captures a URL that is valid but not correct, plus any other errors except Exception: self.login_confirmed.set('Error, check login info and try again') #gets headers without logging in to API again - a bit of a hack with the JSON loads (bc the StringVar doesn't return key/value pair), but it works for now def get_headers(self): headers_string = self.authenticate.get() if self.authenticate.get() == '': messagebox.showerror('Error!', 'Please log in to the ArchivesSpace API') return else: valid_json = headers_string.replace("'", "\"") headers_json = json.loads(valid_json) return headers_json #opens CSV def opencsv(self): filename = self.csv_filename.get() if self.csv_filename.get() == '': messagebox.showinfo('Error!', 'Please choose an input CSV') return else: try: file = open(filename, 'r', encoding='utf-8', errors='replace') csvin = csv.reader(file) #Skips first two rows next(csvin, None) next(csvin, None) return csvin except: problem = messagebox.showerror('Error', 'Could not open CSV file.') logging.exception('Error: ') return def outputcsv(self): filename = self.csv_filename.get() newname = filename.rsplit(".", 1)[0] if self.csv_filename.get() == '': messagebox.showinfo('Error!', 'Please choose an input CSV') return else: c = open(newname + '_outfile.csv', 'a', encoding='utf-8', newline='') csvoutputfile = newname + '_outfile.csv' self.csv_output.set(str(csvoutputfile)) writer = csv.writer(c) return (c, writer) def timer(self, start): elapsedTime = time.time() - start m, s = divmod(elapsedTime, 60) h, m = divmod(m, 60) self.elapsed_time.set('%d:%02d:%02d' % (h, m, s)) #gets a list of repositories def repos(self, header_value): repo_list = requests.get(self.api_url.get() + '/repositories', headers=header_value).json() repo_d = {} for repo in repo_list: if repo['repo_code'] not in repo_d: repo_d[repo['repo_code']] = repo['uri'][14:] return repo_d #the ao_id here is the parent archival object ID def create_child_component(self, header_value, repo_num, ao_id, unit_id, extent_type, ao_title, container): ''''This function creates a new archival component, based on the data in the born-digtial accessioning worksheet''' #First, check if there is a value in the top container field. There won't always be one. if container != '': try: #form a new child component using data from the DAS spreadsheet child_component = {"publish": True, "title": ao_title, "level": "item", "component_id": unit_id, "jsonmodel_type": "archival_object","linked_events": [], "extents": [{"number": '1', "portion": "whole", "extent_type": extent_type, "jsonmodel_type": "extent"}], "instances": [{"instance_type": 'mixed_materials', "jsonmodel_type": 'instance', "sub_container": {"jsonmodel_type": 'sub_container', "top_container": {"ref": container} } } ], "resource": {"ref": '/repositories/'+repo_num+'+/resources/'+self.resource_id.get()}, "parent": {"ref": '/repositories/'+repo_num+'/archival_objects/'+ao_id}} except Exception as exc: logging.exception('Error: ') #Do I want this here or do I want to continue when something goes wrong? messagebox.showerror('Error!', 'Something went wrong. Please check error log.') return #if there is no value in the top container field of the DAS spreadsheet, create a child component without a top container else: child_component = {"publish": True, "title": ao_title, "level": "item", "component_id": unit_id, "jsonmodel_type": "archival_object","linked_events": [], "extents": [{ "number": '1', "portion": "whole", "extent_type": extent_type, "jsonmodel_type": "extent"}], "resource": {"ref": '/repositories/'+repo_num+'+/resources/'+self.resource_id.get()}, "parent": {"ref": '/repositories/'+repo_num+'/archival_objects/'+ao_id}} #convert the data back into JSON child_component_data = json.dumps(child_component) #Post the child archival object child_post = requests.post(self.api_url.get()+'/repositories/'+repo_num+'/archival_objects',headers=header_value,data=child_component_data).json() return child_post #Don't use all of those arguments,but need them to make action() work - can I use ***kwargs in the action part?); or default arguments def update_child_component(self, header_value, repo_num, ao_id, unit_id, extent_type, ao_title=None, container=None): #as of right now this function leaves the ArchivesSpace title intact, but could be modified to take title from spreadsheet component_json = requests.get(self.api_url.get()+'/repositories/'+repo_num+'/archival_objects/'+ao_id,headers=header_value).json() #updates component ID component_json['component_id'] = unit_id #updates extent component_json['extents']= [{ "number": '1', "portion": "whole", "extent_type": extent_type, "jsonmodel_type": "extent"}] component_data = json.dumps(component_json) component_post = requests.post(self.api_url.get()+'/repositories/'+repo_num+'/archival_objects/'+ao_id,headers=header_value,data=component_data).json() return component_post def create_event (self, header_value, user, ao_id, repo_num, event_type, outcome_value, date_value, note_value): '''This function creates an event in ASpace, based on the four possible parameters provided in the born-digital accessioning worksheet''' agent_authorizor = user['agent_record']['ref'] # Get the event type event_type = event_type.lower() # Get the event outcome outcome_value = outcome_value.lower() # Get the event date - add a check so that if there's only 2 digits for YY make it YYYY if date_value != '': if '-' in date_value: date_value = date_value.replace('-', '/') if date_value[-4:].isdigit(): date_value = datetime.datetime.strptime(date_value, '%m/%d/%Y').strftime('%Y-%m-%d') else: date_value = datetime.datetime.strptime(date_value, '%m/%d/%y').strftime('%Y-%m-%d') event = {"event_type": event_type, "jsonmodel_type": "event", "outcome": outcome_value, "outcome_note": note_value, "linked_agents": [{ "role": "authorizer", "ref": agent_authorizor }], "linked_records": [{ "role": "source", "ref": '/repositories/'+repo_num+'/archival_objects/'+ao_id }], "date": { "begin": date_value, "date_type": "single", "label": "event", "jsonmodel_type": "date" }} # Post that event event_post = requests.post(self.api_url.get()+'/repositories/'+repo_num+'/events',headers=header_value,json=event).json() logging.debug(str(event_post)) return event_post def get_top_containers(self, csv_var, repo_dictionary, header_value): logging.debug('Setting parent ID') #takes the first parent URL and sets it as the parent self.parent_id.set(csv_var[0][2].rpartition("_")[2]) logging.debug(self.parent_id.get()) #this gets a list of top containers for the parent component - assumes there will only be one parent...is this true?? parent_component = requests.get(self.api_url.get()+'/repositories/'+repo_dictionary.get(csv_var[0][0])+'/archival_objects/'+self.parent_id.get(),headers=header_value).json() tc_list = [instance['sub_container']['top_container']['ref'] for instance in parent_component['instances']] tuplelist = [] for tc_uri in tc_list: top_container = requests.get(self.api_url.get() + tc_uri, headers=header_value).json() tuplelist.append((top_container['uri'], top_container['indicator'])) return tuplelist #this function runs when either the create or update button is pushed. When the create button is pressed, the action variable takes #on the value of the create function, and when the update button is pressed the action variable takes the value of the update function def process_file(self, action): #Initiates the confirmation dialog go = self.areyousure() if go == True: #captures start time starttime = time.time() headers = self.get_headers() if headers != None: #Gets current user - Kevin has proposed changing this to accept a user besides the current user current_user = requests.get(self.api_url.get() + '/users/current-user', headers=headers).json() repo_dict = self.repos(headers) csvfile = self.opencsv() csvlist = [row for row in csvfile] #takes the resource id and sets it as a StringVar logging.debug('Setting resource ID') if '/#' in str(csvlist[0][2]): self.resource_id.set(csvlist[0][2].partition('/#')[0].rpartition('/')[2]) else: self.resource_id.set(csvlist[0][2].partition('#')[0].rpartition('/')[2]) logging.debug(self.resource_id.get()) #see if this works - and see what happens when you set Open in ArchivesSpace URL if action == self.create_child_component: tc_indicator_list = self.get_top_containers(csvlist, repo_dict, headers) if csvlist != None: x = 0 fileobject, csvoutfile = self.outputcsv() try: for i, row in enumerate(csvlist, 1): logging.debug('Working on row ' + str(i)) #should be a better way to skip empty/invalid rows, but i've added this for now - CHANGE THIS!!!! if row[0] in repo_dict: # save the original row length - used to get event data later on original_row_length = len(row) # Getting data from CSV file repo = repo_dict.get(row[0]) parent_ao_id = str(row[2]).rpartition("_")[2] #if calling the update component script, will set the URL as the most recently updated record - #this is for the Open in ArchivesSpace button if action == self.update_child_component: self.parent_id.set(parent_ao_id) #gets the title of the ao, accounting for any HTML that might be present title = cgi.escape(row[3]) component_id = row[4] extent = row[5] top_container = row[6] if top_container != '': logging.debug('Matching top_containers') for uri, indicator in tc_indicator_list: if uri != None: if indicator == top_container: top_container = uri else: #should continue with script or no?? logging.debug('uri == None') #this runs either the create archival objects or update archival objects script, and returns the result logging.debug('Calling action function') updated_component = action(headers, repo, parent_ao_id, component_id, extent, title, top_container) logging.debug('Finishing action function') if updated_component != None: if 'uri' in updated_component: updated_component_uri = updated_component['uri'] row.append(updated_component_uri) #creating events based on the rows in the spreadsheet if original_row_length > 9 and row[8] != '': new_event = self.create_event(headers, current_user, updated_component_uri, repo, row[8], row[9], row[10], cgi.escape(row[11])) row.append(new_event['uri']) if original_row_length > 13 and row[14] != '': new_event = self.create_event(headers, current_user, updated_component_uri, repo, row[12], row[13], row[14], cgi.escape(row[15])) row.append(new_event['uri']) if original_row_length > 17 and row[16] != '': new_event = self.create_event(headers, current_user, updated_component_uri, repo, row[16], row[17], row[18], cgi.escape(row[19])) row.append(new_event['uri']) if original_row_length > 21 and row[20] != '': new_event = self.create_event(headers, current_user, updated_component_uri, repo, row[20], row[21], row[22], cgi.escape(row[23])) row.append(new_event['uri']) x = self.process_results(updated_component, x) csvoutfile.writerow(row) #this catches most errors related to failed posts. else: logging.debug('Error: ' + str(updated_component)) csvoutfile.writerow(row) elif updated_component == None: logging.debug('Component did not create/update') csvoutfile.writerow(row) except: logging.exception('Error: ') csvoutfile.writerow(row) #this will stop the script - should I have it continue instead?? #messagebox.showerror('Error!', 'Something went wrong! Check logs!') #return self.update_attempts.set(str(i)) self.updates_success.set(str(x)) self.timer(starttime) #add logging here logging.debug('Update attempts: ' + str(i)) logging.debug('Updated successfully: ' + str(x)) logging.debug('Elapsed time: ' + self.elapsed_time.get()) #change this so that it's inside the loop done = self.script_finished() fileobject.close() else: return else: return else: return #connected to "create child component" button def run_create_script(self): self.process_file(self.create_child_component) #connected to "update child component" button def run_update_script(self): self.process_file(self.update_child_component) #Initiate logging - is this all I need? See logging cookbook in Python docs def error_log(self): #make sure this works on all systems...add another temp folder for pre-Windows 10? if sys.platform == "win32": self.log_file.set('\\Windows\\Temp\\error_log.log') else: self.log_file.set('/tmp/error_log.log') #Basic logging config logging.basicConfig(filename=self.log_file.get(), level=logging.DEBUG, format='%(asctime)s %(levelname)s %(name)s %(message)s') def process_results(self, jsonname, counter): for key, value in jsonname.items(): if key == 'status': counter +=1 return counter if key == 'error': logging.debug(str(datetime.datetime.now())) logging.debug(str(jsonname.get('error'))) ### WIDGET FILE HANDLING ### #File open dialog for input CSV button widget def csvbutton(self): filename = filedialog.askopenfilename(parent=self.frame) self.csv_filename.set(str(filename)) return filename #opens csv output file via button widget def opencsvoutput(self): filename = self.csv_output.get() if sys.platform == "win32": os.startfile(filename) else: opener = "open" if sys.platform == "darwin" else "xdg-open" subprocess.call([opener, filename]) #opens program log via button widget - will this work if there is no log? def openerrorlog(self): #filename = self.log_file.get() if sys.platform == "win32": try: os.startfile('\\Windows\\Temp\\error_log.log') except: messagebox.showerror('Error!', 'Error log does not exist') else: opener = "open" if sys.platform == "darwin" else "xdg-open" try: subprocess.call([opener, '/tmp/error_log.log']) except: messagebox.showerror('Error!', 'Error log does not exist') #Opens the parent record in ArchivesSpace staff interface via button widget def openparent_record(self): #this is where I could use the resource ID url_end = self.parent_id.get() resource = self.resource_id.get() get_api = self.api_url.get() base_url = get_api[:-3] #add something here to make sure there are enough/not to many forward slashes...still works but doesn't look right full_url = base_url + '/resources/' + resource + '#tree::archival_object_' + url_end if full_url[-1].isdigit() : try: webbrowser.open(full_url, new=2) except: messagebox.showerror('Error!', '\n Invalid URL') else: if 'https' in base_url: webbrowser.open(base_url, new=2) else: messagebox.showerror('Error!', '\n Invalid URL') #message box confirming actions, that script is about run def areyousure(self): result = messagebox.askyesno('Are you sure?', '\n Click YES to proceed, NO to cancel') if result == True: self.script_status.set('...Updates in progress...') self.script_status.get() if result == False: false = messagebox.showinfo('Updates Canceled', '\n\n Press OK to return to menu') return result #Show script finished message on frame def script_finished(self): # box = messagebox.showinfo('Done!', 'Script finished. Check outfile for details') self.script_status.set('Updates finished!') self.script_status.get() #Clear all GUI inputs - start fresh def clear_inputs(self): r = messagebox.askyesno('Are you sure?', '\nClick YES to clear inputs, NO to cancel') if r == True: self.api_url.set('') self.username.set('') self.password.set('') self.login_confirmed.set('') self.csv_filename.set('') self.update_attempts.set('') self.updates_success.set('') self.elapsed_time.set('') self.script_status.set('') self.parent_id.set('') else: return
def show_streams_mediainfo_function(x): # Stream Viewer global stream_win_text_area, exit_stream_window, stream_window video_input = pathlib.Path(x) # "x" is passed through from main GUI # Defines the path to config.ini and opens it for reading/writing config_file = 'Runtime/config.ini' # Creates (if it doesn't exist) and defines location of config.ini config = ConfigParser() config.read(config_file) detect_font = font.nametofont("TkDefaultFont") # Get default font value into Font object set_font = detect_font.actual().get("family") # set_font_size = detect_font.actual().get("size") try: stream_win_text_area.config(state=NORMAL) stream_win_text_area.delete(1.0, END) except (NameError, TclError): stream_window = Toplevel() stream_window.title("Audio Streams") stream_window.configure(background="#434547") stream_window.resizable(False, False) # Disable resize of this window if config['save_window_locations']['audio window - view streams - position'] != '' and \ config['save_window_locations']['audio window - view streams'] == 'yes': stream_window.geometry(config['save_window_locations']['audio window - view streams - position']) stream_window.protocol('WM_DELETE_WINDOW', exit_stream_window) stream_window.grid_columnconfigure(0, weight=1) stream_window.grid_rowconfigure(0, weight=1) stream_window_frame = LabelFrame(stream_window, text=' Audio Streams ', labelanchor="n") stream_window_frame.grid(column=0, row=0, columnspan=1, padx=5, pady=(0, 3), sticky=N + S + E + W) stream_window_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 10, "bold")) stream_window_frame.grid_rowconfigure(0, weight=1) stream_window_frame.grid_columnconfigure(0, weight=1) stream_win_text_area = scrolledtext.ScrolledText(stream_window_frame, width=80, height=25, tabs=10, spacing2=3, spacing1=2, spacing3=3) stream_win_text_area.config(bg='black', fg='#CFD2D1', bd=8) stream_win_text_area.grid(column=0, pady=5, padx=5, sticky=N + E + S + W) character_space = 30 # Can be changed to adjust space of all items in the list automatically media_info = MediaInfo.parse(video_input) # Uses pymediainfo to get information for track selection for track in media_info.tracks: # For loop to loop through mediainfo tracks # Formatting -------------------------------------------------------------------------------------------------- if track.track_type == 'Audio': # Only grab audio track information if str(track.stream_identifier) != 'None': # Gets stream # audio_track_id_space = 'Track#' + ' ' * int(f'{character_space - len("Track#")}') audio_track_id = audio_track_id_space + f': {str(int(track.stream_identifier) + 1)}\n' else: audio_track_id = '' if str(track.format) != 'None': # Gets format string of tracks (aac, ac3 etc...) audio_format_space = 'Codec' + ' ' * int(f'{character_space - len("Codec")}') audio_format = audio_format_space + f": {str(track.commercial_name)} - ({str(track.format).lower()})\n" else: audio_format = '' if str(track.channel_s) != 'None': # Gets audio channels of input tracks audio_channel_space = 'Channels' + ' ' * int(f'{character_space - len("Channels")}') if str(track.channel_s) == '8': show_channels = '7.1' elif str(track.channel_s) == '6': show_channels = '5.1' elif str(track.channel_s) == '3': show_channels = '2.1' else: show_channels = str(track.channel_s) audio_channels = audio_channel_space + f": {show_channels} - {str(track.channel_layout)}\n" else: audio_channels = '' if str(track.bit_rate_mode) != 'None': # Gets audio bit rate mode audio_bitrate_mode_space = 'Bit rate mode' + ' ' * int(f'{character_space - len("Bit rate mode")}') if str(track.other_bit_rate_mode) != 'None': # Get secondary string of audio bit rate mode audio_bitrate_mode = audio_bitrate_mode_space + f": {str(track.bit_rate_mode)} / " \ f"{str(track.other_bit_rate_mode[0])}\n" else: audio_bitrate_mode = audio_bitrate_mode_space + f": {str(track.bit_rate_mode)}\n" else: audio_bitrate_mode = '' if str(track.other_bit_rate) != 'None': # Gets audio bit rate of input tracks audio_bitrate_space = 'Bit rate' + ' ' * int(f'{character_space - len("Bit rate")}') audio_bitrate = audio_bitrate_space + f": {str(track.other_bit_rate[0])}\n" else: audio_bitrate = '' if str(track.other_language) != 'None': # Gets audio language of input tracks audio_language_space = 'Language' + ' ' * int(f'{character_space - len("Language")}') audio_language = audio_language_space + f": {str(track.other_language[0])}\n" else: audio_language = '' if str(track.title) != 'None': # Gets audio title of input tracks audio_title_space = 'Title' + ' ' * int(f'{character_space - len("Title")}') if len(str(track.title)) > 40: # Counts title character length audio_title = audio_title_space + f": {str(track.title)[:40]}...\n" # If title > 40 characters else: audio_title = audio_title_space + f": {str(track.title)}\n" # If title is < 40 characters else: audio_title = '' if str(track.other_sampling_rate) != 'None': # Gets audio sampling rate of input tracks audio_sampling_rate_space = 'Sampling Rate' + ' ' * int(f'{character_space - len("Sampling Rate")}') audio_sampling_rate = audio_sampling_rate_space + f": {str(track.other_sampling_rate[0])}\n" else: audio_sampling_rate = '' if str(track.other_duration) != 'None': # Gets audio duration of input tracks audio_duration_space = 'Duration' + ' ' * int(f'{character_space - len("Duration")}') audio_duration = audio_duration_space + f": {str(track.other_duration[0])}\n" else: audio_duration = '' if str(track.delay) != 'None': # Gets audio delay of input tracks if str(track.delay) == '0': audio_delay = '' else: audio_delay_space = 'Delay' + ' ' * int(f'{character_space - len("Delay")}') audio_del_to_vid_space = 'Delay to Video' + ' ' * int(f'{character_space - len("Delay to Video")}') audio_delay = audio_delay_space + f': {str(track.delay)}ms\n' \ + audio_del_to_vid_space + f': {str(track.delay_relative_to_video)}ms\n ' else: audio_delay = '' if str(track.other_stream_size) != 'None': # Get tracks stream size audio_track_size_space = 'Stream size' + ' ' * int(f'{character_space - len("Stream size")}') audio_track_stream_size = audio_track_size_space + f": {str(track.other_stream_size[4])}\n" else: audio_track_stream_size = '' if str(track.other_bit_depth) != 'None': # Get tracks bit-depth audio_track_b_depth_space = 'Bit Depth' + ' ' * int(f'{character_space - len("Bit Depth")}') audio_track_bit_depth = audio_track_b_depth_space + f": {(track.other_bit_depth[0])}\n" else: audio_track_bit_depth = '' if str(track.compression_mode) != 'None': audio_track_compression_space = 'Compression' + ' ' * int(f'{character_space - len("Compression")}') audio_track_compression = audio_track_compression_space + f": {str(track.compression_mode)}\n" else: audio_track_compression = '' if str(track.default) != 'None': # Get tracks default boolean audio_track_default_space = 'Default' + ' ' * int(f'{character_space - len("Default")}') audio_track_default = audio_track_default_space + f": {str(track.default)}\n" else: audio_track_default = '' if str(track.forced) != 'None': # Get tracks forced boolean audio_track_forced_space = 'Forced' + ' ' * int(f'{character_space - len("Forced")}') audio_track_forced = audio_track_forced_space + f": {str(track.forced)}" else: audio_track_forced = '' # ---------------------------------------------------------------------------------------------- Formatting audio_track_info = str(audio_track_id + audio_format + audio_channels + audio_bitrate_mode + audio_bitrate + audio_sampling_rate + audio_delay + audio_duration + audio_language + audio_title + audio_track_stream_size + audio_track_bit_depth + audio_track_compression + audio_track_default + audio_track_forced) # Formatting media_info_track_string = 80 * '#' + '\n' + audio_track_info + '\n' + 80 * '#' + '\n' # String to insert stream_win_text_area.configure(state=NORMAL) # Enable textbox stream_win_text_area.insert(INSERT, media_info_track_string) # Insert string stream_win_text_area.insert(INSERT, '\n') # Insert a newline stream_win_text_area.configure(state=DISABLED) # Disable textbox def right_click_menu_func(x_y_pos): # Function for mouse button 3 (right click) to pop up menu right_click_menu.tk_popup(x_y_pos.x_root, x_y_pos.y_root) # This gets the position of cursor def copy_selected_text(): # Function to copy only selected text pya_hotkey('ctrl', 'c') time_sleep(.01) # Slow program incase ctrl+c is slower right_click_menu = Menu(stream_window, tearoff=False) # This is the right click menu right_click_menu.add_command(label='Copy Selected Text', command=copy_selected_text) right_click_menu.add_command(label='Copy All Text', command=pyperclip_copy(stream_win_text_area.get(1.0, END))) stream_window.bind('<Button-3>', right_click_menu_func) # Uses mouse button 3 (right click) to pop up menu Hovertip(stream_win_text_area, 'Right click to copy', hover_delay=1200) # Hover tip tool-tip
class GUI: def fill_all(self): for course in self.selected_course_list: self.fill_table(course, course.color) def fill_table(self, course, bg="green", isRemove=False): for time in course.get_tuple_times(): col = week_days.index(time[0]) rows = start_end_time(time[1]) if "22:00" in time[1]: rows[1]+=1 if not isRemove: collision_list = self.table.find_collision(rows, col, course.name) else: collision_list = [] for row in range(rows[0], rows[1]): if isRemove: self.table.change_cell(row, col, "", bg) else: if row in collision_list: self.table.change_cell(row, col, "-1", "red") else: self.table.change_cell(row, col, course.name, bg) def fetch_courses(self): url = self.url_text.get() if url != "": self.color_num = 0 self.selected_course_list = [] self.current_course = None self.course_list = [] self.courses_listbox.delete(0,"end") soup = soup_requests(url) rows = soup.select(".MsoTableGrid > tbody > tr") for row in rows: cells = row.select("td") cellTexts = [soup_get_text(cells[0]), soup_get_text(cells[2]), soup_get_text(cells[3])] i = 0 if cellTexts[0]!="" and cellTexts[1]!="" and cellTexts[2]!="": i+=1 course = Course(cellTexts[0], cellTexts[1], cellTexts[2]) self.course_list.append(course) self.course_list = sorted(self.course_list,key=lambda course: str(course)) self.filtered_course_list = self.course_list for i,course in enumerate(self.course_list): self.courses_listbox.insert(i+1, course) def add_course(self): if self.current_course: if self.current_course not in self.selected_course_list: for time in self.current_course.get_tuple_times(): col = week_days.index(time[0]) rows = start_end_time(time[1]) collision_list = self.table.find_collision(rows, col, self.current_course.name) if len(collision_list) != 0: self.error_label.config(text="Cloud not be added", bg="red") return if self.color_num == len(colors)-1: self.color_num = 0 else: self.color_num += 1 self.current_course.set_color(colors[self.color_num]) self.selected_course_list.append(self.current_course) size = len(self.selected_course_list) self.fill_table(self.current_course, colors[self.color_num]) self.cur_courses_listbox.insert(size, self.current_course) self.current_course = None def add_list_select(self, event): self.error_label.config(text="", bg=self.main_frame["bg"]) widget = event.widget selecteds = widget.curselection() if selecteds: self.current_course = self.filtered_course_list[selecteds[0]] if self.current_course in self.selected_course_list: return self.table.reset_table() self.fill_all() self.fill_table(self.current_course, "yellow") def remove_course(self): if self.remove_list_selected != None: self.cur_courses_listbox.delete(self.remove_list_selected_index) self.selected_course_list.remove(self.remove_list_selected) self.table.reset_table() self.fill_all() self.remove_list_selected = None def remove_list_select(self, event): widget = event.widget selecteds = widget.curselection() if selecteds: self.remove_list_selected_index = selecteds[0] self.remove_list_selected = self.selected_course_list[self.remove_list_selected_index] def uptade_list(self, *args): term = self.filter_var.get() if term == "": self.filtered_course_list = self.course_list else: term = term.lower() self.filtered_course_list = [] for c in self.course_list: if term in c.name.lower(): self.filtered_course_list.append(c) self.courses_listbox.delete(0,"end") for i, c in enumerate(self.filtered_course_list): self.courses_listbox.insert(i+1, c) def __init__(self): self.main_window = Tk() self.main_window.title("Sehir Course Planner") self.main_window.minsize(1000, 800) self.main_frame = Frame(self.main_window) Label(self.main_frame, text="Sehir Course Planner", bg="black", fg="dodger blue", padx=2, pady=2, font="Area 20").pack(fill="x") #url self.url_frame = Frame(self.main_frame) Label(self.url_frame, text="Course Offerings Url:", font="Area 14").grid(row=0, column=0, padx=10) self.url_text = Entry(self.url_frame, font="Area 12", width=80) self.url_text.grid(row=0, column=1) self.url_text.insert(INSERT, "https://www.sehir.edu.tr/tr/duyurular/2019_2020_akademik_yili_bahar_donemi_ders_programi") Button(self.url_frame, text="Fetch Courses", command=self.fetch_courses).grid(row=0, column=2, padx=10) self.url_frame.pack(padx=15, pady=10) #course frame self.course_frame = LabelFrame(self.main_frame) self.course_left = Frame(self.course_frame) self.course_filter_frame = Frame(self.course_left) Label(self.course_filter_frame, text="Filter:", font="Area 12").grid(row=0, column=0) self.filter_var = StringVar() self.filter_var.trace("w", self.uptade_list) self.filter_entry = Entry(self.course_filter_frame, font="Area 12", textvariable=self.filter_var) self.filter_entry.grid(row=0, column=1) self.course_filter_frame.grid_columnconfigure(0, weight=1) self.course_filter_frame.grid_columnconfigure(1, weight=2) self.course_filter_frame.pack(fill="x",pady=5) self.course_left_listbox_frame = Frame(self.course_left) self.courses_scroll = Scrollbar(self.course_left_listbox_frame) self.courses_scroll.pack(side=RIGHT, fill="y") self.courses_listbox = Listbox(self.course_left_listbox_frame, yscrollcommand=self.courses_scroll.set, height=6) self.courses_listbox.bind("<<ListboxSelect>>", self.add_list_select) self.courses_listbox.pack(fill="x") self.courses_scroll.config(command=self.courses_listbox.yview) self.course_left_listbox_frame.pack(fill="x") self.course_left.grid(sticky="nsew", row=0, column=0, padx=10, pady=10) self.course_mid = Frame(self.course_frame) self.error_label = Label(self.course_mid) self.error_label.pack(fill="x") Button(self.course_mid, text="Add", command=self.add_course).pack(pady=10) Button(self.course_mid, text="Remove", command=self.remove_course).pack(pady=10) self.course_mid.grid(row=0, column=1) self.course_right = Frame(self.course_frame) Label(self.course_right, text="Selected Courses", font="Area 12").pack(fill="x") self.course_right_listbox_frame = Frame(self.course_right) self.selected_courses_scroll = Scrollbar(self.course_right_listbox_frame) self.selected_courses_scroll.pack(side=RIGHT, fill="y") self.cur_courses_listbox = Listbox(self.course_right_listbox_frame, yscrollcommand=self.selected_courses_scroll.set, height=6) self.cur_courses_listbox.bind("<<ListboxSelect>>", self.remove_list_select) self.cur_courses_listbox.pack(fill="x") self.selected_courses_scroll.config(command=self.cur_courses_listbox.yview) self.course_right_listbox_frame.pack(fill="x") self.course_right.grid(sticky="nsew", row=0, column=2, padx=10, pady=10) self.course_frame.grid_columnconfigure(0, weight=10) self.course_frame.grid_columnconfigure(1, weight=1) self.course_frame.grid_columnconfigure(2, weight=10) self.course_frame.pack(fill="x", padx=15, pady=10) self.table = TimeTable(self.main_frame) self.table.fill_table() self.table.pack(fill="x", padx=15, pady=10) self.main_frame.pack(fill="both", expand=True) def show(self): self.main_window.mainloop()
def __init__(self, thread_cls): super().__init__() self.thread_cls = thread_cls self.img = None self.title("Emotion API") self.grid() self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(1, weight=2) self.grid_rowconfigure(4, weight=1) # Create LabelFrames lf_key = LabelFrame(self, text="Emotion API Key") lf_key.grid(row=0, column=0, columnspan=1, sticky=W + E, padx=5, pady=3) lf_key.grid_columnconfigure(0, weight=1) lf_mode = LabelFrame(self, text="Mode") lf_mode.grid(row=1, column=0, columnspan=1, sticky=W + E, padx=5, pady=3) for i in range(3): lf_mode.grid_columnconfigure(i, weight=1) lf_source = LabelFrame(self, text="Image Source", height=50) lf_source.grid(row=2, column=0, columnspan=1, sticky=W + E, padx=5, pady=3) lf_source.rowconfigure(0, weight=1) lf_source.grid_propagate(False) lf_source.columnconfigure(0, weight=1) lf_source.columnconfigure(1, weight=5) lf_source.columnconfigure(2, weight=1) lf_request = LabelFrame(self, text="Request Result") lf_request.grid(row=3, column=0, columnspan=1, sticky=W + E, padx=5, pady=3) lf_request.grid_columnconfigure(0, weight=1) lf_console = LabelFrame(self, text="Console") lf_console.grid(row=4, column=0, columnspan=1, sticky=N + S + W + E, padx=5, pady=3) lf_console.grid_columnconfigure(0, weight=1) lf_console.grid_rowconfigure(0, weight=1) lf_img = LabelFrame(self, text="Output Image") lf_img.grid(row=0, column=1, rowspan=5, sticky=N + S + W + E) lf_img.grid_columnconfigure(0, weight=1) lf_img.grid_rowconfigure(0, weight=1) # Create Input Fields self.ety_key = Entry(lf_key) self.ety_key.insert(END, "bfe9b2f471e04b29a8fabfe3dd9f647d") self.ety_key.grid(sticky=W + E, padx=3) self.var_mode = StringVar() Radiobutton(lf_mode, text="Local Image", variable=self.var_mode, value='local', command=self.change_mode).grid(row=1, column=0) Radiobutton(lf_mode, text="URL Image", variable=self.var_mode, value='url', command=self.change_mode).grid(row=1, column=1) Radiobutton(lf_mode, text="Camera", variable=self.var_mode, value='cam', command=self.change_mode).grid(row=1, column=2) # Local Image Source self.lb_filename = Label(lf_source, text="..") self.btn_fileopen = Button(lf_source, text="Open..", command=self.get_local_img) # URL Image Source self.lb_url = Label(lf_source, text="URL") self.ety_url = Entry(lf_source) self.ety_url.insert(END, "https://i.imgflip.com/qiev6.jpg") self.btn_url = Button(lf_source, text="Get Image", command=self.get_url_img) # Camera Image Source self.btn_get_cam = Button(lf_source, text="Get the Camera Image", command=self.get_cam_img) # set default mode: local raw image self.var_mode.set('local') self.change_mode() # request btn self.btn_request = Button(lf_request, text="Request Result", command=self.run_request, state='disable') self.btn_request.grid(sticky=W + E) # Create Output Console self.console = ScrolledText(lf_console, state='disable', width=60, bg='gray20', fg='white') self.console.grid(sticky=N + S + W + E) # Create Output Image self.plot = ResultImg(lf_img) self.plot.grid(sticky=N + S + W + E)
t1.grid_rowconfigure( 2, weight=1) # weight attr is similar to flex:1 in css flexbox t1.grid_columnconfigure(0, weight=1) section1 = LabelFrame(t1, text="Team Data") # tkinter fieldsets section2 = LabelFrame(t1, text="") section3 = LabelFrame(t1, text="Team List", bd=2) section1.grid(row=0, column=0, padx=20, pady=5, sticky="new") section2.grid(row=1, column=0, padx=20, pady=5, sticky="new") section3.grid(row=2, column=0, columnspan=4, padx=20, pady=5, sticky="nsew") """ SECTION 1 - TEAM DATA """ section1.grid_rowconfigure(0, weight=1) section1.grid_columnconfigure([1, 2], weight=1) team_label = Label(section1, text='Member', font=('bold', 11)) team_label.grid(row=0, column=0, padx=10, pady=10) team_text = StringVar() # below set have assumed for ex. a pc username named fdrandom # would be the user of F.D. in db Team column and on the tk menu team_text.set(f"{userPC[0].upper()}.{userPC[1].upper()}.") # team_text.set to a default value -> team_text.set(TeamPPL[0]) team_dropdown = OptionMenu(section1, team_text, *TeamPPL) # dropdown menu # dropdown menu bg and fg colour when user hovers over team_dropdown['menu'].config(activebackground='#007bff', activeforeground="white") team_dropdown.grid(row=0, column=1, ipadx=15, padx=6, pady=12, sticky="ew") # day from tkcalendar
def open_general_settings(): # General Settings Window global general_settings_window try: # Check if window is already open, if it's open break from function if general_settings_window.winfo_exists(): return except NameError: pass def general_settings_exit_function( ): # Exit function when hitting the 'X' button general_parser = ConfigParser() general_parser.read(config_file) if general_parser['save_window_locations'][ 'general settings'] == 'yes': # If auto save position on try: if general_parser['save_window_locations']['general settings position'] != \ general_settings_window.geometry(): general_parser.set('save_window_locations', 'general settings position', general_settings_window.geometry()) with open(config_file, 'w') as generalfile: general_parser.write(generalfile) except (Exception, ): pass general_settings_window.grab_release() # Release grab on window general_settings_window.destroy() # Close window # Config Parser config_file = 'Runtime/config.ini' config_parser = ConfigParser() config_parser.read(config_file) # Config Parser general_settings_window = Toplevel() # Define toplevel() general_settings_window.title('General Settings') detect_font = font.nametofont( "TkDefaultFont") # Get default font value into Font object set_font = detect_font.actual().get("family") color1 = "#434547" general_settings_window.configure(background=color1) if config_parser['save_window_locations']['general settings position'] == '' or \ config_parser['save_window_locations']['general settings'] == 'no': window_height = 670 window_width = 640 screen_width = general_settings_window.winfo_screenwidth() screen_height = general_settings_window.winfo_screenheight() x_coordinate = int((screen_width / 2) - (window_width / 2)) y_coordinate = int((screen_height / 2) - (window_height / 2)) general_settings_window.geometry( f"{window_width}x{window_height}+{x_coordinate}+{y_coordinate}") elif config_parser['save_window_locations']['general settings position'] != '' and \ config_parser['save_window_locations']['general settings'] == 'yes': general_settings_window.geometry(config_parser['save_window_locations'] ['general settings position']) general_settings_window.protocol('WM_DELETE_WINDOW', general_settings_exit_function) general_settings_window.grab_set( ) # Focus all of tkinters attention on this window only general_settings_window.rowconfigure(0, weight=1) general_settings_window.grid_columnconfigure(0, weight=1) # Themes ---------------------------------------------------------------------------------------------------------- # Hover over button theme --------------------------------------- class HoverButton(Button): def __init__(self, master, **kw): Button.__init__(self, master=master, **kw) self.defaultBackground = self["background"] self.bind("<Enter>", self.on_enter) self.bind("<Leave>", self.on_leave) def on_enter(self, _): self['background'] = self['activebackground'] def on_leave(self, _): self['background'] = self.defaultBackground # --------------------------------------- Hover over button theme # Settings Notebook Frame ----------------------------------------------------------------------------------------- tabs = ttk.Notebook(general_settings_window) tabs.grid(row=0, column=0, columnspan=4, sticky=E + W + N + S, padx=0, pady=0) settings_tab = Frame(tabs, background="#434547") tabs.add(settings_tab, text=' Paths ') for n in range(4): settings_tab.grid_columnconfigure(n, weight=1) for n in range(2): settings_tab.grid_rowconfigure(n, weight=1) # ---------------------------------------------------------------------------------------- Settings Notebook Frame # ---------------------------------------------------------------------------------------------------------- Themes path_frame = LabelFrame(settings_tab, text=' Tool Paths ', labelanchor="n") path_frame.grid(column=0, row=0, columnspan=4, padx=5, pady=(10, 3), sticky=N + S + E + W) path_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 10, "bold")) for p_f in range(5): path_frame.grid_rowconfigure(p_f, weight=1) for p_f in range(4): path_frame.grid_columnconfigure(p_f, weight=1) # FFMPEG Path ----------------------------------------------------------------------------------------------------- ffmpeg_frame = LabelFrame(path_frame, text=' FFMPEG ', labelanchor="nw") ffmpeg_frame.grid(column=0, row=0, columnspan=4, padx=5, pady=(5, 3), sticky=E + W) ffmpeg_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 9, "italic")) ffmpeg_frame.grid_rowconfigure(0, weight=1) ffmpeg_frame.grid_columnconfigure(0, weight=1) ffmpeg_frame.grid_columnconfigure(1, weight=20) def set_ffmpeg_path(): path = filedialog.askopenfilename( title='Select Location to "ffmpeg.exe"', initialdir=pathlib.Path(ffmpeg_entry_box.get()).parent, filetypes=[('ffmpeg', 'ffmpeg.exe')], parent=general_settings_window) if path: ffmpeg_parser = ConfigParser() ffmpeg_parser.read(config_file) ffmpeg = f'"{str(pathlib.Path(path))}"' ffmpeg_parser.set('ffmpeg_path', 'path', ffmpeg) with open(config_file, 'w') as ffmpeg_configfile: ffmpeg_parser.write(ffmpeg_configfile) ffmpeg_entry_box.config(state=NORMAL) ffmpeg_entry_box.delete(0, END) ffmpeg_entry_box.insert( 0, str( pathlib.Path( str(ffmpeg_parser['ffmpeg_path']['path']).replace( '"', '')).resolve())) ffmpeg_entry_box.config(state=DISABLED) set_ffmpeg_path = HoverButton(ffmpeg_frame, text="Set Path", command=set_ffmpeg_path, foreground="white", background="#23272A", borderwidth="3", activebackground='grey') set_ffmpeg_path.grid(row=0, column=0, columnspan=1, padx=5, pady=5, sticky=N + S + E + W) saved_ffmpeg_path = pathlib.Path( str(config_parser['ffmpeg_path']['path']).replace('"', '')).resolve() ffmpeg_entry_box = Entry(ffmpeg_frame, borderwidth=4, background="#CACACA") ffmpeg_entry_box.grid(row=0, column=1, columnspan=3, padx=5, pady=5, sticky=N + S + E + W) ffmpeg_entry_box.insert(0, str(saved_ffmpeg_path)) ffmpeg_entry_box.config(state=DISABLED) # MPV Path -------------------------------------------------------------------------------------------------------- mpv_frame = LabelFrame(path_frame, text=' MPV ', labelanchor="nw") mpv_frame.grid(column=0, row=1, columnspan=4, padx=5, pady=(5, 3), sticky=E + W) mpv_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 9, "italic")) mpv_frame.grid_rowconfigure(0, weight=1) mpv_frame.grid_columnconfigure(0, weight=1) mpv_frame.grid_columnconfigure(1, weight=20) def set_mpv_path(): path = filedialog.askopenfilename(title='Select Location to "mpv.exe"', initialdir=pathlib.Path( mpv_entry_box.get()).parent, filetypes=[('mpv', 'mpv.exe')], parent=general_settings_window) if path: mpv_cfg_parser = ConfigParser() mpv_cfg_parser.read(config_file) mpv = f'"{str(pathlib.Path(path))}"' mpv_cfg_parser.set('mpv_player_path', 'path', mpv) with open(config_file, 'w') as mpv_cfg: mpv_cfg_parser.write(mpv_cfg) mpv_entry_box.config(state=NORMAL) mpv_entry_box.delete(0, END) mpv_entry_box.insert( 0, str( pathlib.Path( str(mpv_cfg_parser['mpv_player_path']['path']).replace( '"', '')).resolve())) mpv_entry_box.config(state=DISABLED) set_mpv_path = HoverButton(mpv_frame, text="Set Path", command=set_mpv_path, foreground="white", background="#23272A", borderwidth="3", activebackground='grey') set_mpv_path.grid(row=0, column=0, columnspan=1, padx=5, pady=5, sticky=N + S + E + W) saved_mpv_path = pathlib.Path( str(config_parser['mpv_player_path']['path']).replace('"', '')).resolve() mpv_entry_box = Entry(mpv_frame, borderwidth=4, background="#CACACA") mpv_entry_box.grid(row=0, column=1, columnspan=3, padx=5, pady=5, sticky=N + S + E + W) mpv_entry_box.insert(0, str(saved_mpv_path)) mpv_entry_box.config(state=DISABLED) # Media Info Gui Path --------------------------------------------------------------------------------------------- mediainfogui_frame = LabelFrame(path_frame, text=' MediaInfo GUI ', labelanchor="nw") mediainfogui_frame.grid(column=0, row=2, columnspan=4, padx=5, pady=(5, 3), sticky=E + W) mediainfogui_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 9, "italic")) mediainfogui_frame.grid_rowconfigure(0, weight=1) mediainfogui_frame.grid_columnconfigure(0, weight=1) mediainfogui_frame.grid_columnconfigure(1, weight=20) def set_mediainfogui_path(): path = filedialog.askopenfilename( title='Select Location to "mediainfo.exe"', initialdir=pathlib.Path(mediainfogui_entry_box.get()).parent, filetypes=[('mediainfo', 'mediainfo.exe')], parent=general_settings_window) if path: mediainfo_cfg_parser = ConfigParser() mediainfo_cfg_parser.read(config_file) mediainfogui = f'"{str(pathlib.Path(path))}"' mediainfo_cfg_parser.set('mediainfogui_path', 'path', mediainfogui) with open(config_file, 'w') as mediainfo_cfg: mediainfo_cfg_parser.write(mediainfo_cfg) mediainfogui_entry_box.config(state=NORMAL) mediainfogui_entry_box.delete(0, END) mediainfogui_entry_box.insert( 0, str( pathlib.Path( str(mediainfo_cfg_parser['mediainfogui_path'] ['path']).replace('"', '')).resolve())) mediainfogui_entry_box.config(state=DISABLED) set_mediainfogui_path = HoverButton(mediainfogui_frame, text="Set Path", command=set_mediainfogui_path, foreground="white", background="#23272A", borderwidth="3", activebackground='grey') set_mediainfogui_path.grid(row=0, column=0, columnspan=1, padx=5, pady=5, sticky=N + S + E + W) saved_mediainfogui_path = pathlib.Path( str(config_parser['mediainfogui_path']['path']).replace('"', '')).resolve() mediainfogui_entry_box = Entry(mediainfogui_frame, borderwidth=4, background="#CACACA") mediainfogui_entry_box.grid(row=0, column=1, columnspan=3, padx=5, pady=5, sticky=N + S + E + W) mediainfogui_entry_box.insert(0, str(saved_mediainfogui_path)) mediainfogui_entry_box.config(state=DISABLED) # FDK-AAC Path ---------------------------------------------------------------------------------------------------- fdkaac_frame = LabelFrame(path_frame, text=' FDK-AAC ', labelanchor="nw") fdkaac_frame.grid(column=0, row=3, columnspan=4, padx=5, pady=(5, 3), sticky=E + W) fdkaac_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 9, "italic")) fdkaac_frame.grid_rowconfigure(0, weight=1) fdkaac_frame.grid_columnconfigure(0, weight=1) fdkaac_frame.grid_columnconfigure(1, weight=20) saved_fdkaac_path = None def set_fdk_aac_path(): path = filedialog.askopenfilename( title='Select Location to "fdkaac.exe"', initialdir=pathlib.Path(fdkaac_entry_box.get()).parent, filetypes=[('FDK-AAC', 'fdkaac.exe')], parent=general_settings_window) if path: fdk_parser = ConfigParser() fdk_parser.read(config_file) fdkaac = f'"{str(pathlib.Path(path))}"' fdk_parser.set('fdkaac_path', 'path', fdkaac) with open(config_file, 'w') as fdk_cfg: fdk_parser.write(fdk_cfg) fdkaac_entry_box.config(state=NORMAL) fdkaac_entry_box.delete(0, END) fdkaac_entry_box.insert( 0, str( pathlib.Path( str(fdk_parser['fdkaac_path']['path']).replace( '"', '')).resolve())) fdkaac_entry_box.config(state=DISABLED) set_fdkaac_path = HoverButton(fdkaac_frame, text="Set Path", command=set_fdk_aac_path, foreground="white", background="#23272A", borderwidth="3", activebackground='grey') set_fdkaac_path.grid(row=0, column=0, columnspan=1, padx=5, pady=5, sticky=N + S + E + W) if config_parser['fdkaac_path']['path'] == '': saved_fdkaac_path = 'not installed'.title() elif config_parser['fdkaac_path']['path'] != '': if pathlib.Path( str(config_parser['fdkaac_path']['path']).replace( '"', '')).exists(): saved_fdkaac_path = '"' + str( pathlib.Path( str(config_parser['fdkaac_path']['path']).replace( '"', '')).resolve()) + '"' else: saved_fdkaac_path = 'not installed'.title() func_parser = ConfigParser() func_parser.read(config_file) func_parser.set('fdkaac_path', 'path', '') with open(config_file, 'w') as configfile: func_parser.write(configfile) fdkaac_entry_box = Entry(fdkaac_frame, borderwidth=4, background="#CACACA") fdkaac_entry_box.grid(row=0, column=1, columnspan=3, padx=5, pady=5, sticky=N + S + E + W) fdkaac_entry_box.insert(0, str(saved_fdkaac_path).replace('"', '')) fdkaac_entry_box.config(state=DISABLED) # QAAC Path ------------------------------------------------------------------------------------------------------- qaac_frame = LabelFrame(path_frame, text=' QAAC ', labelanchor="nw") qaac_frame.grid(column=0, row=4, columnspan=4, padx=5, pady=(5, 3), sticky=E + W) qaac_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 9, "italic")) qaac_frame.grid_rowconfigure(0, weight=1) qaac_frame.grid_rowconfigure(1, weight=1) for q_f in range(4): qaac_frame.grid_columnconfigure(q_f, weight=1) saved_qaac_path = None def set_qaac_path(): path = filedialog.askopenfilename( title='Select Location to "qaac64.exe"', initialdir=pathlib.Path(qaac_entry_box.get()).parent, filetypes=[('qaac64', 'qaac64.exe')], parent=general_settings_window) if path: qaac_parser = ConfigParser() qaac_parser.read(config_file) qaac = f'"{str(pathlib.Path(path))}"' qaac_parser.set('qaac_path', 'path', qaac) with open(config_file, 'w') as qaac_cfg: qaac_parser.write(qaac_cfg) qt_folder_path = pathlib.Path( pathlib.Path( str(qaac_parser['qaac_path']['path']).replace( '"', '')).resolve().parent / 'QTfiles64') qaac_parser.set('qaac_path', 'qt_path', f'"{str(qt_folder_path)}"') with open(config_file, 'w') as qaac_cfg: qaac_parser.write(qaac_cfg) qaac_entry_box.config(state=NORMAL) qaac_entry_box.delete(0, END) qaac_entry_box.insert( 0, str( pathlib.Path( str(qaac_parser['qaac_path']['path']).replace( '"', '')).resolve())) qaac_entry_box.config(state=DISABLED) update_qaac_file_paths() set_qaac_path = HoverButton(qaac_frame, text="Set Path", command=set_qaac_path, foreground="white", background="#23272A", borderwidth="3", activebackground='grey') set_qaac_path.grid(row=0, column=0, columnspan=1, padx=5, pady=5, sticky=N + S + E + W) if config_parser['qaac_path']['path'] == '': saved_qaac_path = 'not installed'.title() elif config_parser['qaac_path']['path'] != '': if pathlib.Path( str(config_parser['qaac_path']['path']).replace('"', '')).exists(): saved_qaac_path = '"' + str( pathlib.Path( str(config_parser['qaac_path']['path']).replace( '"', '')).resolve()) + '"' else: saved_qaac_path = 'not installed'.title() func_parser = ConfigParser() func_parser.read(config_file) func_parser.set('qaac_path', 'path', '') with open(config_file, 'w') as configfile: func_parser.write(configfile) qaac_entry_box = Entry(qaac_frame, borderwidth=4, background="#CACACA") qaac_entry_box.grid(row=0, column=1, columnspan=3, padx=5, pady=5, sticky=N + S + E + W) qaac_entry_box.insert(0, str(saved_qaac_path).replace('"', '')) qaac_entry_box.config(state=DISABLED) def update_qaac_file_paths(): global qt_folder, list_of_qaac_files update_parser = ConfigParser() update_parser.read(config_file) if update_parser['qaac_path'][ 'path'] == '': # if path to qaac is empty qt_folder = pathlib.Path(pathlib.Path.cwd() / 'Apps' / 'qaac' / 'QTfiles64') elif update_parser['qaac_path'][ 'path'] != '': # if path to qaac is not empty qt_folder = pathlib.Path( pathlib.Path( str(update_parser['qaac_path']['path']).replace( '"', '')).resolve().parent / 'QTfiles64') pathlib.Path(qt_folder).mkdir(parents=True, exist_ok=True) list_of_qaac_files = [ pathlib.Path(qt_folder / 'ASL.dll'), pathlib.Path(qt_folder / 'CoreAudioToolbox.dll'), pathlib.Path(qt_folder / 'CoreFoundation.dll'), pathlib.Path(qt_folder / 'icudt62.dll'), pathlib.Path(qt_folder / 'libdispatch.dll'), pathlib.Path(qt_folder / 'libicuin.dll'), pathlib.Path(qt_folder / 'libicuuc.dll'), pathlib.Path(qt_folder / 'objc.dll') ] update_qaac_file_paths() def check_for_qaac_files(): global list_of_qaac_files checked_qaac_files = [] for files in list_of_qaac_files: checked_qaac_files.append(pathlib.Path(files).is_file()) if all(checked_qaac_files): qaac_status_label.config(text='Status: Ready') else: qaac_status_label.config(text='Status: Missing QTFiles') general_settings_window.after(1000, check_for_qaac_files) qaac_status_label = Label(qaac_frame, text="", background="#434547", foreground="white", width=10) qaac_status_label.grid(row=1, column=0, columnspan=2, padx=(5, 5), pady=(2, 0), sticky=W + E) check_for_qaac_files() qt_files_download = HoverButton( qaac_frame, text="Download QTfiles64", command=lambda: webbrowser.open( 'https://github.com/AnimMouse/QTFiles/releases'), foreground="white", background="#23272A", borderwidth="3", activebackground='grey') qt_files_download.grid(row=1, column=2, columnspan=1, padx=5, pady=(2, 0), sticky=N + S + E + W) qt_files_dir = HoverButton(qaac_frame, text="Open QTfiles64 Directory", command=lambda: webbrowser.open(qt_folder), foreground="white", background="#23272A", borderwidth="3", activebackground='grey') qt_files_dir.grid(row=1, column=3, columnspan=1, padx=5, pady=(2, 0), sticky=N + S + E + W) # save path frame ------------------------------------------------------------------------------------------------- save_path_frame = LabelFrame(settings_tab, text=' Save Paths ', labelanchor="n") save_path_frame.grid(column=0, row=1, columnspan=4, padx=5, pady=(10, 3), sticky=N + S + E + W) save_path_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 10, "bold")) save_path_frame.grid_rowconfigure(0, weight=1) save_path_frame.grid_rowconfigure(1, weight=1) for s_p in range(4): save_path_frame.grid_columnconfigure(s_p, weight=1) # Manual Auto Path ------------------------------------------------------------------------------------------------ manual_auto_frame = LabelFrame(save_path_frame, text=' Manual/Auto Encode Path ', labelanchor="nw") manual_auto_frame.grid(column=0, row=0, columnspan=4, padx=5, pady=(5, 3), sticky=E + W) manual_auto_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 9, "italic")) manual_auto_frame.grid_rowconfigure(0, weight=1) manual_auto_frame.grid_columnconfigure(0, weight=2) manual_auto_frame.grid_columnconfigure(1, weight=20) manual_auto_frame.grid_columnconfigure(3, weight=1) def set_manual_auto_path(): path = filedialog.askdirectory(title='Output Path Manual/Auto', parent=general_settings_window) if path: manual_path_parser = ConfigParser() manual_path_parser.read(config_file) path = str(pathlib.Path(path)) manual_path_parser.set('output_path', 'path', path) with open(config_file, 'w') as manual_path_configfile: manual_path_parser.write(manual_path_configfile) manual_auto_entry_box.config(state=NORMAL) manual_auto_entry_box.delete(0, END) manual_auto_entry_box.insert( 0, str( pathlib.Path(str( manual_path_parser['output_path']['path'])))) manual_auto_entry_box.config(state=DISABLED) set_manual_auto_path = HoverButton(manual_auto_frame, text="Set Path", command=set_manual_auto_path, foreground="white", background="#23272A", borderwidth="3", activebackground='grey') set_manual_auto_path.grid(row=0, column=0, columnspan=1, padx=5, pady=5, sticky=N + S + E + W) saved_manual_auto_path = None if config_parser['output_path']['path'] == 'file input directory': saved_manual_auto_path = str( config_parser['output_path']['path']).title() elif config_parser['output_path']['path'] != 'file input directory': saved_manual_auto_path = str( pathlib.Path(config_parser['output_path']['path']).resolve()) manual_auto_entry_box = Entry(manual_auto_frame, borderwidth=4, background="#CACACA") manual_auto_entry_box.grid(row=0, column=1, columnspan=2, padx=5, pady=5, sticky=N + S + E + W) manual_auto_entry_box.insert(0, saved_manual_auto_path) manual_auto_entry_box.config(state=DISABLED) def reset_manual_auto_path(): msg = messagebox.askyesno( title='Prompt', message='Reset path to directory of input file?', parent=general_settings_window) if msg: reset_manual_path_parser = ConfigParser() reset_manual_path_parser.read(config_file) reset_manual_path_parser.set('output_path', 'path', 'file input directory') with open(config_file, 'w') as r_mp_cfg: reset_manual_path_parser.write(r_mp_cfg) manual_auto_entry_box.config(state=NORMAL) manual_auto_entry_box.delete(0, END) manual_auto_entry_box.insert( 0, str(reset_manual_path_parser['output_path']['path']).title()) manual_auto_entry_box.config(state=DISABLED) reset_manual_auto_path = HoverButton(manual_auto_frame, text="X", command=reset_manual_auto_path, foreground="white", background="#23272A", borderwidth="3", activebackground='grey') reset_manual_auto_path.grid(row=0, column=3, columnspan=1, padx=5, pady=5, sticky=N + S + E + W) # Batch Path ------------------------------------------------------------------------------------------------------ batch_frame = LabelFrame(save_path_frame, text=' Batch Processing Path ', labelanchor="nw") batch_frame.grid(column=0, row=1, columnspan=4, padx=5, pady=(5, 3), sticky=E + W) batch_frame.configure(fg="#3498db", bg="#434547", bd=3, font=(set_font, 9, "italic")) batch_frame.grid_rowconfigure(0, weight=1) batch_frame.grid_columnconfigure(0, weight=2) batch_frame.grid_columnconfigure(1, weight=20) batch_frame.grid_columnconfigure(3, weight=1) def set_batch_path(): path = filedialog.askdirectory(title='Output Path Manual/Auto', parent=general_settings_window) if path: bath_path_parser = ConfigParser() bath_path_parser.read(config_file) path = str(pathlib.Path(path)) bath_path_parser.set('batch_path', 'path', path) with open(config_file, 'w') as batch_cfg: bath_path_parser.write(batch_cfg) batch_entry_box.config(state=NORMAL) batch_entry_box.delete(0, END) batch_entry_box.insert( 0, str(pathlib.Path(str(bath_path_parser['batch_path']['path'])))) batch_entry_box.config(state=DISABLED) set_batch_path_button = HoverButton(batch_frame, text="Set Path", command=set_batch_path, foreground="white", background="#23272A", borderwidth="3", activebackground='grey') set_batch_path_button.grid(row=0, column=0, columnspan=1, padx=5, pady=5, sticky=N + S + E + W) saved_batch_path = None if config_parser['batch_path']['path'] == 'file input directory': saved_batch_path = str(config_parser['batch_path']['path']).title() elif config_parser['batch_path']['path'] != 'file input directory': saved_batch_path = str( pathlib.Path(config_parser['batch_path']['path']).resolve()) batch_entry_box = Entry(batch_frame, borderwidth=4, background="#CACACA") batch_entry_box.grid(row=0, column=1, columnspan=2, padx=5, pady=5, sticky=N + S + E + W) batch_entry_box.insert(0, saved_batch_path) batch_entry_box.config(state=DISABLED) def reset_batch_path(): msg = messagebox.askyesno( title='Prompt', message='Reset path to directory of input file?', parent=general_settings_window) if msg: reset_batch_path_parser = ConfigParser() reset_batch_path_parser.read(config_file) reset_batch_path_parser.set('batch_path', 'path', 'file input directory') with open(config_file, 'w') as reset_bp_cfg: reset_batch_path_parser.write(reset_bp_cfg) batch_entry_box.config(state=NORMAL) batch_entry_box.delete(0, END) batch_entry_box.insert( 0, str(reset_batch_path_parser['batch_path']['path']).title()) batch_entry_box.config(state=DISABLED) reset_batch_path_button = HoverButton(batch_frame, text="X", command=reset_batch_path, foreground="white", background="#23272A", borderwidth="3", activebackground='grey') reset_batch_path_button.grid(row=0, column=3, columnspan=1, padx=5, pady=5, sticky=N + S + E + W)
class MainClass: def __init__(self, path): self.path = path self.root = Tk() self.filename_label = LabelFrame(self.root, text="File:") self.action_frame = LabelFrame(self.root, text="Action:") self.rename_entry = None self.rename_canvas = Canvas(self.action_frame) self.rename_button = Button(self.rename_canvas, text="Rename file", font="bold", command=self.rename_file) self.configure_root(300, 600) self.init_filename_label() self.init_action_frame() @property def file_basename(self): return os.path.basename(f"{self.path}") def configure_root(self, width, height, bg_color="black"): self.root.grid_columnconfigure(0, weight=1) self.root.configure(bg=bg_color) self.root.title("Downloads manager") self.root.minsize(width, height) self.root.geometry(f"{width}x{height}+500+200") def init_filename_label(self): self.filename_label.grid(row=0, column=0, sticky="nsew") file_name_label = Label(self.filename_label, text=f"Name: {self.file_basename}", font="bold") file_path_label = Label(self.filename_label, text=f"Path: {self.path}", font="bold") file_name_label.pack(anchor="w") file_path_label.pack(anchor="w") def init_action_frame(self): self.action_frame.grid(row=1, column=0, sticky="nsew") self.action_frame.grid_columnconfigure(0, weight=1) open_button = Button(self.action_frame, text="Open file", font="bold", command=self.open_file) copy_button = Button(self.action_frame, text="Copy file", font="bold", command=self.copy_file) move_button = Button(self.action_frame, text="Move file", font="bold", command=self.move_file) do_nothing_button = Button(self.action_frame, text="Quit", font="bold", command=self.close_window) open_button.grid(row=0, column=0, sticky="nsew") self.rename_canvas.grid(row=1, column=0, sticky="nsew") self.rename_button.pack(fill=X) copy_button.grid(row=2, column=0, sticky="nsew") move_button.grid(row=3, column=0, sticky="nsew") do_nothing_button.grid(row=4, column=0, sticky="nsew") def open_file(self): if sys.platform == 'win32': os.startfile(self.path) elif sys.platform == 'darwin': subprocess.call(['open', self.path]) else: subprocess.call(['xdg-open', self.path]) def rename_file(self): for button in self.rename_canvas.winfo_children(): button.destroy() self.rename_entry = Entry(self.rename_canvas) self.rename_entry.pack(fill=BOTH) self.rename_entry.bind('<Return>', self.set_new_name) def set_new_name(self, new_name): filepath = os.path.dirname(self.path) new_name = self.rename_entry.get() new_path = filepath + "/" + new_name os.rename(self.path, new_path) self.path = new_path self.rename_canvas.winfo_children()[0].destroy() self.rename_button = Button(self.rename_canvas, text="Rename file", font="bold", command=self.rename_file) self.rename_button.pack(fill=X) def move_file(self): new_path = filedialog.askdirectory(initialdir=".", title="Select destination directory:") if new_path: new_path = new_path + f"/{self.file_basename}" os.rename(self.path, new_path) self.path = new_path def copy_file(self): new_path = filedialog.askdirectory(initialdir=".", title="Select destination directory:") if new_path: new_path = new_path + f"/{self.file_basename}" copyfile(self.path, new_path) def close_window(self): self.root.destroy()
def create_general_form(self, tab): form = Frame(tab) center = LabelFrame(form, padx=90, pady=30, width=450, height=250) btm_frame = Frame(form, pady=3, width=450, height=40) # layout all of the main containers form.pack(fill=tk.BOTH, expand=True) center.pack(fill=tk.BOTH, expand=True) btm_frame.pack(side=tk.RIGHT, padx=5, pady=5) center.grid_propagate(False) btm_frame.pack_propagate(False) center.grid_rowconfigure(0, pad=20) center.grid_rowconfigure(1, pad=20) center.grid_columnconfigure(1, weight=2, pad=20) en_file = Entry(center, state='disabled', width=200) en_file.grid(row=0, column=1, columnspan=2, padx=5, sticky='W') # Center elements def open_file(): en_file.config(state='normal') en_file.delete(0, 'end') en_file.config(state='disabled') file = filedialog.askopenfilename( initialdir=os.path.join(os.getcwd(), 'inputs'), title="Select file", filetypes=(("csv files", "*.csv"), ("XES files", "*.xes"), ("all files", "*.*"))) en_file.config(state='normal') en_file.insert(0, os.path.basename(file)) en_file.config(state='disabled') b_select = Button(center, text="Select event-log", command=open_file) b_select.grid(row=0, sticky='W') self.general_form.append({'name': 'file', 'obj': en_file}) lb_exec_mode = Label(center, text="Exec. Mode: ") lb_exec_mode.grid(row=1, sticky='W') cb_exec_mode = ttk.Combobox(center) cb_exec_mode.set('single') cb_exec_mode['values'] = ('single', 'optimizer') cb_exec_mode.grid(row=1, column=1, padx=5, sticky='W') self.general_form.append({'name': 'exec_mode', 'obj': cb_exec_mode}) lb_eval_metric = Label(center, text="Evaluation metric: ") lb_eval_metric.grid(row=2, sticky='W') cb_eval_metric = ttk.Combobox(center) cb_eval_metric.set('tsd') cb_eval_metric['values'] = ('tsd', 'dl_mae', 'tsd_min', 'mae') cb_eval_metric.grid(row=2, column=1, padx=5, sticky='W') self.general_form.append({'name': 'sim_metric', 'obj': cb_eval_metric}) lb_rep = Label(center, text="Repetitions: ") lb_rep.grid(row=3, sticky='W') var = tk.IntVar() sl_rep = Scale(center, variable=var, from_=1, to=30, resolution=1, orient=tk.HORIZONTAL) sl_rep.grid(row=3, column=1, padx=5, sticky='W') self.general_form.append({'name': 'repetitions', 'obj': sl_rep}) # Bottom elements b_ok = Button(btm_frame, text="Next", command=self.next_tab) b_ok.grid(row=0) form.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5) return form