I'm trying to resize certain layered tkinter components, mostly because I'm curious. Right now, seems stuck in trying to resize a frame containing a text widget. here is my attempt:
import tkinter as tk
def make_draggable(widget):
widget.bind("<Button-1>", on_drag_start)
widget.bind("<B1-Motion>", on_drag_motion)
widget.bind("<Button-3>", on_resize_start)
widget.bind("<B3-Motion>", on_resize_motion)
def on_drag_start(event):
widget = event.widget
widget._drag_start_x = event.x
widget._drag_start_y = event.y
def on_drag_motion(event):
widget = event.widget
x = widget.winfo_x() - widget._drag_start_x + event.x
y = widget.winfo_y() - widget._drag_start_y + event.y
widget.place(x=x, y=y)
def on_resize_start(event):
widget = event.widget
widget._resize_start_x = event.x
widget._resize_start_y = event.y
widget._resize_width = widget.winfo_width()
widget._resize_height = widget.winfo_height()
def on_resize_motion(event):
widget = event.widget
width = widget._resize_width + event.x - widget._resize_start_x
height = widget._resize_height + event.y - widget._resize_start_y
widget.place(width=width, height=height)
widget.winfo_children()[0].configure(width=width, height=height)
main = tk.Tk()
frame = tk.Frame(main, bd=4, bg="grey")
frame.place(x=10, y=10)
make_draggable(frame)
notes = tk.Text(frame)
notes.pack()
main.mainloop()
It is based on this other answer on SO.
This works, but only when right-clicking and dragging the mouse on the bottom and right side of the frame (the gray part). I don't know how to make it work on the other directions (eg: top and left, and if possible, the edges too)
How can this be done for all directions?
Note: I'm using 3.8.10 and Tk version 8.6.9 (patch level), on Win10
When you resize from the top or the left you should also be changing the position. In addition, the resizing is reversed. If you drag from the left to the right, the width becomes less and the x increases. So first you need to check which border you are dragging.
def on_resize_motion(event):
widget = event.widget
if widget._resize_start_x < 4:
x = widget.winfo_x() - widget._resize_start_x + event.x
width = widget.winfo_width() - (event.x - widget._resize_start_x)
else:
x = widget.winfo_x()
width = widget._resize_width + event.x - widget._resize_start_x
if widget._resize_start_y < 4:
y = widget.winfo_y() - widget._resize_start_y + event.y
height = widget.winfo_height() - (event.y - widget._resize_start_y)
else:
y = widget.winfo_y()
height = widget._resize_height + event.y - widget._resize_start_y
This subtracts the difference in mouse position if you started on the left or top border. The else part is the same as what you had.
Finally, you need to update both x and y and the size.
widget.place(x=x, y=y, width=width, height=height)