def getWidthAndHeight(currentMessage: Message, settings: Settings, font: Font) -> (int, int): fontColor = currentMessage.overrides.fontColor if currentMessage.overrides.fontColor else settings.messageSettings.color xCoord = 0 yCoord = 0 canvas = Canvas() box = (0, 0, 0, 0) for part in sorted(currentMessage.parts, key=lambda x: x.sortOrder): if part.partType == "Pixel Gap": xCoord += int(part.value) elif part.partType == "Text": for char in part.value: canvas.create_text(xCoord, yCoord, fill=fontColor, text=char, font=font, tags="currentMessage", anchor=W) box = canvas.bbox(canvas.find_withtag("currentMessage")[-1]) xCoord = box[2] elif part.partType == "Text From File": fileText = readFile(part.value) for char in fileText: canvas.create_text(xCoord, yCoord, fill=fontColor, text=char, font=font, tags="currentMessage", anchor=W) box = canvas.bbox(canvas.find_withtag("currentMessage")[-1]) xCoord = box[2] elif part.partType == "Image": try: img = PhotoImage(Image.open(part.value)) canvas.create_image(xCoord, yCoord, image=img, anchor=W, tags="currentMessage") box = canvas.bbox(canvas.find_withtag("currentMessage")[-1]) xCoord = box[2] except Exception as e: print("Error loading image: " + str(e)) width = box[2] height = 0 for elem in canvas.find_withtag("currentMessage"): box = canvas.bbox(elem) height = max(height, box[3] - box[1]) canvas.delete("all") del canvas return width, height
class ScrollableFrame(ttk.Frame): """ Consider me a regular frame with a vertical scrollbar on the right, after adding/removing widgets to/from me call my method update() to refresh the scrollable area. Don't pack() me, nor place() nor grid(). I work best when I am alone in the parent frame. https://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-group-of-widgets-in-tkinter/3092341#3092341 """ def __init__(self, win_frame, x_frame, y_frame, *args, **kw): # scrollbar on right in parent yscrollbar = Scrollbar(y_frame) yscrollbar.pack(side=RIGHT, fill=Y, expand=False) # scrollbar on bottom in parent xscrollbar = Scrollbar(x_frame, orient=HORIZONTAL) xscrollbar.pack(side="top", fill=X, expand=False, pady=10) # canvas on left in parent self.canvas = Canvas(win_frame, yscrollcommand=yscrollbar.set, xscrollcommand=xscrollbar.set, background="#ffffff") self.canvas.pack(side=LEFT, fill=BOTH, expand=True) def fill_canvas(event): "enlarge the windows item to the canvas width" self.canvas.configure(scrollregion=self.canvas.bbox("all")) self.canvas.bind("<Configure>", fill_canvas) yscrollbar.config(command=self.canvas.yview) xscrollbar.config(command=self.canvas.xview) # create the scrollable frame and assign it to the windows item of the canvas style = ttk.Style() style.configure("BW.TLabel", foreground="black", background="white") kw["style"] = "BW.TLabel" ttk.Frame.__init__(self, win_frame, *args, **kw) self.windows_item = self.canvas.create_window(0, 0, window=self, anchor=NW) def update(self): """ Update changes to the canvas before the program gets back the mainloop, then update the scrollregion """ self.update_idletasks() self.canvas.config(scrollregion=self.canvas.bbox(self.windows_item))
def zipForward(settings: Settings, canvas: Canvas, scrollSpeed: float): deltaY = 1 try: for elem in canvas.find_withtag("currentMessage"): crashPrevention = 0 while crashPrevention < 5000 and int( (canvas.bbox(elem)[3] + canvas.bbox(elem)[1]) / 2) != int( int(settings.windowSettings.height) / 2): canvas.move(elem, 0, deltaY) pause(scrollSpeed) crashPrevention += 1 deltaY = deltaY * -1 except TypeError: return
def rotateImage(angle): global imagePath global image global im global im_width global im_height global im_size global photo global canvas global xscrollbar global yscrollbar global t canvas.destroy() canvas = Canvas(root, height=canvasHeight, width=canvasWidth, xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set) canvas.place(x=canvasxPosition, y=canvasyPosition) im = Image.open(imagePath.get()) im_width, im_height = im.size im = im.resize((int(im_width * imageMagnification.get()), int(im_height * imageMagnification.get())), Image.ANTIALIAS) im = im.rotate(angle * 180 / pi) photo = ImageTk.PhotoImage(im) image = canvas.create_image(0, 0, anchor=NW, image=photo) canvas.grid(row=0, column=0, sticky=N + S + E + W) canvas.config(scrollregion=canvas.bbox(ALL)) xscrollbar.config(command=canvas.xview) yscrollbar.config(command=canvas.yview) canvas.bind("<Motion>", crop) canvas.bind("<ButtonPress-1>", printcoord) canvas.bind('<B1-Motion>', onGrow)
def query_and_result(self,query_from_client): query = str(query_from_client) n_relevant_docs,relevant_docs = self.start_search(query=query) # create canvas canvas = Canvas(self.master) canvas.grid(row=4, columnspan=3, sticky="news") # create another frame canvas_Frame = Frame(canvas) canvas.create_window((0, 0), window=canvas_Frame, anchor=N + W) if n_relevant_docs > 0: sort_var = IntVar() sort_time_chack_btn = Checkbutton(self.master,text="sort by time",onvalue=0 ,variable=sort_var,command=lambda :self.sort_by_time(canvas_Frame,relevant_docs)) sort_pop_chack_btn = Checkbutton(self.master,text="sort by popularity",onvalue=1,variable=sort_var,command=lambda :self.sort_by_pop(canvas_Frame,relevant_docs)) sort_chack_btn = Checkbutton(self.master, text="sort by relevant", onvalue=2, variable=sort_var, command=lambda: self.print_results(canvas_Frame, relevant_docs)) sort_chack_btn.grid(row=3, column=0) sort_pop_chack_btn.grid(row=3, column=1) sort_time_chack_btn.grid(row=3, column=2) #create scrollbar scrollbar = Scrollbar(self.master, orient="vertical", command=canvas.yview) scrollbar.grid(row=3, columnspan=4,sticky=E) #bind canvas and scrollbar canvas.configure(yscrollcommand=scrollbar.set) canvas.bind('<Configure>',lambda e: canvas.configure(scrollregion=canvas.bbox("all"))) n_text = "There is "+str(n_relevant_docs)+" results" n_lable = Label(canvas_Frame, text=n_text, font=("serif", 10)) n_lable.grid(row=3, column=1) self.print_results(canvas_Frame= canvas_Frame,relevant_docs=relevant_docs)
def add_scrolling_figure(figure, frame): canvas = Canvas(frame) canvas.grid(row=0, column=0, sticky=tk.NSEW) x_scrollbar = Scrollbar(frame, orient=tk.HORIZONTAL) y_scrollbar = Scrollbar(frame) x_scrollbar.grid(row=1, column=0, sticky=tk.EW) y_scrollbar.grid(row=0, column=1, sticky=tk.NS) canvas.config(xscrollcommand=x_scrollbar.set) x_scrollbar.config(command=canvas.xview) canvas.config(yscrollcommand=y_scrollbar.set) y_scrollbar.config(command=canvas.yview) # plug in the figure fig_agg = FigureCanvasTkAgg(figure, canvas) mpl_canvas = fig_agg.get_tk_widget() mpl_canvas.grid(sticky=tk.NSEW) # and connect figure with scrolling region canvas.create_window(0, 0, window=mpl_canvas) canvas.config(scrollregion=canvas.bbox(tk.ALL))
def on_frame_configure(canvas: tkinter.Canvas) -> None: """ Resets the scrollbar region to encompass the inner frame :param canvas: """ # Note: bbox is a bounding box canvas.configure(scrollregion=canvas.bbox("all"))
class MsgWindow(Frame): def __init__(self, parent, **kwargs): self.parent = parent self.canvas = Canvas(self.parent, borderwidth=0, width=500, height=500) super().__init__(self.canvas, **kwargs) scroll_frame = Frame(self.parent, height=504, width=20) scroll_frame.pack(side="right", anchor="ne", fill="y") self._scrollbar = Scrollbar(scroll_frame, command=self.canvas.yview, orient="vertical") self._scrollbar.place(x=1, y=0, height=504) self.canvas.config(yscrollcommand=self._scrollbar.set) self.canvas.pack(fill="both") self.frame_id = self.canvas.create_window((2, 4), window=self, anchor="nw", tags="self") self.canvas.bind("<Configure>", self.onConfig) def onConfig(self, event=None): """ update scroll region, keep the bottom text in view """ self.canvas.update_idletasks() self.canvas.config(scrollregion=self.canvas.bbox("all")) if event is not None: self.canvas.itemconfig(self.frame_id, width=event.width) # if called and not event bound, no scrolling self.canvas.yview_moveto(1.0)
def createListFrame(self): # TODO rename self.list_frame = Frame(master=self) self.list_frame.pack(side='left', padx=0, pady=0, fill="both", expand=True) canvas = Canvas(self.list_frame, bg="gray") scroll_y = Scrollbar(self.list_frame, orient="vertical", command=canvas.yview) scroll_frame = Frame(canvas, bg="gray") void_label = Label(master=scroll_frame, text=" " * 255, bg="gray") void_label.pack(padx=2, pady=2, side="bottom") for e in self.windowList: self.createWindowFrame(scroll_frame, windowObject=e) canvas.create_window(0, 0, anchor='nw', window=scroll_frame) canvas.update_idletasks() scroll_frame.update() canvas.configure( scrollregion=canvas.bbox( 'all' ), # scrollregion=canvas.bbox('all') #TODO: #20 scrollregion yscrollcommand=scroll_y.set) canvas.pack(fill='both', expand=True, side='left') scroll_y.pack(fill='y', side='right')
def ayudaArchivo(raizMain): raizVetana = tkinter.Toplevel(raizMain) raizVetana.title("Definición de variables") raizVetana.geometry("760x600") scrollbar = Scrollbar(raizVetana) can = Canvas(raizVetana, yscrollcomman=scrollbar.set) scrollbar.config(command=can.yview) scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y) #Frame principal frameIniForm = Frame(can) can.pack(side="left", fill="both", expand=True) can.create_window(0,0,window=frameIniForm,anchor='nw') frameHead = Frame(frameIniForm) frameHead.grid(row=0 , column=0, padx=0,pady=15) #Frame de logos y titulo presentaFra = Frame(frameHead, highlightbackground="black", highlightcolor="black", highlightthickness=1, bd= 5) presentaFra.grid(row=0 , column=0, padx=10) tituloFra = Frame(presentaFra) tituloFra.grid(row=0, column=0) Label(tituloFra,text="Ingresar información del comportamineto de pago", font=("Times New Roman",18,"bold","italic"),width=49).grid(row=0, column=0, padx=5) #Frame de banderas frameAmar = Frame(frameHead, background="#FFFB00", width="715", height="5") frameAmar.grid(row=1, column=0) frameAmar = Frame(frameHead, background="#FFFFFF", width="715", height="5") frameAmar.grid(row=2, column=0) frameAmar = Frame(frameHead, background="#0D6AE1", width="715", height="5") frameAmar.grid(row=3, column=0) frameExpli = Frame(frameIniForm) frameExpli.grid(row=1, column=0) Label(frameExpli, text="Los siguientes pasos describen el proceso para ingresar información", font=("",10)).grid(row=0,column=0) Label(frameExpli, text="de una persona con respecto a su comportamiento de pago.", font=("",10)).grid(row=1,column=0) Label(frameExpli, text="Paso 1:", font=("",10,"bold")).grid(row=2,column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Con la ayuda de la herramiento Microsoft Excel creee un archivo en formato .csv (Separado por comas).", font=("",10)).grid(row=3, column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Paso 2:", font=("",10,"bold")).grid(row=4,column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Ingrese solo el valor del comportamineto de pago mes a mes de manera vertical en la columana 'A' del documento.", font=("",10)).grid(row=5, column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Paso 3:", font=("",10,"bold")).grid(row=6,column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Ingrese la información de manera ascendente conforme al tiempol ejemplo: Mes 1, Mes 2 ... Mes n.", font=("",10)).grid(row=7, column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Paso 4:", font=("",10,"bold")).grid(row=8,column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Guarde el documento asegurandoce que el formato a guardar es de tipo .csv.", font=("",10)).grid(row=9, column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Paso 5:", font=("",10,"bold")).grid(row=10,column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Selecione el boton 'Subir archivo' del formulario y busque el documento guardado anteriormente.", font=("",10)).grid(row=11, column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Paso 6:", font=("",10,"bold")).grid(row=12,column=0,sticky="w", padx=5, pady=5) Label(frameExpli, text="Selecione el boton 'Abrir'.", font=("",10)).grid(row=13, column=0,sticky="w", padx=5, pady=5) raizVetana.update() can.config(scrollregion=can.bbox("all"))
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
class ScrollFrame(Frame): # https://gist.github.com/mp035/9f2027c3ef9172264532fcd6262f3b01 by mp035 def __init__(self, parent): super().__init__(parent) # create a frame (self) self.canvas = Canvas(self, borderwidth=0, background='white') # place canvas on self self.viewPort = Frame(self.canvas, background='white') # place a frame on the canvas, this frame will hold the child widgets self.vsb = Scrollbar(self, orient="vertical", command=self.canvas.yview) # place a scrollbar on self self.vsb2 = Scrollbar(self, orient="horizontal", command=self.canvas.xview) self.canvas.configure(yscrollcommand=self.vsb.set) # attach scrollbar action to scroll of canvas self.canvas.configure(xscrollcommand=self.vsb2.set) self.vsb.pack(side="right", fill="y") # pack scrollbar to right of self self.vsb2.pack(side="bottom", fill="x") self.canvas.pack(side="left", fill="both", expand=True) # pack canvas to left of self and expand to fil self.canvas_window = self.canvas.create_window((4, 4), window=self.viewPort, anchor="nw", # add view port frame to canvas tags="self.viewPort") self.viewPort.bind("<Configure>", self.onFrameConfigure) # bind an event whenever the size of the viewPort frame changes. self.onFrameConfigure( None) # perform an initial stretch on render, otherwise the scroll region has a tiny border until the first resize def onFrameConfigure(self, event): '''Reset the scroll region to encompass the inner frame''' self.canvas.configure(scrollregion=self.canvas.bbox( "all")) # whenever the size of the frame changes, alter the scroll region respectively.
class ScrollableFrame(Frame): def __init__(self, parent, *args, **kwargs): super().__init__(parent, *args, **kwargs) self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) self.canvas = Canvas(self) self.inner_frame = Frame(self.canvas) self.vertical_scrollbar = Scrollbar(self, orient=VERTICAL, command=self.canvas.yview) self.horizontal_scrollbar = Scrollbar(self, orient=HORIZONTAL, command=self.canvas.xview) self.canvas.configure(yscrollcommand=self.vertical_scrollbar.set, xscrollcommand=self.horizontal_scrollbar.set) self.canvas.grid(row=0, column=0, sticky='news') self.vertical_scrollbar.grid(row=0, column=1, sticky='ns') self.horizontal_scrollbar.grid(row=1, column=0, stick='we') self.canvas.create_window((4, 4), window=self.inner_frame, anchor='nw') self.inner_frame.bind("<Configure>", self._on_frame_configure) # noinspection PyUnusedLocal def _on_frame_configure(self, event): self.canvas.configure(scrollregion=self.canvas.bbox("all"))
class ScrollFrame(Frame): def __init__(self, parent): super().__init__(parent) # create a frame (self) self.canvas = Canvas(self, borderwidth=0) #place canvas on self self.viewPort = Frame( self.canvas ) #place a frame on the canvas, this frame will hold the child widgets self.vsb = Scrollbar( self, orient="vertical", command=self.canvas.yview) #place a scrollbar on self self.canvas.configure(yscrollcommand=self.vsb.set ) #attach scrollbar action to scroll of canvas self.vsb.pack(side="right", fill="y") #pack scrollbar to right of self self.canvas.pack( side="left", fill="both", expand=True) #pack canvas to left of self and expand to fil self.canvas.create_window( (4, 4), window=self.viewPort, anchor="nw", #add view port frame to canvas tags="self.viewPort") self.viewPort.bind( "<Configure>", self.onFrameConfigure ) #bind an event whenever the size of the viewPort frame changes. def onFrameConfigure(self, event): '''Reset the scroll region to encompass the inner frame''' self.canvas.configure( scrollregion=self.canvas.bbox("all") ) #whenever the size of the frame changes, alter the scroll region respectively.
def create(self): self.pack(side=BOTTOM, fill=BOTH, expand=TRUE) canv = Canvas(self, bg="white", relief=SUNKEN) # canv.config(width=300, height=200) canv.config(scrollregion=(0, 0, 300, 1000)) canv.config(highlightthickness=0) #, scrollregion=canv.bbox(ALL)) sbar = Scrollbar(self) sbar.config(command=canv.yview) canv.config(yscrollcommand=sbar.set) sbar.pack(side=RIGHT, fill=Y) canv.pack(expand=YES, fill=BOTH, scrollregion=canv.bbox(ALL)) for i in range(10): canv.create_text(150, 50 + (i * 100), fill='beige') canv.bind('<Double-1>', self.onDoubleClick) # set event handler self.canvas = canv self.main_elements.canvas = self.canvas self.shape_setup.canvas = self.canvas self.shape_setup.set_binds() # self.canvas.bind('<4>', lambda event: self.canvas.xview('scroll', -1, 'units')) # self.canvas.bind('<5>', lambda event: self.canvas.xview('scroll', 1, 'units')) canv.bind('<MouseWheel>', self.rollWheel) # canv.bind('<Button-5>', self.rollWheel) self.parent.update()
class ScrolledFrame(Frame): def __init__(self, master=None, **kw): self.frame = Frame(master) self.vbar = Scrollbar(self.frame) self.vbar.pack(side='right', fill='y') self.canvas = Canvas(self.frame, yscrollcommand=self.vbar.set, borderwidth=0, relief='flat', highlightthickness=0, height=400, width=300) super().__init__(self.canvas, **kw) self.canvas.pack(side='left', fill='both') self.vbar.configure(command=self.canvas.yview) self.canvas.create_window((4, 4), window=self, anchor='nw') self.bind( "<Configure>", lambda e: self.canvas.config(scrollregion=self.canvas.bbox("all"))) frame_meths = vars(Frame).keys() methods = vars(Pack).keys() | vars(Grid).keys() | vars(Place).keys() methods = methods.difference(frame_meths) for m in methods: if m[0] != '_' and m != 'config' and m != 'configure': setattr(self, m, getattr(self.frame, m))
def addcheck(): global canvas canvas = Canvas(window) scroll_y = Scrollbar(window, orient="vertical", command=canvas.yview) global frame frame = Frame(canvas) for item in return_val: #Checkbutton(frame, text=item,variable=self.var,onvalue=(lambda x=item:x),offvalue="") Button(frame, text=item, command=(lambda x=item: BUTTON(x))).pack(side=TOP, fill=BOTH) canvas.create_window(0, 0, anchor='nw', window=frame) canvas.update_idletasks() canvas.configure(scrollregion=canvas.bbox('all'), yscrollcommand=scroll_y.set) canvas.pack(fill='both', expand=True, side='left') scroll_y.pack(fill='y', side='right') btngetauc.destroy() ent2.pack(side=TOP, fill=BOTH) ent2.insert(0, "Year") entlot.pack(side=TOP, fill=BOTH) entlot.insert(0, "LOT") btn.pack(side=TOP, fill=BOTH) lable.pack(side=TOP, fill=BOTH)
class VerticalScrollGrid(Frame): def __init__(self, root): Frame.__init__(self, root) self.canvas = Canvas(root, borderwidth=0) self.frame = Frame(self.canvas) self.vsb = Scrollbar(root, orient="vertical", command=self.canvas.yview) self.canvas.configure(yscrollcommand=self.vsb.set) self.vsb.grid(row=0, column=1, sticky='NS') self.vsb.configure(command=self.canvas.yview) self.canvas.grid(row=0, column=0, sticky='NSEW') self.canvas.create_window((4, 4), window=self.frame, anchor="nw", tags="self.frame") self.frame.bind("<Configure>", self.onFrameConfigure) self.frame.bind_all("<MouseWheel>", self.on_mousewheel) # self.frame.bind("<Button-4>", self.on_mousewheel_up) # self.frame.bind("<Button-5>", self.on_mousewheel_down) def onFrameConfigure(self, event): '''Reset the scroll region to encompass the inner frame''' self.canvas.configure(scrollregion=self.canvas.bbox("all")) # def on_mousewheel_down(self, event): self.canvas.yview_scroll(1, "units") # def on_mousewheel_up(self, event): self.canvas.yview_scroll(-1, "units") def on_mousewheel(self, event): self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units") def go_to_top(self, event=None): self.canvas.yview_moveto(0)
class VerticalScrollPack(Frame): def __init__(self, root): Frame.__init__(self, root) self.canvas = Canvas(root, borderwidth=0) self.frame = Frame(self.canvas) self.vsb = Scrollbar(root, orient="vertical", command=self.canvas.yview) self.canvas.configure(yscrollcommand=self.vsb.set) self.vsb.pack(side="right", fill="y") self.canvas.pack(side="left", fill="both", expand=True) self.canvas.create_window((4, 4), window=self.frame, anchor="nw", tags="self.frame") self.frame.bind("<Configure>", self.onFrameConfigure) self.frame.bind_all("<MouseWheel>", self.on_mousewheel) def onFrameConfigure(self, event): '''Reset the scroll region to encompass the inner frame''' self.canvas.configure(scrollregion=self.canvas.bbox("all")) def on_mousewheel(self, event): self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units") def go_to_top(self, event=None): self.canvas.yview_moveto(0)
class Scrollable(Frame): def __init__(self, master, outer_kwargs={}): Frame.__init__(self, master, **outer_kwargs) self.master = master self.canvas = Canvas(self, borderwidth=0, highlightthickness=0) self.frame = Frame(self.canvas, borderwidth=0) self.scrollbar = Scrollbar(self, orient=VERTICAL, command=self.canvas.yview) self.canvas.configure(yscrollcommand=self.scrollbar.set) self.scrollbar.pack(side=RIGHT, fill=Y, expand=False) self.canvas.pack(side=LEFT, fill=BOTH, expand=True) self.canvas.create_window((0, 0), window=self.frame, tag='self.frame') self.frame.bind( '<Configure>', lambda event: self.canvas.configure( scrollregion=self.canvas.bbox('all'))) self.canvas.bind( '<Configure>', lambda event: self.canvas.itemconfig('self.frame', width=event.width)) self.canvas.bind_all( '<MouseWheel>', lambda event: self.canvas.yview_scroll( -2 * event.delta // 120, 'units')) self.canvas.yview_moveto(0) def scroll_to(self, coord: float): self.canvas.yview_moveto(coord) def get_coord(self): return self.canvas.yview()
class Scrollable(ttk.Frame): """Luo tkinter-frame:n, joka sisältää scrollbarin. Koodi (pienin muutoksin) on saatu täältä: https://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-group-of-widgets-in-tkinter/3092341 """ def __init__(self, frame): scrollbar = ttk.Scrollbar(frame) scrollbar.pack(side=constants.RIGHT, fill=constants.Y, expand=False) self.canvas = Canvas(frame, yscrollcommand=scrollbar.set) self.canvas.pack(side=constants.LEFT, fill=constants.BOTH, expand=True) scrollbar.config(command=self.canvas.yview) self.canvas.bind('<Configure>', self.__fill_canvas) ttk.Frame.__init__(self, frame) self.windows_item = self.canvas.create_window(0, 0, window=self, anchor=constants.NW) def __fill_canvas(self, event): """Suurentaa windows item:n canvas-leveyteen""" canvas_width = event.width self.canvas.itemconfig(self.windows_item, width=canvas_width) def update(self): """Päivittää canvas-olion scrollregionin""" self.update_idletasks() self.canvas.config(scrollregion=self.canvas.bbox(self.windows_item))
def change_map(map: Map, canvas: Canvas, path: str, button_index: int, window): if path: map.change_map(path, window) width = canvas.winfo_width() height = canvas.winfo_height() if map.image_id: canvas.delete(map.image_id) map.image_id = canvas.create_image(width / 2, height / 2, anchor="center", image=map.image) print(canvas.bbox(map.image_id)) if map.last_line_id: canvas.tag_raise(map.last_line_id) for oval in map.path_delimitation: canvas.tag_raise(oval) if map.current_button: map.current_button.configure(bg="white") map.boutons_heures[button_index].configure(bg="gray") print(map.boutons_heures[button_index]) map.current_button = map.boutons_heures[button_index] map.current_button_index = button_index if map.etape == "tracé": map.show_instruction("Tracez la route voulue") elif map.etape == "courant": map.show_instruction( "Choisissez une heure de départ et tracez les courants du trajet" ) for foreground_item in map.foreground_items: canvas.tag_raise(foreground_item)
def addScrollingFigure(figure, frame): global canvas, mplCanvas, interior, interior_id, cwid # set up a canvas with scrollbars canvas = Canvas(frame) canvas.grid(row=1, column=1, sticky=Tkconstants.NSEW) xScrollbar = Scrollbar(frame, orient=Tkconstants.HORIZONTAL) yScrollbar = Scrollbar(frame) xScrollbar.grid(row=2, column=1, sticky=Tkconstants.EW) yScrollbar.grid(row=1, column=2, sticky=Tkconstants.NS) canvas.config(xscrollcommand=xScrollbar.set) xScrollbar.config(command=canvas.xview) canvas.config(yscrollcommand=yScrollbar.set) yScrollbar.config(command=canvas.yview) # plug in the figure figAgg = FigureCanvasTkAgg(figure, canvas) mplCanvas = figAgg.get_tk_widget() #mplCanvas.grid(sticky=Tkconstants.NSEW) # and connect figure with scrolling region cwid = canvas.create_window(0, 0, window=mplCanvas, anchor=Tkconstants.NW) printBboxes("Init") canvas.config(scrollregion=canvas.bbox(Tkconstants.ALL),width=200,height=200)
def update_accidents_table(): for widget in accidents_tab.winfo_children(): widget.destroy() headers = ['Cars', 'Lap', 'Session', '', ''] scrollbar = Scrollbar(accidents_tab, orient='vertical') scrollbar.grid(row=0, column=1, sticky='ns') canvas = Canvas(accidents_tab, yscrollcommand=scrollbar.set) canvas.create_image(0, 0, anchor='ne') canvas['scrollregion'] = (0, 0, 0, (len(listed_accidents) + 1) * 30) canvas['width'] = 565 canvas['height'] = 370 canvas.grid(row=0, column=0) scrollbar.config(command=canvas.yview) canvas.config(scrollregion=canvas.bbox("all")) table = Frame(canvas) for j, column in enumerate(headers): label = Label(table, text=column, width=15, height=2, font='Helvetica 8 bold') label.grid(row=0, column=j, sticky="nsew", padx=1, pady=1) table.grid_columnconfigure(j, weight=1) for i, row in enumerate(listed_accidents): for j, column in enumerate(row): label = Label(table, text=column, bg='Light Gray', height=1) label.grid(row=i + 1, column=j, sticky="nsew", padx=1, pady=1) table.grid_columnconfigure(j, weight=1) if j == 2: dismiss_button = Button( table, text="Racing Incident", bg='medium sea green', width=5, command=lambda row=i: dismiss_accident(row)) penalty_button = Button(table, text="Penalty", bg='indian red', width=5, command=lambda row=i: add_penalty(row)) dismiss_button.grid(row=i + 1, column=j + 1, padx=1, pady=1, sticky="nsew") penalty_button.grid(row=i + 1, column=j + 2, padx=1, pady=1, sticky="nsew") table.grid_columnconfigure(j + 1, weight=1) canvas.create_window((0, 0), window=table, anchor='nw')
def canvas_write(input_image, canvas_width=800, canvas_height=600): def get_char_dimensions(canvas, selected_font): oneChar = canvas.create_text(20, 20, text=" ", font=selected_font) bounds = canvas.bbox(oneChar) # returns a tuple like (x1, y1, x2, y2) char_width = bounds[2] - bounds[0] char_height = bounds[3] - bounds[1] print(f'Char width: {char_width} Char height: {char_height}') canvas.delete(oneChar) return (char_width, char_height) def resize_to_ratio(input_image, char_dimensions): width, height = input_image.size image_ratio = width / height adjusted_width, adjusted_height = width, height if width * char_dimensions[0] > canvas_width: adjusted_width = math.floor(canvas_width / char_dimensions[0]) adjusted_height = math.floor(adjusted_width / image_ratio) while adjusted_height * char_dimensions[1] > canvas_height: adjusted_width = adjusted_width - 1 adjusted_height = math.floor(adjusted_width / image_ratio) # Font has usually has higher height, so we increase width accordinly to avoid elongated images font_ratio = char_dimensions[0]/char_dimensions[1] adjusted_width = math.floor(adjusted_width / font_ratio) print(f'Width: {adjusted_width} Height: {adjusted_height}') resized_image = input_image.resize((adjusted_width, adjusted_height), Image.ANTIALIAS) return resized_image root = Tk() canvas = Canvas(root, width=canvas_width, height=canvas_height) #Smaller font gives more details font_size = 4 monospace_font = font.Font(family='Consolas', size=font_size) char_dimensions = get_char_dimensions(canvas, monospace_font) resized_input = resize_to_ratio(input_image, char_dimensions) resized_input = find_edges(resized_input) ascii_image = convert_to_ascii(resized_input) text_file = open("res.txt", "w") text_file.write(ascii_image) text_file.close() # Draw image to canvas drawn_text = canvas.create_text(canvas_width/2, canvas_height/2, text=ascii_image, font=monospace_font, anchor="c") text_bbox = canvas.bbox(drawn_text) rect_item = canvas.create_rectangle(text_bbox, outline="red", fill="white") canvas.tag_raise(drawn_text,rect_item) canvas.pack() root.mainloop()
class Window(Frame): def __init__(self, parent): super(Window, self).__init__(parent) self.parent = parent self.grid(row=0,column=0) # Entry, Start self.entry = Entry(self) self.entry.grid(column=0, row=0, padx=1,pady=0) self.entry.bind('<Return>',self.started) self.btn_start = Button(self, text='start',command=self.started) self.btn_start.grid(column=1, row=0, padx=2, pady=2) # Result self.results=Frame(self, background='blue') self.canvas=Canvas(self.results, background='green') self.labels_frame=Frame(self.canvas, background='pink') self.scrollbar = ttk.Scrollbar(self.results, orient='vertical', command=self.canvas.yview) self.heading=Label(self.labels_frame, text='Suchergebnisse:', anchor='w',width=50) self.results.grid(row=1,column=0,sticky='w',padx=2,pady=2, columnspan=2) self.canvas.grid(row=0,column=0, padx=2,pady=2)#todo delete padding #self.labels_frame.grid(row=0,column=0, padx=2,pady=2)#benötigt obwohl canvas.create_window? self.heading.grid(column=0,row=0,columnspan=3,sticky='wesn', padx=2, pady=2) self.canvas.create_window(0, 0, anchor='nw', window=self.labels_frame)#,height=250,width=300) def started(self, events=None): self.found_foods=[] for i in range(int(self.entry.get())): self.found_foods.append(i) self.create_labels() def create_labels(self): labels=[] for found_food in self.found_foods: name_label = Label(self.labels_frame, text=found_food, anchor='w') category_label = Label(self.labels_frame, text='--missing yet--', anchor='w') labels.append([name_label,category_label]) self.update_view(labels) def update_view(self,labels): self.del_old_labels() for row,labelrow in enumerate(labels): for col,element in enumerate(labelrow): element.grid(row=row+1, column=col, padx=1,pady=1, sticky='wsen') if len(self.found_foods)>10: #10 nur als Bsp 0self.canvas.update_idletasks() #no idea what this does self.canvas.config(yscrollcommand=self.scrollbar.set) self.canvas.config(height=250,width=300) self.canvas.configure(scrollregion=self.canvas.bbox('all')) self.scrollbar.grid(row=0,column=1, sticky='ns',padx=2,pady=2) else: self.scrollbar.grid_forget() def del_old_labels(self): for label in self.labels_frame.grid_slaves(): if int(label.grid_info()["row"]) > 0: label.grid_forget()
def calculer_decalage_latitude(event, map: Map, canvas: Canvas): x, y, _, _ = canvas.bbox(map.image_id) map.settings["decalage_pixels_latitude"] = event.y - y if map.last_line_id: canvas.delete(map.last_line_id) map.save_settings() map.etape = "tracé" map.show_instruction("Tracez la route voulue")
class ListDialog(object): def __init__ (self, master, items, message, accept_func): self.accept_func = accept_func self.top = Toplevel(master) self.top.transient(master) self.top.rowconfigure(0, weight=1) self.top.rowconfigure(1, weight=3) self.top.rowconfigure(2, weight=0) self.top.columnconfigure(0, weight=1) self.top.columnconfigure(1, weight=1) self.top.resizable(width=True, height=True) self.frame = Frame(self.top) self.frame.rowconfigure(0, weight=1) self.frame.rowconfigure(1, weight=0) self.frame.columnconfigure(0, weight=1) self.frame.columnconfigure(1, weight=0) self.frame.grid(row=0, column=0, sticky=(N, S, W, E), columnspan=2) self.canvas = Canvas(self.frame) self.canvas.create_text(0, 0, text=message, anchor=NW) self.canvas.grid(row=0, column=0, sticky=(N, W, S, E)) self.vscroll = Scrollbar(self.frame, command=self.canvas.yview) self.vscroll.grid(row=0, column=1, sticky=(N, S)) self.canvas['yscrollcommand'] = self.vscroll.set self.hscroll = Scrollbar(self.frame, command=self.canvas.xview, orient=HORIZONTAL) self.hscroll.grid(row=1, column=0, sticky=(W, E), columnspan=2) self.canvas['xscrollcommand'] = self.hscroll.set self.canvas['scrollregion'] = self.canvas.bbox('all') self.canvas.bind('<Button-4>', self.scroll) self.canvas.bind('<Button-5>', self.scroll) self.canvas.bind('<MouseWheel>', self.scroll) self.view = NameView(self.top, sorted(items)) self.view.widget.grid(row=1, column=0, columnspan=2, sticky=(N, W, E, S)) self.delbutton = Button(self.top, text='Ok', command=self.accept ) self.cancelbutton = Button(self.top, text='Cancel', command=self.cancel) self.delbutton.grid(row=2, column=0) self.cancelbutton.grid(row=2, column=1) self.view.widget.focus_set() def accept(self): self.accept_func(self.view.selection()) self.top.destroy() def cancel(self): self.result = None self.top.destroy() def scroll(self, event): if event.num == 4 or event.delta > 0: self.canvas.yview(SCROLL, -1, UNITS) elif event.num == 5 or event.delta < 0: self.canvas.yview(SCROLL, 1, UNITS)
def view_admin(): try: admin_list = [session.query(Admin).filter_by(username="******").first()] admin_list += session.query(Admin).filter( Admin.username != "admin").all() except: messagebox.showerror("Error", "Couldn't Fetch The Admins' Table From The DB") session.rollback() return subwindow = Toplevel(window) subwindow.title("Admins") subwindow.geometry("450x600+400+200") canvas = Canvas(subwindow) scrollable_frame = Frame(canvas) scrollable_frame.bind( "<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all"))) canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") scrollbary = Scrollbar(subwindow, orient="vertical", command=canvas.yview) scrollbarx = Scrollbar(subwindow, orient="horizontal", command=canvas.xview) canvas.configure(xscrollcommand=scrollbarx.set) canvas.configure(yscrollcommand=scrollbary.set) scrollbary.pack(side="right", fill="y") scrollbarx.pack(side="bottom", fill="x") canvas.pack(side="left", fill="both", expand=True) ttk.Label(scrollable_frame, text="index").grid(row=0, column=0, ipadx=5, ipady=1) ttk.Label(scrollable_frame, text="UserName").grid(row=0, column=1, ipadx=5, ipady=1) for i in range(len(admin_list)): ttk.Label(scrollable_frame, text=i + 1).grid(row=i + 1, column=0, ipadx=5, ipady=1) ttk.Label( scrollable_frame, text=admin_list[i].username, ).grid(row=i + 1, column=1, ipadx=5, ipady=1) ttk.Button( scrollable_frame, text="Remove", command=lambda username=admin_list[i].username: remove_admin( username), ).grid(row=i + 1, column=7, ipadx=1, ipady=1)
def upload_film_data(): current_folder = os.getcwd() os.chdir(os.path.dirname(sys.argv[0])) img = Image.open(Globals.map_dose_film_dataset.get()) if(not (img.width == 1016 or img.width == 576)): messagebox.showerror("Error", "Dpi in image has to be 127 or 72") return Globals.map_dose_isocenter_map_x_coord_scaled = [] Globals.map_dose_isocenter_map_x_coord_unscaled = [] Globals.map_dose_isocenter_map_y_coord_scaled = [] Globals.map_dose_isocenter_map_y_coord_unscaled = [] mark_isocenter_window = tk.Toplevel(Globals.tab3) mark_isocenter_window.grab_set() frame = Frame(mark_isocenter_window, bd=2, relief=SUNKEN) frame.grid_rowconfigure(0, weight=1) frame.grid_columnconfigure(0, weight=1) canvas = Canvas(frame, bd=0) canvas.grid(row=0, column=0, sticky=N+S+E+W) scale_horizontal = img.width/408 scale_vertical = img.height/508 img = img.resize((408,508)) img = ImageTk.PhotoImage(image=img) os.chdir(current_folder) canvas.image = img w = 10 + img.width() h = 10 + img.height() mark_isocenter_window.geometry("%dx%d+0+0" % (w, h)) canvas.create_image(0,0,image=img,anchor="nw") canvas.config(scrollregion=canvas.bbox(ALL), cursor='sb_up_arrow') #x_coor = [] #y_coor = [] def findCoords(event): Globals.map_dose_isocenter_map_x_coord_scaled.append(event.x*scale_vertical) Globals.map_dose_isocenter_map_y_coord_scaled.append(event.y*scale_horizontal) Globals.map_dose_isocenter_map_x_coord_unscaled.append(event.x) Globals.map_dose_isocenter_map_y_coord_unscaled.append(event.y) canvas.create_oval(event.x-2, event.y-2, event.x+2, event.y+2, fill='red') if (len(Globals.map_dose_isocenter_map_x_coord_scaled)==1): canvas.config(cursor='sb_down_arrow') elif(len(Globals.map_dose_isocenter_map_x_coord_scaled)==2): canvas.config(cursor='sb_right_arrow') elif(len(Globals.map_dose_isocenter_map_x_coord_scaled)==3): canvas.config(cursor='sb_left_arrow') else: #mark_isocenter_window.destroy() draw_image_with_marks(img, scale_horizontal, scale_vertical, mark_isocenter_window, frame) canvas.bind("<Button 1>",findCoords) frame.pack(fill='both', expand=1)
class GUI(): """ Method gets a Tk instance (master) and a model instance implemented with nengo. It then creates a GUI with the polts that where specified in create_plot(...). """ def __init__(self, master, model): self.f = 0 master.rowconfigure(0, weight=1) master.columnconfigure(0, weight=1) self.frame = tk.Frame(master) self.frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) self.frame.grid(sticky=NSEW) self.frame.rowconfigure(0, weight=1) self.frame.columnconfigure(0, weight=1) self.scroll_canvas = Canvas(self.frame) self.scroll_canvas.grid(row=0, column=0, sticky=NSEW) xScrollbar = Scrollbar(self.frame, orient=HORIZONTAL) yScrollbar = Scrollbar(self.frame) xScrollbar.grid(row=1, column=0, sticky=EW) yScrollbar.grid(row=0, column=1, sticky=NS) self.scroll_canvas.config(xscrollcommand=xScrollbar.set) xScrollbar.config(command=self.scroll_canvas.xview) self.scroll_canvas.config(yscrollcommand=yScrollbar.set) yScrollbar.config(command=self.scroll_canvas.yview) self.create_plot(model) self.figure_canvas = FigureCanvasTkAgg(self.f, master=self.scroll_canvas) self.canvas = self.figure_canvas.get_tk_widget() self.canvas.pack(side=tk.TOP, fill=tk.BOTH, padx=5, pady=5, expand=1) self.scroll_canvas.create_window(0, 0, window=self.canvas) self.scroll_canvas.config(scrollregion=self.scroll_canvas.bbox(ALL)) self.figure_canvas.show() self.toolbar = NavigationToolbar2TkAgg(self.figure_canvas, self.scroll_canvas) self.toolbar.pack() self.toolbar.update() """ Adds the specified plots to the figure displayed in the GUI. It gets a model instance implemented with nengo """ def create_plot(self, model): self.f = Figure(figsize=(16, 9), dpi=80) """ Example plot which plots the integrators back connection, its input, its real value and the real robot goal angle """ self.ax00 = self.f.add_axes((.2, .2, .6, .6), axisbg=(.75, .75, .75), frameon=True) self.ax00.plot(model.sim.trange(), model.sim.data[model.integrator_probe], label = 'Integrator') self.ax00.plot(model.sim.trange(), model.sim.data[model.integrator_connection_probe], label = 'Con') self.ax00.plot(model.sim.trange(), model.sim.data[model.integrator_self_connection_probe], label = 'Self Con') self.ax00.plot(model.sim.trange(), model.sim.data[model.robot_goal_neuron_probe][:, 2], label = 'Real') self.ax00.legend()
class RadiobuttonEntry(ttk.Frame): """State entry for the entire conflict. A set of RadioButtonSeries.""" def __init__(self, master, conflict): """State entry widget for the entire conflict.""" ttk.Frame.__init__(self, master) self.conflict = conflict self.rbeCanvas = Canvas(self) self.rdBtnFrame = ttk.Frame(self.rbeCanvas) self.scrollY = ttk.Scrollbar(self, orient=VERTICAL, command=self.rbeCanvas.yview) self.rbeCanvas.grid(column=0, row=0, columnspan=2, sticky=NSEW) self.scrollY.grid(column=2, row=0, sticky=NSEW) self.rbeCanvas.configure(yscrollcommand=self.scrollY.set) self.canvWindow = self.rbeCanvas.create_window((0, 0), window=self.rdBtnFrame, anchor='nw') self.rowconfigure(0, weight=1) self.entryText = StringVar(value='') vcmd = self.register(self.onValidate) self.entryBx = ttk.Entry(self, textvariable=self.entryText, validate="key", validatecommand=(vcmd, '%S', '%P')) self.entryBx.grid(column=0, row=1, sticky=NSEW) self.entryBx.bind('<Return>', self.generateAdd) self.warnText = StringVar(value='') self.warnLab = ttk.Label(self, textvariable=self.warnText, width=18) self.warnLab.grid(column=1, row=1, sticky=NSEW) self.codeText = StringVar(value='') vcmd2 = self.register(self.onValidate2) self.codeBx = ttk.Entry(self, textvariable=self.codeText, validate="key", validatecommand=(vcmd2, '%S', '%P')) self.codeBx.grid(column=0, row=2, sticky=NSEW) self.codeBx.bind('<Return>', self.generateAdd) self.warnText2 = StringVar(value='') self.warnLab2 = ttk.Label(self, textvariable=self.warnText2) self.warnLab2.grid(column=1, row=2, sticky=NSEW) self.addBtn = ttk.Button(self, text='Add as Prefered State', command=self.generateAdd) self.stageBtn = ttk.Button(self, text='Add to Staging', command=self.generateStage) self.addBtn.grid(column=0, row=4, columnspan=2, sticky=NSEW) self.stageBtn.grid(column=0, row=5, columnspan=2, sticky=NSEW) self.isDisabled = False self.columnconfigure(0, weight=1) self.reloadOpts() self.regexValidChars = re.compile(r'^[-\d, fi]*$') self.regexStatesIf = re.compile(r'^ *(-)?(\d+) *iff? *(-)?(\d+) *$') self.regexStates = re.compile(r' *(-)?(\d+) *') self.hasValidIf = False def resize(self, event=None): """Adjust the canvas widget if the window is resized.""" self.rbeCanvas.configure(scrollregion=self.rbeCanvas.bbox("all")) self.rbeCanvas["width"] = self.rbeCanvas.bbox("all")[2] def generateAdd(self, event=None): """Generate event if a preference is added.""" self.event_generate('<<AddPref>>') def generateStage(self, event=None): """Generate event if a preference is staged.""" self.event_generate('<<StagePref>>') def reloadOpts(self): """Reload options for all decision makers.""" self.rbeCanvas.delete(self.canvWindow) self.rdBtnFrame.destroy() self.rdBtnFrame = ttk.Frame(self.rbeCanvas) self.canvWindow = self.rbeCanvas.create_window((0, 0), window=self.rdBtnFrame, anchor='nw') self.rdBtnFrame.bind('<<RdBtnChg>>', self.rdBtnChgCmd) self.rdBtnFrame.bind("<Configure>", self.resize) self.rdBtnSrs = [] self.stringVarList = [] for x, dm in enumerate(self.conflict.decisionMakers): a = RadiobuttonSeries(self.rdBtnFrame, dm) self.rdBtnSrs.append(a) a.setOpts(dm.options) a.grid(column=0, row=int(x), sticky=NSEW) self.stringVarList += a.stringVarList self.rdBtnChgCmd() if self.isDisabled: self.disable() def disable(self, event=None): """Disable the widget and all children.""" self.isDisabled = True self.entryBx['state'] = 'disabled' self.codeBx['state'] = 'disabled' self.addBtn['state'] = 'disabled' self.stageBtn['state'] = 'disabled' for srs in self.rdBtnSrs: srs.disable() def enable(self, event=None): """Enable the widget and all children.""" self.isDisabled = False self.entryBx['state'] = 'normal' self.codeBx['state'] = 'normal' self.addBtn['state'] = 'normal' self.stageBtn['state'] = 'normal' for srs in self.rdBtnSrs: srs.enable() def setStates(self, dashOne): """Set the states shown on the radiobuttons.""" if dashOne == 'clear': for var in self.stringVarList: var.set('-') self.entryText.set('-' * len(self.stringVarList)) return if len(dashOne) != len(self.stringVarList): raise Exception("string is wrong length: {}".format(dashOne)) for x, y in enumerate(dashOne): self.stringVarList[x].set(y) self.entryText.set(dashOne) self.hasValidIf = False def getStates(self): """Get the states shown on the radiobuttons in YN- format.""" if self.hasValidIf: return self.ifCond states = [] for srs in self.rdBtnSrs: states.extend(srs.getStates()) return states def onValidate(self, chg, res): """Validation of entrybox state description string.""" if chg in ['Y', 'N', 'y', 'n', '-']: if len(res) < len(self.stringVarList): self.warnText.set('Entry too short') return True if len(res) == len(self.stringVarList): self.setStates(res.upper()) self.warnText.set('') return True return False def onValidate2(self, chg, res): """Validate condition input string.""" if self.regexValidChars.match(res): if "if" in res: m = self.regexStatesIf.match(res) if m: self.warnText2.set('') self.handleIf(res, m.groups()) else: self.warnText2.set('Invalid') else: states = res.split(',') sts2 = [] for st in states: m = self.regexStates.match(st) if m: sts2.append(m.groups()) else: self.warnText2.set('Invalid') return True self.warnText2.set('') setTo = '-' * len(self.stringVarList) for neg, st in sts2: if int(st) > len(self.stringVarList): self.warnText2.set(st + ' is too large') return True if setTo[int(st) - 1] != "-": self.warnText2.set("Too many " + st + "s") return True if neg: setTo = setTo[:(int(st) - 1)] + 'N' + setTo[int(st):] else: setTo = setTo[:(int(st) - 1)] + 'Y' + setTo[int(st):] self.setStates(setTo) return True self.warnText2.set('Invalid') return False def handleIf(self, string, states): """Q if P (equivalent to 'If p, then q').""" if int(states[1]) > len(self.stringVarList): self.warnText2.set(states[1] + ' is too large') return True elif int(states[3]) > len(self.stringVarList): self.warnText2.set(states[3] + ' is too large') return True elif states[1] == states[3]: self.warnText2.set("duplicate") return True q = [self.conflict.options[int(states[1]) - 1], "N" if states[0] else "Y"] nq = [self.conflict.options[int(states[1]) - 1], "Y" if states[0] else "N"] # not q p = [self.conflict.options[int(states[3]) - 1], "N" if states[2] else "Y"] np = [self.conflict.options[int(states[3]) - 1], "Y" if states[2] else "N"] # not p newCondition = None if "iff" in string: newCondition = self.conflict.newCompoundCondition([[p, q], [np, nq]]) else: newCondition = self.conflict.newCompoundCondition([[p, q], [np, q], [np, nq]]) self.setStates(' ' * len(self.stringVarList)) self.hasValidIf = True self.ifCond = newCondition def rdBtnChgCmd(self, *args): """Update display on input through radiobuttons.""" val = ''.join([x.get() for x in self.stringVarList]) self.entryText.set(val) self.warnText.set('') val = [[i + 1, x.get()] for i, x in enumerate(self.stringVarList) if (x.get() != "-")] outVar = [] for i, x in val: if x == "N": outVar.append("-" + str(i)) else: outVar.append(str(i)) self.codeText.set(", ".join(outVar)) self.warnText2.set('')
class RadiobuttonEntry(ttk.Frame): """State entry for all DMs, and controls for adding the infeasibles. Uses a set of RadioButtonSeries elements. """ def __init__(self, master, conflict): """Initialize the widget.""" ttk.Frame.__init__(self, master) self.conflict = conflict self.dmLookup = {dm.name: dm for dm in self.conflict.decisionMakers} dmNames = tuple(self.dmLookup.keys()) self.activeDMname = StringVar(value=dmNames[0]) self.activeDM = self.dmLookup[dmNames[0]] dmSelLabel = ttk.Label(self, text="Decision Maker") dmSelLabel.grid(column=0, row=0) self.dmSelector = ttk.Combobox(self, textvariable=self.activeDMname, values=dmNames, state='readonly') self.dmSelector.grid(column=1, row=0, sticky=NSEW) self.dmSelector.bind('<<ComboboxSelected>>', self.dmSel) self.rbeCanvas = Canvas(self) self.rdBtnFrame = ttk.Frame(self.rbeCanvas) self.scrollY = ttk.Scrollbar(self, orient=VERTICAL, command=self.rbeCanvas.yview) self.rbeCanvas.grid(column=0, row=1, columnspan=2, sticky=NSEW) self.scrollY.grid(column=2, row=1, sticky=NSEW) self.rbeCanvas.configure(yscrollcommand=self.scrollY.set) self.canvWindow = self.rbeCanvas.create_window( (0, 0), window=self.rdBtnFrame, anchor='nw') self.rowconfigure(1, weight=1) self.entryText = StringVar(value='') vcmd = self.register(self.onValidate) self.entryBx = ttk.Entry(self, textvariable=self.entryText, validate="key", validatecommand=(vcmd, '%S', '%P')) self.entryBx.grid(column=0, row=2, columnspan=2, sticky=NSEW) self.entryBx.bind('<Return>', self.generateAdd) self.warnText = StringVar(value='') self.addBtn = ttk.Button(self, text='Remove as Misperceived Condition', command=self.generateAdd) self.mutExBtn = ttk.Button(self, text='Perceived as Mutually Exclusive', command=self.generateMutEx) self.warnLab = ttk.Label(self, textvariable=self.warnText) self.warnLab.grid(column=0, row=3, sticky=NSEW) self.addBtn.grid(column=0, row=4, columnspan=2, sticky=NSEW) self.mutExBtn.grid(column=0, row=5, columnspan=2, sticky=NSEW) self.reloadOpts() def resize(self, event=None): """Resize the scroll region of the main canvas element.""" self.rbeCanvas.configure(scrollregion=self.rbeCanvas.bbox("all")) self.rbeCanvas["width"] = self.rbeCanvas.bbox("all")[2] def generateAdd(self, *args): """Prompt response to addition of an infeasible state.""" self.event_generate('<<addMisperceived>>') def generateMutEx(self, *args): """Prompt response to addition of a mutually exclusive set.""" self.event_generate('<<AddMutEx>>') def reloadOpts(self): """Reload all options for all DMs.""" self.rbeCanvas.delete(self.canvWindow) self.rdBtnFrame.destroy() self.rdBtnFrame = ttk.Frame(self.rbeCanvas) self.canvWindow = self.rbeCanvas.create_window( (0, 0), window=self.rdBtnFrame, anchor='nw') self.rdBtnFrame.bind('<<RdBtnChg>>', self.rdBtnChgCmd) self.rdBtnFrame.bind("<Configure>", self.resize) self.rdBtnSrs = [] self.stringVarList = [] for x, dm in enumerate(self.conflict.decisionMakers): a = RadiobuttonSeries(self.rdBtnFrame, dm) self.rdBtnSrs.append(a) a.setOpts(dm.options) a.grid(column=0, row=int(x), sticky=NSEW) self.stringVarList += a.stringVarList self.rdBtnChgCmd() def setStates(self, dashOne): """Change the condition selected on the radio buttons.""" if len(dashOne) != len(self.stringVarList): raise Exception('string length does not match number ' 'of options: {}'.format(dashOne)) for x, y in enumerate(dashOne): self.stringVarList[x].set(y) self.entryText.set(dashOne) def getStates(self): """Get the condition selected on the radio buttons.""" states = [] for srs in self.rdBtnSrs: states.extend(srs.getStates()) return states def onValidate(self, chg, res): """Validate manually entered condition characters and length.""" if chg in ['Y', 'N', 'y', 'n', '-']: if len(res) < len(self.stringVarList): self.warnText.set('Entry too short') return True if len(res) == len(self.stringVarList): self.setStates(res.upper()) self.warnText.set('') return True return False def rdBtnChgCmd(self, *args): """Set the entry box value to match the radiobuttons.""" val = ''.join([x.get() for x in self.stringVarList]) self.entryText.set(val) def dmSel(self, *args): """Prompt response to a different DM being selected.""" dmName = self.activeDMname.get() self.activeDM = self.dmLookup[dmName] self.event_generate('<<ChangeDM>>')
class GraphView(View): WIN_PADDING_Y = 16 POINT_MARGIN = 2 def __init__(self, params): super(GraphView, self).__init__(params) self._ids = params["ids"] if "ids" in params else "" self._ids = [int(i) for i in self._ids.split(' ')] self._labels = params["labels"] if "labels" in params else "" self._labels = [l for l in self._labels.split(' ')] self._colors = [c for c in params["colors"].split(' ')] if "colors" in \ params else None if not self._colors: self._colors = self._get_auto_colors(len(self._ids)) if not len(self._ids) == len(self._labels) == len(self._colors): raise RuntimeError("ids, labels and colors must share the same size") self._min = float(params["min"]) if "min" in params else -1000 self._max = float(params["max"]) if "max" in params else 1000 if self._min > self._max: self._min, self._max = self._max, self._min self._diff = abs(self._max - self._min) self._data = [_GraphData() for _ in range(len(self._ids))] self._data_view = [_GraphDataView(self._colors[i]) for i in range( len(self._ids))] self._graph_x = 0 self._tk = Tk() self._tk.title("Graph view %s" % str(self._labels)) self._canvas = Canvas(self._tk, width = 640, height = 480) self._canvas.pack(fill = tkinter.BOTH, expand = 1) self._tk.update() self._win_size = self._tk.winfo_width(), self._tk.winfo_height() # graph_rect only works as providing the area but not coord self._graph_rect = self._win_size self._tk.minsize(320, 240) self._tk.protocol("WM_DELETE_WINDOW", self.on_press_close) self._tk.bind("<Configure>", self.on_config) self._canvas.config(background = config.COL_GREY_900) self._full_redraw() self._file = open("graph_%s_%i.csv" % (str(self._labels), int(time.time() * 1000)), "w") self._file.write(','.join(self._labels) + '\n') self._tk.after(16, self._refresh) def run(self): super(GraphView, self).run() self._tk.mainloop() def on_new_input(self): try: hex_data = binascii.unhexlify(self.get_input()) except TypeError as e: logging.debug(str(e)) return count = int(len(hex_data) / GraphView._MSG_SIZE) for i in (x * 6 for x in range(count)): if hex_data[i] in self._ids: value_type = hex_data[i + 1] value_bytes = hex_data[i + 2:i + 6] if value_type == GraphView._MSG_TYPE_INT: value = int.from_bytes(value_bytes, byteorder = "big", signed = True) elif value_type == GraphView._MSG_TYPE_FLOAT: value = struct.unpack(">f", value_bytes)[0] else: logging.error("Unknown type: " + str(value_type)) continue self._tk.after_idle(self._put_value, hex_data[i], value) def on_dismiss(self): self._tk.after_idle(self.on_press_close) def on_press_close(self): self._tk.destroy() self.join_io_thread() def on_config(self, event): win_size = (event.width, event.height) if win_size != self._win_size: self._win_size = win_size self._full_redraw() def is_test_input(self): return False def gen_test_input(self): while True: for i in range(int(self._min), int(self._max)): sleep(0.1) yield "0000%08x" % (random.randrange(-100, 100) & 0xFFFFFFFF) \ + "0100%08x\n" % (i & 0xFFFFFFFF) def _put_value(self, id, value): pos = self._ids.index(id) if self._data[pos].size() == 0: for d in self._data: d.append() elif self._data[pos].get_value(-1) is not None: for d in self._data: d.append() if self._data[pos].size() > 1: self._write_prev_records() self._data[pos].put_value(value) graph_w = self._win_size[0] - self._graph_x; count = int(graph_w / GraphView.POINT_MARGIN + 1) for d in self._data: d.shrink(count) def _write_prev_records(self): write = ','.join((str(d.get_value(-2)) for d in self._data)) + '\n' self._file.write(write) self._file.flush() def _refresh(self): self._redraw_graph() self._tk.after(16, self._refresh) def _full_redraw(self): self._canvas.delete("all") bounding_box = self._redraw_data_labels() self._graph_rect = 0, 0, self._win_size[0], bounding_box[1] self._redraw_y_labels() for v in self._data_view: v.clear_lines(); self._redraw_graph() def _redraw_data_labels(self): top = self._win_size[1] x = GraphView._DATA_LABEL_PADDING for l, c in zip(self._labels, self._colors): t = self._canvas.create_text(x, self._win_size[1] - GraphView._DATA_LABEL_PADDING, anchor = tkinter.SW, fill = c, font = config.FONT, text = '-' + l) bounding_box = self._canvas.bbox(t) top = min(top, bounding_box[1]) x = bounding_box[2] + GraphView._DATA_LABEL_PADDING return 0, top, x, self._win_size[1] def _redraw_y_labels(self): height = self._graph_rect[3] - self._graph_rect[1] \ - GraphView.WIN_PADDING_Y * 2 count = max(int(height / 50), 2) labels = [] max_label_size = 0 longest_label = None longest_label_i = None for i in range(count): ratio = i / (count - 1) value = self._max - self._diff * ratio value_label = ("%.2f" % value) if value % 1 != 0 else str(value) labels.append(value_label) if len(value_label) > max_label_size: max_label_size = len(value_label) longest_label = value_label longest_label_i = i label_id = self._canvas.create_text(0, height * (longest_label_i \ / (count - 1)) + GraphView.WIN_PADDING_Y, anchor = tkinter.W, fill = config.COL_GREY_100, font = config.FONT, text = longest_label) bounding_box = self._canvas.bbox(label_id) width = bounding_box[2] - bounding_box[0] self._graph_x = width + GraphView.POINT_MARGIN for i in range(count): ratio = i / (count - 1) y = height * ratio + GraphView.WIN_PADDING_Y if i != longest_label_i: self._canvas.create_text(width, y, anchor = tkinter.E, fill = config.COL_GREY_100, font = config.FONT, text = labels[i]) self._canvas.create_line(self._graph_x, y, self._graph_rect[2], y, fill = config.COL_GREY_700) def _redraw_graph(self): graph_h = self._graph_rect[3] - GraphView.WIN_PADDING_Y * 2 for d, v in zip(self._data, self._data_view): v.populate(d.get_values(), self._max, self._diff, self._graph_x, graph_h) v.draw(self._canvas) def _get_auto_colors(self, size) -> list: product = GraphView._COLOR_REPO[:min(size, len(GraphView._COLOR_REPO))] while len(product) < size: product.append("#%06x" % random.randrange(0xFFFFFF)) return product _LABEL_SIZE = 10 _DATA_LABEL_PADDING = 8 _MSG_SIZE = 6 _MSG_TYPE_INT = 0 _MSG_TYPE_FLOAT = 1 _COLOR_REPO = ["#F44336", "#4CAF50", "#2196F3", "#FFEB3B", "#607D8B", "#9C27B0", "#009688", "#673AB7", "#795548"]
class mainGUI(Frame, bootloader, GuiController): """ Contains the main view for the application """ def __init__(self): """ Create the initial application GUI environment (tool bars, and other static elements) """ Frame.__init__(self, self.root) self.thread_entry_field = '' # Hold both search string, and drives autoRefresh logic self.menuBar = Menu() self.fileMenu = Menu(self.menuBar, tearoff=0) self.menuBar.add_cascade(label="File", menu=self.fileMenu, underline=1) self.fileMenu.add_command(label="Quit", command=self.root.destroy, underline=1) self.optionsMenu = Menu(self.menuBar, tearoff=0) self.menuBar.add_cascade(label="Options", menu=self.optionsMenu) self.optionsMenu.add_command(label="Settings", command=self.editSettings, underline=1) self.helpMenu = Menu(self.menuBar, tearoff=0) self.menuBar.add_cascade(label="Help", menu=self.helpMenu) self.helpMenu.add_command(label="Help", command=self.program_help, underline=1) self.helpMenu.add_command(label="About", command=self.program_about, underline=1) self.master.config(menu=self.menuBar) self.topFrame = Frame() self.thread_entry_box = Entry(self.topFrame) self.thread_entry_box.insert(0, self.DEFAULT_THREAD_TEXT) self.thread_entry_box.bind('<Return>', lambda event: self.add_thread_GUI()) # Bind needs to send the event to the handler self.thread_entry_box.pack(side='left', fill='x', expand='True', padx=5) self.add_thread_btn = Button(self.topFrame) self.add_thread_btn['text'] = 'Add New Thread' self.add_thread_btn['command'] = lambda: self.add_thread_GUI() self.add_thread_btn.pack(side='left', padx=0) self.topFrame.pack(fill='x') self.create_thread_frame() def create_thread_frame(self): """ Sets up the main thread frame (where the magic happens) """ # Sets up frame self.thread_list_canvas = Canvas(self.root, borderwidth=0) self.thread_list_frame = Frame(self.thread_list_canvas) # Creates scroll bar self.vsb = Scrollbar(self.root, orient="vertical", command=self.thread_list_canvas.yview) self.thread_list_canvas.configure(yscrollcommand=self.vsb.set) self.vsb.pack(side="right", fill="y") self.hsb = Scrollbar(self.root, orient="horizontal", command=self.thread_list_canvas.xview) self.thread_list_canvas.configure(xscrollcommand=self.hsb.set) self.hsb.pack(side="bottom", fill="x") # Packs frame self.thread_list_canvas.pack(side="left", fill="both", expand=True) self.thread_list_canvas.create_window((4, 4), window=self.thread_list_frame, anchor="nw", tags="self.frame") self.thread_list_frame.bind("<Configure>", self.OnFrameConfigure) self.create_thread_list_box() def OnFrameConfigure(self, event): """Reset the scroll region to encompass the inner frame""" self.thread_list_canvas.configure(scrollregion=self.thread_list_canvas.bbox("all")) # noinspection PyAttributeOutsideInit def create_thread_list_box(self): """ Creates the message list box for the create method """ def hover_on(widget): widget['fg'] = 'dark blue' # widget['underline'] = True def hover_off(widget): widget['fg'] = 'black' # widget['underline'] = False for individual_thread in self.MESSAGE_THREADS: # Fetch Message List from model if individual_thread.is_valid_thread(): self.bg_color = 'green' else: self.bg_color = 'red' self.individual_thread_frame = Frame(self.thread_list_frame, bg=self.bg_color) # Create frame for each thread rowToInsertAt = self.MESSAGE_THREADS.index(individual_thread) self.text_color = 'black' self.threadText = Label(self.individual_thread_frame, bg=self.bg_color, fg=self.text_color) self.threadText['text'] = "[ Thread #: " + individual_thread.threadId + " ]" self.threadText.bind("<Enter>", lambda event, text=self.threadText: hover_on(text)) self.threadText.bind("<Leave>", lambda event, text=self.threadText: hover_off(text)) self.threadText.bind("<Button-1>", lambda event, thread_in=individual_thread: self.open_in_web_browser(thread_in)) self.threadText.grid(column=0, row=0, sticky='w', padx=0) self.image_count_text = Label(self.individual_thread_frame, bg=self.bg_color) num_of_images = individual_thread.get_number_of_images() if 0 < int(num_of_images) < 10: # Format padding num_of_images = '00' + num_of_images if 10 < int(num_of_images) < 100: # Format padding num_of_images = '0' + num_of_images self.image_count_text['text'] = " [ # Images: " + num_of_images + " ]" self.image_count_text.bind("<Enter>", lambda event, text=self.image_count_text: hover_on(text)) self.image_count_text.bind("<Leave>", lambda event, text=self.image_count_text: hover_off(text)) self.image_count_text.bind("<Button-1>", lambda event, thread_in=individual_thread: self.open_in_file_browser(thread_in)) self.image_count_text.grid(column=1, row=0, sticky='e', padx=0) self.deleteButton = Button(self.individual_thread_frame) self.deleteButton['text'] = 'Delete' self.deleteButton['command'] = lambda thread_in=individual_thread: self.delete_thread_GUI(thread_in) self.deleteButton.grid(column=2, row=0, sticky='e', padx=0) self.individual_thread_frame.grid(row=rowToInsertAt, sticky='w', pady=2) @staticmethod def open_in_file_browser(individual_thread): logging.debug(os.getcwd() + os.sep + individual_thread.threadId) if os.name == "nt": subprocess.Popen('explorer "' + os.getcwd() + os.sep + individual_thread.threadId + '"') @staticmethod def open_in_web_browser(individual_thread): webbrowser.open( url="http://boards.4chan.org/" + individual_thread.board + "/thread/" + individual_thread.threadId, new=2) def add_thread_GUI(self): entry_box_text = str(self.thread_entry_box.get()) if entry_box_text not in self.MESSAGE_THREADS and entry_box_text != self.DEFAULT_THREAD_TEXT \ and entry_box_text.isnumeric(): try: self.add_thread(entry_box_text.strip(' ')) except ThreadNotFound: messagebox.showwarning(message="Thread Not Found") else: messagebox.showwarning(message="Please enter a valid new thread ID") self.thread_entry_box.select_range(start=0, end=99) # Selects the contents so the user can just type the next message self.refresh_GUI() def delete_thread_GUI(self, thread_in): self.delete_thread(thread_in) self.refresh_GUI() def refresh_GUI(self): """ Refreshes the message list AND GUI window (used by auto refresh)""" self.refresh_thread_list() self.refresh_GUI_Window() def refresh_GUI_Window(self): """ Refreshes just the GUI window""" self.thread_list_canvas.destroy() self.vsb.destroy() self.hsb.destroy() self.create_thread_frame() @staticmethod def program_about(): message = settings.__desc__ + '\n' + settings.__version__ messagebox.showinfo(title='About', message=message) @staticmethod def program_help(): message = 'See readme.md' messagebox.showinfo(title='About', message=message)
def __createWindowOnId(self, itemId, content): if self.currentlyRenderedWindow != None: self.currentlyRenderedWindow() # self.__remove(self.currentlyRenderedWindow) idtuple = self.localCanvas.coords(itemId) if idtuple: x = idtuple[0] y = idtuple[1] frm = Frame(self.localCanvas) frm.grid(row=0, column=0) canv = Canvas(frm) vscroll = Scrollbar(frm, orient="vertical", command=canv.yview) vscroll.grid(row=0, column=1, sticky=N + S) canv.grid(row=0, column=0) canv["yscrollcommand"] = vscroll.set aframe = Frame(canv) aframe.grid(row=0, column=0) Label(aframe, text=content, anchor="center", background="#CCFFCC", borderwidth=6, relief="ridge", justify="left").grid(row=1, column=0) canvWindow = canv.create_window(x, y, window=aframe) canv.coords(canvWindow, x, y) self.localCanvas.update_idletasks() canv["scrollregion"] = canv.bbox("all") def destroyAll(): self.__remove(canvWindow) canv.destroy() aframe.destroy() vscroll.destroy() frm.destroy() self.currentlyRenderedWindow = destroyAll Button(frm, text="Close", command=lambda : destroyAll()).grid(row=2, column=0)
class TKinterDisplay(Display): ''' classdocs ''' ''' Constructor ''' def __init__(self, lineThickness=3, maxH=1920, maxW=1080): master = Tk() master.maxsize(maxH, maxW) self.localCanvas = Canvas(master, width=400, height=400) self.currentlyRenderedWindow = None self.lineThickness = lineThickness self.vsb = Scrollbar(master, orient="vertical", command=self.localCanvas.yview) self.hsb = Scrollbar(master, orient="horizontal", command=self.localCanvas.xview) self.localCanvas.configure(yscrollcommand=self.vsb.set) self.localCanvas.configure(xscrollcommand=self.hsb.set) master.bind("<Configure>", self.__eventOnFrameConfigure) self.hsb.pack(side="bottom", fill="x") self.vsb.pack(side="right", fill="y") self.localCanvas.pack() self.__sampleDraw() '''''' @abstractmethod def drawSquare(self, xywhTuple, tags=None, colour=None, content=None): x2 = xywhTuple[0] + xywhTuple[2] y2 = xywhTuple[1] + xywhTuple[3] square = self.localCanvas.create_rectangle(xywhTuple[0], xywhTuple[1], x2, y2, width=self.lineThickness, tags=tags, fill=colour, activeoutline="white") def handler(event, self=self, content=content): return self.__eventOnClick(event, content) self.localCanvas.tag_bind(square, "<ButtonRelease-1>", handler) return square @abstractmethod def drawCircle(self, xywhTuple, tags=None , colour=None, content=None): x2 = xywhTuple[0] + xywhTuple[2] y2 = xywhTuple[1] + xywhTuple[3] circle = self.localCanvas.create_oval(xywhTuple[0], xywhTuple[1], x2, y2, width=self.lineThickness, tags=tags, fill=colour, activeoutline="white") def handler(event, self=self, content=content): return self.__eventOnClick(event, content) self.localCanvas.tag_bind(circle, "<ButtonRelease-1>", handler) return circle @abstractmethod def connectIdWithLine(self, id1, id2, tags=None, colour=None): # Gets the coordinates of id1 and then calulates centre point id1tuple = self.__getCoords(id1) x1 = id1tuple[0] + ((id1tuple[2] - id1tuple[0]) / 2) y1 = id1tuple[1] + ((id1tuple[3] - id1tuple[1]) / 2) # Gets the coordinates of id2 and then calulates centre point id2tuple = self.__getCoords(id2) x2 = id2tuple[0] + ((id2tuple[2] - id2tuple[0]) / 2) y2 = id2tuple[1] + ((id2tuple[3] - id2tuple[1]) / 2) # Calculates, using trig, the angle of the line at shape id1. This gives the radius of the ellipse opposite = y1 - y2 adjacent = x1 - x2 x1angle = 0 x2angle = 0 hyp = 0 if adjacent != 0 and opposite != 0: hyp = math.sqrt(math.pow(opposite, 2) + math.pow(adjacent, 2)) x1angle = math.tan(opposite / adjacent) x2angle = math.tan(adjacent / opposite) else: if opposite == 0: hyp = adjacent else: hyp = opposite x1angle = math.radians(90) x2angle = math.radians(270) a1 = (id1tuple[2] - id1tuple[0]) / 2 b1 = (id1tuple[3] - id1tuple[1]) / 2 a2 = (id2tuple[2] - id2tuple[0]) / 2 b2 = (id2tuple[3] - id2tuple[1]) / 2 r1 = a1 * b1 / (math.sqrt(((a1 * a1) * (math.pow(math.sin(x1angle), 2))) + ((b1 * b1) * math.pow(math.cos(x1angle), 2)))) r2 = a2 * b2 / (math.sqrt(((a2 * a2) * (math.pow(math.sin(x2angle), 2))) + ((b2 * b2) * math.pow(math.cos(x2angle), 2)))) x1 = x1 + ((r1 / hyp) * (x2 - x1)) y1 = y1 + ((r1 / hyp) * (y2 - y1)) #x2 = x2 + ((r2 / hyp) * (x1 - x2)) #y2 = y2 - ((r2 / hyp) * (y1 - y2)) return self.__drawLine(x1, y1, x2, y2, tags, colour) @abstractmethod def renderTextInId(self, tagTocentreOn, tagsToAddTo, content, funcContent): id1tuple = self.__getCoords(tagTocentreOn) x1 = id1tuple[0] + ((id1tuple[2] - id1tuple[0]) / 2) y1 = id1tuple[1] + ((id1tuple[3] - id1tuple[1]) / 2) txt = self.__renderText(x1, y1, (id1tuple[2] - id1tuple[0]), content, tagsToAddTo) def handler(event, self=self, content=funcContent): return self.__eventOnClick(event, content) self.localCanvas.tag_bind(txt, "<ButtonRelease-1>", handler) return txt @abstractmethod def move(self, tag, xamount, yamount): self.localCanvas.move(tag, xamount, yamount) @abstractmethod def runDisplay(self): self.localCanvas.mainloop() def __hideId(self, objectId): self.localCanvas.itemconfigure(objectId, state="hidden") pass def __showId(self, objectId): self.localCanvas.itemconfigure(objectId, state="normal") pass def __sampleDraw(self): self.localCanvas.create_oval(0, 0, 0, 0, width=0) def __renderText(self, x, y, width, content, tag): val = self.localCanvas.create_text(x, y, width=width, text=content, tags=tag, justify="center", font="Helvetica 8 bold", anchor="center") self.localCanvas.tag_raise(val) return val def __drawLine(self, x1, y1, x2, y2, tags=None, colour="black"): line = self.localCanvas.create_line(x1, y1, x2, y2, tags=tags, width=self.lineThickness, arrow="first", arrowshape=(16,20,6),fill=colour, smooth=True) self.localCanvas.tag_lower(line) return # line def __remove(self, num): self.localCanvas.delete(num) def __getCoords(self, ident): return self.localCanvas.coords(ident) def __eventOnFrameConfigure(self, event): '''Reset the scroll region to encompass the inner frame''' assert self.localCanvas coord_tuple = self.localCanvas.bbox("all") if not coord_tuple: logging.error("Frame reconfigure error on coordinate acquire.") else: reconWidth = coord_tuple[2] - coord_tuple[0] reconHeight = coord_tuple[3] - coord_tuple[1] self.localCanvas.configure(width=reconWidth) self.localCanvas.configure(height=reconHeight) self.localCanvas.configure(scrollregion=self.localCanvas.bbox("all")) self.localCanvas.update_idletasks() def __eventOnClick(self, event, content): self.__createWindowOnId(self.localCanvas.find_withtag(CURRENT), content) def __createWindowOnId(self, itemId, content): if self.currentlyRenderedWindow != None: self.currentlyRenderedWindow() # self.__remove(self.currentlyRenderedWindow) idtuple = self.localCanvas.coords(itemId) if idtuple: x = idtuple[0] y = idtuple[1] frm = Frame(self.localCanvas) frm.grid(row=0, column=0) canv = Canvas(frm) vscroll = Scrollbar(frm, orient="vertical", command=canv.yview) vscroll.grid(row=0, column=1, sticky=N + S) canv.grid(row=0, column=0) canv["yscrollcommand"] = vscroll.set aframe = Frame(canv) aframe.grid(row=0, column=0) Label(aframe, text=content, anchor="center", background="#CCFFCC", borderwidth=6, relief="ridge", justify="left").grid(row=1, column=0) canvWindow = canv.create_window(x, y, window=aframe) canv.coords(canvWindow, x, y) self.localCanvas.update_idletasks() canv["scrollregion"] = canv.bbox("all") def destroyAll(): self.__remove(canvWindow) canv.destroy() aframe.destroy() vscroll.destroy() frm.destroy() self.currentlyRenderedWindow = destroyAll Button(frm, text="Close", command=lambda : destroyAll()).grid(row=2, column=0)