class AbstractTimeSelectionStartScreen(AbstractTimeSelectionBaseScreen): def __init__(self, parent, controller, **kw): AbstractTimeSelectionBaseScreen.__init__(self, parent, controller, **kw) def init_widgets(self): AbstractTimeSelectionBaseScreen.init_widgets(self) self.screen_instruction_1_filename_label = PLabel(self.content_wrapper) self.screen_instruction_2_label = PLabel(self.content_wrapper) self.empty_label_1 = PLabel(self.content_wrapper) def add_widgets_to_frame(self): self.pack_title_and_instruction_widgets() self.empty_label_1.pack() self.screen_instruction_1_filename_label.pack() self.screen_instruction_2_label.pack() self.pack_lower_half_widgets() self.content_wrapper.place(relx=SCREENS_REL_X, rely=SCREEN_REL_Y_45, anchor=CENTER) def on_show_frame(self): self.set_instruction_1_filename(self.controller.get_filename_of_video_with_0_offset() + "\n") self.set_error_message("") def update_frame(self, data): AbstractTimeSelectionBaseScreen.update_frame(self, data) def on_hide_frame(self): pass def set_input_checks(self): AbstractTimeSelectionBaseScreen.set_input_checks(self) def on_input_check_success(self): AbstractTimeSelectionBaseScreen.on_input_check_success(self) def prev_button_command(self): AbstractTimeSelectionBaseScreen.prev_button_command(self) def next_button_command(self): AbstractTimeSelectionBaseScreen.next_button_command(self) def set_instruction_1_filename(self, file_of_video_to_open): self.screen_instruction_1_filename_label.configure(text=file_of_video_to_open) def set_instruction_2_text(self, timestamp_instr_text): self.screen_instruction_2_label.configure(text=timestamp_instr_text)
class FinalScreen(GuiBaseFrame): def __init__(self, parent, controller, **kw): GuiBaseFrame.__init__(self, parent, controller, **kw) def init_widgets(self): self.text_container = Frame(self) self.screen_title = Header1Label(self.text_container, text="Stereo Rectification Complete!") self.text_1 = PLabel(self.text_container, text=("\n".join([ "Your videos have been stereo rectified!", "You can find them in the follow " "paths on your system:" ]))) self.filenames = PLabel(self.text_container) self.thanks_label = PLabel(self.text_container, text="Thank you for your patience!") self.finish_button = Button(self.text_container, text="Finish and Close Window", command=lambda: sys.exit()) def add_widgets_to_frame(self): self.screen_title.pack() self.text_1.pack() self.filenames.pack() self.thanks_label.pack() self.finish_button.pack() self.text_container.place(relx=SCREENS_REL_X, rely=SCREEN_REL_Y_45, anchor=CENTER) def on_show_frame(self): self.filenames.configure(text=("\n".join([ "Left video:", self.controller.left_video_filename_sr, "", "Right video:", self.controller.right_video_filename_sr ]))) def on_hide_frame(self): pass
class VideoScanProgressScreen(GuiBaseFrame): def __init__(self, parent, controller, **kw): GuiBaseFrame.__init__(self, parent, controller, **kw) self.counting_left_frames = None def init_widgets(self): self.content_wrapper = Frame(self) self.content_wrapper.configure(background="white") self.screen_title = Header1Label( self.content_wrapper, text="Scanning video for information...\n") self.progress_bar = Progressbar(self.content_wrapper, orient=HORIZONTAL, mode="indeterminate", length=WINDOW_WIDTH / 2) self.wait_text = PLabel( self.content_wrapper, text="\nThis might take a few minutes." "\nPlease do not change the video files while this is running.\n") self.left_frames_count = PLabel(self.content_wrapper, text=LEFT_FRAMES_COUNT_PREFIX + "0") self.right_frames_count = PLabel(self.content_wrapper, text=RIGHT_FRAMES_COUNT_PREFIX + "0") self.elapsed_time_label = PLabel(self.content_wrapper) self.empty_space = PLabel(self.content_wrapper, text=" ") self.next_button = Button( self.content_wrapper, text="Next", state=DISABLED, command=lambda: self.controller.show_next_frame()) def add_widgets_to_frame(self): self.screen_title.pack() self.progress_bar.pack() self.wait_text.pack() self.left_frames_count.pack() self.right_frames_count.pack() self.elapsed_time_label.pack() self.empty_space.pack() self.next_button.pack() self.content_wrapper.place(relx=SCREENS_REL_X, rely=SCREEN_REL_Y_45, anchor=CENTER) def on_show_frame(self): self.start_time = time.time() self.progress_bar.start() self.frame_count_thread = threading.Thread( target=self.controller.video_frame_loader.count_frames_in_videos, kwargs={"controller": self.controller}) self.frame_count_thread.start() self.master.after(50, self.check_thread) def update_frame(self, data): if LEFT_FRAMES_COUNT_PREFIX in data: self.left_frames_count.configure(text=data) if RIGHT_FRAMES_COUNT_PREFIX in data: self.right_frames_count.configure(text=data) self.elapsed_time_label.configure( text=ELAPSED_TIME_PREFIX + str(datetime.timedelta(seconds=int(time.time() - self.start_time)))) def on_hide_frame(self): self.progress_bar.stop() def check_thread(self): if self.frame_count_thread.is_alive(): self.master.after(50, self.check_thread) else: self.progress_bar.stop() self.wait_text.configure(text="\nDone!\nPress Next to continue.\n") self.next_button.configure(state=NORMAL)
class FrameMatchingValidationScreen(GuiBaseFrame): def __init__(self, parent, controller, **kw): GuiBaseFrame.__init__(self, parent, controller, **kw) self.left_video_filename = None self.right_video_filename = None self.video_frame_loader = None self.frame_num = 0 def init_widgets(self): self.buttons = [] self.content_wrapper = Frame(self) self.title_label = Header1Label(self.content_wrapper, text="Frame Offset Validation") self.subtitle_label = PLabel( self.content_wrapper, text= "Use the buttons below to ensure that the video frame offset is valid. Press Next when finished." ) self.left_frame_num_label = PLabel(self.content_wrapper) self.right_frame_num_label = PLabel(self.content_wrapper) self.left_video_label = PLabel(self.content_wrapper) self.right_video_label = PLabel(self.content_wrapper) self.left_offset_label = PLabel(self.content_wrapper) self.right_offset_label = PLabel(self.content_wrapper) self.left_offset_inc_instr = PLabel( self.content_wrapper, text="Increase left video offset by:") self.right_offset_inc_instr = PLabel( self.content_wrapper, text="Increase right video offset by:") self.left_offset_inc_10_button = Button( self.content_wrapper, text="+10", command=lambda: self.adjust_left_offset(10)) self.left_offset_inc_5_button = Button( self.content_wrapper, text="+5", command=lambda: self.adjust_left_offset(5)) self.left_offset_inc_1_button = Button( self.content_wrapper, text="+1", command=lambda: self.adjust_left_offset(1)) self.right_offset_inc_1_button = Button( self.content_wrapper, text="+1", command=lambda: self.adjust_right_offset(1)) self.right_offset_inc_5_button = Button( self.content_wrapper, text="+5", command=lambda: self.adjust_right_offset(5)) self.right_offset_inc_10_button = Button( self.content_wrapper, text="+10", command=lambda: self.adjust_right_offset(10)) self.buttons.extend([ self.left_offset_inc_10_button, self.left_offset_inc_5_button, self.left_offset_inc_1_button, self.right_offset_inc_1_button, self.right_offset_inc_5_button, self.right_offset_inc_10_button ]) self.video_navigation_label = PLabel(self.content_wrapper, text="Video frame navigation:") self.left_video_frame_inc_10_button = Button( self.content_wrapper, text=BACK_10_FRAMEs_TEXT, command=lambda: self.adjust_frame_num(-10)) self.left_video_frame_inc_5_button = Button( self.content_wrapper, text=BACK_5_FRAMEs_TEXT, command=lambda: self.adjust_frame_num(-5)) self.left_video_frame_inc_1_button = Button( self.content_wrapper, text=BACK_1_FRAME_TEXT, command=lambda: self.adjust_frame_num(-1)) self.right_video_frame_inc_1_button = Button( self.content_wrapper, text=FORWARD_1_FRAME_TEXT, command=lambda: self.adjust_frame_num(1)) self.right_video_frame_inc_5_button = Button( self.content_wrapper, text=FORWARD_5_FRAMES_TEXT, command=lambda: self.adjust_frame_num(5)) self.right_video_frame_inc_10_button = Button( self.content_wrapper, text=FORWARD_10_FRAMES_TEXT, command=lambda: self.adjust_frame_num(10)) self.buttons.extend([ self.left_video_frame_inc_10_button, self.left_video_frame_inc_5_button, self.left_video_frame_inc_1_button, self.right_video_frame_inc_1_button, self.right_video_frame_inc_5_button, self.right_video_frame_inc_10_button ]) self.left_video_frame_inc_300_button = Button( self.content_wrapper, text=BACK_300_FRAMEs_TEXT, command=lambda: self.adjust_frame_num(-300)) self.left_video_frame_inc_150_button = Button( self.content_wrapper, text=BACK_150_FRAMEs_TEXT, command=lambda: self.adjust_frame_num(-150)) self.left_video_frame_inc_30_button = Button( self.content_wrapper, text=BACK_30_FRAMEs_TEXT, command=lambda: self.adjust_frame_num(-30)) self.right_video_frame_inc_30_button = Button( self.content_wrapper, text=FORWARD_30_FRAMES_TEXT, command=lambda: self.adjust_frame_num(30)) self.right_video_frame_inc_150_button = Button( self.content_wrapper, text=FORWARD_150_FRAMES_TEXT, command=lambda: self.adjust_frame_num(150)) self.right_video_frame_inc_300_button = Button( self.content_wrapper, text=FORWARD_300_FRAMES_TEXT, command=lambda: self.adjust_frame_num(300)) self.buttons.extend([ self.left_video_frame_inc_300_button, self.left_video_frame_inc_150_button, self.left_video_frame_inc_30_button, self.right_video_frame_inc_30_button, self.right_video_frame_inc_150_button, self.right_video_frame_inc_300_button ]) self.next_button = Button( self.content_wrapper, text="Next", command=lambda: self.controller.show_next_frame()) def add_widgets_to_frame(self): self.title_label.grid(row=TITLE_ROW, column=0, columnspan=12) self.subtitle_label.grid(row=SUBTITLE_ROW, column=0, columnspan=12) self.left_frame_num_label.grid(row=FRAME_NUM_ROW, column=0, columnspan=6) self.right_frame_num_label.grid(row=FRAME_NUM_ROW, column=6, columnspan=6) self.left_video_label.grid(row=VIDEO_FRAMES_ROW, column=0, columnspan=6) self.right_video_label.grid(row=VIDEO_FRAMES_ROW, column=6, columnspan=6) self.left_offset_label.grid(row=OFFSET_INC_INSTR_ROW, column=0, columnspan=2) self.right_offset_label.grid(row=OFFSET_INC_INSTR_ROW, column=10, columnspan=2) self.left_offset_inc_instr.grid(row=OFFSET_INC_INSTR_ROW, column=3, columnspan=3) self.right_offset_inc_instr.grid(row=OFFSET_INC_INSTR_ROW, column=6, columnspan=3) self.left_offset_inc_10_button.grid(row=OFFSET_INC_BUTTONS, column=3) self.left_offset_inc_5_button.grid(row=OFFSET_INC_BUTTONS, column=4) self.left_offset_inc_1_button.grid(row=OFFSET_INC_BUTTONS, column=5) self.right_offset_inc_1_button.grid(row=OFFSET_INC_BUTTONS, column=6) self.right_offset_inc_5_button.grid(row=OFFSET_INC_BUTTONS, column=7) self.right_offset_inc_10_button.grid(row=OFFSET_INC_BUTTONS, column=8) self.video_navigation_label.grid(row=VIDEO_NAVIGATION_ROW, column=0, columnspan=12) self.left_video_frame_inc_10_button.grid(row=VIDEO_BUTTONS_ROW_1, column=0, columnspan=2) self.left_video_frame_inc_5_button.grid(row=VIDEO_BUTTONS_ROW_1, column=2, columnspan=2) self.left_video_frame_inc_1_button.grid(row=VIDEO_BUTTONS_ROW_1, column=4, columnspan=2) self.right_video_frame_inc_1_button.grid(row=VIDEO_BUTTONS_ROW_1, column=6, columnspan=2) self.right_video_frame_inc_5_button.grid(row=VIDEO_BUTTONS_ROW_1, column=8, columnspan=2) self.right_video_frame_inc_10_button.grid(row=VIDEO_BUTTONS_ROW_1, column=10, columnspan=2) self.left_video_frame_inc_300_button.grid(row=VIDEO_BUTTONS_ROW_2, column=0, columnspan=2) self.left_video_frame_inc_150_button.grid(row=VIDEO_BUTTONS_ROW_2, column=2, columnspan=2) self.left_video_frame_inc_30_button.grid(row=VIDEO_BUTTONS_ROW_2, column=4, columnspan=2) self.right_video_frame_inc_30_button.grid(row=VIDEO_BUTTONS_ROW_2, column=6, columnspan=2) self.right_video_frame_inc_150_button.grid(row=VIDEO_BUTTONS_ROW_2, column=8, columnspan=2) self.right_video_frame_inc_300_button.grid(row=VIDEO_BUTTONS_ROW_2, column=10, columnspan=2) self.next_button.grid(row=NEXT_BUTTON_ROW, column=0, columnspan=12) self.content_wrapper.place(relx=SCREENS_REL_X, rely=SCREEN_REL_Y_50, anchor=CENTER) def set_video_frame(self, frame_num, left_offset, right_offset): _, left_img = \ self.controller.video_frame_loader.get_left_frame_tkinter_with_resize(frame_num + left_offset, VIDEO_PREVIEW_WIDTH, VIDEO_PREVIEW_HEIGHT) _, right_img = \ self.controller.video_frame_loader.get_right_frame_tkinter_with_resize(frame_num + right_offset, VIDEO_PREVIEW_WIDTH, VIDEO_PREVIEW_HEIGHT) self.left_video_label.configure(image=left_img) self.left_video_label.image = left_img self.right_video_label.configure(image=right_img) self.right_video_label.image = right_img def on_show_frame(self): self.update_UI() def update_frame(self, data): pass def on_hide_frame(self): pass def update_UI(self): self.ensure_frame_num_is_valid() self.set_video_frame(self.frame_num, self.controller.video_offsets.left_offset, self.controller.video_offsets.right_offset) self.left_frame_num_label.configure( text=LEFT_FRAME_NUM_PREFIX + str(self.frame_num + self.controller.video_offsets.left_offset)) self.right_frame_num_label.configure( text=RIGHT_FRAME_NUM_PREFIX + str(self.frame_num + self.controller.video_offsets.right_offset)) self.left_offset_label.configure( text=LEFT_OFFSET_PREFIX + str(self.controller.video_offsets.left_offset)) self.right_offset_label.configure( text=RIGHT_OFFSET_PREFIX + str(self.controller.video_offsets.right_offset)) def ensure_frame_num_is_valid(self): if self.frame_num < 0: self.frame_num = 0 left_offset = self.controller.video_offsets.left_offset right_offset = self.controller.video_offsets.right_offset last_frame_left = self.controller.video_frame_loader.last_frame_num_left last_frame_right = self.controller.video_frame_loader.last_frame_num_right if self.frame_num + left_offset > last_frame_left: self.frame_num = last_frame_left - left_offset if self.frame_num + right_offset > last_frame_right: self.frame_num = last_frame_left - right_offset def adjust_frame_num(self, value): self.frame_num += value self.update_UI() def adjust_left_offset(self, value): self.controller.video_offsets.left_offset += value self.normalize_offsets() self.update_UI() def adjust_right_offset(self, value): self.controller.video_offsets.right_offset += value self.normalize_offsets() self.update_UI() def normalize_offsets(self): if self.controller.video_offsets.left_offset > self.controller.video_offsets.right_offset: self.controller.video_offsets.left_offset -= self.controller.video_offsets.right_offset self.controller.video_offsets.right_offset = 0 elif self.controller.video_offsets.left_offset < self.controller.video_offsets.right_offset: self.controller.video_offsets.right_offset -= self.controller.video_offsets.left_offset self.controller.video_offsets.left_offset = 0 else: self.controller.video_offsets.left_offset = 0 self.controller.video_offsets.right_offset = 0
class SrFrameSelection(GuiBaseFrame): def __init__(self, parent, controller, **kw): GuiBaseFrame.__init__(self, parent, controller, **kw) def init_widgets(self): self.content_wrapper = Frame(self) self.screen_title = Header1Label(self.content_wrapper, text=SR_FRAME_SELECTION_TITLE) self.screen_description = PLabel( self.content_wrapper, text="Please select a frame that has a satisfactory " "stereo rectification result.") def add_widgets_to_frame(self): self.grid_rowconfigure(0, weight=1) self.grid_columnconfigure(0, weight=1) self.screen_title.grid(row=0, column=0, columnspan=3) self.screen_description.grid(row=1, columnspan=3) self.content_wrapper.place(relx=SCREENS_REL_X, rely=0.48, anchor=CENTER) def on_show_frame(self): self.canvas_wrappers = [] self.canvases = [] self.page_num = 0 if len(self.controller.sr_results) == 0: self.controller.show_frame(SrNoFramesFoundScreen) else: pages = int(ceil(len(self.controller.sr_results) / 10.0)) for page in range(0, pages): canvas_wrapper = Frame(self.content_wrapper, borderwidth="1", relief="solid") canvas = Canvas(canvas_wrapper, width=int(WINDOW_WIDTH * 7 / 8), height=(WINDOW_HEIGHT * 2 / 3)) scroll_bar = Scrollbar(canvas_wrapper, orient=VERTICAL, command=canvas.yview) results_list_frame = Frame(canvas) canvas.configure(yscrollcommand=scroll_bar.set) canvas.create_window(0, 0, window=results_list_frame) canvas.bind_all("<Up>", self.on_up_key) canvas.bind_all("<Down>", self.on_down_key) canvas.bind_all("<Left>", self.on_left_key) canvas.bind_all("<Right>", self.on_right_key) canvas.grid(row=0, column=0, sticky="nsew") scroll_bar.grid(row=0, column=1, sticky="ns") canvas_wrapper.grid(row=2, column=0, columnspan=3, sticky="nsew") select_buttons_on_page = [] for row in range(0, RESULTS_PER_PAGE): result_num = page * RESULTS_PER_PAGE + row if result_num < len(self.controller.sr_results): frame_num = self.controller.sr_results[result_num][ FRAME_NUM_LABEL] result_entry = Frame(results_list_frame, borderwidth="1", relief="solid") description = PLabel( result_entry, text="Frame #" + str(int(frame_num)) + ", Time: " + str(datetime.timedelta(seconds=frame_num / 30))) preview_wrapper = Frame(result_entry) left_video_preview = Label( preview_wrapper, image=self.controller.sr_results[result_num][LEFT]) right_video_preview = Label( preview_wrapper, image=self.controller.sr_results[result_num] [RIGHT]) select_button = SrSelectButton( preview_wrapper, self.controller, self.controller.sr_results[result_num] [SR_MAP_LABEL], text="Select") select_buttons_on_page.append(select_button) description.pack() left_video_preview.grid(row=row, column=0) right_video_preview.grid(row=row, column=1) select_button.grid(row=row, column=2) preview_wrapper.pack() result_entry.pack() for i in range(0, len(select_buttons_on_page)): select_buttons_on_page[i].configure( command=select_buttons_on_page[i].use_sr_map) self.master.update_idletasks() canvas.config(scrollregion=canvas.bbox("all")) canvas.yview_moveto(0) self.canvas_wrappers.append(canvas_wrapper) self.canvases.append(canvas) self.prev_result_page = Button( self.content_wrapper, text="<", command=lambda: self.prev_page_command()) self.page_info_label = PLabel( self.content_wrapper, text=get_page_info_label_message(self.page_num, len(self.canvases), RESULTS_PER_PAGE)) self.next_result_page = Button( self.content_wrapper, text=">", command=lambda: self.next_page_command()) self.prev_result_page.grid(row=3, column=0) self.page_info_label.grid(row=3, column=1) self.next_result_page.grid(row=3, column=2) self.canvas_wrappers[self.page_num].tkraise() def update_frame(self, data): pass def on_hide_frame(self): pass def on_up_key(self, event): self.canvases[self.page_num].yview_scroll(-7, 'units') def on_down_key(self, event): self.canvases[self.page_num].yview_scroll(7, 'units') def on_left_key(self, event): self.prev_page_command() def on_right_key(self, event): self.next_page_command() def prev_page_command(self): if self.page_num > 0: self.page_num -= 1 self.canvas_wrappers[self.page_num].tkraise() self.page_info_label.configure(text=get_page_info_label_message( self.page_num, len(self.canvases), RESULTS_PER_PAGE)) def next_page_command(self): if self.page_num < len(self.canvas_wrappers) - 1: self.page_num += 1 self.canvas_wrappers[self.page_num].tkraise() self.page_info_label.configure(text=get_page_info_label_message( self.page_num, len(self.canvases), RESULTS_PER_PAGE))
class AbstractTimeSelectionBaseScreen(GuiBaseFrame): def __init__(self, parent, controller, **kw): GuiBaseFrame.__init__(self, parent, controller, **kw) self.input_checks = [] self.set_input_checks() def init_widgets(self): self.content_wrapper = Frame(self) self.screen_title = Header1Label(self.content_wrapper) self.screen_instruction_1_label = PLabel(self.content_wrapper) self.input_content_wrapper = Frame(self.content_wrapper) self.hour_input, self.minute_input, self.seconds_input = setup_hms_input( self, self.input_content_wrapper) self.error_message_label = PLabel(self.content_wrapper, fg="red") self.button_wrapper = Frame(self.content_wrapper) self.back_button = Button(self.button_wrapper, text="Back", command=lambda: self.prev_button_command()) self.next_button = Button(self.button_wrapper, text="Next", command=lambda: self.next_button_command()) def add_widgets_to_frame(self): GuiBaseFrame.add_widgets_to_frame(self) def on_show_frame(self): GuiBaseFrame.on_show_frame(self) def update_frame(self, data): GuiBaseFrame.update_frame(self, data) def on_hide_frame(self): GuiBaseFrame.on_hide_frame(self) def set_input_checks(self): raise NotImplementedError def on_input_check_success(self): raise NotImplementedError def next_button_command(self): if self.perform_input_checks(): self.set_error_message("") self.on_input_check_success() self.controller.show_next_frame() def prev_button_command(self): self.controller.show_prev_frame() def perform_input_checks(self): for input_check in self.input_checks: if not input_check(self): return False return True def pack_title_and_instruction_widgets(self): self.screen_title.pack() self.screen_instruction_1_label.pack() # Packs inputs, error message labels, and buttons def pack_lower_half_widgets(self): self.input_content_wrapper.pack() self.error_message_label.pack() self.back_button.grid(row=0, column=0) self.next_button.grid(row=0, column=1) self.button_wrapper.pack() def set_title(self, title): self.screen_title.configure(text=title) def set_instruction_1_text(self, text): self.screen_instruction_1_label.configure(text=text) def set_error_message(self, error_message): self.error_message_label.configure(text=error_message) def add_input_check(self, input_check_lambda): self.input_checks.append(input_check_lambda)
class AbstractProgressScreen(GuiBaseFrame): # Backend logic thread should be making calls to controller.update_frame() to update the UI while logic runs. def __init__(self, parent, controller, backend_logic_function, **kw): GuiBaseFrame.__init__(self, parent, controller, **kw) self.backend_logic_function = backend_logic_function def init_widgets(self): self.content_wrapper = Frame(self) self.content_wrapper.configure(bg="white") self.screen_title = Header1Label(self.content_wrapper) self.empty_space_1 = PLabel(self.content_wrapper) self.progress_bar_control_var = DoubleVar() self.progress_bar = Progressbar(self.content_wrapper, orient=HORIZONTAL, mode="determinate", length=WINDOW_WIDTH / 2, variable=self.progress_bar_control_var) self.wait_text = PLabel(self.content_wrapper) self.information_display = PLabel(self.content_wrapper) self.empty_space_2 = PLabel(self.content_wrapper) self.next_button = Button(self.content_wrapper, text="Next", state=DISABLED, command=lambda: self.on_next_button()) def add_widgets_to_frame(self): self.screen_title.pack() self.empty_space_1.pack() self.progress_bar.pack() self.wait_text.pack() self.information_display.pack() self.empty_space_2.pack() self.next_button.pack() self.content_wrapper.place(relx=SCREENS_REL_X, rely=SCREEN_REL_Y_45, anchor=CENTER) def on_show_frame(self): self.wait_text.configure( text="\nThis might take a few minutes." "\nPlease do not change the video files while this is " "running.\n") self.start_time = time.time() self.backend_logic_thread = threading.Thread( target=self.backend_logic_function, kwargs={"controller": self.controller}) self.backend_logic_thread.start() self.master.after(THREAD_CHECK_ALIVE_INTERVAL_MS, self.check_thread) # Data should be a dictionary with keys "percent_done" and "message_list". def update_frame(self, data): percent_done = data[PROGRESS_SCREEN_PERCENT_DONE] message_list = data[PROGRESS_SCREEN_MESSAGE_LIST] self.progress_bar_control_var.set(percent_done) elapsed_time_seconds = int(time.time() - self.start_time) elapsed_time_message = ELAPSED_TIME_PREFIX + str( datetime.timedelta(seconds=elapsed_time_seconds)) if elapsed_time_seconds == 0: estimated_time_left_string = ESTIMATED_TIME_LEFT_PREFIX + "Calculating..." else: estimated_time_left_seconds = int( elapsed_time_seconds / percent_done * 100.0) - elapsed_time_seconds estimated_time_left_string = ESTIMATED_TIME_LEFT_PREFIX + \ str(datetime.timedelta(seconds=estimated_time_left_seconds)) message_list.append(elapsed_time_message) message_list.append(estimated_time_left_string) self.set_information_display_text(message_list) def on_hide_frame(self): self.progress_bar.stop() def set_title(self, title): self.screen_title.configure(text=title) def set_information_display_text(self, message_list): self.information_display.configure(text=("\n".join(message_list))) def check_thread(self): if self.backend_logic_thread.is_alive(): self.master.after(THREAD_CHECK_ALIVE_INTERVAL_MS, self.check_thread) else: self.progress_bar.stop() self.wait_text.configure(text="\nDone!\nPress Next to continue.\n") self.next_button.configure(state=NORMAL) def on_next_button(self): self.controller.show_next_frame()