Tkinter - CheckboxTreeview,每个元素都有工具提示

问题描述 投票:0回答:1

我有一个带有 CheckboxTreeview 小部件的 Python 工具。树视图中的某些内容太长而无法显示。如果是这种情况,我想向用户提供工具提示。我的工具中其他地方已经有工具提示,但我无法将工具提示设置为 CheckboxTreeview 中的各个内容。你知道有什么办法吗?这怎么可能?

下面是一个最小的示例,我想在其中提供工具提示以供参考

ref2
。这怎么可能?

import tkinter as tk
from tkinter import ttk
from ttkwidgets import CheckboxTreeview

class CreateToolTip(object):
    def __init__(self, widget, text='tooltip text', wraplength=180):
        self.waittime = 400 #miliseconds
        self.bg = '#fdfde3'
        self.wraplength = wraplength   #pixels
        self.widget = widget
        self.text = text
        self.widget.bind("<Enter>", self.enter)
        self.widget.bind("<Leave>", self.leave)
        self.widget.bind("<ButtonPress>", self.leave)
        self.id = None
        self.tw = None

    def enter(self, event=None):
        self.schedule()

    def leave(self, event=None):
        self.unschedule()
        self.hidetip()

    def schedule(self):
        self.unschedule()
        self.id = self.widget.after(self.waittime, self.showtip)

    def unschedule(self):
        id = self.id
        self.id = None
        if id:
            self.widget.after_cancel(id)

    def showtip(self, event=None):
        x, y, cx, cy = self.widget.bbox("insert")
        self.tw = tk.Toplevel(self.widget)
        self.tw.wm_overrideredirect(True)
        tk.Label(self.tw, text=self.text, justify='left',background=self.bg,
                 relief='solid', borderwidth=1,wraplength = self.wraplength
                 ).pack(ipadx=10)
        x += self.widget.winfo_rootx()
        y += self.widget.winfo_rooty()
        self.tw.wm_geometry("+%d+%d" % (x, y))

    def hidetip(self):
        tw = self.tw
        self.tw= None
        if tw:
            tw.destroy()


class App():
    def __init__(self, master):  
        self.master = master
        self.master.geometry('300x400')
        self.master.columnconfigure(0, weight=1)
        self.tree = CheckboxTreeview(self.master)
        xsb = ttk.Scrollbar(self.master, orient='horizontal', command=self.tree.xview)
        ysb = ttk.Scrollbar(self.master, orient='vertical', command=self.tree.yview)
        self.tree.configure(yscroll=ysb.set)
        self.tree['columns']=('x', 'y')
        self.tree.column('x', anchor='e', width=40)
        self.tree.column('y', width=40)
        self.tree.heading('#0', text='abc', anchor='w')
        self.tree.heading('x', text='x', anchor='w')
        self.tree.heading('y', text='y', anchor='w')
        self.tree.grid(row=0, column=0)
        ysb.grid(row=0, column=1, sticky='ns')
        xsb.grid(row=1, column=0, sticky='ew')
        self.master.frame = tk.Frame(self.master, highlightbackground="black", highlightthickness=2)
        self.master.frame.grid(row=4, column=0, columnspan=2, sticky='w')
        ref = tk.Label(self.master.frame, text='TEXT', font=tk.font.Font(size=16, weight='bold'))
        ref.grid(row=0, column=0)
        CreateToolTip(ref, text='tooltip')
        
        ref1 = self.tree.insert('', 'end', text='node 1', values=('x1', 'y1'), open=True)
        ref2 = self.tree.insert('', 'end', text='node 2 - this is a very long text where a tooltip should be displayed', values=('x2', 'y2'), open=True)

root = tk.Tk()
app = App(root)
app.master.mainloop()
python tkinter checkbox treeview
1个回答
0
投票

您需要删除对“插入”bbox 的依赖并将工具提示行为直接绑定到树项。试试这个方法:

class CreateToolTip(object):
    def __init__(self, widget, text='tooltip text', wraplength=180):
        self.waittime = 400  # milliseconds
        self.hidetime = 2000
        self.wraplength = wraplength   #pixels
        self.widget = widget
        self.text = text
        self.widget.bind("<Enter>", self.enter)
        self.widget.bind("<Leave>", self.leave)
        self.widget.bind("<ButtonPress>", self.leave)
        self.id = None
        self.tw = None
        self.hide_id = None  # new timer for auto-hide

    def enter(self, event=None):
        self.schedule()

    def leave(self, event=None):
        self.unschedule()
        self.schedule_hide()

    def schedule_hide(self):
        if self.hide_id:
            self.widget.after_cancel(self.hide_id)
        self.hide_id = self.widget.after(self.hidetime, self.hidetip)

    def schedule(self):
        self.unschedule()
        self.id = self.widget.after(self.waittime, self.showtip)

    def unschedule(self):
        if self.id:
            self.widget.after_cancel(self.id)
            self.id = None

    def unschedule(self):
        if self.id:
            self.widget.after_cancel(self.id)
            self.id = None
        if self.hide_id:
            self.widget.after_cancel(self.hide_id)
            self.hide_id = None

    def showtip(self, event=None):
        x = self.widget.winfo_rootx() + self.widget.winfo_width()//2
        y = self.widget.winfo_rooty()

        self.hidetip()

        self.tw = tk.Toplevel(self.widget)
        self.tw.wm_overrideredirect(True)

        label = tk.Label(self.tw, text=self.text, justify='left',
                      background="#ffffe0", relief='solid', borderwidth=1,
                      wraplength=self.wraplength)
        label.pack()

        self.tw.wm_geometry(f"+{x}+{y}")
        self.schedule_hide()

    def hidetip(self):
        if self.tw:
            self.tw.destroy()
            self.tw = None



class App():
    def __init__(self, master):
        self.master = master
        self.master.geometry('300x400')
        self.master.columnconfigure(0, weight=1)
        self.tree = CheckboxTreeview(self.master)
        xsb = ttk.Scrollbar(self.master, orient='horizontal', command=self.tree.xview)
        ysb = ttk.Scrollbar(self.master, orient='vertical', command=self.tree.yview)
        self.tree.configure(yscroll=ysb.set)
        self.tree['columns']=('x', 'y')
        self.tree.column('x', anchor='e', width=40)
        self.tree.column('y', width=40)
        self.tree.heading('#0', text='abc', anchor='w')
        self.tree.heading('x', text='x', anchor='w')
        self.tree.heading('y', text='y', anchor='w')
        self.tree.grid(row=0, column=0)
        ysb.grid(row=0, column=1, sticky='ns')
        xsb.grid(row=1, column=0, sticky='ew')

        self.tree.bind('<Motion>', self.show_tree_tooltip)
        self.current_tooltip = None

        self.master.frame = tk.Frame(self.master, highlightbackground="black", highlightthickness=2)
        self.master.frame.grid(row=4, column=0, columnspan=2, sticky='w')
        ref = tk.Label(self.master.frame, text='TEXT', font=tk.font.Font(size=16, weight='bold'))
        ref.grid(row=0, column=0)
        CreateToolTip(ref, text='This is a ToolTip!!!')

        ref1 = self.tree.insert('', 'end', text='node 1', values=('x1', 'y1'), open=True)
        ref2 = self.tree.insert('', 'end',
                               text='node 2 - this is a very long text where a tooltip should be displayed',
                               values=('x2', 'y2'),
                               open=True)

        self.tooltips = {
            ref1: "Tooltip for node 1",
            ref2: "node 2 - this is a very long text where a tooltip should be displayed"
        }

    def show_tree_tooltip(self, event):
        item = self.tree.identify_row(event.y)

        if not item:
            if self.current_tooltip:
                self.current_tooltip.leave()
            return

        if item in self.tooltips:
            if self.current_tooltip and self.current_tooltip.text != self.tooltips[item]:
                self.current_tooltip.hidetip()
                self.current_tooltip = None

            if not self.current_tooltip:
                self.current_tooltip = CreateToolTip(self.tree, text=self.tooltips[item], wraplength=200)
                self.current_tooltip.showtip()
        else:
            if self.current_tooltip:
                self.current_tooltip.leave()
                self.current_tooltip = None



root = tk.Tk()
app = App(root)
app.master.mainloop()

这样,每个项目就有单独的工具提示。我还添加了一个“计时器”来隐藏工具提示。你需要进一步调整它,因为我的工作间隔现在刚刚结束,哈哈。

希望这有帮助!干杯!

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.