Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使工具提示显示在由框限定的画布区域上?_Python_Tkinter_Tooltip - Fatal编程技术网

Python 如何使工具提示显示在由框限定的画布区域上?

Python 如何使工具提示显示在由框限定的画布区域上?,python,tkinter,tooltip,Python,Tkinter,Tooltip,我试图弄清楚如何使工具提示显示在由框限定的画布区域上。理想情况下,如果用户将鼠标悬停在该点上,且误差在10像素以内,则会出现工具提示 import tkinter as tk; from idlelib.ToolTip import ToolTip; windowWidth = 960; windowHeight = 720; canvasWidth = windowWidth - 10; canvasHeight = windowHeight - 10; ''' Main Window '

我试图弄清楚如何使工具提示显示在由框限定的画布区域上。理想情况下,如果用户将鼠标悬停在该点上,且误差在10像素以内,则会出现工具提示

import tkinter as tk;
from 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);

就我所知,没有办法用tk做到这一点。我最终导入了Pmw并使用了balloon。

事实上,我刚刚完成了一个类的测试,该类为画布上绘制的任何内容创建工具提示,无论是通过标记还是通过id寻址

import tkinter as tk
import tkinter.ttk as ttk


class CanvasTooltip:
    '''
    It creates a tooltip for a given canvas tag or id as the mouse is
    above it.

    This class has been derived from the original Tooltip class I updated
    and posted back to StackOverflow at the 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, originally 500
        self.wraplength = wraplength  # in pixels, originally 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 the top

            if offscreen_again:
                # No further checks will be done.

                # TIP:
                # A further mod might automagically augment the
                # wraplength when the tooltip is too high to be
                # kept inside the screen.
                y1 = 0

            return x1, y1

        bg = self.bg
        pad = self.pad
        canvas = self.canvas

        # creates a toplevel window
        self.tw = tk.Toplevel(canvas.master)

        # Leaves only the label and removes the 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 over any rectangle with your mouse pointer to see it '
                     'changing to yellow and stay on it long enough (less than '
                     'a second) to let it show its own customized '
                     'CanvasTooltip instance.\n\n'

                     'Click once using the mouse left button over a rectangle '
                     'to start dragging it to the desired new position and '
                     'release the left button when you are done.\n\n'

                     'Double click inside the canvas using the mouse left '
                     'button to redraw a new set of rectangles.\n\n'
                     'HtH. ;) Alberto Vassena')

        # texts generated at 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 at 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 at 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 a 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 at a 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'
            for i 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 is 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()
将tkinter作为tk导入
将tkinter.ttk导入为ttk
类CanvasTooltip:
'''
当鼠标移动时,它会为给定的画布标记或id创建工具提示
在它上面。
该类是从原始工具提示类I中派生的
并通过以下链接发回StackOverflow:
https://stackoverflow.com/questions/3221956/
在tkinter中制作工具提示的最简单方法是什么/
41079350#41079350
Alberto Vassena于2016年12月10日发布。
'''
定义初始化(自我、画布、标记或id、,
*,
bg=“#fffea”,
pad=(5,3,5,3),
text='canvas info',
等待时间=400,
wraplength=250):
self.waittime=waittime#以毫秒为单位,最初为500
self.wraplength=wraplength#以像素为单位,最初为180
self.canvas=画布
self.text=文本
self.canvas.tag_绑定(tag_或_id,“,self.onEnter)
self.canvas.tag\u绑定(tag\u或\u id,“,self.onLeave)
self.canvas.tag\u绑定(tag\u或\u id,“,self.onLeave)
self.bg=bg
self.pad=pad
self.id=None
self.tw=无
def onEnter(自身,事件=无):
self.schedule()
def onLeave(自身,事件=无):
self.unschedule()
self.hide()
def计划(自我):
self.unschedule()
self.id=self.canvas.after(self.waittime,self.show)
def计划外(自我):
id=self.id
self.id=None
如果id u3;:
self.canvas.after\u取消(id\u0)
def显示(自身,事件=无):
def tip_pos_计算器(画布、标签、,
*,
尖端δ=(10,5),垫=(5,3,5,3)):
c=帆布
s_宽度,s_高度=c.winfo_屏幕宽度(),c.winfo_屏幕高度()
宽度,高度=(填充[0]+label.winfo_reqwidth()+填充[2],
pad[1]+label.winfo_reqheight()+pad[3])
鼠标x,鼠标y=c.winfo_指针xy()
x1,y1=鼠标x+尖端δ[0],鼠标y+尖端δ[1]
x2,y2=x1+宽度,y1+高度
x_delta=x2-s_宽度
如果x_δ<0:
x_δ=0
y_δ=y2-s_高度
如果y_δ<0:
y_δ=0
屏幕外=(x_增量,y_增量)!=(0, 0)
如果在屏幕外:
如果x_δ:
x1=鼠标x-尖端δ[0]-宽度
如果y_δ:
y1=鼠标_y-尖端_δ[1]-高度
屏幕外再次=y1<0#在顶部
如果再次脱离屏幕,请执行以下操作:
#不会进行进一步检查。
#提示:
#进一步的mod可能会自动增强
#工具提示太高而无法显示时的wraplength
#放在屏幕里面。
y1=0
返回x1,y1
bg=self.bg
pad=self.pad
canvas=self.canvas
#创建顶层窗口
self.tw=tk.Toplevel(canvas.master)
#只保留标签并删除应用程序窗口
self.tw.wm_overrideredirect(真)
win=传统帧(self.tw,
背景=背景,
边框宽度=0)
标签=ttk.标签(赢,
text=self.text,
justify=tk.LEFT,
背景=背景,
卸压=tk.固体,
borderwidth=0,
wraplength=self.wraplength)
label.grid(padx=(pad[0],pad[2]),
pady=(pad[1],pad[3]),
粘性=tk.NSEW)
win.grid()
x、 y=提示位置计算器(画布、标签)
self.tw.wm_几何体(“++%d++%d”%(x,y))
def隐藏(自我):
如果self.tw:
self.tw.destroy()
self.tw=无
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
随机输入
定义进一步的文本():
info_text=('\n\n用鼠标指针在任何矩形上移动以查看它'
'更改为黄色并在上面停留足够长的时间(少于'
'一秒钟),让它显示自己的自定义'
'CanVastToolTip实例。\n\n'
'在矩形上使用鼠标左键单击一次'
'开始将其拖动到所需的新位置并'
'完成后释放左按钮。\n\n'
'使用鼠标左键双击画布内部'
'按钮重新绘制一组新的矩形。\n\n'
“嗯。”(阿尔贝托·瓦塞纳)
#在以下位置生成的文本:http://lorem-ipsum.perbang.dk/
短文=(“Lorem ipsum dolor sit amet,mauris tellus,”
“波尔蒂托·托森特·欧麦格纳·阿利奎特·洛雷姆,”
“cursus坐ac,in.Dolor aliquet,cum integer。”
“Proin aliquet,porttitor pulvinar mauris.Tellus”
“莱克图斯,阿米特·克拉斯,内克·拉克斯·奎斯·马莱苏亚达”
“尼布·埃利芬德·纳姆,在埃格特a·内克·图尔皮斯,埃拉特”
“wisi semper”)
中文本=('Lorem ipsum door sit amet,suspendisse aenean'
“伊普苏姆·索利西图丁,佩伦茨克·努克·乌尔特里塞斯ac”
“呃,阿尔库精英turpis sentecus convallis.Ac orci”