1

So after posting another question about this issue I realised the problem was only happening with my custom resize bind. When I resize the window by the default edges of the window the Issue does not happen and the contents of the canvas is drawn accurately - however when using my custom resize bind the contents of the canvas is laggy and lags behind the true position of the window.

import tkinter as tk


def resize(self, event=None):
    y=root.winfo_height()

    x1 = root.winfo_pointerx()
    x0 = root.winfo_rootx()

    root.geometry("%sx%s" % (x1-x0,y))

root=tk.Tk()

canvas = tk.Canvas(root,bg='red')

canvas.pack(padx=20,pady=20)

inside=tk.Frame(root)
inside.pack(fill='both')

for i in range(10):
    x=tk.Label(inside,text='Lsdkfjhaskfjhskljdfhaskjfhksfhkjasdhf')
    x.pack()

g=tk.Button(root,text='Drag to resize')

g.bind('<B1-Motion>',resize)
g.pack()

canvas.create_window(5,5,window=inside,anchor='nw')

Original content: enter image description here

Screenshot while resizing window with manual bind via button - as you can see the content is not visible while resizing the window and lags behind where the canvas is.

enter image description here

The issue is fixed if I call root.update() at the start of my resize function however this then causes a recursion depth error to the thousands of calls being made to update in such a small period of time.

Finally to repeat. When resizing with the default window Resize nudges at the edge of the window the canvas resizes perfectly with perfect draw rate and the content stays visible all the time. Why is my binding not acting the same way?

Maks Ovnik
  • 65
  • 9
  • Without code, your question is far too vague. Generally speaking, calling `update` is not the correct solution, but that depends on the exact nature of the problem you are trying to solve. – Bryan Oakley Nov 27 '19 at 21:33
  • ***"Calling `root.update()`"***: If you have to use `.update()` you are doing something special or probably **very wrong**. Read [Tkinter understanding mainloop](https://stackoverflow.com/questions/29158220/tkinter-understanding-mainloop). ***"speed up the draw rate of a Scrollable Canvas"***: Read [how-to-limit-the-number-of-events-generated-by-widget](https://stackoverflow.com/questions/58906587/how-to-limit-the-number-of-events-generated-by-widget) – stovfl Nov 27 '19 at 21:44
  • @MaksOvnik: It's not clear what you want to accomplish? You assign `.Frame(root)` to `root` instead of `canvas` then you layout it using `.create_window(...,window=inside ...`. You bind `.bind(''` to a `Button` and resize the whole `root` window with `root.geometry(...`. – stovfl Nov 28 '19 at 09:17
  • The frame is meant to be assigned to the canvas however this doesn't change the problem at all. When you put your mouse near the right side boundary of a program a little cursor appears that lets you resize the window. Try clicking the button, holding it down and dragging your mouse to the right. I want the window to resize in a normal manner, the same way that it does when using the default windows bind. However when using my custom event catching method. The contents of the canvas glitches. – Maks Ovnik Nov 28 '19 at 11:46
  • @MaksOvnik Read [how-can-you-profile-a-python-script?](https://stackoverflow.com/questions/582336/how-can-you-profile-a-python-script?), compare with the *default* and find the bottelneck. – stovfl Nov 28 '19 at 17:02

2 Answers2

4

Geometry calculations are quite complex in general (and Tk has some fairly sophisticated solvers behind the scenes for handling them) so they only run when the GUI is considered to be "idle". Idleness occurs when the event queue would otherwise block, waiting for the next message from the external world, i.e., when there's nothing else queued up for immediate attention. Tk also postpones redrawing (another actually really expensive operation) the same way; it makes the UI seem far faster than it really is. This was critical back 20 years ago and more, and yet is still really useful now.

But it breaks if there there is a total flood of events coming in, and drags can do that, especially when there's resizing involved. That's why you can do update idletasks (in Tcl/Tk notation) and update_idletasks() (in Tkinter notation). That that does is immediately process all the pending idle event callbacks without taking further real events, running the pending resize computations and redraws. It is far less likely to trigger reentrant event processing than a full update(), which is the problem you were hitting (and why update is considered harmful under normal circumstances).

Note that it is important to let the event loop itself have some time to process still, as parts of handling widget resizes are inevitably done via real events (as they impact upon the OS/GUI). By far the best way to do that is to just make sure to return normally from your event handlers as soon as practical.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • Hi thanks, I tried using update_idletasks however it seemed to make no difference on the draw rate of the canvas and it still performs slowly in relation to the windows resize bind. Is there not a way I can copy the way windows handles resizing in a method that runs when the bind is triggered. – Maks Ovnik Nov 30 '19 at 21:06
-1

Are you using the right bind event? Try ''

g.bind('<ButtonRelease-1>',resize)
Daniel Huckson
  • 1,157
  • 1
  • 13
  • 35
  • This moves the window when I release my mouse but I want standard window behaviour where the window is resized live. This works fine with the standard Windows 10 bind however using my Button which should work exactly the same produces tearing issues. – Maks Ovnik Nov 28 '19 at 00:01
  • @Maks Ovnik; I'm on Linux KDE and your code works the same if I size by using the boarder or the Button. I get no tearing. – Daniel Huckson Nov 28 '19 at 00:10