You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter+CustomTkinter多窗口场景下幽灵点击与悬停事件串扰问题求助

Tkinter+CustomTkinter多窗口场景下幽灵点击与悬停事件串扰问题求助

我现在遇到了一个非常头疼的问题:在Tkinter+CustomTkinter的应用里打开第二个窗口后,出现了幽灵点击和悬停事件串扰的情况,想请教大家:

  • 有没有办法正确隔离悬停和点击事件,让它们只作用于当前激活的窗口?
  • 有没有和类相关的解决方案可以防止这种事件污染?

环境说明

我使用的是MacOS系统,Python版本为3.11,项目依赖Tkinter、CustomTkinter和TkinterDnD。

复现步骤

  1. 运行程序
  2. 点击“Phenotype Selection”按钮打开新窗口
  3. 点击主GUI的某个位置,优先选择窗口边缘区域
  4. 不要点击Phenotype Selection窗口,直接将鼠标移到它上面

发生的异常情况

  1. 即使光标停留在第二个窗口上,主GUI按钮的悬停效果仍会被触发
  2. 悬停和点击事件明显在窗口之间“泄露”了
  3. 主应用(MainApp)使用了overrideredirect(True),需要手动处理悬停事件,但当另一个窗口打开时,它会错误识别鼠标位置

额外观察

  1. 第二个窗口没有使用overrideredirect(True),自身行为完全正常
  2. 主GUI会错误地注册悬停事件,哪怕鼠标明明在第二个窗口的范围内
  3. 我们已经尝试了多种修复思路,但都没有解决问题

相关代码

import tkinter as tk
import customtkinter as ctk
from tkinterdnd2 import DND_FILES, TkinterDnD  # Use this import for drag-and-drop support

ctk.set_appearance_mode("Dark")
ctk.set_default_color_theme("blue")

class LayoutBarApp(ctk.CTkFrame):
  """ Main Layout Bar with custom buttons. """
  def __init__(self, parent):
      super().__init__(parent)
      self.pack_propagate(False)
      self.pack(side="top", fill="x")
      self.active_button = None
      self.buttons = {}

      # Create layout buttons
      self.create_layout_buttons()

  def open_phenotype_selection_window(self):
      """ Opens a new window for Phenotype Selection. """
      if hasattr(self, "phenotype_window") and self.phenotype_window.winfo_exists():
          self.phenotype_window.lift()  # Bring existing window to front
          return

      self.phenotype_window = ctk.CTkToplevel(self)  # Use CTkToplevel for consistency with CTk
      self.phenotype_window.title("Phenotype Selection")
      self.phenotype_window.geometry("400x300+400+100")  # Adjust size/position as needed
      self.phenotype_window.resizable(False, False)

      # Add a label
      label = ctk.CTkLabel(self.phenotype_window, text="Select Phenotype", font=("Arial", 16, "bold"))
      label.pack(pady=10)

      # Example: Button inside the new window
      close_button = ctk.CTkButton(self.phenotype_window, text="Close", command=self.phenotype_window.destroy)
      close_button.pack(pady=10)


  def create_layout_buttons(self):
      """ Create buttons with their icons and commands. """
      button_actions = {
          "Order Search": None,
          "Phenotype Selection": self.open_phenotype_selection_window,  # ✅ Assigned function
          "Bounding Box": None,
          "Landmark Movement": None,
          "Face Measurement": None,
      }

      for btn_text, action in button_actions.items():

          button = ctk.CTkButton(
              self,
              text=btn_text.replace(" ", "\n"),
              command=lambda b=btn_text, action=action: self.activate_button(b, action),  # ✅ Corrected lambda

              fg_color=("#3b8ed0", "#1f6aa5"),
              hover_color=("#2a75c0", "#155a8a")
          )
          button.pack(side="left", padx=(5, 0), pady=5)
          self.buttons[btn_text] = button


  def activate_button(self, button_name, action):
      """ Handles button activation (highlighting) and executes the assigned action. """

      # ✅ Get the actual root coordinates to adjust hover issues
      root_x = self.winfo_rootx()
      root_y = self.winfo_rooty()

      mouse_x = self.winfo_pointerx() - root_x
      mouse_y = self.winfo_pointery() - root_y

      print(f"Mouse Position Adjusted: ({mouse_x}, {mouse_y}), Button:{button_name} Self:{self}, Action{action}")  # ✅ Debugging hover issue

      # Reset previous button color
      if self.active_button:
          self.buttons[self.active_button].configure(
              fg_color=("#3b8ed0", "#1f6aa5"),
              hover_color=("#2a75c0", "#155a8a")
          )

      # Set new active button
      self.active_button = button_name
      self.buttons[button_name].configure(
          fg_color="green",
          hover_color="#006400"
      )
      # Execute the function if it exists
      if action:
          action()

class MainApp(TkinterDnD.Tk):  
  """ Root Tkinter App holding both Sidebar and Layout Bar. """
  def __init__(self):
      super().__init__()

      self.overrideredirect(True)  # Removes system title bar
      self.geometry("782x60+330+0")
      self.resizable(False, False)
      self.title("GUI")

      # Main Layout Bar
      self.layout_bar = LayoutBarApp(self)

if __name__ == "__main__":
  app = MainApp()
  app.mainloop()

备注:内容来源于stack exchange,提问作者Chad Ify

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 08:54:35