Skip to content

Commit 6fbc375

Browse files
authored
Bugfix uninitilized variable access introduced on #123 (#141)
* Del: reference to uninitialized QGraphicsView variable When there is no thumbnail for the current print, we shouldn't referece `self.thumbnail_view` since it hasn't been initialized. When the print stops for whatever reason we want to delete the object, but if it hasn't been initilialized there is nothing to delete. So we must only delete when the print stops if the class has been attributed. * Added clear thumbnail object on print stop * Small refactor, exit method when page is not visible * Calculate and scale thumbnail pixmap on set When setting the pixmap on the progress bar, the image was not scaled and the inner rect was not calculated. This resulted in the pixmap not showing. Now when setting the progressbar thumbnail this is calculated so that the pixmap can be shown in the middle of the progress bar circumference. * Del forgotten print() * Refactor and handle show event Refactored some methods, including accessing values in dicts, by using .get(). Now the slot `on_fileinfo` only runs when the `jobStatusPage` is visible this is because the request for file information is done on `file.py` and the confirmation page. This whould result in the slot triggering multiple times before it was actually necessary and on asking for imformation for all files, while we only want information on one file. Now the request for file information is done when the `jobStatusPage` is actually visible. The `showEvent` method requests the file information when that event is triggered on the class. * Split print state logic into seperate method Split the state logic in a seperate method (`_handle_print_state(state: str))` just so it's more readable than handling all `print_status` object updates in a single method. It was getting to big of a method. * Change print state event dispatch logic
1 parent 6f4c3e3 commit 6fbc375

2 files changed

Lines changed: 89 additions & 106 deletions

File tree

‎BlocksScreen/lib/panels/widgets/jobStatusPage.py‎

Lines changed: 78 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ def toggle_thumbnail_expansion(self) -> None:
8585
self.headerWidget.show()
8686
self.show()
8787

88+
def showEvent(self, a0) -> None:
89+
"""Reimplemented method, handle `show` Event"""
90+
if self._current_file_name:
91+
self.request_file_info.emit(self._current_file_name)
92+
8893
def eventFilter(self, sender_obj: QtCore.QObject, event: events.QEvent) -> bool:
8994
"""Filter events,
9095
@@ -110,9 +115,7 @@ def _load_thumbnails(self, *thumbnails) -> None:
110115
logger.debug("Unable to load thumbnails, no thumbnails provided")
111116
return
112117
self.create_thumbnail_widget()
113-
self.thumbnail_view.installEventFilter(
114-
self
115-
) # Filter events on this widget, for clicks
118+
self.thumbnail_view.installEventFilter(self)
116119
scene = QtWidgets.QGraphicsScene()
117120
_biggest_thumb = self.thumbnail_graphics[-1]
118121
self.thumbnail_view.setSceneRect(
@@ -172,11 +175,13 @@ def on_print_start(self, file: str) -> None:
172175
else:
173176
raise TypeError("QApplication.instance expected non None value")
174177
except Exception as e:
175-
logger.debug(f"Unexpected error while posting print job start event: {e}")
178+
logger.debug("Unexpected error while posting print job start event: %s", e)
176179

177180
@QtCore.pyqtSlot(dict, name="on_fileinfo")
178181
def on_fileinfo(self, fileinfo: dict) -> None:
179182
"""Handle received file information/metadata"""
183+
if not self.isVisible():
184+
return
180185
self.total_layers = str(fileinfo.get("layer_count", "?"))
181186
self.layer_display_button.setText("?")
182187
self.layer_display_button.secondary_text = str(self.total_layers)
@@ -185,24 +190,59 @@ def on_fileinfo(self, fileinfo: dict) -> None:
185190

186191
@QtCore.pyqtSlot(name="pause_resume_print")
187192
def pause_resume_print(self) -> None:
188-
"""Handle pause/resume print job"""
189-
if not getattr(self, "_pause_locked", False):
190-
self._pause_locked = True
191-
self.pause_printing_btn.setEnabled(False)
192-
193-
if self._internal_print_status == "printing":
194-
self.print_pause.emit()
195-
self._internal_print_status = "paused"
196-
197-
elif self._internal_print_status == "paused":
198-
self.print_resume.emit()
199-
self._internal_print_status = "printing"
200-
201-
QtCore.QTimer.singleShot(5000, self._unlock_pause_button)
202-
203-
def _unlock_pause_button(self):
204-
self._pause_locked = False
205-
self.pause_printing_btn.setEnabled(True)
193+
"""Handle pause/resume print job button clicked"""
194+
self.pause_printing_btn.setEnabled(False)
195+
if self._internal_print_status == "printing":
196+
self._internal_print_status = "paused"
197+
self.print_pause.emit()
198+
elif self._internal_print_status == "paused":
199+
self._internal_print_status = "printing"
200+
self.print_resume.emit()
201+
202+
def _handle_print_state(self, state: str) -> None:
203+
"""Handle print state change received from
204+
printer_status object updated
205+
"""
206+
valid_states = {"printing", "paused"}
207+
invalid_states = {"cancelled", "complete", "error", "standby"}
208+
lstate = state.lower()
209+
if lstate in valid_states:
210+
self._internal_print_status = lstate
211+
if lstate == "paused":
212+
self.pause_printing_btn.setText(" Resume")
213+
self.pause_printing_btn.setPixmap(
214+
QtGui.QPixmap(":/ui/media/btn_icons/play.svg")
215+
)
216+
elif lstate == "printing":
217+
self.pause_printing_btn.setText("Pause")
218+
self.pause_printing_btn.setPixmap(
219+
QtGui.QPixmap(":/ui/media/btn_icons/pause.svg")
220+
)
221+
self.pause_printing_btn.setEnabled(True)
222+
self.request_query_print_stats.emit({"print_stats": ["filename"]})
223+
self.show_request.emit()
224+
lstate = "start"
225+
elif lstate in invalid_states:
226+
self._current_file_name = ""
227+
self._internal_print_status = ""
228+
self.total_layers = "?"
229+
self.file_metadata.clear()
230+
self.hide_request.emit()
231+
if hasattr(self, "thumbnail_view"):
232+
getattr(self, "thumbnail_view").deleteLater()
233+
# Send Event on Print state
234+
if hasattr(events, str("Print" + lstate.capitalize())):
235+
event_obj = getattr(events, str("Print" + lstate.capitalize()))
236+
event = event_obj(self._current_file_name, self.file_metadata)
237+
instance = QtWidgets.QApplication.instance()
238+
if instance:
239+
instance.postEvent(self.window(), event)
240+
return
241+
logger.error(
242+
"QApplication.instance expected non None value,\
243+
Unable to post event %s",
244+
str("Print" + lstate.capitalize()),
245+
)
206246

207247
@QtCore.pyqtSlot(str, dict, name="on_print_stats_update")
208248
@QtCore.pyqtSlot(str, float, name="on_print_stats_update")
@@ -216,82 +256,42 @@ def on_print_stats_update(self, field: str, value: dict | float | str) -> None:
216256
value (dict | float | str): The value for the field.
217257
"""
218258
if isinstance(value, str):
259+
if "state" in field:
260+
self._handle_print_state(value)
219261
if "filename" in field:
220262
self._current_file_name = value
221263
if self.js_file_name_label.text().lower() != value.lower():
222264
self.js_file_name_label.setText(self._current_file_name)
223-
self.request_file_info.emit(value) # Request file metadata
224-
if "state" in field:
225-
if value.lower() == "printing" or value == "paused":
226-
self._internal_print_status = value
227-
if value == "paused":
228-
self.pause_printing_btn.setText(" Resume")
229-
self.pause_printing_btn.setPixmap(
230-
QtGui.QPixmap(":/ui/media/btn_icons/play.svg")
231-
)
232-
elif value == "printing":
233-
self.pause_printing_btn.setText("Pause")
234-
self.pause_printing_btn.setPixmap(
235-
QtGui.QPixmap(":/ui/media/btn_icons/pause.svg")
236-
)
237-
self.request_query_print_stats.emit({"print_stats": ["filename"]})
238-
self.show_request.emit()
239-
value = "start" # This is for event compatibility
240-
elif value in ("cancelled", "complete", "error", "standby"):
241-
self._current_file_name = ""
242-
self._internal_print_status = ""
243-
self.total_layers = "?"
244-
self.file_metadata.clear()
245-
self.hide_request.emit()
246-
self.thumbnail_view.deleteLater()
247-
self.thumbnail_view_layout.deleteLater()
248-
249-
if hasattr(events, str("Print" + value.capitalize())):
250-
event_obj = getattr(events, str("Print" + value.capitalize()))
251-
event = event_obj(self._current_file_name, self.file_metadata)
252-
try:
253-
instance = QtWidgets.QApplication.instance()
254-
if instance:
255-
instance.postEvent(self.window(), event)
256-
else:
257-
raise TypeError(
258-
"QApplication.instance expected non None value"
259-
)
260-
except Exception as e:
261-
logger.info(
262-
f"Unexpected error while posting print job start event: {e}"
263-
)
264-
265+
if self.isVisible():
266+
self.request_file_info.emit(value)
265267
if not self.file_metadata:
266268
return
269+
if not self.isVisible():
270+
return
267271
if isinstance(value, dict):
268272
if "total_layer" in value.keys():
269-
self.total_layers = value["total_layer"]
273+
self.total_layers = value.get("total_layer", "?")
270274
self.layer_display_button.secondary_text = str(self.total_layers)
271275
if "current_layer" in value.keys():
272-
if value["current_layer"] is not None:
273-
_current_layer = value["current_layer"]
274-
if _current_layer is not None:
275-
self.layer_display_button.setText(f"{int(_current_layer)}")
276+
_current_layer = value.get("current_layer", None)
277+
if _current_layer:
278+
self.layer_display_button.setText(f"{int(_current_layer)}")
276279
elif isinstance(value, float):
277280
if "total_duration" in field:
278-
self.print_total_duration = value
279-
_time = estimate_print_time(int(self.print_total_duration))
281+
_time = estimate_print_time(int(value))
280282
_print_time_string = (
281283
f"{_time[0]}Day {_time[1]}H {_time[2]}min {_time[3]} s"
282284
if _time[0] != 0
283285
else f"{_time[1]}H {_time[2]}min {_time[3]}s"
284286
)
285287
self.print_time_display_button.setText(_print_time_string)
286-
elif "print_duration" in field:
287-
self.current_print_duration_seconds = value
288-
elif "filament_used" in field:
289-
self.filament_used_mm = value
290288

291289
@QtCore.pyqtSlot(str, list, name="on_gcode_move_update")
292290
def on_gcode_move_update(self, field: str, value: list) -> None:
293291
"""Handle gcode move"""
294-
if "gcode_position" in field: # Without offsets
292+
if not self.isVisible():
293+
return
294+
if "gcode_position" in field:
295295
if self._internal_print_status == "printing":
296296
_current_layer = calculate_current_layer(
297297
z_position=value[2],
@@ -314,12 +314,10 @@ def virtual_sdcard_update(self, field: str, value: float | bool) -> None:
314314
field (str): Name of the updated field on the virtual_sdcard object
315315
value (float | bool): The updated information for the corresponding field
316316
"""
317-
if isinstance(value, bool):
318-
...
317+
if not self.isVisible():
318+
return
319319
if "progress" == field:
320320
self.printing_progress_bar.setValue(value)
321-
if "file_position" == field:
322-
...
323321

324322
def _setupUI(self) -> None:
325323
"""Setup widget ui"""
@@ -330,8 +328,6 @@ def _setupUI(self) -> None:
330328
sizePolicy.setHorizontalStretch(1)
331329
sizePolicy.setVerticalStretch(1)
332330
sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
333-
# ----------------------------------size policy
334-
335331
self.setSizePolicy(sizePolicy)
336332
self.setMinimumSize(QtCore.QSize(710, 420))
337333
self.setMaximumSize(QtCore.QSize(720, 420))
@@ -369,7 +365,6 @@ def _setupUI(self) -> None:
369365
font = QtGui.QFont()
370366
font.setFamily("Montserrat")
371367
font.setPointSize(14)
372-
# ------------------------------Header
373368
self.js_file_name_icon = BlocksLabel(parent=self)
374369
self.js_file_name_icon.setSizePolicy(sizePolicy)
375370
self.js_file_name_icon.setMinimumSize(QtCore.QSize(60, 60))
@@ -383,7 +378,6 @@ def _setupUI(self) -> None:
383378
QtGui.QPixmap(":/files/media/btn_icons/file_icon.svg"),
384379
)
385380
self.js_file_name_icon.setObjectName("js_file_name_icon")
386-
387381
self.js_file_name_label = BlocksLabel(parent=self)
388382
self.js_file_name_label.setEnabled(True)
389383
self.js_file_name_label.setSizePolicy(sizePolicy)
@@ -395,7 +389,6 @@ def _setupUI(self) -> None:
395389
self.js_file_name_label.setObjectName("js_file_name_label")
396390
self.job_status_header_layout.addWidget(self.js_file_name_icon)
397391
self.job_status_header_layout.addWidget(self.js_file_name_label)
398-
# -----------------------------buttons
399392
font.setPointSize(18)
400393
self.pause_printing_btn = BlocksCustomButton(self)
401394
self.pause_printing_btn.setSizePolicy(sizePolicy)
@@ -430,45 +423,34 @@ def _setupUI(self) -> None:
430423
self.tune_menu_btn.setText("Tune")
431424
self.stop_printing_btn.setText("Cancel")
432425
self.pause_printing_btn.setText("Pause")
433-
# -----------------------------Progress bar
434426
self.printing_progress_bar = CustomProgressBar(self)
435427
self.printing_progress_bar.setMinimumHeight(150)
436428
self.printing_progress_bar.setObjectName("printing_progress_bar")
437429
self.printing_progress_bar.setSizePolicy(sizePolicy)
438430
self.job_status_progress_layout.addWidget(self.printing_progress_bar)
439-
440-
# -----------------------------display buttons
441-
442431
self.layer_display_button = DisplayButton(self)
443432
self.layer_display_button.button_type = "display_secondary"
444433
self.layer_display_button.setEnabled(False)
445434
self.layer_display_button.setSizePolicy(sizePolicy)
446-
447435
self.layer_display_button.setMinimumSize(QtCore.QSize(200, 80))
448-
449436
self.layer_display_button.setProperty(
450437
"icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/layers.svg")
451438
)
452439
self.layer_display_button.setObjectName("layer_display_button")
453-
454440
self.print_time_display_button = DisplayButton(self)
455441
self.print_time_display_button.button_type = "normal"
456442
self.print_time_display_button.setEnabled(False)
457443
self.print_time_display_button.setSizePolicy(sizePolicy)
458-
459444
self.print_time_display_button.setMinimumSize(QtCore.QSize(200, 80))
460-
461445
self.print_time_display_button.setProperty(
462446
"icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/time.svg")
463447
)
464448
self.print_time_display_button.setObjectName("print_time_display_button")
465-
466449
self.job_stats_display_layout.addWidget(
467450
self.layer_display_button,
468451
0,
469452
QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignVCenter,
470453
)
471-
472454
self.job_stats_display_layout.addWidget(
473455
self.print_time_display_button,
474456
0,
@@ -480,7 +462,6 @@ def create_thumbnail_widget(self) -> None:
480462
"""Create thumbnail graphics view widget"""
481463
self.thumbnail_view = QtWidgets.QGraphicsView()
482464
self.thumbnail_view.setMinimumSize(QtCore.QSize(48, 48))
483-
# self.thumbnail_view.setMaximumSize(QtCore.QSize(300, 300))
484465
self.thumbnail_view.setAttribute(
485466
QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True
486467
)

‎BlocksScreen/lib/utils/blocks_progressbar.py‎

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,27 +40,29 @@ def set_pen_width(self, value) -> None:
4040
self._pen_width = value
4141
self.update()
4242

43+
def _scale_pixmap(self) -> None:
44+
self._inner_rect = self._calculate_inner_geometry()
45+
self._pixmap_cached = self._pixmap.scaled(
46+
self._inner_rect.size().toSize(),
47+
QtCore.Qt.AspectRatioMode.KeepAspectRatio,
48+
QtCore.Qt.TransformationMode.SmoothTransformation,
49+
)
50+
4351
def set_inner_pixmap(self, pixmap: QtGui.QPixmap) -> None:
4452
"""Set the inner icon pixmap on the progress bar
4553
circumference.
4654
"""
4755
self._pixmap = pixmap
48-
self.update()
56+
self._scale_pixmap()
4957

5058
def resizeEvent(self, a0) -> None:
51-
"""Re-implemented method, handle widget resize Events
59+
"""Reimplemented method, handle widget resize Events
5260
5361
Currently rescales the set pixmap so it has the optimal
5462
size.
5563
"""
56-
self._inner_rect = self._calculate_inner_geometry()
57-
self._pixmap_cached = self._pixmap.scaled(
58-
self._inner_rect.size().toSize(),
59-
QtCore.Qt.AspectRatioMode.KeepAspectRatio,
60-
QtCore.Qt.TransformationMode.SmoothTransformation,
61-
)
64+
self._scale_pixmap()
6265
self.update()
63-
return super().resizeEvent(a0)
6466

6567
def sizeHint(self) -> QtCore.QSize:
6668
"""Re-implemented method, preferable widget size"""

0 commit comments

Comments
 (0)