'Why is canvas.create_rectangle not working when used in tkinter.after()

I am trying to display an overlay using the overlay package which is built on top of tkinter. When I run this process, the output is correct and I see the overlay displays the correct fill colors (i.e. 3 rectangles are green, red, blue)

_overlay = Overlay(
  window.data["kCGWindowBounds"]["X"],
  window.data["kCGWindowBounds"]["Y"]
)

screen = Screen(
  window.data["kCGWindowBounds"]["X"], 
  window.data["kCGWindowBounds"]["Y"], 
  window.data["kCGWindowBounds"]["Height"], 
  window.data["kCGWindowBounds"]["Width"]
)

screen.capture()

pattern = Pattern()
pattern.convertImageToRGB()

pixelOne = pattern.getColorOnePixel()
pixelTwo = pattern.getColorTwoPixel()

_overlay.displayPattern(pixelOne, pixelTwo)

overlay.Window.launch()

...

def displayPattern(self, pixelOne, pixelTwo):
  colors = COLOR_ONE_PIXEL_MAP.get(pixelOne, "Undefined") + COLOR_TWO_PIXEL_MAP.get(pixelTwo, "Undefined")

  pattern = COLOR_PATTERN_MAP.get(colors, "Undefined")

  canvas = tk.Canvas(
    self.window.root,
    width=162,
    height=12,
    bd=0,
    highlightthickness=0
  )

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

  if pattern != "Undefined":
    print(pattern)

    canvas.create_rectangle(-1, -1, 54, 12, fill=COLOR_FILL_MAP.get(pattern[:2]), outline=COLOR_FILL_MAP.get(pattern[:2]))
    canvas.create_rectangle(54, -1, 108, 12, fill=COLOR_FILL_MAP.get(pattern[3] + pattern[4]), outline=COLOR_FILL_MAP.get(pattern[3] + pattern[4]))
    canvas.create_rectangle(108, -1, 162, 12, fill=COLOR_FILL_MAP.get(pattern[6] + pattern[7]), outline=COLOR_FILL_MAP.get(pattern[6] + pattern[7]))

    self.window.root.update()

Now I need to continue to run this process so that when information on the window that the program is using updates, this function gets run again. So I update this logic to this:

overlay.Window.after(
  500, 
  proceed, 
  window.data["kCGWindowBounds"]["X"], 
  window.data["kCGWindowBounds"]["Y"], 
  window.data["kCGWindowBounds"]["Height"], 
  window.data["kCGWindowBounds"]["Width"]
)

overlay.Window.launch()

...

def proceed(x, y, height, width):
  while True:
    screen = Screen(
      x,
      y,
      height,
      width
    )

    screen.capture()

    pattern = Pattern()
    pattern.convertImageToRGB()

    pixelOne = pattern.getColorOnePixel()
    pixelTwo = pattern.getColorTwoPixel()

    _overlay.displayPattern(pixelOne, pixelTwo)

    time.sleep(.5)

I'm seeing the correct output in the print() (i.e. GG RR BB green red blue), but those fill colors are no longer being applied to the canvas.create_rectangle method. Is there something I'm missing with the after() process and packing tkinter canvas elements?



Solution 1:[1]

tkinter (like other GUIs) doesn't draw/update elements at once but it waits for end of your function to redraw/update all elements in one moment - this way it has less work and window doesn't blink.

Problem is that your function runs while True so it never ends.

You may use root.update() inside loop to force tkinter to redraw elements

def proceed(x, y, height, width):
  while True:
    screen = Screen(
      x,
      y,
      height,
      width
    )

    screen.capture()

    pattern = Pattern()
    pattern.convertImageToRGB()

    pixelOne = pattern.getColorOnePixel()
    pixelTwo = pattern.getColorTwoPixel()

    _overlay.displayPattern(pixelOne, pixelTwo)

    overlay.Window.update()   # <--- force tkinter to redraw/update window

    time.sleep(.5)

OR you can use after(500, process, ...) instead of while True and time.sleep()

def proceed(x, y, height, width):

    screen = Screen(
      x,
      y,
      height,
      width
    )

    screen.capture()

    pattern = Pattern()
    pattern.convertImageToRGB()

    pixelOne = pattern.getColorOnePixel()
    pixelTwo = pattern.getColorTwoPixel()

    _overlay.displayPattern(pixelOne, pixelTwo)

    overlay.Window.after(500, process, x, y, height, width)  # <--- run again after 500ms

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 furas