Tkinter:鼠标拖动没有边框的窗口,例如。 overridedirect(1)

时间:2010-10-29 19:35:23

标签: python windows user-interface window tkinter

关于如何创建允许用户鼠标拖动无边界窗口的事件绑定的任何建议,例如。使用overridedirect(1)创建的窗口?

使用案例:我们想创建一个浮动工具栏/调色板窗口(没有边框),我们的用户可以在桌面上拖动它们。

这就是我的想法(伪代码):

  1. window.bind( '<Button-1>', onMouseDown )捕获鼠标的初始位置。

  2. window.bind( '<Motion-1>', onMouseMove )在鼠标开始移动时跟踪鼠标的位置。

  3. 计算移动了多少鼠标并计算newXnewY个位置。

  4. 使用window.geometry( '+%d+%d' % ( newX, newY ) )移动窗口。

  5. Tkinter是否提供足够的功能以允许我实施手头的任务?或者是否有更容易/更高级别的方法来实现我想要做的事情?

5 个答案:

答案 0 :(得分:10)

是的,Tkinter公开了足够的功能来做到这一点,不,没有更容易/更高级别的方法来实现你想做的事情。你几乎有正确的想法。

这是一个例子:

import Tkinter as tk
import tkFileDialog 

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.StartMove)
        self.grip.bind("<ButtonRelease-1>", self.StopMove)
        self.grip.bind("<B1-Motion>", self.OnMotion)

    def StartMove(self, event):
        self.x = event.x
        self.y = event.y

    def StopMove(self, event):
        self.x = None
        self.y = None

    def OnMotion(self, event):
        deltax = event.x - self.x
        deltay = event.y - self.y
        x = self.winfo_x() + deltax
        y = self.winfo_y() + deltay
        self.geometry("+%s+%s" % (x, y))



app=App()
app.mainloop()

答案 1 :(得分:2)

这是我的解决方案:

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()

答案 2 :(得分:1)

试试这个,它肯定有效;

  1. 创建一个事件函数来移动窗口:

    def movewindow(事件):         root.geometry('+ {0} + {1}'。format(event.x_root,event.y_root))

  2. 绑定窗口:

    root.bind('',movewindow)

  3. 现在您可以触摸窗口并拖动

答案 3 :(得分:0)

此代码与Bryan的解决方案相同,但不使用overridedirect。

它已通过以下测试:python 3.7,Debian GNU / Linux 10(破坏者),Gnome 3.30

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.resizable(0, 0)  # Window not resizable
        self.wm_attributes('-type', 'splash')  # Hide title bar (Linux)

        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.StartMove)
        self.grip.bind("<ButtonRelease-1>", self.StopMove)
        self.grip.bind("<B1-Motion>", self.OnMotion)

    def StartMove(self, event):
        self.x = event.x
        self.y = event.y

    def StopMove(self, event):
        self.x = None
        self.y = None

    def OnMotion(self, event):
        deltax = event.x - self.x
        deltay = event.y - self.y
        x = self.winfo_x() + deltax
        y = self.winfo_y() + deltay
        self.geometry("+%s+%s" % (x, y))


app = App()
app.mainloop()

答案 4 :(得分:0)

LoïcFaure-Lacroix的想法很有用,以下是我在Python3.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