I know how to remove a border from a Tkinter window using overrideredirect
, but whenever I do that the window becomes unresponsive. I can't move it using alt and dragging, or any other method.
I want to make an application that looks like one of those "riced" applications that are just a bare window, and obviously I can't get very far if it just sits unresponsive in the upper-left corner. So, how do I do this?

- 10,297
- 2
- 41
- 62

- 343
- 3
- 10
4 Answers
To make the window draggable, put bindings for <Button-1>
(mouse clicks) and <B1-Motion>
(mouse movements) on the window.
All you need to do is store the x and y values of a mouse down event and then during mouse motion events, you position the window based on the current pointer x and y, delta the original event x and y.
The handler for the mouse click binding stores the original event x and y.
The handler for the mouse movement binding calls the TopLevel method geometry()
to reposition the window, based on current mouse position and the offset you have stored from the most recent mouse click. You supply a geometry string to the geometry method.
Here is a very minimal example which does not take into account the edges of the screen:
import tkinter
class Win(tkinter.Tk):
def __init__(self,master=None):
tkinter.Tk.__init__(self,master)
self.overrideredirect(True)
self._offsetx = 0
self._offsety = 0
self.bind('<Button-1>',self.clickwin)
self.bind('<B1-Motion>',self.dragwin)
def dragwin(self,event):
x = self.winfo_pointerx() - self._offsetx
y = self.winfo_pointery() - self._offsety
self.geometry('+{x}+{y}'.format(x=x,y=y))
def clickwin(self,event):
self._offsetx = event.x
self._offsety = event.y
win = Win()
win.mainloop()
EDIT by TheLizzard:
The code above works but doesn't behave correctly when there is more than one widget so this is the fixed code:
import tkinter as tk
class Win(tk.Tk):
def __init__(self):
super().__init__()
super().overrideredirect(True)
self._offsetx = 0
self._offsety = 0
super().bind("<Button-1>" ,self.clickwin)
super().bind("<B1-Motion>", self.dragwin)
def dragwin(self,event):
x = super().winfo_pointerx() - self._offsetx
y = super().winfo_pointery() - self._offsety
super().geometry(f"+{x}+{y}")
def clickwin(self,event):
self._offsetx = super().winfo_pointerx() - super().winfo_rootx()
self._offsety = super().winfo_pointery() - super().winfo_rooty()
root = Win()
label_1 = tk.Label(root, text="Label 1")
label_1.pack(side="left")
label_2 = tk.Label(root, text="Label 2")
label_2.pack(side="left")
root.mainloop()

- 7,248
- 2
- 11
- 31

- 865
- 9
- 15
-
1I had just fixed the issue with the window jumping in your code, use ButtonPress-1 instead of Button-1 – omgimdrunk Jan 23 '17 at 11:08
-
2Unfortunately, my window is still jumping - only if I click the far bottom-right edge it is not. – Alex Dec 14 '17 at 12:15
Thanks to @dusty's answer, it had a jumping problem, and I solved it by saving the window location.
import tkinter
class Win(tkinter.Tk):
def __init__(self,master=None):
tkinter.Tk.__init__(self,master)
self.overrideredirect(True)
self._offsetx = 0
self._offsety = 0
self._window_x = 500
self._window_y = 100
self._window_w = 500
self._window_h = 500
self.geometry('{w}x{h}+{x}+{y}'.format(w=self._window_w,h=self._window_h,x=self._window_x,y=self._window_y))
self.bind('<Button-1>',self.clickwin)
self.bind('<B1-Motion>',self.dragwin)
def dragwin(self,event):
delta_x = self.winfo_pointerx() - self._offsetx
delta_y = self.winfo_pointery() - self._offsety
x = self._window_x + delta_x
y = self._window_y + delta_y
self.geometry("+{x}+{y}".format(x=x, y=y))
self._offsetx = self.winfo_pointerx()
self._offsety = self.winfo_pointery()
self._window_x = x
self._window_y = y
def clickwin(self,event):
self._offsetx = self.winfo_pointerx()
self._offsety = self.winfo_pointery()
win = Win()
win.mainloop()
self._window_x
and self._window_y
are the primary position of the window.
self._window_h
and self._window_w
are the height and width of the window.

- 1,420
- 6
- 17
This solution is works for me:
from tkinter import *
import mouse
global x, y
def standard_bind():
root.bind('<B1-Motion>', lambda e: event(e, Mode=True))
def event(widget, Mode=False):
global x, y
if Mode:
x = widget.x
y = widget.y
root.bind('<B1-Motion>', lambda e: event(e))
root.geometry('+%d+%d' % (mouse.get_position()[0]-x, mouse.get_position()[1]-y))
root = Tk()
root.overrideredirect(True)
root.bind('<B1-Motion>', lambda e: event(e, Mode=True))
root.bind('<ButtonRelease-1>', lambda e: standard_bind())
root.geometry('%dx%d+%d+%d' % (600, 60, 50, 50))
mainloop()

- 1
- 1
-
You should describe what the code does and why, instead of pasting just plain code. – Aleksander Ikleiw Sep 08 '20 at 18:32
-
There is no point to using the `mouse` module and this code doesn't follow PEP 8. Also the first parameter of your `event` function is not a widget it is a `tkinter.Event` object. – TheLizzard Aug 07 '21 at 19:14
Here a bit more sophisticated method which assumes that you don't want to just click any where on the tkinter app to move it, but rather clicking on the title bar to move the app around while retaining the familiar "X" to close the app.
Works for python3.0 and later
Since tkinter does not (by default) allow you to directly achieve this, we must:
- Remove the tkinter frame's title bar
- Create our own title bar and recreate the "x" for closing the app
- bind the event for clicking, such that the app moves when dragged
from tkinter import * root = Tk() root.title('The Name of Your Application') root.geometry("500x300") # remove title bar root.overrideredirect(True) def move_app(e): root.geometry(f'+{e.x_root}+{e.y_root}') def quitter(e): root.quit() #root.destroy() # Create Fake Title Bar title_bar = Frame(root, bg="darkgreen", relief="raised", bd=0) title_bar.pack(expand=1, fill=X) # Bind the titlebar title_bar.bind("<B1-Motion>", move_app) # Create title text title_label = Label(title_bar, text=" My Awesome App!!", bg="darkgreen", fg="white") title_label.pack(side=LEFT, pady=4) # Create close button on titlebar close_label = Label(title_bar, text=" X ", bg="darkgreen", fg="white", relief="sunken", bd=0) close_label.pack(side=RIGHT, pady=4) close_label.bind("<Button-1>", quitter) my_button = Button(root, text="CLOSE!", font=("Helvetica, 32"), command=root.quit) my_button.pack(pady=100) root.mainloop()

- 134
- 1
- 7