Tkinter: Mouse drag a window without borders, eg. overridedirect(1)

后端 未结 5 1439
说谎
说谎 2020-11-27 20:18

Any suggestions on how one might create event bindings that would allow a user to mouse drag a window without borders, eg. a window created with overridedirect(1)

相关标签:
5条回答
  • 2020-11-27 21:07

    Try this, and it surely works;

    1. Create an event function to move window:

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

    2. Bind window:

      root.bind('', movewindow)

    Now you can touch the the window and drag

    0 讨论(0)
  • 2020-11-27 21:09

    Yes, Tkinter exposes enough functionality to do this, and no, there are no easier/higher-level ways to achive what you want to do. You pretty much have the right idea.

    Here's one example, though it's not the only way:

    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()
    
    0 讨论(0)
  • 2020-11-27 21:16

    The idea of Loïc Faure-Lacroix is useful, the following is my own simple code snippets on Python3.7.3, hope it will help:

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

    But the position of the mouse is always in the upper left corner of the window. How can I keep it unchanged? Looking forward to a better answer!


    Thanks to Bryan Oakley, because at the beginning I couldn't run your code on my computer, I didn't pay attention to it. Just now after the modification, it was very good to run, and the above situation would not happen (the mouse is always in the upper left corner), The updated code recently as follows:

    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
    
    0 讨论(0)
  • 2020-11-27 21:17

    This code is the same as Bryan's solution but it does not use overridedirect.

    It was tested with: python 3.7, Debian GNU/Linux 10 (buster), 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()
    
    0 讨论(0)
  • 2020-11-27 21:18

    Here is my solution:

    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()
    
    0 讨论(0)
提交回复
热议问题