yolo自动化项目实例解析(七)自建UI--工具栏选项

在上一章我们基本实现了关于预览窗口的显示,现在我们主要完善一下工具栏菜单按键

一、添加工具栏ui

1、配置文件读取

我们后面要改的东西越来越多了,先加个变量文件方便我们后面调用

下面我们使用的config.get意思是从./datas/setting.ini文件中读取关键字PACKS_TASK对应的路径,如果没有的话默认值为./datas/Task/

vi state.py

复制代码
# -*- coding: utf-8 -*-
import configparser
import json
import os
import sys

# 创建 ConfigParser 对象
config = configparser.ConfigParser()
# 加载 INI 文件
config.read("./datas/setting.ini")


#Task任务目录路径
PACKS_TASK = config.get('seting', 'PACKS_TASK', fallback='./datas/Task/')

2、工具栏添加按钮

复制代码
    #添加任务包名为按钮 
    def add_tool_item(self, dir_):


        action_item = QWidgetAction(self)
        dir_ = dir_.replace("/", "\\")

        if dir_[-1] == "\\":
            dir_ = dir_[:-1]

        #这里把路径下的目录名取出来当作按钮名称
        bt_item = QPushButton(dir_.split("\\")[-1].strip())
        bt_item.setMaximumWidth(int(80 * ratio))

        #读取项目的说明打印出来
        try:
            with open(dir_ + "/" + "使用说明.txt", "r", encoding="utf-8") as f:
                txt = f.read()
        except:
            try:
                with open(dir_ + "/" + "使用说明.txt", "r", encoding="utf-8") as f:
                    txt = f.read()
            except:
                txt = "无  \n(可以在任务包文件夹下创建一个 使用说明.txt 文件 来添加说明)"

        bt_item.setToolTip(dir_ + "\n使用说明:" + txt + "\n")
        bt_item.setStyleSheet("border: none; padding: 3px;")

        #绑定按钮的功能
        bt_item.clicked.connect(functools.partial(self.show_tool_item, dir_))

        #添加动作
        action_item.setDefaultWidget(bt_item)
        #按钮添加到工具栏
        self.toolBar.addAction(action_item)

    #按钮触发函数,先放着有个东西
    def show_tool_item(self, dir_):
        pass

3、自动触发添加

复制代码
class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        

       ...


        #添加任务包
        self.load_task_packs()


 
    #取任务包的路径,循环触发工具栏添加按钮
    def load_task_packs(self):
        self.toolBar.clear()
        packs = state.PACKS_TASK.split("#@@#")
        try:
            if len(packs) >= 1:
                for pack in packs:
                    if pack != "":
                        self.add_tool_item(pack)
            else:

                self.add_tool_item(state.PACKS_TASK)
        except:
            pass

4、工具栏移动、任务删除

这里在add_tool_item中添加了关于上下移动和删除的按钮,以及对应的触发函数

复制代码
    def add_tool_item(self, dir_):


        action_item = QWidgetAction(self)
        dir_ = dir_.replace("/", "\\")

        if dir_[-1] == "\\":
            dir_ = dir_[:-1]

        #这里把路径下的目录名取出来当作按钮名称
        bt_item = QPushButton(dir_.split("\\")[-1].strip())
        bt_item.setMaximumWidth(int(80 * ratio))

        #读取项目的说明打印出来
        try:
            with open(dir_ + "/" + "使用说明.txt", "r", encoding="utf-8") as f:
                txt = f.read()
        except:
            try:
                with open(dir_ + "/" + "使用说明.txt", "r", encoding="utf-8") as f:
                    txt = f.read()
            except:
                txt = "无  \n(可以在任务包文件夹下创建一个 使用说明.txt 文件 来添加说明)"

        bt_item.setToolTip(dir_ + "\n使用说明:" + txt + "\n")
        bt_item.setStyleSheet("border: none; padding: 3px;")

        #绑定按钮的功能
        bt_item.clicked.connect(functools.partial(self.show_tool_item, dir_))

        #添加动作
        action_item.setDefaultWidget(bt_item)
        #按钮添加到工具栏
        self.toolBar.addAction(action_item)



        menu = QMenu(self)

        action_menu_down = QAction('顺序 ↓', self)
        action_menu_down.triggered.connect(functools.partial(self.down_tool_item, len(self.toolBar.actions())))
        menu.addAction(action_menu_down)
        action_menu_up = QAction('顺序 ↑', self)
        action_menu_up.triggered.connect(functools.partial(self.up_tool_item, len(self.toolBar.actions())))
        menu.addAction(action_menu_up)
        action_menu_del = QAction('删除任务包', self)
        action_menu_del.triggered.connect(functools.partial(self.del_tool_item, action_item, bt_item, dir_))
        menu.addAction(action_menu_del)
        # 将菜单关联到工具栏上
        bt_item.setContextMenuPolicy(Qt.CustomContextMenu)
        bt_item.customContextMenuRequested.connect(lambda pos: menu.exec_(bt_item.mapToGlobal(pos)))
        self.change_tool_show_style(dir_)

    def del_tool_item(self, action_item, bt_item, dir_):
        self.toolBar.removeAction(action_item)
        if state.PATH_TASK.replace("/", "\\") == dir_:
            self.datas = []
            self.row = 0
            self.column = -1
            # 清空当前布局
            for i in reversed(range(self.g_box.count())):
                self.g_box.itemAt(i).widget().setParent(None)
        del bt_item, action_item  # 删除动作对象和bt对象

        txt_ = ""
        packs = state.PACKS_TASK.split("#@@#")

        if len(packs) >= 1:
            for pack in packs:

                if os.path.realpath(dir_) != os.path.realpath(pack) and pack != "":
                    txt_ = txt_ + pack + "#@@#"
        state.PACKS_TASK = txt_
        print(f"成功移除{dir_}任务包")
        self.sg.mysig_tishi.emit(f"成功移除{dir_}任务包")

    def down_tool_item(self, idex):
        task_list = state.PACKS_TASK.split("#@@#")
        if idex < len(task_list) - 1:
            # 将指定索引位置的成员与其前一个成员交换位置
            task_list[idex], task_list[idex + 1] = task_list[idex + 1], task_list[idex]

        state.PACKS_TASK = ""
        for item in task_list:
            if item != "":
                state.PACKS_TASK += "#@@#" + item

        self.load_task_packs()

    def up_tool_item(self, idex):
        task_list = state.PACKS_TASK.split("#@@#")
        if idex > 0:
            # 将指定索引位置的成员与其后一个成员交换位置
            task_list[idex], task_list[idex - 1] = task_list[idex - 1], task_list[idex]
        state.PACKS_TASK = ""
        for item in task_list:
            if item != "":
                state.PACKS_TASK += "#@@#" + item

        self.load_task_packs()

不知道按钮为什么时灵时不灵,不重要先忽略

二、工具栏触发函数

1、更新变量

复制代码
# -*- coding: utf-8 -*-
import configparser
import json
import os
import sys

# 创建 ConfigParser 对象
config = configparser.ConfigParser()
# 加载 INI 文件
config.read("./datas/setting.ini")


#Task任务目录路径
PACKS_TASK = config.get('seting', 'PACKS_TASK', fallback='./datas/Task/')

PATH_TASK = config.get('seting', 'PATH_TASK', fallback='./datas/Task/')




PROVIDERS = config.get('seting', 'PROVIDERS', fallback="""["CUDAExecutionProvider", "CPUExecutionProvider"]""")
PROVIDERS = json.loads(PROVIDERS.replace("'", '"'))
LIANZHAOFUWU = config.get('seting', 'LIANZHAOFUWU', fallback='./datas/jiaoben/躺宝连招插件.exe')
DUANGKOUHAO = config.get('seting', 'DUANGKOUHAO', fallback='29943')
GAME_TITLE = config.get('seting', 'GAME_TITLE', fallback='原神')
LIANZHAO = config.get('seting', 'LIANZHAO', fallback='阵容1草神2久岐忍3钟离4雷神.txt')
PATH_TASK = config.get('seting', 'PATH_TASK', fallback='./datas/Task/')
PATH_JIAOBEN = config.get('seting', 'PATH_JIAOBEN', fallback='./datas/JiaoBen/')
PATH_JUESE = config.get('seting', 'PATH_JUESE', fallback='./datas/img/juese/')
PATH_ADDRESS = config.get('seting', 'PATH_ADDRESS', fallback='./datas/img/address/')
WEIGHTS = config.get('seting', 'WEIGHTS', fallback='./datas/yolov5s_320.onnx')
IMGSIZE_WIDTH = int(config.get('seting', 'IMGSIZE_WIDTH', fallback='320'))
IMGSIZE_HEIGHT = int(config.get('seting', 'IMGSIZE_HEIGHT', fallback='320'))
WINDOW_WIDTH = int(config.get('seting', 'WINDOW_WIDTH', fallback="640"))
WINDOW_HEIGHT = int(config.get('seting', 'WINDOW_HEIGHT', fallback="900"))
WINDOW_LEFT = int(config.get('seting', 'WINDOW_LEFT', fallback="0"))
WINDOW_TOP = int(config.get('seting', 'WINDOW_TOP', fallback="300"))

CMD_WIDTH = int(config.get('seting', 'CMD_WIDTH', fallback="800"))
CMD_HEIGHT = int(config.get('seting', 'CMD_HEIGHT', fallback="400"))
CMD_LEFT = int(config.get('seting', 'CMD_LEFT', fallback="500"))
CMD_TOP = int(config.get('seting', 'CMD_TOP', fallback="300"))

ON_SHUTDOWN = int(config.get('seting', 'ON_SHUTDOWN', fallback="0"))
ON_JIXING = int(config.get('seting', 'ON_JIXING', fallback="0"))
ON_NEXTPACK = int(config.get('seting', 'ON_NEXTPACK', fallback="0"))
ON_LIANZHAOBUJIANCE = int(config.get('seting', 'ON_LIANZHAOBUJIANCE', fallback="0"))
ON_STARTWITH = int(config.get('seting', 'ON_STARTWITH', fallback="0"))
TIMEOUT_DAGUAI = int(config.get('seting', 'TIMEOUT_DAGUAI', fallback='120'))

2、保存窗口配置

复制代码
    def save_ini_seting(self):
        try:
            hwnd = ctypes.windll.kernel32.GetConsoleWindow()
            if hwnd:
                rect = win32gui.GetWindowRect(hwnd)
                x, y, w, h = rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]
            else:
                x, y, w, h = state.CMD_LEFT, state.CMD_TOP, state.CMD_WIDTH, state.CMD_HEIGHT

            # 创建 ConfigParser 对象
            config = configparser.ConfigParser()
            # 添加节和键-值对
            config['seting'] = {
                "GAME_TITLE": state.GAME_TITLE,
                'LIANZHAO': state.LIANZHAO,
                'LIANZHAOFUWU': state.LIANZHAOFUWU,
                'DUANGKOUHAO': state.DUANGKOUHAO,
                'PATH_TASK': state.PATH_TASK,
                'PATH_JIAOBEN': state.PATH_JIAOBEN,
                'PACKS_TASK': state.PACKS_TASK,
                'WEIGHTS': state.WEIGHTS,
                'PROVIDERS': state.PROVIDERS,
                'IMGSIZE_WIDTH': str(state.IMGSIZE_WIDTH),
                'IMGSIZE_HEIGHT': str(state.IMGSIZE_HEIGHT),
                'WINDOW_WIDTH': str(self.width()),
                'WINDOW_HEIGHT': str(self.height()),
                'WINDOW_LEFT': str(self.x()),
                'WINDOW_TOP': str(self.y()),
                'CMD_WIDTH': str(w),
                'CMD_HEIGHT': str(h),
                'CMD_LEFT': str(x),
                'CMD_TOP': str(y),
                'ON_SHUTDOWN': str(state.ON_SHUTDOWN),
                'ON_JIXING': str(state.ON_JIXING),
                'ON_NEXTPACK': str(state.ON_NEXTPACK),
                'ON_STARTWITH': str(state.ON_STARTWITH),
                'ON_LIANZHAOBUJIANCE': str(state.ON_LIANZHAOBUJIANCE),
                'TIMEOUT_DAGUAI': str(state.TIMEOUT_DAGUAI)
            }
            # 写入配置到 INI 文件
            with open("./datas/setting.ini", 'w') as configfile:
                config.write(configfile)
        except:
            pass

3、获取工作栏动作

复制代码
    def change_tool_show_style(self, dir_):
        # 获取工具栏上的所有动作
        actions_list = self.toolBar.actions()

        # 遍历处理每个动作
        for action in actions_list:
            # 在这里对每个动作进行处理

            bt_item = action.defaultWidget()
            if dir_ == bt_item.toolTip().replace("/", "\\").split("\n")[0]:
                bt_item.setStyleSheet("border-width: 1px; padding: 3px;")
            else:
                bt_item.setStyleSheet("border: none; padding: 3px;")

4、更新任务-路由

后续这里打算通过判断脚本的id来选择不同的任务,比如说我们下面注释的内容中,我们会通过工具栏中目录下的jiaoben.ini 配置文件中的type 去判断这个任务具体是要做什么

复制代码
   def update_tasks(self):
        try:
            self.datas = []
            self.row = 0
            self.column = -1

            # 清空当前布局
            for i in reversed(range(self.g_box.count())):
                self.g_box.itemAt(i).widget().setParent(None)
            # 遍历文件夹下有哪些目录
            # 判断这个路径是否存在
            if not os.path.exists(state.PATH_TASK):
                state.PATH_TASK = "./datas/Task/"

            # # 创建 ConfigParser 对象
            # config_main = configparser.ConfigParser()
            # # 加载 INI 文件
            #
            # config_main.read(os.path.join(state.PATH_TASK, "细节参数.ini"))
            # self.run_times = int(config_main.get('seting', 'run_times', fallback='1'))
            # self.action_run_times.setText(f"设置:当前任务包 执行次数:{self.run_times}")
            #
            # # 获取文件夹列表
            # folders = [item for item in os.listdir(state.PATH_TASK) if
            #            os.path.isdir(os.path.join(state.PATH_TASK, item))]
            # # 将文件夹名称中的数字提取出来,并按照数字大小排序
            # sorted_folders = sorted(folders, key=lambda x: extract_number(x))
            # for item in sorted_folders:
            #     item_path = os.path.join(state.PATH_TASK, item)
            #     if os.path.isdir(item_path):
            #         # 创建 ConfigParser 对象
            #         config = configparser.ConfigParser()
            #         # 加载 INI 文件
            #         config.read(os.path.join(item_path, "jiaoben.ini"))
            #         if config.get('seting', 'type', fallback='1') == "2":
            #             # 副本任务
            #             self.add_taskfuben(item_path, config)
            #         elif config.get('seting', 'type', fallback='1') == "3":
            #             # 脚本任务
            #             self.add_taskjiaoben(item_path, config)
            #         elif config.get('seting', 'type', fallback='1') == "4":
            #             # 脚本任务
            #             self.add_xuanjue(item_path, config)
            #         elif config.get('seting', 'type', fallback='1') == "5":
            #             # 脚本任务
            #             self.add_xuanlianzhao(item_path, config)
            #         elif config.get('seting', 'type', fallback='1') == "6":
            #             self.add_taskpy(item_path, config)
            #         else:
            #             # 锄地任务
            #             self.add_task(item_path, config)
        except Exception:
            print(f"请选择任务文件夹,目前没有这个文件夹{state.PATH_TASK}")

5、保存

复制代码
    def save(self):

        for idex in range(len(self.datas)):
            self.returnPressed_name(idex)
        # 重写closeEvent方法,在窗口关闭时调用quit()退出应用程序

        for i, data in enumerate(self.datas):
            dir_ = os.path.join(state.PATH_TASK, data["name"])
            self.save_ini(dir_, data)
        self.update_tasks()
        self.save_ini_seting()

6、补全点击后触发函数

复制代码
    def show_tool_item(self, dir_):

        self.save()
        state.PATH_TASK = dir_
        self.save_ini_seting()
        self.update_tasks()
        self.change_tool_show_style(dir_)
        print(f"成功设置{state.PATH_TASK}为当前任务文件夹")

7、全量代码

复制代码
import configparser
import ctypes
import functools
import os
import re
import sys

import win32gui
# 导入PyQt5模块
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import state
# 导入UI文件生成的类
from ui.show import Ui_DockWidget
from ui.main import Ui_mainWindow
def extract_number(folder_name):
    numbers = re.findall(r'\d+', folder_name)
    return int(numbers[0]) if numbers else float('inf')

class MySignal(QObject):
    # 无参数信号,可能用于触发显示某个路径或轨迹的操作
    mysig_show_xunlu = pyqtSignal()

    # 无参数信号,可能与YOLOv模型有关,用于触发显示模型输出或其他相关操作
    mysig_show_yolov = pyqtSignal()


# 定义FormShow类,继承自QDockWidget和Ui_DockWidget
class FormShow(QDockWidget, Ui_DockWidget):
    def __init__(self, parent=None):
        super(QDockWidget, self).__init__(parent)  # 调用父类构造函数
        self.parent = parent  # 保存父窗口引用
        self.setParent(parent)  # 设置父窗口
        self.setupUi(self)  # 初始化UI界面
        self.set_ui()  # 自定义设置UI界面

        # 设置窗口标题
        self.setWindowTitle("检测预览")

        # 设置标签控件属性
        self.lb_yolov.setScaledContents(True)
        self.lb_yolov.setAlignment(Qt.AlignCenter)
        self.lb_xunlu.setAlignment(Qt.AlignCenter)

        # 移动窗口位置
        self.move(0, 0)

        # 设置窗口保持在最顶层
        self.setWindowFlags(Qt.WindowStaysOnTopHint)

        # 计算窗口大小
        self.window_height = int(270 * ratio)
        self.window_width = int(480 * ratio)

        # 设置窗口最小尺寸
        self.setMinimumSize(self.window_width, self.window_height * 2)

        # 连接按钮点击事件
        self.bt_jia.clicked.connect(self.clicked_jia)
        self.bt_jian.clicked.connect(self.clicked_jian)

    # 自定义UI设置
    def set_ui(self):
        pass  # 此处可添加更多UI设置

    # 按钮"加"点击事件处理
    def clicked_jia(self):
        # 如果窗口高度加上增量后超过屏幕高度,则返回
        if self.window_height + 108 * ratio > 1080 * ratio:
            return

        # 更新窗口大小
        self.window_height += int(108 * ratio)
        self.window_width += int(190 * ratio)

        # 设置标签固定高度
        self.lb_xunlu.setFixedHeight(self.window_height)

        # 根据窗口宽度调整标签位置
        if self.width() >= self.lb_yolov.width() + self.lb_xunlu.width():
            self.lb_yolov.move(self.lb_xunlu.width(), 0)
        else:
            self.lb_yolov.move(0, self.lb_xunlu.height())

        # 设置标签固定大小
        self.lb_yolov.setFixedHeight(self.window_height)
        self.lb_yolov.setFixedWidth(self.window_width)

    # 按钮"减"点击事件处理
    def clicked_jian(self):
        # 如果窗口高度减去增量后小于最小高度,则返回
        if self.window_height - 108 * ratio < 270 * ratio:
            return

        # 更新窗口大小
        self.window_height -= int(108 * ratio)
        self.window_width -= int(190 * ratio)

        # 设置标签固定高度
        self.lb_xunlu.setFixedHeight(self.window_height)

        # 根据窗口宽度调整标签位置
        if self.width() >= self.lb_yolov.width() + self.lb_xunlu.width():
            self.lb_yolov.move(self.lb_xunlu.width(), 0)
        else:
            self.lb_yolov.move(0, self.lb_xunlu.height())

        # 设置标签固定大小
        self.lb_yolov.setFixedHeight(self.window_height)
        self.lb_yolov.setFixedWidth(self.window_width)

    # 重写关闭事件
    def closeEvent(self, event):
        # 关闭窗口时取消主窗口上的动作选中状态
        self.parent.action_isShow.setChecked(False)

    # 重写调整大小事件
    def resizeEvent(self, event):
        # 根据窗口宽度调整标签位置
        if self.width() >= self.lb_yolov.width() + self.lb_xunlu.width():
            self.lb_yolov.move(self.lb_xunlu.width(), 0)
        else:
            self.lb_yolov.move(0, self.lb_xunlu.height())


# 定义MainWindow类,继承自QMainWindow和Ui_mainWindow
class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()  # 调用父类构造函数
        self.setupUi(self)  # 设置UI布局
        self.retranslateUi(self)  # 重新翻译UI组件的文字

        # 修改窗口样式为黑灰色,高亮
        self.set_ui()

        # 设置窗口标题
        self.setWindowTitle(f"修改主页标题")

        # 设置窗口尺寸
        self.resize(640, 900)

        # 设置窗口起始位置
        self.move(0, 300)

        # 创建网格布局
        self.g_box = QGridLayout()

        # 创建一个中间部件
        self.container_widget = QWidget()

        # 将网格布局设置给中间部件
        self.container_widget.setLayout(self.g_box)

        # 设置布局左上对齐
        self.g_box.setAlignment(Qt.AlignTop | Qt.AlignLeft)

        # 设置布局边距
        self.g_box.setContentsMargins(0, 0, 0, 0)

        # 设置布局左对齐
        self.g_box.setAlignment(Qt.AlignTop)

        # 将中间部件设置为QScrollArea的子部件
        self.sa_main.setWidget(self.container_widget)

        # 获取纵向滚动条控件
        vertical_scrollbar = self.findChild(QScrollArea)
        self.v_scrollbar = vertical_scrollbar.verticalScrollBar()

        # 设置窗口保持在最顶层
        self.setWindowFlags(Qt.WindowStaysOnTopHint)

        # 初始化变量
        self.row = 0
        self.column = -1
        self.run_times = 1
        self.column_step = 310

        # 获取主窗口的状态栏对象
        self.statusbar = self.statusBar()

        # 设置状态栏文本
        self.statusbar.showMessage('欢迎使用')

        # 初始化数据列表
        self.datas = []

        # 创建一个计时器,用于延迟布局
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)  # 设置为单次触发
        self.timer.timeout.connect(self.update_layout)

        # 绑定信号槽
        self.connect_set()

        # 创建定时器  用于周期显示图片
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.on_timer_timeout)
        self.timer.start(5000)  # 每5秒触发一次

        #添加任务包
        self.load_task_packs()



    def load_task_packs(self):
        self.toolBar.clear()
        packs = state.PACKS_TASK.split("#@@#")
        try:
            if len(packs) >= 1:
                for pack in packs:
                    if pack != "":
                        self.add_tool_item(pack)
            else:

                self.add_tool_item(state.PACKS_TASK)
        except:
            pass


    def add_tool_item(self, dir_):


        action_item = QWidgetAction(self)
        dir_ = dir_.replace("/", "\\")

        if dir_[-1] == "\\":
            dir_ = dir_[:-1]

        #这里把路径下的目录名取出来当作按钮名称
        bt_item = QPushButton(dir_.split("\\")[-1].strip())
        bt_item.setMaximumWidth(int(80 * ratio))

        #读取项目的说明打印出来
        try:
            with open(dir_ + "/" + "使用说明.txt", "r", encoding="utf-8") as f:
                txt = f.read()
        except:
            try:
                with open(dir_ + "/" + "使用说明.txt", "r", encoding="utf-8") as f:
                    txt = f.read()
            except:
                txt = "无  \n(可以在任务包文件夹下创建一个 使用说明.txt 文件 来添加说明)"

        bt_item.setToolTip(dir_ + "\n使用说明:" + txt + "\n")
        bt_item.setStyleSheet("border: none; padding: 3px;")

        #绑定按钮的功能
        bt_item.clicked.connect(functools.partial(self.show_tool_item, dir_))

        #添加动作
        action_item.setDefaultWidget(bt_item)
        #按钮添加到工具栏
        self.toolBar.addAction(action_item)



        menu = QMenu(self)

        action_menu_down = QAction('顺序 ↓', self)
        action_menu_down.triggered.connect(functools.partial(self.down_tool_item, len(self.toolBar.actions())))
        menu.addAction(action_menu_down)
        action_menu_up = QAction('顺序 ↑', self)
        action_menu_up.triggered.connect(functools.partial(self.up_tool_item, len(self.toolBar.actions())))
        menu.addAction(action_menu_up)
        action_menu_del = QAction('删除任务包', self)
        action_menu_del.triggered.connect(functools.partial(self.del_tool_item, action_item, bt_item, dir_))
        menu.addAction(action_menu_del)
        # 将菜单关联到工具栏上
        bt_item.setContextMenuPolicy(Qt.CustomContextMenu)
        bt_item.customContextMenuRequested.connect(lambda pos: menu.exec_(bt_item.mapToGlobal(pos)))
        self.change_tool_show_style(dir_)

    def del_tool_item(self, action_item, bt_item, dir_):
        self.toolBar.removeAction(action_item)
        if state.PATH_TASK.replace("/", "\\") == dir_:
            self.datas = []
            self.row = 0
            self.column = -1
            # 清空当前布局
            for i in reversed(range(self.g_box.count())):
                self.g_box.itemAt(i).widget().setParent(None)
        del bt_item, action_item  # 删除动作对象和bt对象

        txt_ = ""
        packs = state.PACKS_TASK.split("#@@#")

        if len(packs) >= 1:
            for pack in packs:

                if os.path.realpath(dir_) != os.path.realpath(pack) and pack != "":
                    txt_ = txt_ + pack + "#@@#"
        state.PACKS_TASK = txt_
        print(f"成功移除{dir_}任务包")
        self.sg.mysig_tishi.emit(f"成功移除{dir_}任务包")

    def down_tool_item(self, idex):
        task_list = state.PACKS_TASK.split("#@@#")
        if idex < len(task_list) - 1:
            # 将指定索引位置的成员与其前一个成员交换位置
            task_list[idex], task_list[idex + 1] = task_list[idex + 1], task_list[idex]

        state.PACKS_TASK = ""
        for item in task_list:
            if item != "":
                state.PACKS_TASK += "#@@#" + item

        self.load_task_packs()

    def up_tool_item(self, idex):
        task_list = state.PACKS_TASK.split("#@@#")
        if idex > 0:
            # 将指定索引位置的成员与其后一个成员交换位置
            task_list[idex], task_list[idex - 1] = task_list[idex - 1], task_list[idex]
        state.PACKS_TASK = ""
        for item in task_list:
            if item != "":
                state.PACKS_TASK += "#@@#" + item

        self.load_task_packs()









    def save_ini_seting(self):
        try:
            hwnd = ctypes.windll.kernel32.GetConsoleWindow()
            if hwnd:
                rect = win32gui.GetWindowRect(hwnd)
                x, y, w, h = rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]
            else:
                x, y, w, h = state.CMD_LEFT, state.CMD_TOP, state.CMD_WIDTH, state.CMD_HEIGHT

            # 创建 ConfigParser 对象
            config = configparser.ConfigParser()
            # 添加节和键-值对
            config['seting'] = {
                "GAME_TITLE": state.GAME_TITLE,
                'LIANZHAO': state.LIANZHAO,
                'LIANZHAOFUWU': state.LIANZHAOFUWU,
                'DUANGKOUHAO': state.DUANGKOUHAO,
                'PATH_TASK': state.PATH_TASK,
                'PATH_JIAOBEN': state.PATH_JIAOBEN,
                'PACKS_TASK': state.PACKS_TASK,
                'WEIGHTS': state.WEIGHTS,
                'PROVIDERS': state.PROVIDERS,
                'IMGSIZE_WIDTH': str(state.IMGSIZE_WIDTH),
                'IMGSIZE_HEIGHT': str(state.IMGSIZE_HEIGHT),
                'WINDOW_WIDTH': str(self.width()),
                'WINDOW_HEIGHT': str(self.height()),
                'WINDOW_LEFT': str(self.x()),
                'WINDOW_TOP': str(self.y()),
                'CMD_WIDTH': str(w),
                'CMD_HEIGHT': str(h),
                'CMD_LEFT': str(x),
                'CMD_TOP': str(y),
                'ON_SHUTDOWN': str(state.ON_SHUTDOWN),
                'ON_JIXING': str(state.ON_JIXING),
                'ON_NEXTPACK': str(state.ON_NEXTPACK),
                'ON_STARTWITH': str(state.ON_STARTWITH),
                'ON_LIANZHAOBUJIANCE': str(state.ON_LIANZHAOBUJIANCE),
                'TIMEOUT_DAGUAI': str(state.TIMEOUT_DAGUAI)
            }
            # 写入配置到 INI 文件
            with open("./datas/setting.ini", 'w') as configfile:
                config.write(configfile)
        except:
            pass



    def change_tool_show_style(self, dir_):
        # 获取工具栏上的所有动作
        actions_list = self.toolBar.actions()

        # 遍历处理每个动作
        for action in actions_list:
            # 在这里对每个动作进行处理

            bt_item = action.defaultWidget()
            if dir_ == bt_item.toolTip().replace("/", "\\").split("\n")[0]:
                bt_item.setStyleSheet("border-width: 1px; padding: 3px;")
            else:
                bt_item.setStyleSheet("border: none; padding: 3px;")



    def show_tool_item(self, dir_):

        self.save()
        state.PATH_TASK = dir_
        self.save_ini_seting()
        self.update_tasks()
        self.change_tool_show_style(dir_)
        print(f"成功设置{state.PATH_TASK}为当前任务文件夹")



    def save(self):

        for idex in range(len(self.datas)):
            self.returnPressed_name(idex)
        # 重写closeEvent方法,在窗口关闭时调用quit()退出应用程序

        for i, data in enumerate(self.datas):
            dir_ = os.path.join(state.PATH_TASK, data["name"])
            self.save_ini(dir_, data)
        self.update_tasks()
        self.save_ini_seting()



    def update_tasks(self):
        try:
            self.datas = []
            self.row = 0
            self.column = -1

            # 清空当前布局
            for i in reversed(range(self.g_box.count())):
                self.g_box.itemAt(i).widget().setParent(None)
            # 遍历文件夹下有哪些目录
            # 判断这个路径是否存在
            if not os.path.exists(state.PATH_TASK):
                state.PATH_TASK = "./datas/Task/"

            # # 创建 ConfigParser 对象
            # config_main = configparser.ConfigParser()
            # # 加载 INI 文件
            #
            # config_main.read(os.path.join(state.PATH_TASK, "细节参数.ini"))
            # self.run_times = int(config_main.get('seting', 'run_times', fallback='1'))
            # self.action_run_times.setText(f"设置:当前任务包 执行次数:{self.run_times}")
            #
            # # 获取文件夹列表
            # folders = [item for item in os.listdir(state.PATH_TASK) if
            #            os.path.isdir(os.path.join(state.PATH_TASK, item))]
            # # 将文件夹名称中的数字提取出来,并按照数字大小排序
            # sorted_folders = sorted(folders, key=lambda x: extract_number(x))
            # for item in sorted_folders:
            #     item_path = os.path.join(state.PATH_TASK, item)
            #     if os.path.isdir(item_path):
            #         # 创建 ConfigParser 对象
            #         config = configparser.ConfigParser()
            #         # 加载 INI 文件
            #         config.read(os.path.join(item_path, "jiaoben.ini"))
            #         if config.get('seting', 'type', fallback='1') == "2":
            #             # 副本任务
            #             self.add_taskfuben(item_path, config)
            #         elif config.get('seting', 'type', fallback='1') == "3":
            #             # 脚本任务
            #             self.add_taskjiaoben(item_path, config)
            #         elif config.get('seting', 'type', fallback='1') == "4":
            #             # 脚本任务
            #             self.add_xuanjue(item_path, config)
            #         elif config.get('seting', 'type', fallback='1') == "5":
            #             # 脚本任务
            #             self.add_xuanlianzhao(item_path, config)
            #         elif config.get('seting', 'type', fallback='1') == "6":
            #             self.add_taskpy(item_path, config)
            #         else:
            #             # 锄地任务
            #             self.add_task(item_path, config)
        except Exception:
            print(f"请选择任务文件夹,目前没有这个文件夹{state.PATH_TASK}")

























    def on_timer_timeout(self):
        # 每隔一段时间自动显示图片
        self.sg.mysig_show_xunlu.emit()
        self.sg.mysig_show_yolov.emit()

    # 绑定信号槽
    def connect_set(self):
        # 创建一个顶级菜单
        self.menu = self.menuBar()
        self.menu_view = self.menu.addMenu("视图")

        # 创建一个动作
        self.action_isShow = QAction("显示检测结果窗口", self)
        self.action_isShow.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F11))
        self.action_isShow.triggered.connect(self.hotkey_isShow)
        self.action_isShow.setCheckable(True)
        self.action_isShow.setChecked(True)
        self.menu_view.addAction(self.action_isShow)

        # 打开预测窗口
        self.hotkey_isShow()

        self.sg = MySignal()
        self.sg.mysig_show_xunlu.connect(self.show_xunlu)
        self.sg.mysig_show_yolov.connect(self.show_yolov)

    def show_xunlu(self, image_path="./datas/111.png"):
        # 加载本地图片
        pixmap = QPixmap(image_path)

        # 设置图片到 lb_xunlu 控件
        self.fromshow.lb_xunlu.setPixmap(pixmap)

        # 设置宽度固定,高度自适应
        self.fromshow.window_width = int(self.fromshow.window_height * pixmap.width() / pixmap.height())
        self.fromshow.lb_xunlu.setFixedHeight(self.fromshow.window_height)
        self.fromshow.lb_xunlu.setFixedWidth(self.fromshow.window_width)
        self.fromshow.lb_xunlu.setScaledContents(True)

    def show_yolov(self, image_path="./datas/111.png"):
        # 加载本地图片
        pixmap1 = QPixmap(image_path)

        # 设置图片到 lb_yolov 控件
        self.fromshow.lb_yolov.setPixmap(pixmap1)

        # 根据窗口宽度调整 lb_yolov 的位置
        if self.fromshow.width() >= self.fromshow.lb_yolov.width() + self.fromshow.lb_xunlu.width():
            self.fromshow.lb_yolov.move(self.fromshow.lb_xunlu.width(), 0)
        else:
            self.fromshow.lb_yolov.move(0, self.fromshow.lb_xunlu.height())

    # 打开预测窗口
    def hotkey_isShow(self):
        # 尝试创建悬浮窗口实例
        if not hasattr(self, "fromshow"):
            self.fromshow = FormShow(self)  # 创建悬浮窗口实例

            self.addDockWidget(Qt.TopDockWidgetArea, self.fromshow)  # 添加悬浮窗口到主窗口

    # 更新布局
    def update_layout(self):
        try:
            # 获取主窗口的宽度
            width = self.centralWidget().width()

            # 计算每行可以容纳的组件数量
            num_per_row = (width) // (self.column_step * ratio)
            if num_per_row < 1:
                num_per_row = 1

            # 清空当前布局
            for i in reversed(range(self.g_box.count())):
                self.g_box.itemAt(i).widget().setParent(None)

            # 重新添加组件到网格布局
            for i, data in enumerate(self.datas):
                self.row = int(i // num_per_row)
                self.column = int(i % num_per_row)
                self.g_box.addWidget(data["f_item"], self.row, self.column)
        except:
            pass

    # 设置主窗口样式
    def set_ui(self):
        # 设置主题样式为 Flatwhite
        from qt_material import apply_stylesheet
        apply_stylesheet(app, theme='dark_pink.xml')

        # 设置窗口样式表
        self.setStyleSheet("""
        QScrollBar::handle:horizontal {
            background-color: #A50F2C;  /* 设置滑块颜色 */
        }
        QScrollBar::handle:horizontal:hover {
            background-color: #FF1744;  /* 设置滑块颜色 */
        }
        QPushButton:hover {
            background-color: #DFC472;  /* 设置颜色 */
        }
        QPlainTextEdit {
            padding: 0px;
            margin: 0px;
        }
        QPushButton {
            padding: 0px;
            margin: 1px;
        }
        """ + "font-family: {}; font-size: {}pt;".format(font.family(), font.pointSize()))


# 主程序入口
if __name__ == '__main__':
    # 获取屏幕宽度和高度
    screen_width = ctypes.windll.user32.GetSystemMetrics(0)
    screen_height = ctypes.windll.user32.GetSystemMetrics(1)

    # 初始化QT应用
    app = QApplication(sys.argv)

    # 计算分辨率比例
    ratio = screen_width / 2560

    # 设置全局字体大小
    base_font_size = 13
    new_font_size = int(base_font_size * ratio)
    font = QFont("Arial", new_font_size)

    # 创建主窗口实例
    window_main = MainWindow()

    # 显示主窗口
    window_main.show()

    # 监听消息不关闭
    sys.exit(app.exec_())
相关推荐
用户03284722207010 小时前
如何搭建本地yum源(上)
运维
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工3 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智3 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_3 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
施努卡机器视觉4 天前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造
dayuOK63074 天前
写作卡壳怎么办?我的“5分钟启动法”
人工智能·职场和发展·自动化·新媒体运营·媒体
AC赳赳老秦4 天前
用 OpenClaw 搭建服务器故障应急响应系统,自动处理 80% 常见运维故障
android·运维·服务器·python·rxjava·deepseek·openclaw