I’m working on a form with around 70 TextBox inputs, each bound to fields in self.item via write-back data binding (e.g., self.item[‘Value_1’], …, self.item[‘Value_70’]).
Each of these inputs is supposed to trigger a redraw of a Canvas using this method:
def canvas_cartridge_reset(self, **event_args):
if not self.item:
return
for key, value in self.item.items():
print(f"{key}: {value}")
self.canvas_cartridge.clear_rect(
0, 0,
self.canvas_cartridge.get_width(),
self.canvas_cartridge.get_height()
)
draw.draw_cartridge(self.canvas_cartridge, self.item)
I’m calling this method from the change, lost_focus, and enter_pressed events of the text boxes.
The method fires on all three events — I can confirm that from the print statements. The dictionary self.item is fully populated on all events. However, the canvas only visually updates when triggered by lost_focus or enter_pressed, not on change.
Interestingly, I use a nearly identical setup in another form and it works fine with change events there — so I’m stumped.
Has anyone seen this behavior before? Any insight into why the canvas doesn’t redraw on the change event?
I don’t know what’s happening with your specific situation, but in general, you should draw the state of the canvas on its own reset event handler, and when you want it to repaint call the canvas’ reset_context() function. Then you’re not relying on the canvas to realize it needs to update its visual appearance, and all your drawing code is in one spot.
I often run into two types of issues when working with canvases: either the redraw doesn’t happen when it should, or it happens too frequently — and quite often both problems occur in the same app.
To address the first issue (missed redraws), I end up calling the redraw logic from an increasing number of events to ensure it eventually runs.
But this creates the second issue (excessive redraws), which I solve using a debounced redraw mechanism with a timer. I define two functions — schedule_redraw() and perform_redraw().
schedule_redraw() sets the timer interval to 0.1 seconds and returns immediately.
The timer’s tick event triggers perform_redraw(), which does the actual canvas drawing and then disables the timer by setting the interval back to 0.
This way, multiple rapid redraw triggers are collapsed into a single one, avoiding unnecessary redraws.
You might also find this related thread helpful — it describes a similar issue with redrawing custom components: