全局使用tkinter的bind_all绑定事件时如何设置指定widget为例外?
实现方案
核心思路是在移动逻辑执行前做拦截判断,直接对比控件实例而非硬编码路径,稳定性和可维护性更高。
具体修改步骤
- 给
Move类增加排除控件集合,在拖拽起始位置记录环节就做拦截,避免无效操作:
class Move(): def __init__(self): self._x = 0 self._y = 0 # 新增排除控件集合 self.excluded_widgets = set() def start_move2(self, event): # 如果触发事件的控件在排除列表中,直接返回不记录拖拽起始点 if event.widget in self.excluded_widgets: return self._x = event.x self._y = event.y def stop_move2(self, event): self._x = None self._y = None def on_move2(self, event): # 加一层保险,避免起始点异常记录的情况 if self._x is None or self._y is None or event.widget in self.excluded_widgets: return deltax = event.x - self._x deltay = event.y - self._y win = event.widget.winfo_toplevel() new_position = "+{}+{}".format(win.winfo_x() + deltax, win.winfo_y() + deltay) win.geometry(new_position)
- 在
A1类的open方法中,把需要排除的两个按钮加入排除集合:
在创建完self._btn_1和self._btn_2后,添加两行代码:
# 将需要排除的控件加入集合 self.excluded_widgets.add(self._btn_1) self.excluded_widgets.add(self._btn_2)
修改说明
- 抛弃了原代码中硬编码
winfo_parent路径的判断方式,直接对比控件实例,不管布局怎么调整都不会失效 - 拦截逻辑放在移动操作执行之前,不会出现先移动再判断的无效操作
- 后续需要新增排除控件,只需要往
excluded_widgets集合里添加对应实例即可,拓展性极强
完整可运行代码
from tkinter import * class Move(): def __init__(self): self._x = 0 self._y = 0 self.excluded_widgets = set() def start_move2(self, event): if event.widget in self.excluded_widgets: return self._x = event.x self._y = event.y def stop_move2(self, event): self._x = None self._y = None def on_move2(self, event): if self._x is None or self._y is None or event.widget in self.excluded_widgets: return deltax = event.x - self._x deltay = event.y - self._y win = event.widget.winfo_toplevel() new_position = "+{}+{}".format(win.winfo_x() + deltax, win.winfo_y() + deltay) win.geometry(new_position) class A1 (Frame, Move): def __init__(self, master=None, **kwargs): super().__init__(master, **kwargs) self.master = master self.btn = Button(self, text='opens', command=self.open) self.btn.pack() self.bind_all("<ButtonPress-1>", self.start_move2) self.bind_all("<B1-Motion>", self.on_move2) self.bind_all("<ButtonRelease-1>", self.stop_move2) def open(self): self.w1 = Toplevel(self) self.w1.overrideredirect(1) self.w1.wm_attributes ('-topmost', True) self.w2 = Toplevel(self) self.w2.overrideredirect(1) self.w2.wm_attributes ('-topmost', True) self.w1.geometry('300x150') self.w2.geometry('300x150') self.frame_1 = Frame(self.w1, bg='green') self.label_1 = Label(self.frame_1, text='___windows 1___', bg='green2', width=50) self.btn_1 = Button(self.label_1, text='AAAAAAA') self._frame_1 = Frame(self.frame_1, bg='green') self._label_1 = Label(self._frame_1, text='windows 1', bg='green2', width=50) self._btn_1 = Button(self._label_1, text='button 2 - A') self._bbn_11 = Button(self._label_1, text='button 3 - A') self.frame_2 = Frame(self.w2, bg='green') self.label_2 = Label(self.frame_2, text='___windows 2___', bg='green2', width=50) self.btn_2 = Button(self.label_2, text='BBBBBBB') self._frame_2 = Frame(self.frame_2, bg='green') self._label_2 = Label(self._frame_2, text='windows 1', bg='green2', width=50) self._btn_2 = Button(self._label_2, text='button 2 - B') self._bbn_22 = Button(self._label_2, text='button 3 - B') # 添加排除控件 self.excluded_widgets.add(self._btn_1) self.excluded_widgets.add(self._btn_2) self.frame_1.pack() self.label_1.pack() self.btn_1.pack() self._frame_1.pack() self._label_1.pack() self._btn_1.pack() self._bbn_11.pack() self.frame_2.pack() self.label_2.pack() self.btn_2.pack() self._frame_2.pack() self._label_2.pack() self._btn_2.pack() self._bbn_22.pack() root = Tk() app = A1(root, bg='black') app.pack(side=BOTTOM, fill=BOTH) root.mainloop()
内容的提问来源于stack exchange,提问作者Jackie Ck
相关产品推荐
相关产品推荐

