| 587 | mb.showerror("Error", "Interactive HTML not found. Click Visualize! first.") |
| 588 | |
| 589 | def load_image(self): |
| 590 | if not hasattr(self, '_zoom_factor'): |
| 591 | self._zoom_factor = 1.0 |
| 592 | self.base.resizable(True, True) |
| 593 | self.base.geometry("1100x780") |
| 594 | |
| 595 | # Destroy previous canvas so its <Configure> binding stops firing |
| 596 | if hasattr(self, 'canvas') and self.canvas and self.canvas.winfo_exists(): |
| 597 | self.canvas.destroy() |
| 598 | |
| 599 | self._src_img = None # cached PIL source; cleared when image_file changes |
| 600 | self._src_img_path = None |
| 601 | self._resize_job = None # pending debounce after-id |
| 602 | |
| 603 | self.canvas = Canvas(self.ThirdFrame, bd=0, bg="grey", |
| 604 | xscrollcommand=self.xscrollbar.set, |
| 605 | yscrollcommand=self.yscrollbar.set) |
| 606 | self.canvas.grid(column=0, row=0, sticky=(N, W, E, S)) |
| 607 | self.xscrollbar.config(command=self.canvas.xview) |
| 608 | self.yscrollbar.config(command=self.canvas.yview) |
| 609 | self.canvas.bind("<Configure>", self._on_canvas_resize) |
| 610 | |
| 611 | def _on_canvas_resize(self, event): |
| 612 | """Debounce rapid <Configure> events — only redraw after 120ms of quiet.""" |