def notebook_init(self): self.style.element_create('close', 'image', 'img_close', ('active', 'pressed', '!disabled', 'img_close_pressed'), ('active', '!disabled', 'img_close_mouse_over')) self.style.layout('NotebookBtn', [('Notebook.client', {'sticky': 'nsew'})]) self.style.layout('NotebookBtn.Tab', [ ('Notebook.tab', {'sticky': 'nsew', 'children': [ ('Notebook.padding', {'side': 'top', 'sticky': 'nsew', 'children': [ ('Notebook.focus', {'side': 'top', 'sticky': 'nsew', 'children': [ ('Notebook.label', {'side': 'left', 'sticky': 'nsew'}), ('Notebook.close', {'side': 'right', 'sticky': 'nsew'}) ]}) ]}) ]}) ]) self.style.configure('NotebookBtn.Tab', padding=2, image='tab_doc') self.style.map('NotebookBtn.Tab', background=[('selected', '#f0f0f0')]) self.root.bind_class('TNotebook', '<ButtonPress-1>', self.tab_btn_press, True) self.root.bind_class('TNotebook', '<ButtonRelease-1>', self.tab_btn_release) tabs = Notebook(self.root, style='NotebookBtn') tabs.grid(column=0, row=1, sticky='nsew') tabs.columnconfigure(0, weight=1) tabs.rowconfigure(0, weight=1) return tabs
class Window(Frame): def __init__(self, root): super().__init__(root) self.master = root self.master.title('Plotting Tool') self.master.geometry('800x600+700+25') self.master.columnconfigure(0, weight=1) self.master.rowconfigure(0, weight=1) self.AddWigets() def AddWigets(self): # Set colours here so they can all be change at once. buttonColour = '#00c85d' self.temp = 0 # --- Make the "Tab Group" aka Notebook. self.tabGroup = Notebook(self.master) self.tabGroup.grid(column=0, row=0, sticky='nsew') self.tabGroup.columnconfigure(0, weight=1) self.tabGroup.rowconfigure(0, weight=1) ################################################################### # --- Add the first tab (input). self.tab1 = Frame(self.tabGroup) self.tabGroup.add(self.tab1, text='Input') # Add a label for the first drop down. self.dd1Label = Label(self.tab1, text='Choose your favorite Cola:') # .grid(..., sticky='w', ...) makes the label stick to the west (left) # side of the "area" it has been assigned. self.dd1Label.grid(column=0, row=0, sticky='w', padx=(0, 10), pady=(20, 10)) # Add the first drop down. # Get the drop down options. dd1List = self.GetList1() self.dd1Str = StringVar(self.tab1) # Set the option the drop down starts on. self.dd1Str.set(dd1List[0]) self.dd1 = OptionMenu(self.tab1, self.dd1Str, *dd1List) # Mess with the look of the drop down this can also change the colour, # font size ect. self.dd1.config(relief='groove') self.dd1.grid(column=1, row=0, sticky='NESW', padx=0, pady=(20, 10)) # Add a label for the second drop down. self.dd2Label = Label(self.tab1, text='Please choose your favorite type of beer:') self.dd2Label.grid(column=0, row=1, sticky='w', padx=(0, 10), pady=10) # Add the second drop down. dd2List = self.GetList2() self.dd2Str = StringVar(self.tab1) self.dd2Str.set(dd2List[0]) self.dd2 = OptionMenu(self.tab1, self.dd2Str, *dd2List) self.dd2.config(relief='groove') self.dd2.grid(column=1, row=1, sticky='NESW', padx=(0, 10), pady=10) # Add the run button. # command=self.RunModel executes (aka calls) the function (aka a # method of this class) RunModel. self.runButton = Button(self.tab1, text='Run', command=self.RunModel) self.runButton.config(background=buttonColour, relief='flat') self.runButton.grid(column=0, row=2, columnspan=2, padx=0, pady=(40, 0), ipadx=10, ipady=5) ####################################################################### # --- Add the second tab (output). self.tab2 = Frame(self.tabGroup) self.tabGroup.add(self.tab2, text='Output') # Controls the resizing of the graph config controls and the graph it # self. self.tab2.columnconfigure(0, weight=1) self.tab2.columnconfigure(0, minsize=250) self.tab2.columnconfigure(1, weight=3) self.tab2.rowconfigure(0, weight=1) # Add two frames to split tab2 to enable spacing of the graph. self.Split1 = Frame(self.tab2) self.Split1.grid(column=0, row=0, sticky='nesw', padx=(0, 20), pady=0) self.Split2 = Frame(self.tab2) self.Split2.grid(column=1, row=0, sticky='nesw', padx=(20, 0), pady=0) # This enables the resizing behavior of the graph, tab2's config # controls the resizing of the left and right side. self.Split2.columnconfigure(0, weight=1) self.Split2.rowconfigure(0, weight=1) # Add a x-axis drop down label. self.ddXLabel = Label(self.Split1, text='X-Axis Variable:') self.ddXLabel.grid(column=0, row=0, sticky='w', padx=(0, 10), pady=(20, 10)) # Add a x-axis drop down. ddXList = self.GetListX() self.ddXStr = StringVar(self.Split1) self.ddXStr.set(ddXList[0]) self.ddX = OptionMenu(self.Split1, self.ddXStr, *ddXList) self.ddX.config(relief='groove') self.ddX.grid(column=1, row=0, sticky='NESW', padx=0, pady=(20, 10)) # Add a y-axis drop down label. self.ddYLabel = Label(self.Split1, text='Y-Axis Variable:') self.ddYLabel.grid(column=0, row=1, sticky='w', padx=(0, 10), pady=(20, 10)) # Add a y-axis drop down. ddYList = self.GetListY() self.ddYStr = StringVar(self.Split1) self.ddYStr.set(ddYList[0]) self.ddY = OptionMenu(self.Split1, self.ddYStr, *ddYList) self.ddY.config(relief='groove') self.ddY.grid(column=1, row=1, sticky='nsew', padx=0, pady=(20, 10)) # Add a plot button to save dev time. # command=self.Plotter executes the function Plotter. self.plotButton = Button(self.Split1, text='Plot', command=self.Plotter) self.plotButton.config(background=buttonColour, relief='flat') self.plotButton.grid(column=0, row=2, columnspan=2, padx=0, pady=(40, 0), ipadx=10, ipady=5) # --- Here we work on the graph. # I don't know how to fix the dpi problem. f = Figure(figsize=(5, 5), dpi=100) self.a = f.add_subplot(111) self.canvas = FigureCanvasTkAgg(f, self.Split2) self.canvas.get_tk_widget().grid(column=0, row=0, sticky='nsew') self.canvas.draw() ########################################################################### # --- Callbacks def GetList1(self): # Replace with a proper import function. cokeList = ['Diet Coke', 'Deit Pepsi', "Aldi's Diet Cola"] return cokeList def GetList2(self): # Replace with a proper import function. beerList = ['Stout', 'Lager', 'Bitter', 'IPA'] return beerList def RunModel(self): # The .get() will pull the value from the drop downs which you can you # to set params for the model fCoke = self.dd1Str.get() fBeer = self.dd2Str.get() print('Run model with inputs:', fCoke, 'and', fBeer + '.') def GetListX(self): # Replace with your x-axis varables if you have them. xAxisList = ['Time (s)', 'Distance (m)', 'Temperature (\u00b0C)'] return xAxisList def GetListY(self): # Replace with your x-axis varables if you have them. yAxisList = ['Mass (kg)', 'Height (m)', 'Speed (m/s)'] return yAxisList def Plotter(self): # This is the function that executers (is called) when the plot button # is pushed. self.temp += 1 line = [self.temp, self.temp + 1] self.a.clear() self.a.plot(line, line) self.canvas.draw()
class ViewResults(Observer, View): """Takes care of the presentation of the Flow diagram.""" def __init__(self, parent, col=0, row=0, root=None): super().__init__(parent, col=col, row=row, sticky=NSEW, scrollbars=False, root=root) self._notebook = Notebook(self._frame, name="nb") self._notebook.columnconfigure(0, weight=1) self._notebook.rowconfigure(0, weight=1) self._notebook.config() self._notebook.grid(sticky=NSEW) self._notebook.grid(sticky=NSEW) self._tabs = [] # type: List[ImageTab] self._results = None self._parent = parent self.image_overlay = np.empty(shape=(0, 0, 0), dtype=np.uint8) # TODO: Work around below should be fixed; need to create a tab first and delete it, or background is old image in constant scale. name_init = "initialization_image" self.add_to_tab(np.zeros((1, 1, 3), dtype=np.uint8), name_init) self.RemoveTab(name_init) self.__temp_data_queue = Queue( ) # used for update function to store data in # add custom event handler to let updates be taken care of in tk main loop parent.root.bind("<<ViewResults.Update>>", self.__update) self._notebook.bind("<<NotebookTabChanged>>", self.__on_tabchange) self.__last_selected_tab = None def __on_tabchange(self, event): try: tab_index = self._notebook.index(self._notebook.select()) except TclError as ex: return # there are no tabs yet if self.__last_selected_tab is not None: self.__last_selected_tab.on_tab_deselect() self.__last_selected_tab = self._tabs[tab_index] self.__last_selected_tab.on_tab_selected() def RemoveTab(self, name): for tab in self._tabs: if name is tab.GetName(): tab.destroy() self._tabs.remove(tab) def add_to_tab(self, npimage, name): if npimage is None: return # check if one exists; if so use that for tab in self._tabs: if tab.GetName() == name: tab.SetImage(npimage=npimage) return #create new tab one tab = ImageTab(name=name, notebook=self._notebook, parent=self) self._tabs.append(tab) self.add_to_tab(npimage=npimage, name=name) def __findAllImagesAndShow(self, flowblock_name): if self._results is None: return imageVars = self._results.FindAllOfType(ImageVar().name) for key, var in imageVars.items(): name = key.split(".")[0] if name == flowblock_name: self.add_to_tab(var.value, name) def __draw_all_drawables_until(self, flowblock_name=None): ''' Draws al drawable results to image_overlay. Images is as large as to fit all drawables. :param flowblock_name: draw until this block. :return: ''' results = self.get_controller().results.get_result_dict( ) # type: Dict[str,Dict[str,Var]] self.image_overlay = np.empty(shape=(0, 0, 0), dtype=np.uint8) logging.debug("Starting drawing of drawables...") for key, value in results.items(): for key2, value2 in value.items(): if type(value2) == list: for value3 in value2: self.image_overlay = value3.draw(self.image_overlay) else: self.image_overlay = value2.draw(self.image_overlay) logging.debug("Finished drawing of drawables.") def __update(self, event): self._results = self.get_controller().results.get_results_for_block() try: flowblock_name = self.__temp_data_queue.get_nowait( )["flowblock_name"] except Empty: flowblock_name = None if not flowblock_name is None: # redraw al drawables self.__draw_all_drawables_until(flowblock_name) # a flowblock has just updated, go and show all containing images self.__findAllImagesAndShow(flowblock_name) def Update(self, *args, **kwargs): self.__temp_data_queue.put_nowait( {"flowblock_name": kwargs.get("flowblock_name", None)}) self._parent.root.event_generate("<<ViewResults.Update>>")