【问题标题】:How to trigger tkinter's "<Enter>" event with mouse down?如何在鼠标按下时触发 tkinter 的“<Enter>”事件?
【发布时间】:2018-12-24 11:23:32
【问题描述】:

在带有 Python 3.7 的 tkinter 中,事件绑定的默认行为是“”事件在鼠标在释放之前被单击后不会被触发。我打算实现一个可滚动的表,以便它检测“”(鼠标左键单击)和“”(鼠标左键单击)事件以及每个表行的小部件“”事件绑定检测鼠标指针何时进入不同的表格行。通过这种方式,我可以通过单击一行并拖动表格来滚动表格。我的假设是即使按住鼠标按钮也会触发“”事件,这是不正确的。所以,我的整个滚动实现碰上了砖墙。我需要在鼠标按下时触发这些事件,否则它将不起作用。我正在做类似的事情:

from tkinter import *

class App:
    def __init__(self):
        self.root = Tk()
        # The name kwarg is used to infer the index of the row in the event handlers.
        self.labels = [Label(text=f"Label #{i}", name=f"row-{i}") for i in range(5)]
        for row, label in enumerate(self.labels):
            label.bind("<Button-1>", self.mouse_down)
            label.bind("<ButtonRelease-1>", self.mouse_up)
            label.bind("<Enter>", self.mouse_enter)
            label.grid(row=row, column=0)
        mainloop()

    def mouse_up(self, event):
        idx = self.index_from_event(event)
        # Do some with the row with the passed index

    def mouse_down(self, event):
        idx = self.index_from_event(event)
        # Do some with the row with the passed index

    def mouse_enter(self, event):
        # I would like for this to be triggered even when the mouse is pressed down.
        # However, by default tkinter doesn't allow this.
        pass

    def index_from_event(self, event):
        # Get the index of the row from the labels name string.
        return str(event.widget).split('-')[-1]

在 tkinter 中按住鼠标按钮 1 时,有什么方法可以启用鼠标输入事件? effbot (http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm) 上的所有文档都提到了 enter 事件:

<Enter>
    The mouse pointer entered the widget (this event doesn’t mean that the user pressed the Enter key!).

【问题讨论】:

  • 您可以使用&lt;B1-Motion&gt; 并使用事件包含的 (x, y) 坐标吗?
  • 这个问题已经在herehere 之前被问过,并且似乎无法完成。按住鼠标会阻止来自其他小部件的事件。您必须使用初始单击小部件中的事件来确定鼠标在哪个小部件上。
  • 我不明白你在做什么。 “可滚动”部分从何而来?
  • @Novel 我的示例代码中没有实现滚动逻辑,因为它与问题无关。

标签: python python-3.x tkinter


【解决方案1】:

不,没有直接的方法可以在按钮按下时绑定到 enter 和 leave 事件,除了首先获得点击的小部件。但是,添加该功能相当容易,

您可以将&lt;B1-Motion&gt; 绑定到所有将在鼠标移动时调用函数的小部件。然后,您可以使用winfo_containing 方法来确定光标下的小部件。使用这些信息,您可以生成一个可以绑定到的虚拟事件(或者您可以跳过虚拟事件并将代码添加到运动事件的处理程序中)。

这是一个人为的例子。当您单击并移动鼠标时,将调用show_info。它跟踪当前小部件并将其与光标下的小部件进行比较。如果不同,它会为前一个小部件生成一个&lt;&lt;B1-Leave&gt;&gt;,并在新的小部件上生成一个&lt;&lt;B1-Enter&gt;&gt;。这些绑定将显示“你好,光标!”当光标在标签上时。

import tkinter as tk

current_widget = None
def show_info(event):
    global current_widget
    widget = event.widget.winfo_containing(event.x_root, event.y_root)
    if current_widget != widget:
        if current_widget:
            current_widget.event_generate("<<B1-Leave>>")
        current_widget = widget
        current_widget.event_generate("<<B1-Enter>>")

def on_enter(event):
    event.widget.configure(text="Hello, cursor!")

def on_leave(event):
    event.widget.configure(text="")

root = tk.Tk()
label = tk.Label(root, bd=1, relief="raised")
l1 = tk.Label(root, text="", width=20, bd=1, relief="raised")
l2 = tk.Label(root, text="", width=20, bd=1, relief="raised")

label.pack(side="top", fill="x")
l1.pack(fill="both", expand=True, padx=20, pady=20)
l2.pack(fill="both", expand=True, padx=20, pady=20)

root.bind_all("<B1-Motion>", show_info)
l1.bind("<<B1-Enter>>", on_enter)
l1.bind("<<B1-Leave>>", on_leave)
l2.bind("<<B1-Enter>>", on_enter)
l2.bind("<<B1-Leave>>", on_leave)

tk.mainloop()

【讨论】:

  • 正确。我喜欢这个解决方案,因为它完全符合我的要求,尽管不幸的是它是一种解决方法。对运动事件的持续调用是否有可能在任何级别上减慢我的应用程序?它目前不是 CPU 密集型的,我希望它保持这种状态。无论如何,就我而言,我想我只需将绑定更改为 事件并检查包含的小部件即可。由于我以某种方式命名了表格小部件,因此我可以简单地使用运动事件并检查名称是否为表格行小部件,如果是则进行滚动。谢谢@BryanOakley
  • @YungGun 这取决于你在回调中做了多少工作来决定它是否会减慢程序的速度。最好的办法是通过单击按钮打开跟踪,然后在释放按钮时退出。
  • 啊,这是一个好主意,而且正是我将要做的。您知道绑定或取消绑定键是一项昂贵的操作吗?因为我会在每次向下/向上单击时绑定和解除绑定,并且我的应用程序会被多次点击,这可能会出现问题。您是说每次单击绑定/取消绑定所有键比在每个运动事件上​​运行运动事件绑定功能更便宜吗?有问题的运动事件将执行单个布尔检查,如果当前未单击鼠标,则返回 false。
  • @YungGun:一点也不贵。我不确定“绑定/取消绑定所有键”是什么意思。这个问题是关于绑定鼠标的,只有几个绑定。了解性能的最简单方法是进行并衡量它
  • 抱歉,这不是最好的说法。在我的情况下,我将大约 30 个小部件绑定到鼠标 1 运动事件,所以如果我在鼠标启动时禁用输入,我必须解除每个小部件鼠标 1 运动事件的绑定,对吗?
猜你喜欢
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-04
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
相关资源
最近更新 更多