Tkinter:无边框拖动窗口,例如:overrideredirect(1)
有没有什么建议可以让用户在没有边框的窗口上拖动,比如用 overridedirect(1)
创建的窗口?
使用场景:我们想创建一个可以漂浮的工具栏/调色板窗口(没有边框),让用户可以在桌面上随意拖动。
这是我目前的想法(伪代码):
window.bind( '<Button-1>', onMouseDown )
用来捕捉鼠标的初始位置。window.bind( '<Motion-1>', onMouseMove )
用来跟踪鼠标开始移动后的位置。计算鼠标移动了多少,并算出
newX
和newY
的新位置。用
window.geometry( '+%d+%d' % ( newX, newY ) )
来移动窗口。
Tkinter 是否提供了足够的功能来让我完成这个任务?或者有没有更简单、更高级的方法来实现我想做的事情?
5 个回答
2
Loïc Faure-Lacroix 的想法很有用,下面是我自己写的一些简单代码,使用的是 Python 3.7.3,希望能帮到你:
from tkinter import *
def move_window(event):
root.geometry(f'+{event.x_root}+{event.y_root}')
root = Tk()
root.bind("<B1-Motion>", move_window)
root.mainloop()
但是,鼠标的位置总是在窗口的左上角。我该怎么做才能让它保持不变呢?期待更好的答案!
感谢 Bryan Oakley,因为一开始我在我的电脑上无法运行你的代码,没太注意。刚刚修改后,运行得很好,之前的问题(鼠标总是在左上角)不再出现了。最近更新的代码如下:
def widget_drag_free_bind(widget):
"""Bind any widget or Tk master object with free drag"""
if isinstance(widget, Tk):
master = widget # root window
else:
master = widget.master
x, y = 0, 0
def mouse_motion(event):
global x, y
# Positive offset represent the mouse is moving to the lower right corner, negative moving to the upper left corner
offset_x, offset_y = event.x - x, event.y - y
new_x = master.winfo_x() + offset_x
new_y = master.winfo_y() + offset_y
new_geometry = f"+{new_x}+{new_y}"
master.geometry(new_geometry)
def mouse_press(event):
global x, y
count = time.time()
x, y = event.x, event.y
widget.bind("<B1-Motion>", mouse_motion) # Hold the left mouse button and drag events
widget.bind("<Button-1>", mouse_press) # The left mouse button press event, long calculate by only once
10
这是我的解决方案:
from tkinter import *
from webbrowser import *
lastClickX = 0
lastClickY = 0
def SaveLastClickPos(event):
global lastClickX, lastClickY
lastClickX = event.x
lastClickY = event.y
def Dragging(event):
x, y = event.x - lastClickX + window.winfo_x(), event.y - lastClickY + window.winfo_y()
window.geometry("+%s+%s" % (x , y))
window = Tk()
window.overrideredirect(True)
window.attributes('-topmost', True)
window.geometry("400x400+500+300")
window.bind('<Button-1>', SaveLastClickPos)
window.bind('<B1-Motion>', Dragging)
window.mainloop()
26
是的,Tkinter提供了足够的功能来实现这个目标,而且没有更简单或更高级的方法来达到你想要的效果。你的想法基本上是正确的。
这里有一个例子,虽然这不是唯一的方法:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.floater = FloatingWindow(self)
class FloatingWindow(tk.Toplevel):
def __init__(self, *args, **kwargs):
tk.Toplevel.__init__(self, *args, **kwargs)
self.overrideredirect(True)
self.label = tk.Label(self, text="Click on the grip to move")
self.grip = tk.Label(self, bitmap="gray25")
self.grip.pack(side="left", fill="y")
self.label.pack(side="right", fill="both", expand=True)
self.grip.bind("<ButtonPress-1>", self.start_move)
self.grip.bind("<ButtonRelease-1>", self.stop_move)
self.grip.bind("<B1-Motion>", self.do_move)
def start_move(self, event):
self.x = event.x
self.y = event.y
def stop_move(self, event):
self.x = None
self.y = None
def do_move(self, event):
deltax = event.x - self.x
deltay = event.y - self.y
x = self.winfo_x() + deltax
y = self.winfo_y() + deltay
self.geometry(f"+{x}+{y}")
app=App()
app.mainloop()