python - Python3 tk, tooltip on canvas area -
i'm trying figure out how can make tooltip appear on canvas area bounded box. ideally, tooltip appear if user hovers on point , within margin of error of 10 pixels.
import tkinter tk; idlelib.tooltip import tooltip; windowwidth = 960; windowheight = 720; canvaswidth = windowwidth - 10; canvasheight = windowheight - 10; ''' main window ''' root = tk.tk(); root.resizable(width=false, height=false); root.geometry('{}x{}'.format(windowwidth, windowheight)); root.title('sample'); ''' canvas ''' canvas = tk.canvas(root, width = canvaswidth, height = canvasheight, bg = 'grey'); canvas.pack(side = tk.right, padx = 5); xo = canvaswidth / 2 yo = canvasheight / 2; point = canvas.create_rectangle(xo - 1, yo - 1, xo + 1, yo + 1, fill = 'magenta', outline = 'magenta'); #tooltip(point, 'origin'); root.mainloop(0);
actually, finished testing class creates tooltips whatever draw on canvas, addressable tag or id.
import tkinter tk import tkinter.ttk ttk class canvastooltip: ''' creates tooltip given canvas tag or id mouse above it. class has been derived original tooltip class updated , posted stackoverflow @ following link: https://stackoverflow.com/questions/3221956/ what-is-the-simplest-way-to-make-tooltips-in-tkinter/ 41079350#41079350 alberto vassena on 2016.12.10. ''' def __init__(self, canvas, tag_or_id, *, bg='#ffffea', pad=(5, 3, 5, 3), text='canvas info', waittime=400, wraplength=250): self.waittime = waittime # in miliseconds, 500 self.wraplength = wraplength # in pixels, 180 self.canvas = canvas self.text = text self.canvas.tag_bind(tag_or_id, "<enter>", self.onenter) self.canvas.tag_bind(tag_or_id, "<leave>", self.onleave) self.canvas.tag_bind(tag_or_id, "<buttonpress>", self.onleave) self.bg = bg self.pad = pad self.id = none self.tw = none def onenter(self, event=none): self.schedule() def onleave(self, event=none): self.unschedule() self.hide() def schedule(self): self.unschedule() self.id = self.canvas.after(self.waittime, self.show) def unschedule(self): id_ = self.id self.id = none if id_: self.canvas.after_cancel(id_) def show(self, event=none): def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)): c = canvas s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight() width, height = (pad[0] + label.winfo_reqwidth() + pad[2], pad[1] + label.winfo_reqheight() + pad[3]) mouse_x, mouse_y = c.winfo_pointerxy() x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1] x2, y2 = x1 + width, y1 + height x_delta = x2 - s_width if x_delta < 0: x_delta = 0 y_delta = y2 - s_height if y_delta < 0: y_delta = 0 offscreen = (x_delta, y_delta) != (0, 0) if offscreen: if x_delta: x1 = mouse_x - tip_delta[0] - width if y_delta: y1 = mouse_y - tip_delta[1] - height offscreen_again = y1 < 0 # out on top if offscreen_again: # no further checks done. # tip: # further mod might automagically augment # wraplength when tooltip high # kept inside screen. y1 = 0 return x1, y1 bg = self.bg pad = self.pad canvas = self.canvas # creates toplevel window self.tw = tk.toplevel(canvas.master) # leaves label , removes app window self.tw.wm_overrideredirect(true) win = tk.frame(self.tw, background=bg, borderwidth=0) label = ttk.label(win, text=self.text, justify=tk.left, background=bg, relief=tk.solid, borderwidth=0, wraplength=self.wraplength) label.grid(padx=(pad[0], pad[2]), pady=(pad[1], pad[3]), sticky=tk.nsew) win.grid() x, y = tip_pos_calculator(canvas, label) self.tw.wm_geometry("+%d+%d" % (x, y)) def hide(self): if self.tw: self.tw.destroy() self.tw = none if __name__ == '__main__': import random def further_text(): info_text = ('\n\ngo on rectangle mouse pointer see ' 'changing yellow , stay on long enough (less ' 'a second) let show own customized ' 'canvastooltip instance.\n\n' 'click once using mouse left button on rectangle ' 'to start dragging desired new position , ' 'release left button when done.\n\n' 'double click inside canvas using mouse left ' 'button redraw new set of rectangles.\n\n' 'hth. ;) alberto vassena') # texts generated @ http://lorem-ipsum.perbang.dk/ short_text = ('lorem ipsum dolor sit amet, mauris tellus, ' 'porttitor torquent eu. magna aliquet lorem, ' 'cursus sit ac, in in. dolor aliquet, cum integer. ' 'proin aliquet, porttitor pulvinar mauris. tellus ' 'lectus, amet cras, neque lacus quis. malesuada ' 'nibh. eleifend nam, in eget a. nec turpis, erat ' 'wisi semper') medium_text = ('lorem ipsum dolor sit amet, suspendisse aenean ' 'ipsum sollicitudin, pellentesque nunc ultrices ac ' 'ut, arcu elit turpis senectus convallis. ac orci ' 'pretium sed gravida, tortor nulla felis ' 'consectetuer, mauris egestas est erat. ut enim ' 'tellus @ diam, ac sagittis vel proin. massa ' 'eleifend orci tortor sociis, scelerisque in pede ' 'metus phasellus, est tempor gravida nam, ante ' 'fusce sem tempor. mi diam auctor vel pede, mus ' 'non mi luctus luctus, lectus sit varius repellat ' 'eu') long_text = ('lorem ipsum dolor sit amet, velit eu nam cursus ' 'quisque gravida sollicitudin, felis arcu interdum ' 'error quam quis massa, et velit libero ligula est ' 'donec. suspendisse fringilla urna ridiculus dui ' 'volutpat justo, quisque nisl eget sed blandit ' 'egestas, libero nullam magna sem dui nam, auctor ' 'vehicula nunc arcu vel sed dictum, tincidunt vitae ' 'id tristique aptent platea. lacus eros nec proin ' 'morbi sollicitudin integer, montes suspendisse ' 'augue lorem iaculis sed, viverra sed interdum eget ' 'ut @ pulvinar, turpis vivamus ac pharetra nulla ' 'maecenas ut. consequat dui condimentum lectus nulla ' 'vitae, nam consequat fusce ac facilisis eget orci, ' 'cras enim donec aenean sed dolor aliquam, elit ' 'lorem in nec fringilla, malesuada curabitur diam ' 'nonummy nisl nibh ipsum. in odio nunc nec porttitor ' 'ipsum, nunc ridiculus platea wisi turpis praesent ' 'vestibulum, suspendisse hendrerit amet quis vivamus ' 'adipiscing elit, ut dolor nec nonummy mauris nec ' 'libero, ad rutrum id tristique facilisis sed ' 'ultrices. convallis velit posuere mauris lectus sit ' 'turpis, lobortis volutpat et placerat leo ' 'malesuada, vulputate id maecenas @ volutpat ' 'vulputate, est augue nec proin ipsum pellentesque ' 'fringilla. mattis feugiat metus ultricies repellat ' 'dictum, suspendisse erat rhoncus ultricies in ipsum, ' 'nulla ante pellentesque blandit ligula sagittis ' 'ultricies, sed tortor sodales pede et duis platea') text = random.choice([short_text, medium_text, long_text, info_text, info_text, info_text]) return 'further info: ' + text class mycanvas(tk.canvas): def clear(self): self.delete('rectangle') def draw(self): width, height = int(self['width']), int(self['height']) colors = ('blue', 'green', 'red', 'brown', 'cyan', 'magenta', 'violet', 'black', 'white') self.tooltips = [] mask = '{} rectangle #{}.\n' in range(20): x, y = random.randint(0, width - 1), random.randint(0, height - 1) w, h = random.randint(5, 100), random.randint(5, 100) tag = 'r{}'.format(i) color = random.choice(colors) text = mask.format(color.capitalize(), tag[1:]) + further_text() id_ = self.create_rectangle(x, y, x + w, y + h, fill=color, activefill='yellow', tags=('rectangle', tag)) tooltip = canvastooltip(self, id_, text=text) self.tooltips.append(tooltip) def redraw(self, event): self.clear() self.draw() def onclick(self, event): coords = self.canvasx(event.x, 1), self.canvasy(event.y, 1) found = self.find_closest(*coords)[0] if found: self.target = found self.drag_x, self.drag_y = coords self.tag_raise(found) else: self.target, self.drag_x, self.drag_y = none, none, none def ondrag(self, event): if self.target none: return coords = self.canvasx(event.x, 1), self.canvasy(event.y, 1) self.move(self.target, coords[0] - self.drag_x, coords[1] - self.drag_y) self.drag_x, self.drag_y = coords def onrelease(self, event): self.target, self.drag_x, self.drag_y = none, none, none def main(): root = tk.tk() frame = ttk.frame(root) c = frame.canvas = mycanvas(frame.master, width=800, height=600) c.draw() c.bind('<double-button-1>', c.redraw) c.tag_bind('rectangle', '<button-1>', c.onclick) c.tag_bind('rectangle', '<b1-motion>', c.ondrag) c.tag_bind('rectangle', '<buttonrelease-1>', c.onrelease) c.grid(column=0, row=0, padx=(0, 0), pady=(0, 0)) frame.grid() root.mainloop() main() hth. in post, in answer, instead, find same solution (with minor changes) can applied other widgets, such buttons, labels , checkboxes.
Comments
Post a Comment