|
19 | 19 | :bases: |
20 | 20 | """ |
21 | 21 | import copy |
| 22 | +import gc |
22 | 23 | import logging |
23 | 24 | import enum |
24 | 25 | import types |
|
34 | 35 | from AnyQt.QtWidgets import QWidget, QAction |
35 | 36 | from AnyQt.QtGui import QWhatsThisClickedEvent |
36 | 37 |
|
37 | | -from AnyQt.QtCore import Qt, QCoreApplication, QEvent, QByteArray |
| 38 | +from AnyQt.QtCore import Qt, QCoreApplication, QEvent, QByteArray, QTimer |
38 | 39 | from AnyQt.QtCore import pyqtSlot as Slot |
39 | 40 |
|
40 | 41 | from orangecanvas.registry import WidgetDescription, OutputSignal |
@@ -213,6 +214,8 @@ def __init__(self, parent=None, **kwargs): |
213 | 214 |
|
214 | 215 | # Tracks the widget in the update loop by the SignalManager |
215 | 216 | self.__updating_widget = None # type: Optional[OWBaseWidget] |
| 217 | + self.__gc_timer = QTimer(self, singleShot=True, interval=100, objectName="gc-timer") |
| 218 | + self.__gc_timer.timeout.connect(self.__run_gc) |
216 | 219 |
|
217 | 220 | def set_scheme(self, scheme): |
218 | 221 | """ |
@@ -364,24 +367,30 @@ def __delete_item(self, item): |
364 | 367 | "Deferring deletion.", widget, item.state) |
365 | 368 | self.__delay_delete[widget] = item |
366 | 369 | else: |
367 | | - widget.processingStateChanged.disconnect( |
368 | | - self.__on_widget_state_changed) |
369 | | - widget.widgetStateChanged.disconnect( |
370 | | - self.__on_widget_state_changed) |
371 | | - widget.deleteLater() |
372 | | - item.widget = None |
| 370 | + self.__delete_widget(item) |
373 | 371 |
|
374 | 372 | def __try_delete(self, item): |
375 | 373 | if not item.state & WidgetManager.DelayDeleteMask: |
376 | | - widget = item.widget |
377 | | - log.debug("Delayed delete for widget %s", widget) |
378 | | - widget.widgetStateChanged.disconnect( |
379 | | - self.__on_widget_state_changed) |
380 | | - widget.processingStateChanged.disconnect( |
381 | | - self.__on_widget_state_changed) |
382 | | - item.widget = None |
383 | | - widget.deleteLater() |
384 | | - del self.__delay_delete[widget] |
| 374 | + log.debug("Delayed delete for widget %s", item.widget) |
| 375 | + self.__delete_widget(item) |
| 376 | + |
| 377 | + def __delete_widget(self, item: Item): |
| 378 | + widget = item.widget |
| 379 | + log.info("Disposing of widget '%s'", widget.captionTitle) |
| 380 | + widget.widgetStateChanged.disconnect( |
| 381 | + self.__on_widget_state_changed) |
| 382 | + widget.processingStateChanged.disconnect( |
| 383 | + self.__on_widget_state_changed) |
| 384 | + item.widget = None |
| 385 | + widget.deleteLater() |
| 386 | + self.__delay_delete.pop(widget, None) |
| 387 | + self.__gc_timer.start() |
| 388 | + |
| 389 | + @Slot() |
| 390 | + def __run_gc(self): |
| 391 | + log.debug("Running gc.collect()") |
| 392 | + n = gc.collect() |
| 393 | + log.debug(f"gc.collect() collected {n} objects") |
385 | 394 |
|
386 | 395 | def create_widget_instance(self, node): |
387 | 396 | # type: (SchemeNode) -> OWBaseWidget |
|
0 commit comments