Refactor automation controls and enhance state management in MainWindow

This commit is contained in:
2025-07-07 11:23:55 +02:00
parent 6cdc3ec876
commit 27947c57e0
+51 -9
View File
@@ -1,4 +1,3 @@
import sys import sys
import os import os
import json import json
@@ -11,7 +10,6 @@ from PyQt6 import QtWidgets, QtGui, QtCore
import cv2 import cv2
import numpy as np import numpy as np
import pyautogui import pyautogui
import mss
from pynput import keyboard from pynput import keyboard
import tkinter as tk import tkinter as tk
from PIL import ImageGrab, Image, ImageTk from PIL import ImageGrab, Image, ImageTk
@@ -135,6 +133,8 @@ class MainWindow(QtWidgets.QMainWindow):
logger.info('Automation loop started.') logger.info('Automation loop started.')
try: try:
while self.running: while self.running:
# Only update the state label, do not log every loop
self.set_state('Looking for matches')
screen = pyautogui.screenshot() screen = pyautogui.screenshot()
screen_np = cv2.cvtColor(np.array(screen), cv2.COLOR_RGB2BGR) screen_np = cv2.cvtColor(np.array(screen), cv2.COLOR_RGB2BGR)
for step in self.current_scenario.steps: for step in self.current_scenario.steps:
@@ -165,6 +165,8 @@ class MainWindow(QtWidgets.QMainWindow):
trigger = len(found) > 0 trigger = len(found) > 0
logger.debug(f"Step '{step.get('name', 'step')}' trigger check: found={found}, cond={cond}, trigger={trigger}") logger.debug(f"Step '{step.get('name', 'step')}' trigger check: found={found}, cond={cond}, trigger={trigger}")
if trigger: if trigger:
self.set_state(f'Performing step: {step.get("name", "step")})')
logger.info(f"Found match for step: {step.get('name', 'step')}. Performing actions.")
# Use the first detected image for position # Use the first detected image for position
ref_img = found[0] if found else step.get('images', [])[0] ref_img = found[0] if found else step.get('images', [])[0]
loc, shape = detections.get(ref_img.get('name'), ((0, 0), (0, 0, 0))) loc, shape = detections.get(ref_img.get('name'), ((0, 0), (0, 0, 0)))
@@ -175,6 +177,8 @@ class MainWindow(QtWidgets.QMainWindow):
time.sleep(0.2) time.sleep(0.2)
except Exception as e: except Exception as e:
logger.error(f'Automation loop error: {e}') logger.error(f'Automation loop error: {e}')
finally:
self.set_state('Paused')
def _perform_step_action(self, action, loc, shape): def _perform_step_action(self, action, loc, shape):
act_type = action['type'] act_type = action['type']
@@ -215,12 +219,24 @@ class MainWindow(QtWidgets.QMainWindow):
time.sleep(duration) time.sleep(duration)
except Exception as e: except Exception as e:
logger.error(f'Error performing step action {act_type}: {e}') logger.error(f'Error performing step action {act_type}: {e}')
def set_state(self, text):
self.state_text = text
self.state_label.setText(f'State: {text}')
def toggle_automation(self):
if self.running:
self.stop_automation()
else:
self.start_automation()
def start_automation(self): def start_automation(self):
logger.info('Starting automation.') logger.info('Starting automation.')
if not self.current_scenario or self.running: if not self.current_scenario or self.running:
logger.warning('Start Automation: No scenario selected or already running.') logger.warning('Start Automation: No scenario selected or already running.')
return return
self.running = True self.running = True
self.set_state('Looking for matches')
self.btn_start_stop.setText('Stop')
self.worker = threading.Thread(target=self.automation_loop, daemon=True) self.worker = threading.Thread(target=self.automation_loop, daemon=True)
self.worker.start() self.worker.start()
self.listener = keyboard.GlobalHotKeys({self.hotkey: self.stop_automation}) self.listener = keyboard.GlobalHotKeys({self.hotkey: self.stop_automation})
@@ -229,9 +245,12 @@ class MainWindow(QtWidgets.QMainWindow):
def stop_automation(self): def stop_automation(self):
logger.info('Stopping automation.') logger.info('Stopping automation.')
self.running = False self.running = False
self.set_state('Paused')
self.btn_start_stop.setText('Start')
if self.listener: if self.listener:
self.listener.stop() self.listener.stop()
self.listener = None self.listener = None
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.setWindowTitle('Scenario Image Automation') self.setWindowTitle('Scenario Image Automation')
@@ -268,11 +287,12 @@ class MainWindow(QtWidgets.QMainWindow):
self.btn_rename_scenario.clicked.connect(self.rename_scenario) self.btn_rename_scenario.clicked.connect(self.rename_scenario)
self.btn_rename_step = QtWidgets.QPushButton("Rename Step") self.btn_rename_step = QtWidgets.QPushButton("Rename Step")
self.btn_rename_step.clicked.connect(self.rename_step) self.btn_rename_step.clicked.connect(self.rename_step)
# Start/Stop # Start/Stop Combined
self.btn_start = QtWidgets.QPushButton('Start') self.btn_start_stop = QtWidgets.QPushButton('Start')
self.btn_start.clicked.connect(self.start_automation) self.btn_start_stop.clicked.connect(self.toggle_automation)
self.btn_stop = QtWidgets.QPushButton('Stop') # State label
self.btn_stop.clicked.connect(self.stop_automation) self.state_label = QtWidgets.QLabel('State: Paused')
self.state_label.setStyleSheet('font-weight: bold; font-size: 16px; color: #0055aa;')
# Layout # Layout
layout = QtWidgets.QGridLayout() layout = QtWidgets.QGridLayout()
layout.addWidget(QtWidgets.QLabel('Scenario:'), 0, 0) layout.addWidget(QtWidgets.QLabel('Scenario:'), 0, 0)
@@ -287,8 +307,8 @@ class MainWindow(QtWidgets.QMainWindow):
layout.addWidget(self.btn_edit_step, 5, 2) layout.addWidget(self.btn_edit_step, 5, 2)
layout.addWidget(self.btn_del_step, 5, 3) layout.addWidget(self.btn_del_step, 5, 3)
layout.addWidget(self.btn_rename_step, 5, 4) layout.addWidget(self.btn_rename_step, 5, 4)
layout.addWidget(self.btn_start, 6, 1) layout.addWidget(self.btn_start_stop, 6, 1)
layout.addWidget(self.btn_stop, 6, 2) layout.addWidget(self.state_label, 6, 2, 1, 3)
central = QtWidgets.QWidget() central = QtWidgets.QWidget()
central.setLayout(layout) central.setLayout(layout)
self.setCentralWidget(central) self.setCentralWidget(central)
@@ -547,6 +567,10 @@ class StepDialog(QtWidgets.QDialog):
self.btn_add_act.clicked.connect(self.add_action) self.btn_add_act.clicked.connect(self.add_action)
self.btn_del_act = QtWidgets.QPushButton('Delete Action') self.btn_del_act = QtWidgets.QPushButton('Delete Action')
self.btn_del_act.clicked.connect(self.delete_action) self.btn_del_act.clicked.connect(self.delete_action)
self.btn_move_up_act = QtWidgets.QPushButton('Move Up')
self.btn_move_up_act.clicked.connect(self.move_action_up)
self.btn_move_down_act = QtWidgets.QPushButton('Move Down')
self.btn_move_down_act.clicked.connect(self.move_action_down)
# Layout # Layout
layout = QtWidgets.QGridLayout() layout = QtWidgets.QGridLayout()
layout.addWidget(QtWidgets.QLabel('Step Name:'), 0, 0) layout.addWidget(QtWidgets.QLabel('Step Name:'), 0, 0)
@@ -572,6 +596,8 @@ class StepDialog(QtWidgets.QDialog):
action_buttons = QtWidgets.QHBoxLayout() action_buttons = QtWidgets.QHBoxLayout()
action_buttons.addWidget(self.btn_add_act) action_buttons.addWidget(self.btn_add_act)
action_buttons.addWidget(self.btn_del_act) action_buttons.addWidget(self.btn_del_act)
action_buttons.addWidget(self.btn_move_up_act)
action_buttons.addWidget(self.btn_move_down_act)
layout.addLayout(action_buttons, 5, 1, 1, 2) layout.addLayout(action_buttons, 5, 1, 1, 2)
btns = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.StandardButton.Ok | QtWidgets.QDialogButtonBox.StandardButton.Cancel) btns = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.StandardButton.Ok | QtWidgets.QDialogButtonBox.StandardButton.Cancel)
@@ -580,6 +606,22 @@ class StepDialog(QtWidgets.QDialog):
layout.addWidget(btns, 6, 1, 1, 2) layout.addWidget(btns, 6, 1, 1, 2)
self.setLayout(layout) self.setLayout(layout)
def move_action_up(self):
idx = self.act_list.currentRow()
if idx > 0:
self.actions[idx-1], self.actions[idx] = self.actions[idx], self.actions[idx-1]
item = self.act_list.takeItem(idx)
self.act_list.insertItem(idx-1, item)
self.act_list.setCurrentRow(idx-1)
def move_action_down(self):
idx = self.act_list.currentRow()
if idx < len(self.actions) - 1 and idx >= 0:
self.actions[idx+1], self.actions[idx] = self.actions[idx], self.actions[idx+1]
item = self.act_list.takeItem(idx)
self.act_list.insertItem(idx+1, item)
self.act_list.setCurrentRow(idx+1)
class NameImageDialog(QtWidgets.QDialog): class NameImageDialog(QtWidgets.QDialog):
def __init__(self, pixmap, parent=None): def __init__(self, pixmap, parent=None):
super().__init__(parent) super().__init__(parent)