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_())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/884151.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RP2040 C SDK GPIO和IRQ 唤醒功能使用

RP2040 C SDK GPIO和中断功能使用 SIO介绍 手册27页&#xff1a; The Single-cycle IO block (SIO) contains several peripherals that require low-latency, deterministic access from the processors. It is accessed via each processor’s IOPORT: this is an auxiliary…

PHP基础知识

一、PHP变量&#xff1a; 变量是用于存储信息的"容器" <?php$x5;$y6;$z$x$y;echo $z; ?> 在 PHP 中&#xff0c;这些$字母被称为变量。 PHP 变量 变量可以是很短的名称&#xff08;如 x 和 y&#xff09;或者更具描述性的名称&#xff08;如 age、carname、…

【Java异常】(简简单单拿捏)

【Java异常】&#xff08;简简单单拿捏&#xff09; 1. 异常的简单介绍2. 异常的抛出2.1 语法 3. 异常的处理3.1 异常声明throws3.2 try-catch捕获并处理 4. 例子&#xff08;try-catch自定义异常&#xff09; 1. 异常的简单介绍 程序员在运行代码时会遇到很多异常&#xff0c…

学习threejs,绘制二维线

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言二、&#x1f340;绘制二维线1. ☘️…

基于Hive和Hadoop的保险分析系统

本项目是一个基于大数据技术的保险分析系统&#xff0c;旨在为用户提供全面的汽车保险信息和深入的保险价格分析。系统采用 Hadoop 平台进行大规模数据存储和处理&#xff0c;利用 MapReduce 进行数据分析和处理&#xff0c;通过 Sqoop 实现数据的导入导出&#xff0c;以 Spark…

2016年国赛高教杯数学建模A题系泊系统的设计解题全过程文档及程序

2016年国赛高教杯数学建模 A题 系泊系统的设计 近浅海观测网的传输节点由浮标系统、系泊系统和水声通讯系统组成&#xff08;如图1所示&#xff09;。某型传输节点的浮标系统可简化为底面直径2m、高2m的圆柱体&#xff0c;浮标的质量为1000kg。系泊系统由钢管、钢桶、重物球、…

SpringBoot使用EasyPoi根据模板导出word or pdf

1、导出效果 1.1 wrod 1.2 pdf 2、依赖 <!--word--><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>4.3.0</version></dependency><dependency><groupId>cn.…

探讨TikTok直播专线的必要性

随着社交媒体的迅速发展&#xff0c;短视频平台如TikTok&#xff08;在中国抖音&#xff09;已成为现代人生活中不可或缺的一部分。TikTok的直播功能因其即时性和互动性受到广泛喜爱&#xff0c;但在中国市场上&#xff0c;主播们在使用这一功能时面临不少挑战&#xff0c;其中…

优选拼团平台架构解析与关键代码逻辑概述

一、系统架构设计 唐古拉优选拼团平台采用多层架构设计&#xff0c;主要包括前端展示层、业务逻辑层、数据访问层及数据存储层。 前端展示层&#xff1a;负责用户界面的展示和交互&#xff0c;包括商品列表、拼团详情、订单管理等页面。前端采用现代前端框架&#xff08;如Vue…

【Linux】图解详谈HTTPS的安全传输

文章目录 1.前置知识2.只使用对称加密3.只使用非对称加密 因为私钥加密只能公钥解开&#xff0c;公钥加密只能私钥解开4.双方都是使用非对称加密5.非对称加密 对称加密6.非对称加密对称加密CA认证&#xff08;一&#xff09;CA认证&#xff08;二&#xff09;https &#xff0…

信息学奥赛的最佳启蒙阶段是小学还是初中?

信息学奥赛&#xff08;NOI&#xff09;近年来越来越受家长和学生的关注&#xff0c;尤其是在编程教育不断升温的背景下&#xff0c;信息学竞赛成为了许多家庭的教育选择之一。家长们往往关心的是&#xff1a;孩子应该在什么年龄段开始接触信息学竞赛&#xff0c;才能打下坚实的…

ArcEngine C#二次开发图层处理:根据属性分割图层(Split)

需求&#xff1a;仅根据某一属性&#xff0c;分割图层&#xff0c;并以属性值命名图层名称保存。 众所周知&#xff0c;ArcGIS ArcToolbox中通过Split可以实现图形分割一个图层&#xff0c;以属性值命名图层&#xff0c;如下图所示。 本文仅仅依据属性值&#xff0c;将一个shp…

统信服务器操作系统【qcow2 镜像空间扩容】方案

使用 qcow2 镜像安装系统,当默认安装系统存储空间不够用时,进行自定义扩容 文章目录 准备环境扩容步骤一、检查环境信息1.查看镜像信息2.查看镜像分区信息3.确认需要扩容的分区名二、扩容1.备份镜像2.创建新的镜像文件,并指定空间3.将系统扩容到新的镜像三、扩容 lvm 分区四…

自然语言处理实战项目:从理论到实现

一、引言 自然语言处理&#xff08;NLP&#xff09;是计算机科学、人工智能和语言学交叉的领域&#xff0c;旨在让计算机能够理解、处理和生成人类语言。随着互联网的飞速发展&#xff0c;大量的文本数据被产生&#xff0c;这为自然语言处理技术的发展提供了丰富的素材&#xf…

从响应到预见:前瞻性客户服务策略的实践与探索

在快速变化的商业环境中&#xff0c;客户服务已不再是简单的需求响应与问题解决&#xff0c;它正逐步演变为企业竞争力的核心要素之一。传统的“响应式”服务模式虽能满足基本的客户需求&#xff0c;但在追求极致客户体验和构建长期忠诚度的今天&#xff0c;显然已显不足。因此…

使用 Puppeteer-Cluster 和代理进行高效网络抓取: 完全指南

文章目录 一、介绍&#xff1f;二、什么是 Puppeteer-Cluster&#xff1f;三、为什么代理在网络抓取中很重要&#xff1f;四、 为什么使用带代理的 Puppeteer-Cluster&#xff1f;五、分步指南&#xff1a; 带代理的 Puppeteer 群集5.1. 步骤 1&#xff1a;安装所需程序库5.2. …

ERROR:start workflow error,dolphinscheduler log重复刷屏(死循环)直至磁盘存满

在使用ds过后发现&#xff0c;我虚拟机中的磁盘内存全部沾满了 查看目录下大于100M的文件&#xff1a; find / -size 100M 查看后发现问题在于ds产生的日志文件特别大而且多&#xff0c; 查看日志后发现日志中一直都在死循环错误&#xff1a;start workflow error 等 其中文件…

命令行gcc -v和g++ -v输出版本不一致

命令行gcc -v和g -v输出版本不一致 前言&#xff1a;本文初编辑于2024年9月27日 CSDN主页&#xff1a;https://blog.csdn.net/rvdgdsva 博客园主页&#xff1a;https://www.cnblogs.com/hassle 博客园本文链接&#xff1a;https://www.cnblogs.com/hassle/p/18435916 赞美大…

Java ERP管理系统源码解析:微服务架构实践Spring Cloud Alibaba与Spring Boot

在当今数字化浪潮的推动下&#xff0c;企业对于高效、稳定且易于扩展的管理系统需求日益增长。为了满足这一需求&#xff0c;我们精心打造了一款基于Java技术的鸿鹄ERP&#xff08;Enterprise Resource Planning&#xff09;管理系统。该系统充分利用了Spring Cloud Alibaba、S…

局域网广域网,IP地址和端口号,TCP/IP 4层协议,协议的封装和分用

前言 在古老的年代&#xff0c;如果我们要实现两台机器进行数据传输&#xff0c; A员工就得去B员工的办公电脑传数据&#xff08;B休息&#xff0c;等A传完&#xff09;&#xff0c;这样就很浪费时间 所以能不能不去B的工位的同时&#xff0c;还能传数据。这时候网络通信就出来…