def _create_ui(self): self.builder = Builder() self.builder.add_from_file(self.uifile) self.builder.get_object(self.rootwidget, self.master) if self.rootmenu: menu = self.builder.get_object(self.rootmenu, top) self.set_menu(menu) #show callbacks defined bag = {} callbacks = self.builder.connect_callbacks({}) if callbacks is not None: for cb in callbacks: def create_cb(cbname): def dummy_cb(event=None): print('on:', cbname) return dummy_cb bag[cb] = create_cb(cb) self.builder.connect_callbacks(bag) self.set_title('Pygubu UI Tester') self.set_resizable()
def __init__(self, master): """ Initialises this gui with an interface. """ Subject.__init__(self) # Call parent constructors Observer.__init__(self) self._update_thread = None # Thread to update the graphs self._builder = Builder() # Setup form from build file self._builder.add_from_file("PartyProblemSimulator/Visualizer/gui.ui") self.mainwindow = self._builder.get_object("frm_main") self._builder.get_object("cnv_display").config(width=250, height=250) self._builder.get_object("cnv_graph_fitness").config(width=500, height=250) self._builder.get_object("cnv_graph_evaluations").config(width=500, height=250) self._setup_eventhandlers()
class UITester(TkApplication): def __init__(self, uifile, rootwidget, rootmenu=None, master=None): self.uifile = uifile self.rootwidget = rootwidget self.rootmenu = rootmenu TkApplication.__init__(self, master) def _create_ui(self): self.builder = Builder() self.builder.add_from_file(self.uifile) self.builder.get_object(self.rootwidget, self.master) if self.rootmenu: menu = self.builder.get_object(self.rootmenu, top) self.set_menu(menu) #show callbacks defined bag = {} callbacks = self.builder.connect_callbacks({}) if callbacks is not None: for cb in callbacks: def create_cb(cbname): def dummy_cb(event=None): print('on:', cbname) return dummy_cb bag[cb] = create_cb(cb) self.builder.connect_callbacks(bag) self.set_title('Pygubu UI Tester') self.set_resizable()
def _create_ui(self): self.builder = Builder() self.builder.add_from_file(sys.argv[1]) self.builder.get_object('mainwindow', self.master) try: menu = self.builder.get_object('mainmenu', top) self.set_menu(menu) except: pass #show callbacks defined self.builder.connect_callbacks({}) self.set_title('Pygubu UI tester') self.set_resizable()
class AllCanvasTab(TkApplication): def _create_ui(self): self.pygubu_builder = Builder() self.pygubu_builder.add_from_file(path.join(SCRIPT_DIR, "forms", "all_screens_tab.ui")) self.canvas = list() self.predator_draw_object = [None, None, None, None] self.setup() def setup(self): self.canvas.append(self._create_canvas('canvas_one')) self.canvas.append(self._create_canvas('canvas_two')) self.canvas.append(self._create_canvas('canvas_three')) self.canvas.append(self._create_canvas('canvas_four')) def _create_canvas(self, identifier): self.pygubu_builder.get_object(identifier + '_label', self.master) return self.pygubu_builder.get_object(identifier, self.master) def change_background(self, color, id_number): self.canvas[id_number].configure(background=color)
def _create_ui(self): self.pygubu_builder = Builder() self.pygubu_builder.add_from_file(path.join(SCRIPT_DIR, "forms", "secondary_window.ui")) self.style = Style() self.canvas = list() self.predator_draw_object = [None, None, None, None] self.current_background_color = BACKGROUND_COLOR self.setup()
class SecondaryWindow(TkApplication): def _create_ui(self): self.pygubu_builder = Builder() self.pygubu_builder.add_from_file(path.join(SCRIPT_DIR, "forms", "secondary_window.ui")) self.style = Style() self.canvas = list() self.predator_draw_object = [None, None, None, None] self.current_background_color = BACKGROUND_COLOR self.setup() def setup(self): self.set_title("Piscis") self.pygubu_builder.get_object('main_frame', self.master) self.canvas.append(self._create_canvas('canvas_one')) self.canvas.append(self._create_canvas('canvas_two')) self.canvas.append(self._create_canvas('canvas_three')) self.canvas.append(self._create_canvas('canvas_four')) self.change_background_color(BACKGROUND_COLOR) def _create_canvas(self, identifier): return self.pygubu_builder.get_object(identifier, self.master) def set_fullscreen(self): self.master.overrideredirect(True) self.master.geometry("%dx%d+0+0" % (self.master.winfo_screenwidth(), self.master.winfo_screenheight())) def change_background_color(self, color): self.style.configure('TFrame', background=color) self.current_background_color = color def change_canvas_background(self, color, id_number): self.canvas[id_number].configure(background=color)
def _create_ui(self): self.pygubu_builder = Builder() self.pygubu_builder.add_from_file(path.join(SCRIPT_DIR, "forms", "main_window.ui")) self.secondary_window = SecondaryWindow(Toplevel()) # self.secondary_window.master.withdraw() self.predator = [None, None, None, None] self.drawer = PredatorDrawer(None) self.current_tab = 0 self.tabs = list() self.remaining_secs = 0 self.all_tab = None self.after_id = 0 self.isDrawOnAllScreenActive = [True, True, True, True] self.predator_factory = PredatorFactory() self.setup()
class Visualizer(Subject, Observer): """ A visualizer gui which waits for updates and provides updates on user actions. """ def __init__(self, master): """ Initialises this gui with an interface. """ Subject.__init__(self) # Call parent constructors Observer.__init__(self) self._update_thread = None # Thread to update the graphs self._builder = Builder() # Setup form from build file self._builder.add_from_file("PartyProblemSimulator/Visualizer/gui.ui") self.mainwindow = self._builder.get_object("frm_main") self._builder.get_object("cnv_display").config(width=250, height=250) self._builder.get_object("cnv_graph_fitness").config(width=500, height=250) self._builder.get_object("cnv_graph_evaluations").config(width=500, height=250) self._setup_eventhandlers() def _setup_eventhandlers(self): # pragma : no cover """ Sets the event handlers for form controls. """ btn_solve = self._builder.get_object("btn_solve") btn_solve.config(command=self._btn_solve_press) def _btn_solve_press(self): """ Notify observers that a problem is ready to be solved. """ if self._validate_input(): # Extract form information if valid self._notify_observers() def _validate_input(self): """ Extracts and validates the input. """ valid = True clique_size = self._builder.get_object("tb_clique_size").get() graph_size = self._builder.get_object("tb_graph_size").get() method = self._builder.get_object("cb_method").get() # Validation try: graph_size = int(graph_size) if graph_size < 1: raise Exception() except Exception: valid = False self._builder.get_object("lbl_error").config(text="Graph size must be an integer > 1.") try: clique_size = int(clique_size) if (clique_size <= 1) or (clique_size > graph_size): raise Exception() except Exception: valid = False self._builder.get_object("lbl_error").config(text="Clique size must be an integer > 1.") if (method not in ["BlindGA", "EvoSAP", "EvoSAP1", "EvoSAP2", "FlipGA", "FlipGA1", "FlipGA2"]) and valid: self._builder.get_object("lbl_error").config(text="Please select a method from the list provided.") valid = False if valid: # Reset error label if entry is valid. self._builder.get_object("lbl_error").config(text="") return valid def _update_gui(self, generation, eval_count, fitness, history, finished, graph):# pragma: no cover """ Updates the relevant gui components. """ self._builder.get_object("lbl_generations").config(text="Generation: {}".format(generation)) self._builder.get_object("lbl_eval_count").config(text="Eval Count: {}".format(eval_count)) self._builder.get_object("lbl_best_fitness").config(text="Best Fitness: {0:.2f}/1".format(fitness)) if finished: self._builder.get_object("lbl_error").config(text="Finished!") self._builder.get_object("btn_solve").config(state="normal") else: self._builder.get_object("lbl_error").config(text="Computing...") # Update plots on seperate threads for efficiency plots_thread = Thread(target=self._draw_plots, args=(history,)) graph_thread = Thread(target=self._draw_graph, args=(graph,)) plots_thread.start() graph_thread.start() plots_thread.join() graph_thread.join() def _draw_graph(self, graph): """ Draws the graph provided. """ cnv_display = self._builder.get_object("cnv_display") cnv_display.delete("all") # Clear canvas vertex_size = 10 edge_thickness = 1 # Draw vertices vertex_offset = vertex_size / 2 center_canvas = (cnv_display.winfo_width() / 2, cnv_display.winfo_height() / 2) distance = center_canvas[0] / 1.5 #Quater of the screen degrees = 360 / len(graph.get_vertices()) for vertex in graph.get_vertices(): # Calculate a new location for the vertex on canvas center_x = center_canvas[0] + ((distance) * sin(degrees * vertex.get_id())) center_y = center_canvas[1] + ((distance) * cos(degrees * vertex.get_id())) vertex.set_location(x=center_x, y=center_y) cnv_display.create_oval(center_x - vertex_offset, center_y - vertex_offset, center_x + vertex_offset, center_y + vertex_offset, fill='cyan') # Draw edges for edge in graph.get_edges(): start_x = edge.get_origin().get_location()[0] # Get locations start_y = edge.get_origin().get_location()[1] end_x = edge.get_target().get_location()[0] end_y = edge.get_target().get_location()[1] colour = self._determine_colour(edge.get_colour()) # Determine colour cnv_display.create_line(start_x, start_y, end_x, end_y, width=edge_thickness, fill=colour) def _draw_plots(self, history): # pragma: no cover """ Draws the plots. """ cnv_graph_fitness = self._builder.get_object("cnv_graph_fitness") cnv_graph_evaluations = self._builder.get_object("cnv_graph_evaluations") cnv_graph_fitness.delete("all") cnv_graph_evaluations.delete("all") # Determine axis locations origin = (50, 220) end_x = (origin[0] + 430, origin[1]) end_y = (origin[0], origin[1] - 210) # Draw graph axis cnv_graph_fitness.create_line(origin[0], origin[1], end_x[0], end_x[1], fill="black") cnv_graph_fitness.create_line(origin[0], origin[1], end_y[0], end_y[1], fill="black") cnv_graph_evaluations.create_line(origin[0], origin[1], end_x[0], end_x[1], fill="black") cnv_graph_evaluations.create_line(origin[0], origin[1], end_y[0], end_y[1], fill="black") # Label axis horizontal_label_location = ((origin[0] + end_x[0])/2, origin[1] + 20) cnv_graph_fitness.create_text(horizontal_label_location[0], horizontal_label_location[1], font="arial 10", text="Generation") cnv_graph_evaluations.create_text(horizontal_label_location[0], horizontal_label_location[1], font="arial 10", text="Generation") # Draw Horizontal labels label_x = 0 label_y = origin[1] + 10 if len(history['fitness']) >= 10: horizontal_increment = (end_x[0] - origin[0]) / 10 # Calculate increments to do horizontally count = 0 while count < 11: label_x = origin[0] + (count * horizontal_increment) # Determine axis details generation = len(history['fitness']) / 10 cnv_graph_fitness.create_text(label_x, label_y, font="arial 8", text="{}".format(int(generation * count))) # Label axis cnv_graph_evaluations.create_text(label_x, label_y, font="arial 8", text="{}".format(int(generation * count))) cnv_graph_fitness.create_line(label_x, label_y - 12, label_x, label_y - 8) # Show a small line on the axis cnv_graph_evaluations.create_line(label_x, label_y - 12, label_x, label_y - 8) count = count + 1 else: # Special case if there are < 10 cases no_increments = len(history['fitness']) horizontal_increment = (end_x[0] - origin[0]) / (no_increments + 1) count = 1 while count <= no_increments: label_x = origin[0] + (count * horizontal_increment) # Determine axis details generation = len(history['fitness']) / 10 cnv_graph_fitness.create_text(label_x, label_y, font="arial 8", text="{}".format(int(generation * count))) # Label axis cnv_graph_evaluations.create_text(label_x, label_y, font="arial 8", text="{}".format(int(generation * count))) cnv_graph_fitness.create_line(label_x, label_y - 12, label_x, label_y - 8) # Show a small line on the axis cnv_graph_evaluations.create_line(label_x, label_y - 12, label_x, label_y - 8) count = count + 1 # Draw points and labels fitness_thread = Thread(target=self._draw_fitness_points, args=(cnv_graph_fitness, origin, end_y, end_x, history['fitness'],)) evals_thread = Thread(target=self._draw_evaluation_points, args=(cnv_graph_evaluations, origin, end_y, end_x, history['evaluation'],)) fitness_thread.start() evals_thread.start() fitness_thread.join() evals_thread.join() def _draw_fitness_points(self, cnv_graph_fitness, graph_origin, vertical_end, horizontal_end, fitness_history): # pragma: no cover """ Draws the fitness graph. """ # Draw vertical axis values (Increments of 0.1 from 0) increment = (graph_origin[1] - vertical_end[1]) / 10 count = 0 while count < 1: text_location = (graph_origin[0], graph_origin[1] - ((count * 10) * increment)) # Add the label slightly to the left of axis cnv_graph_fitness.create_text(text_location[0] - 15, text_location[1], font="arial 8", text="{0:.1f}".format(count)) # Create label cnv_graph_fitness.create_line(text_location[0] - 2, text_location[1], text_location[0] + 2, text_location[1]) count = count + 0.1 # Draw points horizontal_increment = (horizontal_end[0] - graph_origin[0]) / len(fitness_history) # Calculate an even spacing between fitness values count = 0 previous_point = None if len(fitness_history) == 1: # Special case of a single point location_y = graph_origin[1] - (fitness_history[0] * (graph_origin[1] - vertical_end[1])) location_x = graph_origin[0] + ((horizontal_end[0] - graph_origin[0]) / 2) cnv_graph_fitness.create_text(location_x, location_y, fill="blue", text="x") else: while count < len(fitness_history): # Do a line graph location_y = graph_origin[1] - (fitness_history[count] * (graph_origin[1] - vertical_end[1])) location_x = graph_origin[0] + (1 * (horizontal_increment * count)) + 5 current_point = (location_x, location_y) if previous_point is not None: cnv_graph_fitness.create_line(previous_point[0], previous_point[1], current_point[0], current_point[1], fill="blue") previous_point = current_point count = count + 1 def _draw_evaluation_points(self, cnv_graph_evaluations, graph_origin, vertical_end, horizontal_end, evaluation_history): # pragma: no cover """ Draws the evaluation graph. """ # Draw vertical axis values (Increments of 0.1 from 0) increment = (graph_origin[1] - vertical_end[1]) / 10 count = 0 while count <= 1: text_location = (graph_origin[0], graph_origin[1] - ((count * 10) * increment)) # Add the label slightly to the left of axis cnv_graph_evaluations.create_text(text_location[0] - 25, text_location[1], font="arial 8", text="{}".format(int(evaluation_history[-1] * count) + 1)) # Create label cnv_graph_evaluations.create_line(text_location[0] - 2, text_location[1], text_location[0] + 2, text_location[1]) count = count + 0.1 # Draw points horizontal_increment = (horizontal_end[0] - graph_origin[0]) / len(evaluation_history) # Calculate an even spacing between evaluation values count = 0 previous_point = None if len(evaluation_history) == 1: # Special case of a single point location_y = vertical_end[1] # Top most point location_x = graph_origin[0] + ((horizontal_end[0] - graph_origin[0]) / 2) cnv_graph_evaluations.create_text(location_x, location_y, fill="blue", text="x") else: while count < len(evaluation_history): # Do a line graph location_y = graph_origin[1] - ((evaluation_history[count] / evaluation_history[-1]) * (graph_origin[1] - vertical_end[1])) # position varies location_x = graph_origin[0] + (count * (horizontal_increment)) + 5 current_point = (location_x, location_y) if previous_point is not None: cnv_graph_evaluations.create_line(previous_point[0], previous_point[1], current_point[0], current_point[1], fill="blue") previous_point = current_point count = count + 1 def _determine_colour(self, colour_code): """ Determines the colour code of an edge. """ if colour_code == 0: return 'red' elif colour_code == 1: return 'green' elif colour_code == 2: return 'cyan' else: return 'blue' def _notify_observers(self): """ Notifies observers. """ clique_size = int(self._builder.get_object("tb_clique_size").get()) # Get update parameters graph_size = int(self._builder.get_object("tb_graph_size").get()) method = self._builder.get_object("cb_method").get() update_argument = {"clique_size": clique_size, "graph_size": graph_size, "method": method} # Argument to update observers with for o in self._observers: o.update(update_argument) # Disable solve button self._builder.get_object("btn_solve").config(state="disabled") def update(self, args): """ Update details on form to show progress if required. """ if ('graph' and 'generation' and 'evals' and 'best_fitness' and 'finished' and 'history') in args: if (self._update_thread is None) or (not self._update_thread.isAlive()): self._update_thread = Thread(target=self._update_gui, args=(args['generation'], args['evals'], float(args['best_fitness']), args['history'], args['finished'], args['graph'],)) self._update_thread.start()
def _create_ui(self): self.pygubu_builder = Builder() self.pygubu_builder.add_from_file(path.join(SCRIPT_DIR, "forms", "all_screens_tab.ui")) self.canvas = list() self.predator_draw_object = [None, None, None, None] self.setup()
class MainWindow(TkApplication): def _create_ui(self): self.pygubu_builder = Builder() self.pygubu_builder.add_from_file(path.join(SCRIPT_DIR, "forms", "main_window.ui")) self.secondary_window = SecondaryWindow(Toplevel()) # self.secondary_window.master.withdraw() self.predator = [None, None, None, None] self.drawer = PredatorDrawer(None) self.current_tab = 0 self.tabs = list() self.remaining_secs = 0 self.all_tab = None self.after_id = 0 self.isDrawOnAllScreenActive = [True, True, True, True] self.predator_factory = PredatorFactory() self.setup() def setup(self): self.set_title(PISCIS_TITLE) self.pygubu_builder.get_object('main_frame', self.master) self.set_menu(self.pygubu_builder.get_object('main_menu', self.master)) self.create_tabs() self.pygubu_builder.connect_callbacks(self) for i, item in enumerate(self.predator): draw_all_outlines(self.tabs[i], self.all_tab, self.secondary_window, i) def create_tabs(self): self.all_tab = self._create_canvas_tab('tab_all_screens') self.tabs.append(self._create_canvas_tab('tab_single_tab_one')) self.tabs.append(self._create_canvas_tab('tab_single_tab_two')) self.tabs.append(self._create_canvas_tab('tab_single_tab_three')) self.tabs.append(self._create_canvas_tab('tab_single_tab_four')) def _create_canvas_tab(self, identifier): if identifier == 'tab_all_screens': return AllCanvasTab(self.pygubu_builder.get_object(identifier, self.master)) else: self.current_tab += 1 return SingleCanvasTab(self.pygubu_builder.get_object(identifier, self.master), self.current_tab - 1, self) @staticmethod def on_about(): showinfo(PISCIS_TITLE, PISCIS_TITLE + " - " + PISCIS_VERSION + "\n" + PISCIS_CONTACT) def on_exit(self): self.stop_all_simulations() self.master.quit() def stop_all_simulations(self): for i, item in enumerate(self.predator): self.tabs[i].on_stop() def on_fullscreen(self): self.secondary_window.set_fullscreen() def on_change_fullscreen(self): new_color = askcolor(color=self.secondary_window.current_background_color, title="Change Background-Color")[1] self.secondary_window.change_background_color(new_color) def create_predator(self, color, target_diameter, scaling_velocity, starting_position=None): if starting_position is None: starting_position = .5, .5 self.predator_factory.starting_position = starting_position self.predator_factory.target_diameter = target_diameter self.predator_factory.scaling_velocity = scaling_velocity self.predator_factory.color = color return self.predator_factory.create() def get_predator_color(self): return self.predator_factory.color def start_predator(self, predator, id_number): if predator is None: showinfo("No Predator found", "Please place a stimuli first!") return self.isDrawOnAllScreenActive[id_number] = True predator.start_scaling(int(time.time() * 1000)) self.predator[id_number] = predator self.drawer.start() self.start_update() def start_update(self): self.after_id = self.master.after(25, self.update) def update(self): self.after_id = self.master.after(25, self.update) self.render() def render(self): for i, item in enumerate(self.predator): self.draw_predators(i, item) # self.drawer.draw_all_outlines(self.tabs[i], self.all_tab, self.secondary_window, i) def draw_predators(self, i, item): if item is not None: self.drawer.predator = item self.draw_predators_on_all_screens(i) def draw_predators_on_all_screens(self, i): if self.isDrawOnAllScreenActive[i]: self.drawer.draw_predator(self.tabs[i], self.all_tab, self.secondary_window, i) def change_background_color_of_all_canvas(self, id_number, color): self.all_tab.change_background(id_number, color) self.secondary_window.change_canvas_background(id_number, color) def stop_drawing(self): self.drawer.stop()
def _create_ui(self): self.pygubu_builder = Builder() self.pygubu_builder.add_from_file(path.join(SCRIPT_DIR, "forms", "single_canvas_tab.ui")) self.setup()
class SingleCanvasTab(TkApplication): def __init__(self, master, id_number, parent=None): TkApplication.__init__(self, master) self.id_number = id_number self.parent = parent self.change_background_color(self.current_background_color) self.target_diameter = 0 self.scaling_velocity = 0 self.remaining_secs_run = 0 self.remaining_secs_pause = 0 self.predator = None self.predator_draw_object = None self.starting_position = None self.run_timer = None self.pause_timer = None def _create_ui(self): self.pygubu_builder = Builder() self.pygubu_builder.add_from_file(path.join(SCRIPT_DIR, "forms", "single_canvas_tab.ui")) self.setup() def setup(self): self.canvas = self.pygubu_builder.get_object('canvas', self.master) self.canvas.bind("<Button-1>", self.set_starting_position) self.current_background_color = BACKGROUND_COLOR self.color = PREDATOR_COLOR self._create_scale_slider() self._create_speed_slider() self._create_interval_controls() self._create_buttons() self.pygubu_builder.connect_callbacks(self) def _create_scale_slider(self): self.pygubu_builder.get_object('scale', self.master) def _create_speed_slider(self): self.pygubu_builder.get_object('speed', self.master) def _create_interval_controls(self): self.pygubu_builder.get_object('interval', self.master) self.pygubu_builder.get_object('interval_run', self.master) self.pygubu_builder.get_object('interval_pause', self.master) self._create_running_interval_settings() self._create_pausing_interval_settings() def _create_pausing_interval_settings(self): self.interval_seconds_pause = self.pygubu_builder.get_object('spin_seconds_pause', self.master) self.interval_minutes_pause = self.pygubu_builder.get_object('spin_minutes_pause', self.master) self.remaining_secs_label_pause = self.pygubu_builder.get_object('remaining_secs_pause', self.master) def _create_running_interval_settings(self): self.interval_seconds_run = self.pygubu_builder.get_object('spin_seconds_run', self.master) self.interval_minutes_run = self.pygubu_builder.get_object('spin_minutes_run', self.master) self.remaining_secs_label_run = self.pygubu_builder.get_object('remaining_secs_run', self.master) def _create_buttons(self): self.pygubu_builder.get_object('background', self.master) self.pygubu_builder.get_object('stimuli_color', self.master) self.pygubu_builder.get_object('generate', self.master) self.pygubu_builder.get_object('simulate', self.master) def on_generate(self): self.canvas.delete(self.predator_draw_object) self.predator = self.parent.create_predator(self.color, self.target_diameter, self.scaling_velocity, self.starting_position) self.draw_preview_predator() self.parent.isDrawOnAllScreenActive[self.id_number] = False self.starting_position = None def draw_preview_predator(self): drawer = PredatorDrawer(self.predator) width, height = self.canvas.winfo_width(), self.canvas.winfo_height() begin_x, begin_y, end_x, end_y = drawer.calculate_coordinates(width, height, self.target_diameter) self.predator_draw_object = self.canvas.create_oval(begin_x, begin_y, end_x, end_y, fill=self.color, outline=self.color) def on_background(self): new_color = askcolor(color=self.current_background_color, title="Change Background-Color")[1] self.change_background_color(new_color) def on_stimuli_color(self): new_color = askcolor(color=self.parent.get_predator_color(), title="Change Predator-Color")[1] self.color = new_color if self.predator is not None: self.predator.color = self.color def on_scale_slider(self, value): self.target_diameter = float(value) if self.predator is not None: self.predator.set_target_diameter(self.target_diameter) def on_speed_slider(self, value): self.scaling_velocity = float(value) / 5 if self.predator is not None: self.predator.set_scaling_velocity(self.scaling_velocity) def on_start(self): self.parent.start_predator(self.predator, self.id_number) if self.remaining_secs_run > 0: self.update_pause_remaining_seconds_label() self.start_run_timer() def start_run_timer(self): self.run_timer = Timer(1.0, self.reduce_run_remaining_seconds) self.run_timer.start() def reduce_run_remaining_seconds(self): self.remaining_secs_run -= 1 self.update_run_remaining_seconds_label() if int(self.remaining_secs_run) > 0: self.start_run_timer() else: self.on_stop() self.update_run_remaining_seconds_label() self.set_run_remaining_seconds() self.start_pause_timer() def start_pause_timer(self): self.pause_timer = Timer(1.0, self.reduce_pause_remaining_seconds) self.pause_timer.start() def reduce_pause_remaining_seconds(self): self.remaining_secs_pause -= 1 self.update_pause_remaining_seconds_label() if int(self.remaining_secs_pause) > 0: self.start_pause_timer() else: self.update_pause_remaining_seconds_label() self.set_pause_remaining_seconds() self.on_start() def on_stop(self): self.stop_pause_timer() self.stop_run_timer() self.parent.stop_drawing() def stop_pause_timer(self): if self.pause_timer is not None: self.pause_timer.cancel() self.set_pause_remaining_seconds() def stop_run_timer(self): if self.run_timer is not None: self.run_timer.cancel() self.set_run_remaining_seconds() def on_pause_seconds_changed(self): self.set_pause_remaining_seconds() self.update_pause_remaining_seconds_label() def on_pause_minutes_changed(self): self.set_pause_remaining_seconds() self.update_pause_remaining_seconds_label() def set_pause_remaining_seconds(self): self.remaining_secs_pause = self.minutes_to_seconds(self.interval_minutes_pause.get()) + int( self.interval_seconds_pause.get()) def update_pause_remaining_seconds_label(self): self.remaining_secs_label_pause.configure(text=self.remaining_secs_pause) def on_run_seconds_changed(self): self.set_run_remaining_seconds() self.update_run_remaining_seconds_label() def on_run_minutes_changed(self): self.set_run_remaining_seconds() self.update_run_remaining_seconds_label() def set_run_remaining_seconds(self): self.remaining_secs_run = self.minutes_to_seconds(self.interval_minutes_run.get()) + int( self.interval_seconds_run.get()) def update_run_remaining_seconds_label(self): self.remaining_secs_label_run.configure(text=self.remaining_secs_run) def minutes_to_seconds(self, value): return int(value) * MIN_TO_SEC def change_background_color(self, color): self.canvas.configure(background=color) self.parent.change_background_color_of_all_canvas(color, self.id_number) self.current_background_color = color def set_starting_position(self, event): self.starting_position = event.x / self.canvas.winfo_width(), event.y / self.canvas.winfo_height() self.on_generate()
class MacronSetupWizard: def __init__(self): self.root = root = Tk() root.withdraw() root.title('Setup Wizard') root.geometry('500x360') root.iconbitmap(RESOURCE_PATH + 'icon.ico') # Center window root.update_idletasks() width = root.winfo_width() height = root.winfo_height() x = (root.winfo_screenwidth() // 2) - (width // 2) y = (root.winfo_screenheight() // 2) - (height // 2) root.geometry('{}x{}+{}+{}'.format(width, height, x, y)) root.deiconify() root.resizable(width=False, height=False) self.settings = { 'app_name': 'MacronApp', 'install_path': 'C:\Program Files', # TODO: Get default install path 'create_shortcut': True, 'start_after_setup': True } with open(RESOURCE_PATH + '.setupdata') as f: setupData = load(f) self.settings['app_name'] = setupData['app_name'] self.settings['app_repo_url'] = setupData['app_repo_url'] with open(RESOURCE_PATH + 'LICENSE') as f: self.settings['app_license'] = f.read() with open(RESOURCE_PATH + 'intro-view.xml') as f: self.navigate(f.read()) self.mainwindow = self.builder.get_object('Frame_0', root) self.root.title(self.settings['app_name'] + ' Setup Wizard') self.builder.get_object('WelcomeLabel').config( text='Welcome to the {} Setup Wizard'.format( self.settings['app_name'])) self.builder.get_object('IntroLabel').config( text='''This wizard will install {} on your computer. It is recommended that you close all other applications before continuing. Click Next to continue, or Cancel to exit Setup.'''.format( self.settings['app_name'])) # self.set_image( # (160, 310), # self.settings['setup_banner'], # self.builder.get_object('SetupBanner') # ) root.mainloop() def on_intro_next(self): with open(RESOURCE_PATH + 'license-view.xml') as f: self.navigate(f.read()) # self.set_image( # (60, 60), # self.settings['setup_logo'], # self.builder.get_object('SetupLogo') # ) self.builder.get_object('LicenseInput').delete('1.0', END) self.builder.get_object('LicenseInput').insert( '1.0', self.settings['app_license']) self.builder.get_object('LicenseInput').config(state=DISABLED) self.builder.get_object('Radiobutton_5').select() self.builder.get_object('Button_2').configure(state=DISABLED) def on_license_next(self): with open(RESOURCE_PATH + 'settings-view.xml') as f: self.navigate(f.read()) # self.set_image( # (60, 60), # self.settings['setup_logo'], # self.builder.get_object('SetupLogo') # ) self.builder.get_object('SetupReadyLabel').config( text='Setup is ready to download and install {} on your computer.'. format(self.settings['app_name'])) self.builder.get_object('Entry_2').insert( 0, self.settings['install_path']) self.builder.get_object('Checkbutton_3').select() self.builder.get_object('Checkbutton_4').select() def on_settings_next(self): self.settings['create_shortcut'] = self.builder.create_variable( 'boolean:create_shortcut').get() self.settings['start_after_setup'] = self.builder.create_variable( 'boolean:start_after_setup').get() with open(RESOURCE_PATH + 'download-view.xml') as f: self.navigate(f.read()) # self.set_image( # (60, 60), # self.settings['setup_logo'], # self.builder.get_object('SetupLogo') # ) self.builder.get_object('FinishButton').config(state=DISABLED) self.downloadThread = threading.Thread(target=self.download) self.downloadThread.start() def on_license_back(self): with open(RESOURCE_PATH + 'intro-view.xml') as f: self.navigate(f.read()) def on_settings_back(self): with open(RESOURCE_PATH + 'license-view.xml') as f: self.navigate(f.read()) def on_not_accept(self): self.builder.get_object('Button_2').configure(state=DISABLED) def on_accept(self): self.builder.get_object('Button_2').configure(state=NORMAL) def on_browse_dir(self): response = filedialog.askdirectory( title='Please select installation path...') self.settings['install_path'] = response entry = self.builder.get_object('Entry_2') entry.delete(0, END) entry.insert(0, response) def download(self): self.builder.get_object('DownloadStatusLabel').config( text="Obtaining latest release...") def reporthook(blocknum, blocksize, totalsize): self.builder.get_object('DownloadStatusLabel').config( text="Downloading...") readsofar = blocknum * blocksize if totalsize > 0: percent = readsofar * 1e2 / totalsize self.builder.create_variable('double:download_progress').set( percent) self.builder.get_object('DownloadRatio').config( # text='{:.1} %'.format(percent) text="{:.1f} / {:.1f} MB".format(readsofar / 1048576, totalsize / 1048576)) if readsofar >= totalsize: # near the end self.builder.get_object('DownloadStatusLabel').config( text="Download complete") self.builder.get_object('RetryButton').config( state=DISABLED) else: # total size is unknown pass try: repoURL = urlopen(self.settings['app_repo_url'] + '/.setupdata') data = repoURL.read() encoding = repoURL.info().get_content_charset('utf-8') latestSetupData = loads(data.decode(encoding)) try: # download filehandle, _ = urlretrieve( url=latestSetupData['app_repo_url'] + latestSetupData['latest_windows_dist_url'], reporthook=reporthook) try: # install self.builder.get_object('InstallStatusLabel').config( text="Installing...") ZipFile(filehandle).extractall( self.settings['install_path']) if self.settings['create_shortcut']: CoInitialize() appPath = '{}\\{}\\{}.exe'.format( self.settings['install_path'], self.settings['app_name'], self.settings['app_name']) self.createShortcut(path=os.path.join( desktop(), self.settings['app_name'].replace('_', ' ') + '.lnk'), target=appPath, wDir='{}\\{}'.format( self.settings['install_path'], self.settings['app_name']), icon=appPath) self.builder.get_object('InstallStatusLabel').config( text="Installation complete!") self.builder.get_object('FinishButton').config( state=NORMAL) except: messagebox.showwarning( title='{} Setup Wizard'.format( self.settings['app_name']), message= 'Setup is unable to install additional files. Please try again.' ) except: messagebox.showwarning( title='{} Setup Wizard'.format(self.settings['app_name']), message= 'Setup is unable to download additional files. Please make sure that you have an internet connection, then click Retry.' ) except: messagebox.showwarning( title='{} Setup Wizard'.format(self.settings['app_name']), message= 'An unexpected error occured. Setup wizard is unable to obtain additional files. Click Retry.' ) def on_finish(self): if self.settings['start_after_setup']: startfile('{}\\{}\\{}.exe'.format(self.settings['install_path'], self.settings['app_name'], self.settings['app_name'])) self.root.destroy() def on_retry_download(self): response = messagebox.showwarning( type=messagebox.YESNO, title='{} Setup Wizard'.format(self.settings['app_name']), message='Are you sure you want to retry downloading?') if response == 'yes': self.downloadThread = threading.Thread(target=self.download) self.downloadThread.start() def on_cancel(self): response = messagebox.showwarning( type=messagebox.OKCANCEL, title='{} Setup Wizard'.format(self.settings['app_name']), message='Are you sure you want to cancel the installation process?' ) if response == 'ok': # if self.downloadThread: self.downloadThread._Thread_stop() self.root.destroy() # Helpers def navigate(self, next_view_ui): self.builder = Builder() self.builder.add_from_string(next_view_ui) self.mainwindow = self.builder.get_object('Frame_0', self.root) self.builder.connect_callbacks(self) # convert bytes to MB.... GB... etc... def human_bytes(self, num): step_unit = 1000.0 #1024 bad the size for x in ['bytes', 'KB', 'MB', 'GB', 'TB']: if num < step_unit: return "%3.1f %s" % (num, x) num /= step_unit def createShortcut(self, path, target='', wDir='', icon=''): ext = path[-3:] if ext == 'url': shortcut = file(path, 'w') shortcut.write('[InternetShortcut]\n') shortcut.write('URL=%s' % target) shortcut.close() else: shell = Dispatch('WScript.Shell') shortcut = shell.CreateShortCut(path) shortcut.Targetpath = target shortcut.WorkingDirectory = wDir if icon == '': pass else: shortcut.IconLocation = icon shortcut.save()
def navigate(self, next_view_ui): self.builder = Builder() self.builder.add_from_string(next_view_ui) self.mainwindow = self.builder.get_object('Frame_0', self.root) self.builder.connect_callbacks(self)