fix: QObject signals issue - BasePlugin doesn't inherit from QObject
BUG: SkillScannerPlugin cannot be converted to PyQt6.QtCore.QObject CAUSE: BasePlugin inherits from ABC, not QObject. Qt signals (pyqtSignal) must be defined in a QObject subclass. FIX: 1. Created SignalHelper(QObject) class to hold all signals: - hotkey_triggered - update_status_signal - update_session_table_signal - update_counters_signal - enable_scan_button_signal 2. In SkillScannerPlugin.initialize(): - Create self._signals = SignalHelper() - Connect signals from self._signals (not self) 3. In get_ui(): - Connect enable_scan_button_signal after scan_page_btn is created 4. Updated all signal emits to use self._signals.emit() This allows the plugin to use Qt signals for thread-safe UI updates without requiring BasePlugin to inherit from QObject (which would break other plugins).
This commit is contained in:
parent
0155eb0be0
commit
426f0a2ad3
|
|
@ -348,6 +348,15 @@ class SkillOCRThread(QThread):
|
||||||
return skills
|
return skills
|
||||||
|
|
||||||
|
|
||||||
|
class SignalHelper(QObject):
|
||||||
|
"""Helper QObject to hold signals since BasePlugin doesn't inherit from QObject."""
|
||||||
|
hotkey_triggered = pyqtSignal()
|
||||||
|
update_status_signal = pyqtSignal(str, bool, bool) # message, success, error
|
||||||
|
update_session_table_signal = pyqtSignal(object) # skills dict
|
||||||
|
update_counters_signal = pyqtSignal()
|
||||||
|
enable_scan_button_signal = pyqtSignal(bool)
|
||||||
|
|
||||||
|
|
||||||
class SkillScannerPlugin(BasePlugin):
|
class SkillScannerPlugin(BasePlugin):
|
||||||
"""Scan skills using core OCR and track gains via core Log service."""
|
"""Scan skills using core OCR and track gains via core Log service."""
|
||||||
|
|
||||||
|
|
@ -357,15 +366,11 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
description = "Uses core OCR and Log services"
|
description = "Uses core OCR and Log services"
|
||||||
hotkey = "ctrl+shift+s"
|
hotkey = "ctrl+shift+s"
|
||||||
|
|
||||||
# Signals for thread-safe UI updates
|
|
||||||
hotkey_triggered = pyqtSignal()
|
|
||||||
update_status_signal = pyqtSignal(str, bool, bool) # message, success, error
|
|
||||||
update_session_table_signal = pyqtSignal(object) # skills dict
|
|
||||||
update_counters_signal = pyqtSignal()
|
|
||||||
enable_scan_button_signal = pyqtSignal(bool)
|
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
"""Setup skill scanner."""
|
"""Setup skill scanner."""
|
||||||
|
# Create signal helper (QObject) for thread-safe UI updates
|
||||||
|
self._signals = SignalHelper()
|
||||||
|
|
||||||
self.data_file = Path("data/skill_tracker.json")
|
self.data_file = Path("data/skill_tracker.json")
|
||||||
self.data_file.parent.mkdir(parents=True, exist_ok=True)
|
self.data_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
@ -378,12 +383,12 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
self.current_scan_session = {} # Skills collected in current multi-page scan
|
self.current_scan_session = {} # Skills collected in current multi-page scan
|
||||||
self.pages_scanned = 0
|
self.pages_scanned = 0
|
||||||
|
|
||||||
# Connect signals
|
# Connect signals (using signal helper QObject)
|
||||||
self.hotkey_triggered.connect(self._scan_page_for_multi)
|
self._signals.hotkey_triggered.connect(self._scan_page_for_multi)
|
||||||
self.update_status_signal.connect(self._update_multi_page_status_slot)
|
self._signals.update_status_signal.connect(self._update_multi_page_status_slot)
|
||||||
self.update_session_table_signal.connect(self._update_session_table)
|
self._signals.update_session_table_signal.connect(self._update_session_table)
|
||||||
self.update_counters_signal.connect(self._update_counters_slot)
|
self._signals.update_counters_signal.connect(self._update_counters_slot)
|
||||||
self.enable_scan_button_signal.connect(self.scan_page_btn.setEnabled)
|
# Note: enable_scan_button_signal connected in get_ui() after button created
|
||||||
|
|
||||||
# Subscribe to skill gain events from core Log service
|
# Subscribe to skill gain events from core Log service
|
||||||
try:
|
try:
|
||||||
|
|
@ -558,6 +563,9 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
self.scan_page_btn.clicked.connect(self._start_smart_scan)
|
self.scan_page_btn.clicked.connect(self._start_smart_scan)
|
||||||
mp_buttons_layout.addWidget(self.scan_page_btn)
|
mp_buttons_layout.addWidget(self.scan_page_btn)
|
||||||
|
|
||||||
|
# Connect signal helper for button enabling (now that button exists)
|
||||||
|
self._signals.enable_scan_button_signal.connect(self.scan_page_btn.setEnabled)
|
||||||
|
|
||||||
save_all_btn = QPushButton("💾 Save All Scanned")
|
save_all_btn = QPushButton("💾 Save All Scanned")
|
||||||
save_all_btn.setStyleSheet("""
|
save_all_btn.setStyleSheet("""
|
||||||
QPushButton {
|
QPushButton {
|
||||||
|
|
@ -729,7 +737,7 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
|
|
||||||
ocr_service = get_ocr_service()
|
ocr_service = get_ocr_service()
|
||||||
if not ocr_service.is_available():
|
if not ocr_service.is_available():
|
||||||
self.update_status_signal.emit("Error: OCR not available", False, True)
|
self._signals.update_status_signal.emit("Error: OCR not available", False, True)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Capture and OCR
|
# Capture and OCR
|
||||||
|
|
@ -746,10 +754,10 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
self.pages_scanned += 1
|
self.pages_scanned += 1
|
||||||
|
|
||||||
# Update UI via signals (thread-safe)
|
# Update UI via signals (thread-safe)
|
||||||
self.update_session_table_signal.emit(self.current_scan_session)
|
self._signals.update_session_table_signal.emit(self.current_scan_session)
|
||||||
|
|
||||||
# Show success with checkmark and beep
|
# Show success with checkmark and beep
|
||||||
self.update_status_signal.emit(
|
self._signals.update_status_signal.emit(
|
||||||
f"✅ Page {self.pages_scanned} scanned! {len(skills)} skills found. Click Next Page in game →",
|
f"✅ Page {self.pages_scanned} scanned! {len(skills)} skills found. Click Next Page in game →",
|
||||||
True, False
|
True, False
|
||||||
)
|
)
|
||||||
|
|
@ -758,9 +766,9 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
self._play_beep()
|
self._play_beep()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.update_status_signal.emit(f"Error: {str(e)}", False, True)
|
self._signals.update_status_signal.emit(f"Error: {str(e)}", False, True)
|
||||||
finally:
|
finally:
|
||||||
self.enable_scan_button_signal.emit(True)
|
self._signals.enable_scan_button_signal.emit(True)
|
||||||
|
|
||||||
thread = Thread(target=do_scan)
|
thread = Thread(target=do_scan)
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
|
|
@ -899,7 +907,7 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
self._start_auto_scan_with_hotkey()
|
self._start_auto_scan_with_hotkey()
|
||||||
elif mode == 1: # Hotkey only
|
elif mode == 1: # Hotkey only
|
||||||
self._register_hotkey()
|
self._register_hotkey()
|
||||||
self.update_status_signal.emit("Hotkey F12 ready! Navigate to first page and press F12", True, False)
|
self._signals.update_status_signal.emit("Hotkey F12 ready! Navigate to first page and press F12", True, False)
|
||||||
else: # Manual click
|
else: # Manual click
|
||||||
self._scan_page_for_multi()
|
self._scan_page_for_multi()
|
||||||
|
|
||||||
|
|
@ -913,7 +921,7 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
self._register_hotkey()
|
self._register_hotkey()
|
||||||
|
|
||||||
# Start monitoring
|
# Start monitoring
|
||||||
self.update_status_signal.emit("🤖 Auto-detect started! Navigate to page 1...", True, False)
|
self._signals.update_status_signal.emit("🤖 Auto-detect started! Navigate to page 1...", True, False)
|
||||||
|
|
||||||
# Start auto-detection timer
|
# Start auto-detection timer
|
||||||
self.auto_scan_timer = QTimer()
|
self.auto_scan_timer = QTimer()
|
||||||
|
|
@ -948,7 +956,7 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
def _hotkey_scan(self):
|
def _hotkey_scan(self):
|
||||||
"""Scan triggered by F12 hotkey - thread safe via signal."""
|
"""Scan triggered by F12 hotkey - thread safe via signal."""
|
||||||
# Emit signal to safely call from hotkey thread
|
# Emit signal to safely call from hotkey thread
|
||||||
self.hotkey_triggered.emit()
|
self._signals.hotkey_triggered.emit()
|
||||||
|
|
||||||
def _check_for_page_change(self):
|
def _check_for_page_change(self):
|
||||||
"""Auto-detect page changes by monitoring page number area."""
|
"""Auto-detect page changes by monitoring page number area."""
|
||||||
|
|
@ -981,7 +989,7 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
|
|
||||||
# If page changed, trigger scan
|
# If page changed, trigger scan
|
||||||
if self.last_page_number is not None and current_page != self.last_page_number:
|
if self.last_page_number is not None and current_page != self.last_page_number:
|
||||||
self.update_status_signal.emit(f"📄 Page change detected: {current_page}/{total_pages}", True, False)
|
self._signals.update_status_signal.emit(f"📄 Page change detected: {current_page}/{total_pages}", True, False)
|
||||||
self._scan_page_for_multi()
|
self._scan_page_for_multi()
|
||||||
|
|
||||||
self.last_page_number = current_page
|
self.last_page_number = current_page
|
||||||
|
|
@ -1004,7 +1012,7 @@ class SkillScannerPlugin(BasePlugin):
|
||||||
self.auto_scan_active = False
|
self.auto_scan_active = False
|
||||||
|
|
||||||
# Keep hotkey registered
|
# Keep hotkey registered
|
||||||
self.update_status_signal.emit(
|
self._signals.update_status_signal.emit(
|
||||||
"⚠️ Auto-detect unreliable. Use F12 hotkey to scan each page manually!",
|
"⚠️ Auto-detect unreliable. Use F12 hotkey to scan each page manually!",
|
||||||
False, True
|
False, True
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue