예제 #1
0
    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
예제 #2
0
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>>")