如何消除Tkinter中overrideredirect窗口拖动调整时的闪烁?
Tkinter
overrideredirect窗口拖动调整大小闪烁问题及解决方案 问题描述
我有一个overrideredirect窗口,需要通过鼠标拖动调整其大小。当前示例代码可正常运行,但拖动sw、w、nw、n和ne手柄时会出现闪烁(快速拖动时尤为明显),推测是同时调整窗口位置与尺寸导致的。我尝试使用update_idletasks平滑过渡,但无效果。
import tkinter as tk class Box(tk.Tk): def __init__(self): super().__init__() self.drag_point_x = None self.drag_point_y = None self.drag_margin = 15 self.width = 400 self.height = 200 self.x = 300 self.y = 300 self.geometry(f"{self.width}x{self.height}+{self.x}+{self.y}") self.overrideredirect(1) self.bind("<B1-Motion>", self.on_dragging) self.bind("<Button-1>", self.on_click) self.bind("<Motion>", self.on_motion) def on_dragging(self, event): mouse_x = self.winfo_pointerx() mouse_y = self.winfo_pointery() delta_width = self.x - mouse_x delta_height = self.y - mouse_y if self.drag_point == 'e': self.width = mouse_x - self.x elif self.drag_point == 'se': self.width = mouse_x - self.x self.height = mouse_y - self.y elif self.drag_point == 's': self.height = mouse_y - self.y elif self.drag_point == 'sw': self.height = mouse_y - self.y self.width += delta_width self.x = mouse_x elif self.drag_point == 'w': self.width += delta_width self.x = mouse_x elif self.drag_point == 'nw': self.width += delta_width self.height += delta_height self.x = mouse_x self.y = mouse_y elif self.drag_point == 'n': self.height += delta_height self.y = mouse_y elif self.drag_point == 'ne': self.width = mouse_x - self.x self.height += delta_height self.y = mouse_y self.geometry(f"{self.width}x{self.height}+{self.x}+{self.y}") def on_click(self, event): self.drag_point_x = event.x self.drag_point_y = event.y def on_motion(self, event): if event.x < self.drag_margin: if event.y < self.drag_margin: self.config(cursor="size_nw_se") self.drag_point = "nw" elif event.y > self.height - self.drag_margin: self.config(cursor="size_ne_sw") self.drag_point = "sw" else: self.config(cursor="size_we") self.drag_point = "w" elif event.x > self.width - self.drag_margin: if event.y < self.drag_margin: self.config(cursor="size_ne_sw") self.drag_point = "ne" elif event.y > self.height - self.drag_margin: self.config(cursor="size_nw_se") self.drag_point = "se" else: self.config(cursor="size_we") self.drag_point = "e" elif event.y < self.drag_margin: self.config(cursor="size_ns") self.drag_point = "n" elif event.y > self.height - self.drag_margin: self.config(cursor="size_ns") self.drag_point = "s" else: self.config(cursor="") self.drag_point = None if __name__ == "__main__": box = Box() box.mainloop()
更新:带多显示器支持的解决方案代码
以下是基于OneMadGypsy的解决方案编写的代码,新增了多显示器支持:
import tkinter as tk from PIL import ImageGrab from screeninfo import get_monitors class Overlay(tk.Toplevel): def __init__(self, monitor, overlays): tk.Toplevel.__init__(self) self.b_x = 0 self.b_y = 0 self.e_x = 0 self.e_y = 0 self.drag = False self.overlays = overlays self.monitor = monitor self.configure(cursor='cross') self.attributes('-alpha', 0.3) self.attributes('-topmost', True) self.overrideredirect(True) self.geometry(f"{self.monitor.width}x{self.monitor.height}+{self.monitor.x}+{self.monitor.y}") self.canvas = tk.Canvas(self, bg='dark gray') self.canvas.pack(fill='both', expand=True) self.canvas.bind('<B1-Motion>', self.on_drag) self.canvas.bind('<ButtonPress-1>', self.on_press) self.canvas.bind('<ButtonRelease-1>', self.on_release) rect = dict( outline='#0052d6', fill='white', tags='snip_rect', width=2, ) self.canvas.create_rectangle(0, 0, 0, 0, **rect) def on_press(self, event): self.b_x = event.x self.b_y = event.y def on_drag(self, event): self.drag = True self.e_x = event.x self.e_y = event.y self.canvas.coords('snip_rect', self.b_x, self.b_y, self.e_x, self.e_y) def on_release(self, event): self.destroy() for window in self.overlays: if window: window.destroy() self.overlays.clear() if not self.drag: return adjusted_b_x = self.b_x + self.monitor.x adjusted_b_y = self.b_y + self.monitor.y adjusted_e_x = self.e_x + self.monitor.x adjusted_e_y = self.e_y + self.monitor.y image = ImageGrab.grab(bbox=(min(adjusted_b_x, adjusted_e_x), min(adjusted_b_y, adjusted_e_y), max(adjusted_b_x, adjusted_e_x), max(adjusted_b_y, adjusted_e_y)), all_screens=True) image.show() class Snipper: def __init__(self): self.image = None self.overlays = [] def snip(self): monitors = get_monitors() for monitor in monitors: overlay = Overlay(monitor, self.overlays) self.overlays.append(overlay) if __name__ == '__main__': class App(tk.Tk): def __init__(self,** kwargs): tk.Tk.__init__(self, **kwargs) self.image = None self.windows = [] self.snipper = Snipper() tk.Button(self, text='snip', width=50, command=self.snipper.snip).pack() app = App() app.mainloop()
内容的提问来源于stack exchange,提问作者Jason Fyle
相关产品推荐
相关产品推荐

