yolo自动化项目实例解析(二)ui页面整理

news2024/11/25 5:38:52

我们在上一章整理main.py 的if __name__ == '__main__':  内容还留下面这一段,

            app = QApplication(sys.argv)  # 初始化Qt应用
            ratio = screen_width / 2560  # 分辨率比例
            # 设置全局字体大小
            # 计算字体大小
            base_font_size = 13
            # 基准字体大小,适合1920*1080分辨率
            new_font_size = int(base_font_size * ratio)
            font = QFont("Arial", new_font_size)

            # 子控件的宽度
            item_width=320
            item_height=240
            item_height_min = 60
            window_main = MainWindow()
            window_main.show()
            sys.exit(app.exec_())  # 监听消息不关闭

在说这个之前先了解一些基本的ui工具及使用

一、ui工具Qt Designer

pip install pyqt5
pip install pyside2

上面这两个工具支持两个不同版本的ui页面创建,并且保存的文件的依赖库也不一样,我们这里主要用pyqt5

1、启动ui编辑器

#pyqt5
designer


#pyside2
pyside2-designerr

编辑器都一样,执行一个就行,这里打开pyqt5的

 

 

这里注意一下,你创建的ui项目这里的类名,你如果想要在项目里面调用窗口的信息都是基于类名的

2、保存ui文件

我们这里随便整俩按钮,然后保存到项目ui/目录下叫test.ui

 

3、ui转py代码

pyuic5 -o ./test.py ./test.ui

#如果是pyside2 则是
#pyside2-uic --from-imports -o ./test.py  ./test.ui

内容

test.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file './test.ui'
#
# Created by: PyQt5 UI code generator 5.15.11
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(572, 90, 131, 28))
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(572, 240, 131, 28))
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "PushButton1"))
        self.pushButton_2.setText(_translate("MainWindow", "PushButton2"))

4、py调用页面打开

import sys
from PyQt5.Qt import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from ui.test import Ui_MainWindow



#MainWindow 是继承了俩父类QMainWindow 和Ui_MainWindow
#QMainWindow 类是我们上面建窗口的时候的类,提供了一系列那种类型窗口的方法调用
#比如窗口标题、导航条、页面显示啥啥的
#Ui_MainWindow 是我们刚才去窗口的页面主窗口,我们继承后就可以通过self直接调用窗口
class MainWindow(QMainWindow , Ui_MainWindow):
    def __init__(self):
        super().__init__()  # 调用基类构造方法
        self.setupUi(self)  # 设置UI布局
        self.retranslateUi(self)  # 重新翻译UI组件的文字


if __name__ == '__main__':
    app = QApplication(sys.argv)  # 初始化Qt应用

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

    # 显示主窗口
    window_main.show()

    # 进入事件循环
    sys.exit(app.exec_())

5、ui页面与代码交互

import sys
from PyQt5.Qt import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from ui.test import Ui_MainWindow



#MainWindow 是继承了俩父类QMainWindow 和Ui_MainWindow
#QMainWindow 类是我们上面建窗口的时候的类,提供了一系列那种类型窗口的方法调用
#比如窗口标题、导航条、页面显示啥啥的
#Ui_MainWindow 是我们刚才去窗口的页面主窗口,我们继承后就可以通过self直接调用窗口
class MainWindow(QMainWindow , Ui_MainWindow):
    def __init__(self):
        super().__init__()  # 调用基类构造方法
        self.setupUi(self)  # 设置UI布局
        self.retranslateUi(self)  # 重新翻译UI组件的文字

        # 连接按钮箱的信号到槽函数
        self.pushButton.clicked.connect(self.on_push_button_clicked)
        self.pushButton_2.clicked.connect(self.on_push_button_2_clicked)

    def on_push_button_clicked(self):
        print("PushButton1 被点击")

        # 在这里执行PushButton1的操作

    def on_push_button_2_clicked(self):
        print("PushButton2 被点击")

        # 在这里执行PushButton2的操作
if __name__ == '__main__':
    app = QApplication(sys.argv)  # 初始化Qt应用

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

    # 显示主窗口
    window_main.show()

    # 进入事件循环
    sys.exit(app.exec_())

关于按键怎么找

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

        #看这里pushButton 和pushButton_2就是我们要用的链接信号槽的名称
        self.pushButton.setText(_translate("MainWindow", "PushButton1"))
        self.pushButton_2.setText(_translate("MainWindow", "PushButton2"))

 

二、 ui窗口布局代码解析

1、main.py添加调用主窗口 及窗口属性

            ysam = YunShenAutoMap()  # 启动寻路类
            print(ysam)
            app = QApplication(sys.argv)  # 初始化Qt应用
            ratio = screen_width / 2560  # 分辨率比例
            # 设置全局字体大小
            # 计算字体大小
            base_font_size = 13
            # 基准字体大小,适合1920*1080分辨率
            new_font_size = int(base_font_size * ratio)
            font = QFont("Arial", new_font_size)

            # 子控件的宽度
            item_width=320
            item_height=240
            item_height_min = 60
            window_main = MainWindow()
            window_main.show()
            sys.exit(app.exec_())  # 监听消息不关闭
1、新增主窗口ui文件

vi ui/main.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>mainWindow</class>
 <widget class="QMainWindow" name="mainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>原神锄地AI v1.4    F8暂停 F9停止 F10标记</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <widget class="QScrollArea" name="sa_main">
      <property name="widgetResizable">
       <bool>true</bool>
      </property>
      <widget class="QWidget" name="scrollAreaWidgetContents">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>768</width>
         <height>558</height>
        </rect>
       </property>
      </widget>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QStatusBar" name="sb_main"/>
  <widget class="QToolBar" name="toolBar">
   <property name="windowTitle">
    <string>toolBar</string>
   </property>
   <attribute name="toolBarArea">
    <enum>LeftToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <action name="actionSave_All">
   <property name="text">
    <string>Save All</string>
   </property>
  </action>
  <action name="actionAdd_Mode">
   <property name="text">
    <string>Add Task</string>
   </property>
  </action>
  <action name="actionAdd_Script">
   <property name="text">
    <string>Add Script</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections/>
</ui>

转换py

pyuic5 -o ./main.py ./main.ui
2、新增主窗口函数
from PyQt5.QtGui import QFont, QIcon
from ui.main import Ui_mainWindow
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super().__init__()
        self.set_ui()
        self.setupUi(self)

        #设置窗口图标
        self.setWindowIcon(QIcon("datas/logo.png"))
        ##设置窗口标题
        self.setWindowTitle(f"懒人原神AI{state.版本号}  F8暂停 F9停止 F10标记")
        #设置窗口大小
        self.resize(state.WINDOW_WIDTH, state.WINDOW_HEIGHT)
        #设置窗口默认坐标
        self.move(state.WINDOW_LEFT, state.WINDOW_TOP)

    #调整整个页面为灰色
    def set_ui(self):
        # 设置主题样式为 Flatwhite
        # 创建 QtitanRibbon 实例
        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()))


3、运行测试

4、main当前代码整理
import ctypes
import os
import subprocess
import sys
import time
import traceback


from PyQt5.QtWidgets import QApplication, QMainWindow

import state
from auto import main
from wayfinding import *
from logger_module import logger
from jianchaupdate import get_var_data, get_updatetxt
from lanrentools.moni import find_child_window_handle, screen_width




from PyQt5.QtGui import QFont, QIcon
from ui.main import Ui_mainWindow
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super().__init__()
        self.set_ui()
        self.setupUi(self)

        #设置窗口图标
        self.setWindowIcon(QIcon("datas/logo.png"))
        ##设置窗口标题
        self.setWindowTitle(f"AI{state.版本号}  F8暂停 F9停止 F10标记")
        #设置窗口大小
        self.resize(state.WINDOW_WIDTH, state.WINDOW_HEIGHT)
        #设置窗口默认坐标
        self.move(state.WINDOW_LEFT, state.WINDOW_TOP)

    def set_ui(self):
        # 设置主题样式为 Flatwhite
        # 创建 QtitanRibbon 实例
        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__':
    try:
        if ctypes.windll.shell32.IsUserAnAdmin():
            hwnd_cmd = find_child_window_handle(0, "ConsoleWindowClass", "YuanShenAi")
            if hwnd_cmd == 0:
                hwnd_cmd = find_child_window_handle(0, "ConsoleWindowClass", "懒人原神")
            vardata = get_var_data()
            if vardata != False:
                updatetxt = get_updatetxt()
                print(updatetxt)
                print("当前版本号:" + state.版本号)

                if float(vardata[1]) > float(state.版本号):
                    print(
                        "如果更新失败手动下更新包手动覆盖: https://gitee.com/LanRenZhiNeng/lanren-genshin-impact-ai/releases")
                    var = input(f"发现更新的版本 v{vardata[1]} 是否需要更新? (输入yes or no  默认更新)\n")
                    if var == "":
                        var = "yes"
                    if var.lower() != "no":
                        update_process = subprocess.Popen(f'update.exe "{vardata[0]}.exe" "{vardata[2]}"',
                                                          creationflags=subprocess.CREATE_NEW_CONSOLE)
                        time.sleep(1)
                        sys.exit()
            # 运行需要管理员权限的代码
            kernel32 = ctypes.windll.kernel32
            kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), 128)
            os.environ['PNG_IGNORE_WARNINGS'] = '1'

            # 在事件循环中创建一个任务对象并加入事件循环
            aty = main()  # 启动yolov服务

            ysam = YunShenAutoMap()  # 启动寻路类
            print(ysam)
            app = QApplication(sys.argv)  # 初始化Qt应用
            ratio = screen_width / 2560  # 分辨率比例
            # 设置全局字体大小
            # 计算字体大小
            base_font_size = 13
            # 基准字体大小,适合1920*1080分辨率
            new_font_size = int(base_font_size * ratio)
            font = QFont("Arial", new_font_size)

            # 子控件的宽度
            item_width=320
            item_height=240
            item_height_min = 60
            window_main = MainWindow()
            window_main.show()
            sys.exit(app.exec_())  # 监听消息不关闭
        else:
            # 如果不是管理员,则请求以管理员权限重新运行程序
            ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
    except Exception as err:
        if str(err).find("sys.exit")==-1:

            logger.error(traceback.format_exc())

2、 main动态布局、计时器触发

这些都是在main.py的MainWindow类的 __init__初始化函数下添加

1、一些变量和布局

vi main.py

        from PyQt5.QtCore import Qt
        from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget
        self.g_box = QGridLayout() #创建布局 这是一种可以将控件放置在网格单元格中的布局管理器
        self.container_widget = QWidget()  # 创建了一个 QWidget 对象,这个部件将用于容纳你想要添加到滚动区域的所有控件
        self.container_widget.setLayout(self.g_box)  # 将网格布局设置给中间部件,之前创建的 QGridLayout 设置为 QWidget 的布局
        #self.g_box.setAlignment(Qt.AlignTop | Qt.AlignLeft)  # 布局 左上对齐
        self.g_box.setContentsMargins(0, 0, 0, 0)  # 边距 为0则紧贴边缘
        #self.g_box.setAlignment(Qt.AlignTop)
        self.sa_main.setWidget(self.container_widget)  # 将中间部件设置为QScrollArea的子部件

        #始终置顶窗口,除非删除或最小化
        self.setWindowFlags(Qt.WindowStaysOnTopHint)

        #一些基础变量
        self.row = 0
        self.column = -1
        self.run_times=1
        self.column_step=310

        # 所有数据
        self.datas = []

3、添加计时器

在class MainWindow(QMainWindow, Ui_mainWindow):  的init下面添加

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

    #根据窗口宽度动态调整布局
    #主要目的是动态调整布局,以适应窗口大小的变化
    # 通过计算每行可以容纳的组件数量
    # 并重新排列这些组件,可以使界面看起来更加整洁和美观
    def update_layout(self):
        try:
            # 获取主窗口的宽度
            width =self.centralWidget().width()
            # 计算每行可以容纳的组件数量
            num_per_row = (width ) // (self.column_step * ratio)  # 假设每个组件的宽度为200
            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

    import webbrowser
    def connect_set(self):
        '''
        绑定信号
        :return:
        '''

        self.sg = MySignal()
        state. QT_信号=self.sg
        self.sg.mysig_shutdown.connect(self.show_shutdown_dig)
        self.sg.mysig_mouse_through.connect(self.set_mouse_through)
        self.sg.mysig_tishi.connect(self.set_tishi)
        self.sg.mysig_next_pack.connect(self.next_pack)

        self.sg.mysig_show_xunlu.connect(self.show_xunlu)
        self.sg.mysig_show_yolov.connect(self.show_yolov)
        self.sg.mysig_dingwei.connect(self.dingwei)



        self.menu = self.menuBar()
        # 创建一个顶级菜单
        self.menu_file = self.menu.addMenu("文件")
        # 创建一个动作
        self.action_addtask = QAction("新增-AI锄地任务-大世界寻路打怪", self)
        self.action_addtask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_1))
        self.action_addtask.triggered.connect(self.hotkey_addtask)
        self.menu_file.addAction(self.action_addtask)

        # 创建一个动作
        self.action_addtaskfuben = QAction("新增-AI副本任务-任意副本需要录制传送", self)
        self.action_addtaskfuben.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_2))
        self.action_addtaskfuben.triggered.connect(self.hotkey_addtaskfuben)
        self.menu_file.addAction(self.action_addtaskfuben)

        # 创建一个动作
        self.action_addtaskjiaoben = QAction("新增-脚本回放任务-适合采集/挖矿/晶蝶/等等", self)
        self.action_addtaskjiaoben.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_3))
        self.action_addtaskjiaoben.triggered.connect(self.hotkey_addtaskjiaoben)
        self.menu_file.addAction(self.action_addtaskjiaoben)

        # 创建一个动作
        self.action_qiejue = QAction("新增-切换角色任务", self)

        self.action_qiejue.triggered.connect(self.hotkey_qiejue)
        self.menu_file.addAction(self.action_qiejue)

        # 创建一个动作
        self.action_qiehuanlianzhao = QAction("新增-切换连招任务", self)
        self.action_qiehuanlianzhao.triggered.connect(self.hotkey_qiehuanlianzhao)
        self.menu_file.addAction(self.action_qiehuanlianzhao)

        # 创建一个动作
        self.action_importtask = QAction("导入视觉任务", self)
        self.action_importtask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_4))
        self.action_importtask.triggered.connect(self.hotkey_importtask)
        self.menu_file.addAction(self.action_importtask)

        self.action_opentaskdir = QAction("打开任务文件夹", self)
        self.action_opentaskdir.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_5))
        self.action_opentaskdir.triggered.connect(self.hotkey_opentaskdir)
        self.menu_file.addAction(self.action_opentaskdir)

        self.action_selecttaskdir = QAction("导入/选择任务包", self)
        self.action_selecttaskdir.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_6))
        self.action_selecttaskdir.triggered.connect(self.hotkey_selecttaskdir)
        self.menu_file.addAction(self.action_selecttaskdir)

        self.action_setlianzhao = QAction("选择连招脚本", self)
        self.action_setlianzhao.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_7))
        self.action_setlianzhao.triggered.connect(self.hotkey_setlianzhao)
        self.menu_file.addAction(self.action_setlianzhao)

        self.action_addlianzhao = QAction("录制/编辑连招", self)
        self.action_addlianzhao.triggered.connect(self.hotkey_addlianzhao)
        self.menu_file.addAction(self.action_addlianzhao)

        # 创建一个顶级菜单
        self.menu_ck = self.menu.addMenu("选择")
        # 创建一个动作
        self.action_all_ck = QAction("全部选中", self)
        self.action_all_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_8))
        self.action_all_ck.triggered.connect(self.hotkey_all_ck)
        self.menu_ck.addAction(self.action_all_ck)

        self.action_all_not_ck = QAction("全部不选", self)
        self.action_all_not_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_9))
        self.action_all_not_ck.triggered.connect(self.hotkey_all_not_ck)
        self.menu_ck.addAction(self.action_all_not_ck)

        self.action_all_fan_ck = QAction("全部反选", self)
        self.action_all_fan_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_0))
        self.action_all_fan_ck.triggered.connect(self.hotkey_all_fan_ck)
        self.menu_ck.addAction(self.action_all_fan_ck)


        self.action_keys_ack = QAction("选中包含某个关键词的", self)
        self.action_keys_ack.triggered.connect(self.hotkey_keys_ack)
        self.menu_ck.addAction(self.action_keys_ack)

        self.action_num_ck = QAction("选中包含某个区间数字的", self)
        self.action_num_ck.triggered.connect(self.hotkey_num_ck)
        self.menu_ck.addAction(self.action_num_ck)

        self.action_find = QAction("查找并定位到包含某个关键字的任务", self)
        self.action_find.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F))
        self.action_find.triggered.connect(self.hotkey_find)
        self.menu_ck.addAction(self.action_find)



        # 创建一个顶级菜单
        self.menu_run = self.menu.addMenu("操作")
        # 创建一个动作
        self.action_runall = QAction("启动选中任务", self)
        self.action_runall.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F1))
        self.action_runall.triggered.connect(self.hotkey_runall)
        self.menu_run.addAction(self.action_runall)

        self.action_deltask = QAction("删除选中任务", self)
        self.action_deltask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F2))
        self.action_deltask.triggered.connect(self.hotkey_deltask)
        self.menu_run.addAction(self.action_deltask)

        self.action_refresh = QAction("保存任务并刷新顺序", self)
        self.action_refresh.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        self.action_refresh.triggered.connect(self.save)
        self.menu_run.addAction(self.action_refresh)

        # 创建一个动作
        self.action_kuang = QAction("选中任务-是否勾选-矿", self)
        self.action_kuang.setCheckable(True)
        self.action_kuang.setChecked(False)
        self.action_kuang.triggered.connect(self.hotkey_kuang)
        self.action_kuang.setChecked(True)
        self.menu_run.addAction(self.action_kuang)

        # 创建一个动作
        self.action_hua = QAction("选中任务-是否勾选-花", self)
        self.action_hua.setCheckable(True)
        self.action_hua.setChecked(False)
        self.action_hua.triggered.connect(self.hotkey_hua)
        self.action_hua.setChecked(True)
        self.menu_run.addAction(self.action_hua)

        # 创建一个动作
        self.action_guai = QAction("选中任务-是否勾选-怪", self)
        self.action_guai.setCheckable(True)
        self.action_guai.setChecked(False)
        self.action_guai.triggered.connect(self.hotkey_guai)
        self.action_guai.setChecked(True)
        self.menu_run.addAction(self.action_guai)

        # 创建一个动作
        self.action_run_times = QAction(f"设置:当前任务包 执行次数:{self.run_times}", self)
        self.action_run_times.triggered.connect(self.hotkey_run_times)
        self.menu_run.addAction(self.action_run_times)

        # 创建一个顶级菜单
        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.action_isShowCmd = QAction("是否显示控制台", self)
        self.action_isShowCmd.triggered.connect(self.hotkey_isShowCmd)
        self.action_isShowCmd.setCheckable(True)
        self.action_isShowCmd.setChecked(True)
        self.menu_view.addAction(self.action_isShowCmd)

        # 创建一个顶级菜单
        self.menu_yun= self.menu.addMenu("云端")
        # 创建一个动作
        self.action_yunduanlist= QAction("懒人群友云端资源", self)
        self.action_yunduanlist.triggered.connect(self.hotkey_yunduanlist)

        self.menu_yun.addAction(self.action_yunduanlist)

        # 创建一个动作
        self.action_yunduanup1 = QAction("分享-副本打怪任务", self)
        self.action_yunduanup1.triggered.connect( lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/viwvNEP8c"))
        self.menu_yun.addAction(self.action_yunduanup1)

        self.action_yunduanup2 = QAction("分享-打怪锄地任务", self)
        self.action_yunduanup2.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/GjM0zwWAw"))
        self.menu_yun.addAction(self.action_yunduanup2)

        self.action_yunduanup3 = QAction("分享-回放脚本任务", self)
        self.action_yunduanup3.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/9eGN71WCG"))
        self.menu_yun.addAction(self.action_yunduanup3)

        self.action_yunduanup4 = QAction("分享-收集材料任务", self)
        self.action_yunduanup4.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/vWDkt4QRB"))
        self.menu_yun.addAction(self.action_yunduanup4)

        self.action_yunduanup5 = QAction("分享-连招脚本任务", self)
        self.action_yunduanup5.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/DVa5G18rL"))
        self.menu_yun.addAction(self.action_yunduanup5)

        self.action_yunduanup6 = QAction("分享-其它资源分享", self)
        self.action_yunduanup6.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/3ucsnfSr5"))
        self.menu_yun.addAction(self.action_yunduanup6)


        # 创建一个顶级菜单
        self.menu_tools = self.menu.addMenu("工具")

        # 创建一个动作
        self.action_stitchimg = QAction("合成全景大图", self)
        self.action_stitchimg.triggered.connect(self.hotkey_stitchimg)
        self.menu_tools.addAction(self.action_stitchimg)

        # 创建一个顶级菜单
        self.menu_setting = self.menu.addMenu("设置")
        # 创建一个动作
        self.action_runstartwith = QAction("启动改为从这开始", self)
        self.action_runstartwith.setCheckable(True)
        self.action_runstartwith.setChecked(False)
        self.menu_setting.addAction(self.action_runstartwith)


        # 创建一个动作
        self.action_nextpack = QAction("是否自动继续下一个任务包", self)
        self.action_nextpack.setCheckable(True)
        self.action_nextpack.setChecked(False)
        self.action_nextpack.triggered.connect(self.hotkey_nextpack)
        if state.ON_NEXTPACK == 0:
            self.action_nextpack.setChecked(False)
        else:
            self.action_nextpack.setChecked(True)
        self.menu_setting.addAction(self.action_nextpack)

        # 创建一个动作
        self.action_jixing = QAction("是否任务完成后领取纪行奖励", self)
        self.action_jixing.triggered.connect(self.hotkey_jixing)
        self.action_jixing.setCheckable(True)
        if state.ON_JIXING == 0:
            self.action_jixing.setChecked(False)
        else:
            self.action_jixing.setChecked(True)
        self.menu_setting.addAction(self.action_jixing)
        # 创建一个动作
        self.action_shutdown = QAction("是否任务完成后关机", self)
        self.action_shutdown.triggered.connect(self.hotkey_shutdown)
        self.action_shutdown.setCheckable(True)
        if state.ON_SHUTDOWN == 0:
            self.action_shutdown.setChecked(False)
        else:
            self.action_shutdown.setChecked(True)
        self.menu_setting.addAction(self.action_shutdown)

        self.action_lianzhaobujiance = QAction("是否强制把连招搓完", self)
        self.action_lianzhaobujiance.triggered.connect(self.hotkey_lianzhaobujiance)
        self.action_lianzhaobujiance.setCheckable(True)
        if state.ON_LIANZHAOBUJIANCE == 0:
            self.action_lianzhaobujiance.setChecked(False)
        else:
            self.action_lianzhaobujiance.setChecked(True)
        self.menu_setting.addAction(self.action_lianzhaobujiance)

        # 创建一个动作
        self.action_weights = QAction(f"设置AI模型 当前: {state.WEIGHTS.split('/')[-1].split('.')[0]}", self)
        self.action_weights.triggered.connect(self.hotkey_weights)
        self.menu_setting.addAction(self.action_weights)

        # 创建一个动作
        self.action_timeout = QAction(f"设置打怪超时 阈值:{state.TIMEOUT_DAGUAI}秒", self)
        self.action_timeout.triggered.connect(self.hotkey_timeout)

        self.menu_setting.addAction(self.action_timeout)



        # 创建一个顶级菜单
        self.menu_help = self.menu.addMenu("帮助")
        # 创建一个动作
        self.action_about = QAction("关于", self)

        self.action_about.triggered.connect(
            lambda: QMessageBox.information(self, "作者", "python懒人智能 仅供技术研究!请勿用于非法用途否则后果自负!"))
        self.menu_help.addAction(self.action_about)

        # 创建一个动作
        self.action_kaiyuan = QAction("开源地址", self)

        self.action_kaiyuan.triggered.connect(lambda: webbrowser.open("https://gitee.com/LanRenZhiNeng/lanren-genshin-impact-ai"))
        self.menu_help.addAction(self.action_kaiyuan)

        # 创建一个动作
        self.action_zanzhu = QAction("赞助入群", self)

        self.action_zanzhu.triggered.connect(
            lambda: webbrowser.open("http://w.kami.vip/s/FSUtd45z"))
        self.menu_help.addAction(self.action_zanzhu)

        # 创建一个动作
        self.action_jiaocheng = QAction("教程合集", self)
        self.action_jiaocheng.triggered.connect(
            lambda: webbrowser.open("https://www.bilibili.com/video/BV1aS421w7i1"))
        self.menu_help.addAction(self.action_jiaocheng)
        # 创建右键弹出菜单
        menu = QMenu(self)
        menu.addAction(self.action_selecttaskdir)
        # 将菜单关联到工具栏上
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.toolBar.customContextMenuRequested.connect(lambda pos: menu.exec_(self.toolBar.mapToGlobal(pos)))

4、当前全量代码main.py
import ctypes
import os
import subprocess
import sys
import time
import traceback
import webbrowser

from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, QAction, QMessageBox, QMenu
import state
from auto import main
from wayfinding import *
from logger_module import logger
from jianchaupdate import get_var_data, get_updatetxt
from lanrentools.moni import find_child_window_handle, screen_width

from PyQt5.QtCore import QObject, pyqtSignal, Qt


class MySignal(QObject):
    mySignal = pyqtSignal(int, str)  # 定义自定义信号,并指定信号参数类型
    mysig_shutdown = pyqtSignal()
    mysig_mouse_through = pyqtSignal(bool)
    mysig_tishi = pyqtSignal(str)
    mysig_show_xunlu = pyqtSignal()
    mysig_show_yolov = pyqtSignal()
    mysig_dingwei=pyqtSignal(int)
    mysig_next_pack=pyqtSignal()

from PyQt5.QtGui import QFont, QIcon, QKeySequence
from ui.main import Ui_mainWindow
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super().__init__()
        self.set_ui()
        self.setupUi(self)

        #设置窗口图标
        self.setWindowIcon(QIcon("datas/logo.png"))
        ##设置窗口标题
        self.setWindowTitle(f"AI{state.版本号}  F8暂停 F9停止 F10标记")
        #设置窗口大小
        self.resize(state.WINDOW_WIDTH, state.WINDOW_HEIGHT)
        #设置窗口默认坐标
        self.move(state.WINDOW_LEFT, state.WINDOW_TOP)

        from PyQt5.QtCore import Qt
        from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget
        self.g_box = QGridLayout() #创建布局 这是一种可以将控件放置在网格单元格中的布局管理器
        self.container_widget = QWidget()  # 创建了一个 QWidget 对象,这个部件将用于容纳你想要添加到滚动区域的所有控件
        self.container_widget.setLayout(self.g_box)  # 将网格布局设置给中间部件,之前创建的 QGridLayout 设置为 QWidget 的布局
        #self.g_box.setAlignment(Qt.AlignTop | Qt.AlignLeft)  # 布局 左上对齐
        self.g_box.setContentsMargins(0, 0, 0, 0)  # 边距 为0则紧贴边缘
        #self.g_box.setAlignment(Qt.AlignTop)
        self.sa_main.setWidget(self.container_widget)  # 将中间部件设置为QScrollArea的子部件

        #始终置顶窗口,除非删除或最小化
        self.setWindowFlags(Qt.WindowStaysOnTopHint)

        #一些基础变量
        self.row = 0
        self.column = -1
        self.run_times=1
        self.column_step=310

        # 所有数据
        self.datas = []

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


    #根据窗口宽度动态调整布局
    #主要目的是动态调整布局,以适应窗口大小的变化
    # 通过计算每行可以容纳的组件数量
    # 并重新排列这些组件,可以使界面看起来更加整洁和美观
    def update_layout(self):
        try:
            # 获取主窗口的宽度
            width =self.centralWidget().width()
            # 计算每行可以容纳的组件数量
            num_per_row = (width ) // (self.column_step * ratio)  # 假设每个组件的宽度为200
            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
        # 创建 QtitanRibbon 实例
        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__':
    try:
        if ctypes.windll.shell32.IsUserAnAdmin():
            hwnd_cmd = find_child_window_handle(0, "ConsoleWindowClass", "YuanShenAi")
            if hwnd_cmd == 0:
                hwnd_cmd = find_child_window_handle(0, "ConsoleWindowClass", "懒人原神")
            # vardata = get_var_data()
            # if vardata != False:
            #     updatetxt = get_updatetxt()
            #     print(updatetxt)
            #     print("当前版本号:" + state.版本号)
            #
            #     if float(vardata[1]) > float(state.版本号):
            #         print(
            #             "如果更新失败手动下更新包手动覆盖: https://gitee.com/LanRenZhiNeng/lanren-genshin-impact-ai/releases")
            #         var = input(f"发现更新的版本 v{vardata[1]} 是否需要更新? (输入yes or no  默认更新)\n")
            #         if var == "":
            #             var = "yes"
            #         if var.lower() != "no":
            #             update_process = subprocess.Popen(f'update.exe "{vardata[0]}.exe" "{vardata[2]}"',
            #                                               creationflags=subprocess.CREATE_NEW_CONSOLE)
            #             time.sleep(1)
            #             sys.exit()
            # 运行需要管理员权限的代码
            kernel32 = ctypes.windll.kernel32
            kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), 128)
            os.environ['PNG_IGNORE_WARNINGS'] = '1'

            # 在事件循环中创建一个任务对象并加入事件循环
            aty = main()  # 启动yolov服务

            ysam = YunShenAutoMap()  # 启动寻路类
            print(ysam)
            app = QApplication(sys.argv)  # 初始化Qt应用
            ratio = screen_width / 2560  # 分辨率比例
            # 设置全局字体大小
            # 计算字体大小
            base_font_size = 13
            # 基准字体大小,适合1920*1080分辨率
            new_font_size = int(base_font_size * ratio)
            font = QFont("Arial", new_font_size)

            # 子控件的宽度
            item_width=320
            item_height=240
            item_height_min = 60
            window_main = MainWindow()
            window_main.show()
            sys.exit(app.exec_())  # 监听消息不关闭
        else:
            # 如果不是管理员,则请求以管理员权限重新运行程序
            ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
    except Exception as err:
        if str(err).find("sys.exit")==-1:

            logger.error(traceback.format_exc())

三、ui窗口信号解析

设置信号链接及菜单(main)

class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super().__init__()
        self.set_ui()
        self.setupUi(self)

        #设置窗口图标
        self.setWindowIcon(QIcon("datas/logo.png"))
        ##设置窗口标题
        self.setWindowTitle(f"AI{state.版本号}  F8暂停 F9停止 F10标记")
        #设置窗口大小
        self.resize(state.WINDOW_WIDTH, state.WINDOW_HEIGHT)
        #设置窗口默认坐标
        self.move(state.WINDOW_LEFT, state.WINDOW_TOP)

        from PyQt5.QtCore import Qt
        from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget
        self.g_box = QGridLayout() #创建布局 这是一种可以将控件放置在网格单元格中的布局管理器
        self.container_widget = QWidget()  # 创建了一个 QWidget 对象,这个部件将用于容纳你想要添加到滚动区域的所有控件
        self.container_widget.setLayout(self.g_box)  # 将网格布局设置给中间部件,之前创建的 QGridLayout 设置为 QWidget 的布局
        #self.g_box.setAlignment(Qt.AlignTop | Qt.AlignLeft)  # 布局 左上对齐
        self.g_box.setContentsMargins(0, 0, 0, 0)  # 边距 为0则紧贴边缘
        #self.g_box.setAlignment(Qt.AlignTop)
        self.sa_main.setWidget(self.container_widget)  # 将中间部件设置为QScrollArea的子部件

        #始终置顶窗口,除非删除或最小化
        self.setWindowFlags(Qt.WindowStaysOnTopHint)

        #一些基础变量
        self.row = 0
        self.column = -1
        self.run_times=1
        self.column_step=310

        # 所有数据
        self.datas = []

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

        # 布局
        self.connect_set()

    def connect_set(self):
        '''
        绑定信号
        :return:
        '''

        self.sg = MySignal()
        state. QT_信号=self.sg
        self.sg.mysig_shutdown.connect(self.show_shutdown_dig)
        self.sg.mysig_mouse_through.connect(self.set_mouse_through)
        self.sg.mysig_tishi.connect(self.set_tishi)
        self.sg.mysig_next_pack.connect(self.next_pack)

        self.sg.mysig_show_xunlu.connect(self.show_xunlu)
        self.sg.mysig_show_yolov.connect(self.show_yolov)
        self.sg.mysig_dingwei.connect(self.dingwei)



        self.menu = self.menuBar()
        # 创建一个顶级菜单
        self.menu_file = self.menu.addMenu("文件")
        # 创建一个动作
        self.action_addtask = QAction("新增-AI锄地任务-大世界寻路打怪", self)
        self.action_addtask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_1))
        self.action_addtask.triggered.connect(self.hotkey_addtask)
        self.menu_file.addAction(self.action_addtask)

        # 创建一个动作
        self.action_addtaskfuben = QAction("新增-AI副本任务-任意副本需要录制传送", self)
        self.action_addtaskfuben.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_2))
        self.action_addtaskfuben.triggered.connect(self.hotkey_addtaskfuben)
        self.menu_file.addAction(self.action_addtaskfuben)

        # 创建一个动作
        self.action_addtaskjiaoben = QAction("新增-脚本回放任务-适合采集/挖矿/晶蝶/等等", self)
        self.action_addtaskjiaoben.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_3))
        self.action_addtaskjiaoben.triggered.connect(self.hotkey_addtaskjiaoben)
        self.menu_file.addAction(self.action_addtaskjiaoben)

        # 创建一个动作
        self.action_qiejue = QAction("新增-切换角色任务", self)

        self.action_qiejue.triggered.connect(self.hotkey_qiejue)
        self.menu_file.addAction(self.action_qiejue)

        # 创建一个动作
        self.action_qiehuanlianzhao = QAction("新增-切换连招任务", self)
        self.action_qiehuanlianzhao.triggered.connect(self.hotkey_qiehuanlianzhao)
        self.menu_file.addAction(self.action_qiehuanlianzhao)

        # 创建一个动作
        self.action_importtask = QAction("导入视觉任务", self)
        self.action_importtask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_4))
        self.action_importtask.triggered.connect(self.hotkey_importtask)
        self.menu_file.addAction(self.action_importtask)

        self.action_opentaskdir = QAction("打开任务文件夹", self)
        self.action_opentaskdir.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_5))
        self.action_opentaskdir.triggered.connect(self.hotkey_opentaskdir)
        self.menu_file.addAction(self.action_opentaskdir)

        self.action_selecttaskdir = QAction("导入/选择任务包", self)
        self.action_selecttaskdir.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_6))
        self.action_selecttaskdir.triggered.connect(self.hotkey_selecttaskdir)
        self.menu_file.addAction(self.action_selecttaskdir)

        self.action_setlianzhao = QAction("选择连招脚本", self)
        self.action_setlianzhao.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_7))
        self.action_setlianzhao.triggered.connect(self.hotkey_setlianzhao)
        self.menu_file.addAction(self.action_setlianzhao)

        self.action_addlianzhao = QAction("录制/编辑连招", self)
        self.action_addlianzhao.triggered.connect(self.hotkey_addlianzhao)
        self.menu_file.addAction(self.action_addlianzhao)

        # 创建一个顶级菜单
        self.menu_ck = self.menu.addMenu("选择")
        # 创建一个动作
        self.action_all_ck = QAction("全部选中", self)
        self.action_all_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_8))
        self.action_all_ck.triggered.connect(self.hotkey_all_ck)
        self.menu_ck.addAction(self.action_all_ck)

        self.action_all_not_ck = QAction("全部不选", self)
        self.action_all_not_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_9))
        self.action_all_not_ck.triggered.connect(self.hotkey_all_not_ck)
        self.menu_ck.addAction(self.action_all_not_ck)

        self.action_all_fan_ck = QAction("全部反选", self)
        self.action_all_fan_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_0))
        self.action_all_fan_ck.triggered.connect(self.hotkey_all_fan_ck)
        self.menu_ck.addAction(self.action_all_fan_ck)


        self.action_keys_ack = QAction("选中包含某个关键词的", self)
        self.action_keys_ack.triggered.connect(self.hotkey_keys_ack)
        self.menu_ck.addAction(self.action_keys_ack)

        self.action_num_ck = QAction("选中包含某个区间数字的", self)
        self.action_num_ck.triggered.connect(self.hotkey_num_ck)
        self.menu_ck.addAction(self.action_num_ck)

        self.action_find = QAction("查找并定位到包含某个关键字的任务", self)
        self.action_find.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F))
        self.action_find.triggered.connect(self.hotkey_find)
        self.menu_ck.addAction(self.action_find)



        # 创建一个顶级菜单
        self.menu_run = self.menu.addMenu("操作")
        # 创建一个动作
        self.action_runall = QAction("启动选中任务", self)
        self.action_runall.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F1))
        self.action_runall.triggered.connect(self.hotkey_runall)
        self.menu_run.addAction(self.action_runall)

        self.action_deltask = QAction("删除选中任务", self)
        self.action_deltask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F2))
        self.action_deltask.triggered.connect(self.hotkey_deltask)
        self.menu_run.addAction(self.action_deltask)

        self.action_refresh = QAction("保存任务并刷新顺序", self)
        self.action_refresh.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        self.action_refresh.triggered.connect(self.save)
        self.menu_run.addAction(self.action_refresh)

        # 创建一个动作
        self.action_kuang = QAction("选中任务-是否勾选-矿", self)
        self.action_kuang.setCheckable(True)
        self.action_kuang.setChecked(False)
        self.action_kuang.triggered.connect(self.hotkey_kuang)
        self.action_kuang.setChecked(True)
        self.menu_run.addAction(self.action_kuang)

        # 创建一个动作
        self.action_hua = QAction("选中任务-是否勾选-花", self)
        self.action_hua.setCheckable(True)
        self.action_hua.setChecked(False)
        self.action_hua.triggered.connect(self.hotkey_hua)
        self.action_hua.setChecked(True)
        self.menu_run.addAction(self.action_hua)

        # 创建一个动作
        self.action_guai = QAction("选中任务-是否勾选-怪", self)
        self.action_guai.setCheckable(True)
        self.action_guai.setChecked(False)
        self.action_guai.triggered.connect(self.hotkey_guai)
        self.action_guai.setChecked(True)
        self.menu_run.addAction(self.action_guai)

        # 创建一个动作
        self.action_run_times = QAction(f"设置:当前任务包 执行次数:{self.run_times}", self)
        self.action_run_times.triggered.connect(self.hotkey_run_times)
        self.menu_run.addAction(self.action_run_times)

        # 创建一个顶级菜单
        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.action_isShowCmd = QAction("是否显示控制台", self)
        self.action_isShowCmd.triggered.connect(self.hotkey_isShowCmd)
        self.action_isShowCmd.setCheckable(True)
        self.action_isShowCmd.setChecked(True)
        self.menu_view.addAction(self.action_isShowCmd)

        # 创建一个顶级菜单
        self.menu_yun= self.menu.addMenu("云端")
        # 创建一个动作
        self.action_yunduanlist= QAction("懒人群友云端资源", self)
        self.action_yunduanlist.triggered.connect(self.hotkey_yunduanlist)

        self.menu_yun.addAction(self.action_yunduanlist)

        # 创建一个动作
        self.action_yunduanup1 = QAction("分享-副本打怪任务", self)
        self.action_yunduanup1.triggered.connect( lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/viwvNEP8c"))
        self.menu_yun.addAction(self.action_yunduanup1)

        self.action_yunduanup2 = QAction("分享-打怪锄地任务", self)
        self.action_yunduanup2.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/GjM0zwWAw"))
        self.menu_yun.addAction(self.action_yunduanup2)

        self.action_yunduanup3 = QAction("分享-回放脚本任务", self)
        self.action_yunduanup3.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/9eGN71WCG"))
        self.menu_yun.addAction(self.action_yunduanup3)

        self.action_yunduanup4 = QAction("分享-收集材料任务", self)
        self.action_yunduanup4.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/vWDkt4QRB"))
        self.menu_yun.addAction(self.action_yunduanup4)

        self.action_yunduanup5 = QAction("分享-连招脚本任务", self)
        self.action_yunduanup5.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/DVa5G18rL"))
        self.menu_yun.addAction(self.action_yunduanup5)

        self.action_yunduanup6 = QAction("分享-其它资源分享", self)
        self.action_yunduanup6.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/3ucsnfSr5"))
        self.menu_yun.addAction(self.action_yunduanup6)


        # 创建一个顶级菜单
        self.menu_tools = self.menu.addMenu("工具")

        # 创建一个动作
        self.action_stitchimg = QAction("合成全景大图", self)
        self.action_stitchimg.triggered.connect(self.hotkey_stitchimg)
        self.menu_tools.addAction(self.action_stitchimg)

        # 创建一个顶级菜单
        self.menu_setting = self.menu.addMenu("设置")
        # 创建一个动作
        self.action_runstartwith = QAction("启动改为从这开始", self)
        self.action_runstartwith.setCheckable(True)
        self.action_runstartwith.setChecked(False)
        self.menu_setting.addAction(self.action_runstartwith)


        # 创建一个动作
        self.action_nextpack = QAction("是否自动继续下一个任务包", self)
        self.action_nextpack.setCheckable(True)
        self.action_nextpack.setChecked(False)
        self.action_nextpack.triggered.connect(self.hotkey_nextpack)
        if state.ON_NEXTPACK == 0:
            self.action_nextpack.setChecked(False)
        else:
            self.action_nextpack.setChecked(True)
        self.menu_setting.addAction(self.action_nextpack)

        # 创建一个动作
        self.action_jixing = QAction("是否任务完成后领取纪行奖励", self)
        self.action_jixing.triggered.connect(self.hotkey_jixing)
        self.action_jixing.setCheckable(True)
        if state.ON_JIXING == 0:
            self.action_jixing.setChecked(False)
        else:
            self.action_jixing.setChecked(True)
        self.menu_setting.addAction(self.action_jixing)
        # 创建一个动作
        self.action_shutdown = QAction("是否任务完成后关机", self)
        self.action_shutdown.triggered.connect(self.hotkey_shutdown)
        self.action_shutdown.setCheckable(True)
        if state.ON_SHUTDOWN == 0:
            self.action_shutdown.setChecked(False)
        else:
            self.action_shutdown.setChecked(True)
        self.menu_setting.addAction(self.action_shutdown)

        self.action_lianzhaobujiance = QAction("是否强制把连招搓完", self)
        self.action_lianzhaobujiance.triggered.connect(self.hotkey_lianzhaobujiance)
        self.action_lianzhaobujiance.setCheckable(True)
        if state.ON_LIANZHAOBUJIANCE == 0:
            self.action_lianzhaobujiance.setChecked(False)
        else:
            self.action_lianzhaobujiance.setChecked(True)
        self.menu_setting.addAction(self.action_lianzhaobujiance)

        # 创建一个动作
        self.action_weights = QAction(f"设置AI模型 当前: {state.WEIGHTS.split('/')[-1].split('.')[0]}", self)
        self.action_weights.triggered.connect(self.hotkey_weights)
        self.menu_setting.addAction(self.action_weights)

        # 创建一个动作
        self.action_timeout = QAction(f"设置打怪超时 阈值:{state.TIMEOUT_DAGUAI}秒", self)
        self.action_timeout.triggered.connect(self.hotkey_timeout)

        self.menu_setting.addAction(self.action_timeout)



        # 创建一个顶级菜单
        self.menu_help = self.menu.addMenu("帮助")
        # 创建一个动作
        self.action_about = QAction("关于", self)

        self.action_about.triggered.connect(
            lambda: QMessageBox.information(self, "作者", "python懒人智能 仅供技术研究!请勿用于非法用途否则后果自负!"))
        self.menu_help.addAction(self.action_about)

        # 创建一个动作
        self.action_kaiyuan = QAction("开源地址", self)

        self.action_kaiyuan.triggered.connect(lambda: webbrowser.open("https://gitee.com/LanRenZhiNeng/lanren-genshin-impact-ai"))
        self.menu_help.addAction(self.action_kaiyuan)

        # 创建一个动作
        self.action_zanzhu = QAction("赞助入群", self)

        self.action_zanzhu.triggered.connect(
            lambda: webbrowser.open("http://w.kami.vip/s/FSUtd45z"))
        self.menu_help.addAction(self.action_zanzhu)

        # 创建一个动作
        self.action_jiaocheng = QAction("教程合集", self)
        self.action_jiaocheng.triggered.connect(
            lambda: webbrowser.open("https://www.bilibili.com/video/BV1aS421w7i1"))
        self.menu_help.addAction(self.action_jiaocheng)
        # 创建右键弹出菜单
        menu = QMenu(self)
        menu.addAction(self.action_selecttaskdir)
        # 将菜单关联到工具栏上
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.toolBar.customContextMenuRequested.connect(lambda pos: menu.exec_(self.toolBar.mapToGlobal(pos)))




    #根据窗口宽度动态调整布局
    #主要目的是动态调整布局,以适应窗口大小的变化
    # 通过计算每行可以容纳的组件数量
    # 并重新排列这些组件,可以使界面看起来更加整洁和美观
    def update_layout(self):
        try:
            # 获取主窗口的宽度
            width =self.centralWidget().width()
            # 计算每行可以容纳的组件数量
            num_per_row = (width ) // (self.column_step * ratio)  # 假设每个组件的宽度为200
            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
        # 创建 QtitanRibbon 实例
        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()))

上面添加了self.connect_set() 以及函数def connect_set(self):

设置信号槽

        self.sg = MySignal()
        state. QT_信号=self.sg
        self.sg.mysig_shutdown.connect(self.show_shutdown_dig)
        self.sg.mysig_mouse_through.connect(self.set_mouse_through)
        self.sg.mysig_tishi.connect(self.set_tishi)
        self.sg.mysig_next_pack.connect(self.next_pack)

        self.sg.mysig_show_xunlu.connect(self.show_xunlu)
        self.sg.mysig_show_yolov.connect(self.show_yolov)
        self.sg.mysig_dingwei.connect(self.dingwei)
 1、添加自定义信号
class MySignal(QObject):
    mySignal = pyqtSignal(int, str)  # 定义自定义信号,并指定信号参数类型
    mysig_shutdown = pyqtSignal()
    mysig_mouse_through = pyqtSignal(bool)
    mysig_tishi = pyqtSignal(str)
    mysig_show_xunlu = pyqtSignal()
    mysig_show_yolov = pyqtSignal()
    mysig_dingwei=pyqtSignal(int)
    mysig_next_pack=pyqtSignal()
 2、添加关机提示

guanjitishi.py

import os
import sys
from PyQt5.Qt import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class ShutdownConfirmationDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent,Qt.Dialog | Qt.WindowStaysOnTopHint)
        self.initUI()



    def initUI(self):
        self.resize(300, 100)
        self.setWindowTitle('关机确认')
        self.confirmButton = QPushButton('确定', self)
        self.confirmButton.clicked.connect(self.shutdown)
        self.confirmButton.setGeometry(50, 50, 75, 30)

        self.cancelButton = QPushButton('取消', self)
        self.cancelButton.clicked.connect(self.cancelShutdown)
        self.cancelButton.setGeometry(150, 50, 75, 30)

        self.timerLabel = QLabel('倒计时:20', self)
        self.timerLabel.setGeometry(220, 10, 100, 30)

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.countdown)
        self.secondsLeft = 20
        self.timer.start(1000)

    def countdown(self):
        if self.secondsLeft < 0:
            return
        self.secondsLeft -= 1
        self.timerLabel.setText(f'倒计时:{self.secondsLeft}')
        if self.secondsLeft == 0:
            self.shutdown()

    def shutdown(self):
        os.system('shutdown -s -t 10')
        qApp.quit()
        # 调用关机命令

    def cancelShutdown(self):
        self.timer.stop()
        self.close()



# if __name__ == '__main__':
#     app = QApplication(sys.argv)
#     dialog = ShutdownConfirmationDialog()
#     dialog.show()
#     sys.exit(app.exec_())
3、关机对话框、鼠标穿透、更新窗口标题、yolo

 检测结果

    #显示关机确认对话框
    def show_shutdown_dig(self):
        """
        显示关机确认对话框。

        这个方法会从 `demo.ui.guanjitishi` 模块导入 `ShutdownConfirmationDialog` 类,
        创建一个对话框实例,并显示出来。

        使用方法:
        调用 `self.show_shutdown_dig()` 即可显示关机确认对话框。
        """
        from demo.ui.guanjitishi import ShutdownConfirmationDialog
        self.dialog = ShutdownConfirmationDialog(self)
        self.dialog.show()

    #设置窗口的鼠标穿透属性,并调整窗口的透明度。
    def set_mouse_through(self, bool):
        """
        设置窗口的鼠标穿透属性,并调整窗口的透明度。

        参数:
        - bool (bool): 如果为 True,则启用鼠标穿透;否则禁用。

        使用方法:
        调用 `self.set_mouse_through(True)` 启用鼠标穿透,并将窗口透明度设置为 0.9;
        调用 `self.set_mouse_through(False)` 禁用鼠标穿透,并将窗口透明度设置为 1。
        """
        # 调用底层函数设置鼠标穿透
        set_mouse_through(int(self.winId()), bool)

        # 根据传入的布尔值调整窗口透明度
        if bool:
            self.setWindowOpacity(0.9)
        else:
            self.setWindowOpacity(1)

    #在状态栏显示提示信息,并根据全局状态更新窗口标题
    def set_tishi(self, txt):
        """
        在状态栏显示提示信息,并根据全局状态更新窗口标题。

        参数:
        - txt (str): 要显示的提示信息。

        使用方法:
        调用 `self.set_tishi("提示信息")` 可以在状态栏显示提示信息,
        如果全局状态 `state.开关_是否展预测结果` 为 True,则更新窗口标题。
        """
        # 在状态栏显示提示信息
        self.statusbar.showMessage(txt)

        # 如果全局状态允许显示预测结果,则更新窗口标题
        if state.开关_是否展预测结果:
            self.fromshow.setWindowTitle(txt)

    #显示工具项并执行快捷键操作。
    def next_pack(self):
        """
        显示工具项并执行快捷键操作。

        使用方法:
        调用 `self.next_pack()` 可以显示 `state.PATH_TASK` 对应的工具项,
        并执行 `hotkey_runall` 方法。
        """
        # 显示工具项
        self.show_tool_item(state.PATH_TASK)

        # 执行快捷键操作
        self.hotkey_runall()

    #显示路径图像
    def show_xunlu(self):
        """
        显示路径图像。

        使用方法:
        调用 `self.show_xunlu()` 可以显示路径图像。
        如果全局状态 `state.开关_是否展预测结果` 为 True,并且 `state.图片_找图` 不为布尔值,
        则加载图像并显示在 `self.fromshow.lb_xunlu` 控件中。
        """
        from PyQt5.QtGui import QFont, QIcon, QKeySequence, QImage, QPixmap

        # 检查是否需要显示预测结果
        if state.开关_是否展预测结果:
            if type(state.图片_找图) == bool:
                return

            # 加载大图
            big_img_bk = state.图片_找图

            # 将 OpenCV 图像转换为 Qt 中的 QImage
            height, width, channel = big_img_bk.shape
            bytesPerLine = 3 * width
            qImg = QImage(big_img_bk.data, width, height, bytesPerLine, QImage.Format_BGR888)
            pixmap = QPixmap.fromImage(qImg)

            # 设置图像大小并显示
            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)

    #显示 YOLOv 检测结果图像
    def show_yolov(self):
        """
        显示 YOLOv 检测结果图像。

        使用方法:
        调用 `self.show_yolov()` 可以显示 YOLOv 检测结果图像。
        如果全局状态 `state.开关_是否展预测结果` 为 True,并且 `state.图片_YOLOV` 不为布尔值,
        则加载图像并显示在 `self.fromshow.lb_yolov` 控件中。
        """
        from PyQt5.QtGui import QFont, QIcon, QKeySequence, QImage, QPixmap

        # 检查是否需要显示预测结果
        if state.开关_是否展预测结果:
            if type(state.图片_YOLOV) == bool:
                return

            # 加载图像
            img1 = QImage(state.图片_YOLOV.data, state.图片_YOLOV.shape[1], state.图片_YOLOV.shape[0],
                          QImage.Format_BGR888)
            pixmap1 = QPixmap.fromImage(img1)

            # 设置图像位置
            if self.fromshow.width() >= self.fromshow.lb_xunlu.width() + self.fromshow.lb_yolov.width():
                self.fromshow.lb_yolov.move(self.fromshow.lb_xunlu.width(), 0)
            else:
                self.fromshow.lb_yolov.move(0, self.fromshow.lb_xunlu.height())

            # 显示图像
            self.fromshow.lb_yolov.setPixmap(pixmap1)
            
    #定位滚动条到指定位置
    def dingwei(self, idex):
        """
        定位滚动条到指定位置。

        参数:
        - idex (int): 要定位的数据索引。

        使用方法:
        调用 `self.dingwei(idex)` 可以将滚动条定位到指定位置。
        如果 `self.datas[idex]["f_item"]` 存在,则将其标记为非重点项,并调整滚动条位置。
        """
        try:
            # 设置焦点项为非重点项,并清除鼠标按下事件
            self.datas[idex]["f_item"].is_zd = False
            self.datas[idex]["f_item"].mousePressEvent(None)

            # 调整滚动条位置
            self.v_scrollbar.setValue(self.datas[idex]["f_item"].y())
        except Exception as err:
            print("dingwei", err)
            pass

存量代码

import ctypes
import os
import subprocess
import sys
import time
import traceback
import webbrowser

from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget, QAction, QMessageBox, QMenu
import state
from auto import main

from wayfinding import *
from logger_module import logger
from jianchaupdate import get_var_data, get_updatetxt
from lanrentools.moni import find_child_window_handle, screen_width

from PyQt5.QtCore import QObject, pyqtSignal, Qt


class MySignal(QObject):
    mySignal = pyqtSignal(int, str)  # 定义自定义信号,并指定信号参数类型
    mysig_shutdown = pyqtSignal()
    mysig_mouse_through = pyqtSignal(bool)
    mysig_tishi = pyqtSignal(str)
    mysig_show_xunlu = pyqtSignal()
    mysig_show_yolov = pyqtSignal()
    mysig_dingwei=pyqtSignal(int)
    mysig_next_pack=pyqtSignal()

from PyQt5.QtGui import QFont, QIcon, QKeySequence, QImage, QPixmap
from ui.main import Ui_mainWindow
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super().__init__()
        self.set_ui()
        self.setupUi(self)

        #设置窗口图标
        self.setWindowIcon(QIcon("datas/logo.png"))
        ##设置窗口标题
        self.setWindowTitle(f"AI{state.版本号}  F8暂停 F9停止 F10标记")
        #设置窗口大小
        self.resize(state.WINDOW_WIDTH, state.WINDOW_HEIGHT)
        #设置窗口默认坐标
        self.move(state.WINDOW_LEFT, state.WINDOW_TOP)

        from PyQt5.QtCore import Qt
        from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget
        self.g_box = QGridLayout() #创建布局 这是一种可以将控件放置在网格单元格中的布局管理器
        self.container_widget = QWidget()  # 创建了一个 QWidget 对象,这个部件将用于容纳你想要添加到滚动区域的所有控件
        self.container_widget.setLayout(self.g_box)  # 将网格布局设置给中间部件,之前创建的 QGridLayout 设置为 QWidget 的布局
        #self.g_box.setAlignment(Qt.AlignTop | Qt.AlignLeft)  # 布局 左上对齐
        self.g_box.setContentsMargins(0, 0, 0, 0)  # 边距 为0则紧贴边缘
        #self.g_box.setAlignment(Qt.AlignTop)
        self.sa_main.setWidget(self.container_widget)  # 将中间部件设置为QScrollArea的子部件

        #始终置顶窗口,除非删除或最小化
        self.setWindowFlags(Qt.WindowStaysOnTopHint)

        #一些基础变量
        self.row = 0
        self.column = -1
        self.run_times=1
        self.column_step=310

        # 所有数据
        self.datas = []

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

        # 布局
        self.connect_set()

    #设置信号及菜单
    def connect_set(self):
        '''
        绑定信号
        :return:
        '''

        self.sg = MySignal()
        state. QT_信号=self.sg
        self.sg.mysig_shutdown.connect(self.show_shutdown_dig)
        self.sg.mysig_mouse_through.connect(self.set_mouse_through)
        self.sg.mysig_tishi.connect(self.set_tishi)
        self.sg.mysig_next_pack.connect(self.next_pack)

        self.sg.mysig_show_xunlu.connect(self.show_xunlu)
        self.sg.mysig_show_yolov.connect(self.show_yolov)
        self.sg.mysig_dingwei.connect(self.dingwei)



        self.menu = self.menuBar()
        # 创建一个顶级菜单
        self.menu_file = self.menu.addMenu("文件")
        # 创建一个动作
        self.action_addtask = QAction("新增-AI锄地任务-大世界寻路打怪", self)
        self.action_addtask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_1))
        self.action_addtask.triggered.connect(self.hotkey_addtask)
        self.menu_file.addAction(self.action_addtask)

        # 创建一个动作
        self.action_addtaskfuben = QAction("新增-AI副本任务-任意副本需要录制传送", self)
        self.action_addtaskfuben.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_2))
        self.action_addtaskfuben.triggered.connect(self.hotkey_addtaskfuben)
        self.menu_file.addAction(self.action_addtaskfuben)

        # 创建一个动作
        self.action_addtaskjiaoben = QAction("新增-脚本回放任务-适合采集/挖矿/晶蝶/等等", self)
        self.action_addtaskjiaoben.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_3))
        self.action_addtaskjiaoben.triggered.connect(self.hotkey_addtaskjiaoben)
        self.menu_file.addAction(self.action_addtaskjiaoben)

        # 创建一个动作
        self.action_qiejue = QAction("新增-切换角色任务", self)

        self.action_qiejue.triggered.connect(self.hotkey_qiejue)
        self.menu_file.addAction(self.action_qiejue)

        # 创建一个动作
        self.action_qiehuanlianzhao = QAction("新增-切换连招任务", self)
        self.action_qiehuanlianzhao.triggered.connect(self.hotkey_qiehuanlianzhao)
        self.menu_file.addAction(self.action_qiehuanlianzhao)

        # 创建一个动作
        self.action_importtask = QAction("导入视觉任务", self)
        self.action_importtask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_4))
        self.action_importtask.triggered.connect(self.hotkey_importtask)
        self.menu_file.addAction(self.action_importtask)

        self.action_opentaskdir = QAction("打开任务文件夹", self)
        self.action_opentaskdir.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_5))
        self.action_opentaskdir.triggered.connect(self.hotkey_opentaskdir)
        self.menu_file.addAction(self.action_opentaskdir)

        self.action_selecttaskdir = QAction("导入/选择任务包", self)
        self.action_selecttaskdir.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_6))
        self.action_selecttaskdir.triggered.connect(self.hotkey_selecttaskdir)
        self.menu_file.addAction(self.action_selecttaskdir)

        self.action_setlianzhao = QAction("选择连招脚本", self)
        self.action_setlianzhao.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_7))
        self.action_setlianzhao.triggered.connect(self.hotkey_setlianzhao)
        self.menu_file.addAction(self.action_setlianzhao)

        self.action_addlianzhao = QAction("录制/编辑连招", self)
        self.action_addlianzhao.triggered.connect(self.hotkey_addlianzhao)
        self.menu_file.addAction(self.action_addlianzhao)

        # 创建一个顶级菜单
        self.menu_ck = self.menu.addMenu("选择")
        # 创建一个动作
        self.action_all_ck = QAction("全部选中", self)
        self.action_all_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_8))
        self.action_all_ck.triggered.connect(self.hotkey_all_ck)
        self.menu_ck.addAction(self.action_all_ck)

        self.action_all_not_ck = QAction("全部不选", self)
        self.action_all_not_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_9))
        self.action_all_not_ck.triggered.connect(self.hotkey_all_not_ck)
        self.menu_ck.addAction(self.action_all_not_ck)

        self.action_all_fan_ck = QAction("全部反选", self)
        self.action_all_fan_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_0))
        self.action_all_fan_ck.triggered.connect(self.hotkey_all_fan_ck)
        self.menu_ck.addAction(self.action_all_fan_ck)


        self.action_keys_ack = QAction("选中包含某个关键词的", self)
        self.action_keys_ack.triggered.connect(self.hotkey_keys_ack)
        self.menu_ck.addAction(self.action_keys_ack)

        self.action_num_ck = QAction("选中包含某个区间数字的", self)
        self.action_num_ck.triggered.connect(self.hotkey_num_ck)
        self.menu_ck.addAction(self.action_num_ck)

        self.action_find = QAction("查找并定位到包含某个关键字的任务", self)
        self.action_find.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F))
        self.action_find.triggered.connect(self.hotkey_find)
        self.menu_ck.addAction(self.action_find)



        # 创建一个顶级菜单
        self.menu_run = self.menu.addMenu("操作")
        # 创建一个动作
        self.action_runall = QAction("启动选中任务", self)
        self.action_runall.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F1))
        self.action_runall.triggered.connect(self.hotkey_runall)
        self.menu_run.addAction(self.action_runall)

        self.action_deltask = QAction("删除选中任务", self)
        self.action_deltask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F2))
        self.action_deltask.triggered.connect(self.hotkey_deltask)
        self.menu_run.addAction(self.action_deltask)

        self.action_refresh = QAction("保存任务并刷新顺序", self)
        self.action_refresh.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        self.action_refresh.triggered.connect(self.save)
        self.menu_run.addAction(self.action_refresh)

        # 创建一个动作
        self.action_kuang = QAction("选中任务-是否勾选-矿", self)
        self.action_kuang.setCheckable(True)
        self.action_kuang.setChecked(False)
        self.action_kuang.triggered.connect(self.hotkey_kuang)
        self.action_kuang.setChecked(True)
        self.menu_run.addAction(self.action_kuang)

        # 创建一个动作
        self.action_hua = QAction("选中任务-是否勾选-花", self)
        self.action_hua.setCheckable(True)
        self.action_hua.setChecked(False)
        self.action_hua.triggered.connect(self.hotkey_hua)
        self.action_hua.setChecked(True)
        self.menu_run.addAction(self.action_hua)

        # 创建一个动作
        self.action_guai = QAction("选中任务-是否勾选-怪", self)
        self.action_guai.setCheckable(True)
        self.action_guai.setChecked(False)
        self.action_guai.triggered.connect(self.hotkey_guai)
        self.action_guai.setChecked(True)
        self.menu_run.addAction(self.action_guai)

        # 创建一个动作
        self.action_run_times = QAction(f"设置:当前任务包 执行次数:{self.run_times}", self)
        self.action_run_times.triggered.connect(self.hotkey_run_times)
        self.menu_run.addAction(self.action_run_times)

        # 创建一个顶级菜单
        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.action_isShowCmd = QAction("是否显示控制台", self)
        self.action_isShowCmd.triggered.connect(self.hotkey_isShowCmd)
        self.action_isShowCmd.setCheckable(True)
        self.action_isShowCmd.setChecked(True)
        self.menu_view.addAction(self.action_isShowCmd)

        # 创建一个顶级菜单
        self.menu_yun= self.menu.addMenu("云端")
        # 创建一个动作
        self.action_yunduanlist= QAction("懒人群友云端资源", self)
        self.action_yunduanlist.triggered.connect(self.hotkey_yunduanlist)

        self.menu_yun.addAction(self.action_yunduanlist)

        # 创建一个动作
        self.action_yunduanup1 = QAction("分享-副本打怪任务", self)
        self.action_yunduanup1.triggered.connect( lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/viwvNEP8c"))
        self.menu_yun.addAction(self.action_yunduanup1)

        self.action_yunduanup2 = QAction("分享-打怪锄地任务", self)
        self.action_yunduanup2.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/GjM0zwWAw"))
        self.menu_yun.addAction(self.action_yunduanup2)

        self.action_yunduanup3 = QAction("分享-回放脚本任务", self)
        self.action_yunduanup3.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/9eGN71WCG"))
        self.menu_yun.addAction(self.action_yunduanup3)

        self.action_yunduanup4 = QAction("分享-收集材料任务", self)
        self.action_yunduanup4.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/vWDkt4QRB"))
        self.menu_yun.addAction(self.action_yunduanup4)

        self.action_yunduanup5 = QAction("分享-连招脚本任务", self)
        self.action_yunduanup5.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/DVa5G18rL"))
        self.menu_yun.addAction(self.action_yunduanup5)

        self.action_yunduanup6 = QAction("分享-其它资源分享", self)
        self.action_yunduanup6.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/3ucsnfSr5"))
        self.menu_yun.addAction(self.action_yunduanup6)


        # 创建一个顶级菜单
        self.menu_tools = self.menu.addMenu("工具")

        # 创建一个动作
        self.action_stitchimg = QAction("合成全景大图", self)
        self.action_stitchimg.triggered.connect(self.hotkey_stitchimg)
        self.menu_tools.addAction(self.action_stitchimg)

        # 创建一个顶级菜单
        self.menu_setting = self.menu.addMenu("设置")
        # 创建一个动作
        self.action_runstartwith = QAction("启动改为从这开始", self)
        self.action_runstartwith.setCheckable(True)
        self.action_runstartwith.setChecked(False)
        self.menu_setting.addAction(self.action_runstartwith)


        # 创建一个动作
        self.action_nextpack = QAction("是否自动继续下一个任务包", self)
        self.action_nextpack.setCheckable(True)
        self.action_nextpack.setChecked(False)
        self.action_nextpack.triggered.connect(self.hotkey_nextpack)
        if state.ON_NEXTPACK == 0:
            self.action_nextpack.setChecked(False)
        else:
            self.action_nextpack.setChecked(True)
        self.menu_setting.addAction(self.action_nextpack)

        # 创建一个动作
        self.action_jixing = QAction("是否任务完成后领取纪行奖励", self)
        self.action_jixing.triggered.connect(self.hotkey_jixing)
        self.action_jixing.setCheckable(True)
        if state.ON_JIXING == 0:
            self.action_jixing.setChecked(False)
        else:
            self.action_jixing.setChecked(True)
        self.menu_setting.addAction(self.action_jixing)
        # 创建一个动作
        self.action_shutdown = QAction("是否任务完成后关机", self)
        self.action_shutdown.triggered.connect(self.hotkey_shutdown)
        self.action_shutdown.setCheckable(True)
        if state.ON_SHUTDOWN == 0:
            self.action_shutdown.setChecked(False)
        else:
            self.action_shutdown.setChecked(True)
        self.menu_setting.addAction(self.action_shutdown)

        self.action_lianzhaobujiance = QAction("是否强制把连招搓完", self)
        self.action_lianzhaobujiance.triggered.connect(self.hotkey_lianzhaobujiance)
        self.action_lianzhaobujiance.setCheckable(True)
        if state.ON_LIANZHAOBUJIANCE == 0:
            self.action_lianzhaobujiance.setChecked(False)
        else:
            self.action_lianzhaobujiance.setChecked(True)
        self.menu_setting.addAction(self.action_lianzhaobujiance)

        # 创建一个动作
        self.action_weights = QAction(f"设置AI模型 当前: {state.WEIGHTS.split('/')[-1].split('.')[0]}", self)
        self.action_weights.triggered.connect(self.hotkey_weights)
        self.menu_setting.addAction(self.action_weights)

        # 创建一个动作
        self.action_timeout = QAction(f"设置打怪超时 阈值:{state.TIMEOUT_DAGUAI}秒", self)
        self.action_timeout.triggered.connect(self.hotkey_timeout)

        self.menu_setting.addAction(self.action_timeout)



        # 创建一个顶级菜单
        self.menu_help = self.menu.addMenu("帮助")
        # 创建一个动作
        self.action_about = QAction("关于", self)

        self.action_about.triggered.connect(
            lambda: QMessageBox.information(self, "作者", "python懒人智能 仅供技术研究!请勿用于非法用途否则后果自负!"))
        self.menu_help.addAction(self.action_about)

        # 创建一个动作
        self.action_kaiyuan = QAction("开源地址", self)

        self.action_kaiyuan.triggered.connect(lambda: webbrowser.open("https://gitee.com/LanRenZhiNeng/lanren-genshin-impact-ai"))
        self.menu_help.addAction(self.action_kaiyuan)

        # 创建一个动作
        self.action_zanzhu = QAction("赞助入群", self)

        self.action_zanzhu.triggered.connect(
            lambda: webbrowser.open("http://w.kami.vip/s/FSUtd45z"))
        self.menu_help.addAction(self.action_zanzhu)

        # 创建一个动作
        self.action_jiaocheng = QAction("教程合集", self)
        self.action_jiaocheng.triggered.connect(
            lambda: webbrowser.open("https://www.bilibili.com/video/BV1aS421w7i1"))
        self.menu_help.addAction(self.action_jiaocheng)
        # 创建右键弹出菜单
        menu = QMenu(self)
        menu.addAction(self.action_selecttaskdir)
        # 将菜单关联到工具栏上
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.toolBar.customContextMenuRequested.connect(lambda pos: menu.exec_(self.toolBar.mapToGlobal(pos)))

    #显示关机确认对话框
    def show_shutdown_dig(self):
        """
        显示关机确认对话框。

        这个方法会从 `demo.ui.guanjitishi` 模块导入 `ShutdownConfirmationDialog` 类,
        创建一个对话框实例,并显示出来。

        使用方法:
        调用 `self.show_shutdown_dig()` 即可显示关机确认对话框。
        """
        from demo.ui.guanjitishi import ShutdownConfirmationDialog
        self.dialog = ShutdownConfirmationDialog(self)
        self.dialog.show()

    #设置窗口的鼠标穿透属性,并调整窗口的透明度。
    def set_mouse_through(self, bool):
        """
        设置窗口的鼠标穿透属性,并调整窗口的透明度。

        参数:
        - bool (bool): 如果为 True,则启用鼠标穿透;否则禁用。

        使用方法:
        调用 `self.set_mouse_through(True)` 启用鼠标穿透,并将窗口透明度设置为 0.9;
        调用 `self.set_mouse_through(False)` 禁用鼠标穿透,并将窗口透明度设置为 1。
        """
        # 调用底层函数设置鼠标穿透
        set_mouse_through(int(self.winId()), bool)

        # 根据传入的布尔值调整窗口透明度
        if bool:
            self.setWindowOpacity(0.9)
        else:
            self.setWindowOpacity(1)

    #在状态栏显示提示信息,并根据全局状态更新窗口标题
    def set_tishi(self, txt):
        """
        在状态栏显示提示信息,并根据全局状态更新窗口标题。

        参数:
        - txt (str): 要显示的提示信息。

        使用方法:
        调用 `self.set_tishi("提示信息")` 可以在状态栏显示提示信息,
        如果全局状态 `state.开关_是否展预测结果` 为 True,则更新窗口标题。
        """
        # 在状态栏显示提示信息
        self.statusbar.showMessage(txt)

        # 如果全局状态允许显示预测结果,则更新窗口标题
        if state.开关_是否展预测结果:
            self.fromshow.setWindowTitle(txt)

    #显示工具项并执行快捷键操作。
    def next_pack(self):
        """
        显示工具项并执行快捷键操作。

        使用方法:
        调用 `self.next_pack()` 可以显示 `state.PATH_TASK` 对应的工具项,
        并执行 `hotkey_runall` 方法。
        """
        # 显示工具项
        self.show_tool_item(state.PATH_TASK)

        # 执行快捷键操作
        self.hotkey_runall()

    #显示路径图像
    def show_xunlu(self):
        """
        显示路径图像。

        使用方法:
        调用 `self.show_xunlu()` 可以显示路径图像。
        如果全局状态 `state.开关_是否展预测结果` 为 True,并且 `state.图片_找图` 不为布尔值,
        则加载图像并显示在 `self.fromshow.lb_xunlu` 控件中。
        """
        from PyQt5.QtGui import QFont, QIcon, QKeySequence, QImage, QPixmap

        # 检查是否需要显示预测结果
        if state.开关_是否展预测结果:
            if type(state.图片_找图) == bool:
                return

            # 加载大图
            big_img_bk = state.图片_找图

            # 将 OpenCV 图像转换为 Qt 中的 QImage
            height, width, channel = big_img_bk.shape
            bytesPerLine = 3 * width
            qImg = QImage(big_img_bk.data, width, height, bytesPerLine, QImage.Format_BGR888)
            pixmap = QPixmap.fromImage(qImg)

            # 设置图像大小并显示
            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)

    #显示 YOLOv 检测结果图像
    def show_yolov(self):
        """
        显示 YOLOv 检测结果图像。

        使用方法:
        调用 `self.show_yolov()` 可以显示 YOLOv 检测结果图像。
        如果全局状态 `state.开关_是否展预测结果` 为 True,并且 `state.图片_YOLOV` 不为布尔值,
        则加载图像并显示在 `self.fromshow.lb_yolov` 控件中。
        """
        from PyQt5.QtGui import QFont, QIcon, QKeySequence, QImage, QPixmap

        # 检查是否需要显示预测结果
        if state.开关_是否展预测结果:
            if type(state.图片_YOLOV) == bool:
                return

            # 加载图像
            img1 = QImage(state.图片_YOLOV.data, state.图片_YOLOV.shape[1], state.图片_YOLOV.shape[0],
                          QImage.Format_BGR888)
            pixmap1 = QPixmap.fromImage(img1)

            # 设置图像位置
            if self.fromshow.width() >= self.fromshow.lb_xunlu.width() + self.fromshow.lb_yolov.width():
                self.fromshow.lb_yolov.move(self.fromshow.lb_xunlu.width(), 0)
            else:
                self.fromshow.lb_yolov.move(0, self.fromshow.lb_xunlu.height())

            # 显示图像
            self.fromshow.lb_yolov.setPixmap(pixmap1)

    #定位滚动条到指定位置
    def dingwei(self, idex):
        """
        定位滚动条到指定位置。

        参数:
        - idex (int): 要定位的数据索引。

        使用方法:
        调用 `self.dingwei(idex)` 可以将滚动条定位到指定位置。
        如果 `self.datas[idex]["f_item"]` 存在,则将其标记为非重点项,并调整滚动条位置。
        """
        try:
            # 设置焦点项为非重点项,并清除鼠标按下事件
            self.datas[idex]["f_item"].is_zd = False
            self.datas[idex]["f_item"].mousePressEvent(None)

            # 调整滚动条位置
            self.v_scrollbar.setValue(self.datas[idex]["f_item"].y())
        except Exception as err:
            print("dingwei", err)
            pass




    #根据窗口宽度动态调整布局
    #主要目的是动态调整布局,以适应窗口大小的变化
    # 通过计算每行可以容纳的组件数量
    # 并重新排列这些组件,可以使界面看起来更加整洁和美观
    def update_layout(self):
        try:
            # 获取主窗口的宽度
            width =self.centralWidget().width()
            # 计算每行可以容纳的组件数量
            num_per_row = (width ) // (self.column_step * ratio)  # 假设每个组件的宽度为200
            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
        # 创建 QtitanRibbon 实例
        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__':
    try:
        if ctypes.windll.shell32.IsUserAnAdmin():
            hwnd_cmd = find_child_window_handle(0, "ConsoleWindowClass", "YuanShenAi")
            if hwnd_cmd == 0:
                hwnd_cmd = find_child_window_handle(0, "ConsoleWindowClass", "懒人原神")
            # vardata = get_var_data()
            # if vardata != False:
            #     updatetxt = get_updatetxt()
            #     print(updatetxt)
            #     print("当前版本号:" + state.版本号)
            #
            #     if float(vardata[1]) > float(state.版本号):
            #         print(
            #             "如果更新失败手动下更新包手动覆盖: https://gitee.com/LanRenZhiNeng/lanren-genshin-impact-ai/releases")
            #         var = input(f"发现更新的版本 v{vardata[1]} 是否需要更新? (输入yes or no  默认更新)\n")
            #         if var == "":
            #             var = "yes"
            #         if var.lower() != "no":
            #             update_process = subprocess.Popen(f'update.exe "{vardata[0]}.exe" "{vardata[2]}"',
            #                                               creationflags=subprocess.CREATE_NEW_CONSOLE)
            #             time.sleep(1)
            #             sys.exit()
            # 运行需要管理员权限的代码
            kernel32 = ctypes.windll.kernel32
            kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), 128)
            os.environ['PNG_IGNORE_WARNINGS'] = '1'

            # 在事件循环中创建一个任务对象并加入事件循环
            aty = main()  # 启动yolov服务

            ysam = YunShenAutoMap()  # 启动寻路类
            print(ysam)
            app = QApplication(sys.argv)  # 初始化Qt应用
            ratio = screen_width / 2560  # 分辨率比例
            # 设置全局字体大小
            # 计算字体大小
            base_font_size = 13
            # 基准字体大小,适合1920*1080分辨率
            new_font_size = int(base_font_size * ratio)
            font = QFont("Arial", new_font_size)

            # 子控件的宽度
            item_width=320
            item_height=240
            item_height_min = 60
            window_main = MainWindow()
            window_main.show()
            sys.exit(app.exec_())  # 监听消息不关闭
        else:
            # 如果不是管理员,则请求以管理员权限重新运行程序
            ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
    except Exception as err:
        if str(err).find("sys.exit")==-1:

            logger.error(traceback.format_exc())
4、主窗口所需
# hotkey_addtask 方法用于创建一个新的任务目录,并尝试加载该目录下的 jiaoben.ini 文件。
def hotkey_addtask(self):
    try:
        # 构造新任务目录的路径
        dir_ = os.path.join(state.PATH_TASK, "任务" + str(int(time.time())) + str(random.randint(10, 100)))
        if not os.path.exists(dir_):
            os.makedirs(dir_)  # 如果目录不存在,则创建它
            # 创建 ConfigParser 对象
            config = configparser.ConfigParser()
            # 尝试读取新创建的任务目录中的 jiaoben.ini 文件
            config.read(os.path.join(dir_, "jiaoben.ini"))
            self.add_task(dir_, config)  # 添加任务到系统
            self.save_ini(dir_, self.datas[-1])  # 保存数据到 ini 文件
    except Exception as e:
        # 捕获异常并忽略
        pass

# hotkey_addtaskjiaoben 方法用于添加一个脚本任务到指定目录。
def hotkey_addtaskjiaoben(self):
    dir_ = os.path.join(state.PATH_TASK, "任务" + str(int(time.time())) + str(random.randint(10, 100)))
    if not os.path.exists(dir_):
        os.makedirs(dir_)
        # 创建 ConfigParser 对象
        config = configparser.ConfigParser()
        # 尝试读取新创建的任务目录中的 jiaoben.ini 文件
        config.read(os.path.join(dir_, "jiaoben.ini"))
        self.add_taskjiaoben(dir_, config)  # 添加脚本任务到系统
        self.save_ini(dir_, self.datas[-1])  # 保存数据到 ini 文件

# hotkey_qiejue 方法用于切换角色,并保存更改。
def hotkey_qiejue(self):
    dir_ = os.path.join(state.PATH_TASK, "切换角色" + str(int(time.time())) + str(random.randint(10, 100)))
    if not os.path.exists(dir_):
        os.makedirs(dir_)
        # 创建 ConfigParser 对象
        config = configparser.ConfigParser()
        # 尝试读取新创建的任务目录中的 jiaoben.ini 文件
        config.read(os.path.join(dir_, "jiaoben.ini"))
        self.add_xuanjue(dir_, config)  # 添加角色选择到系统
        self.save_ini(dir_, self.datas[-1])  # 保存数据到 ini 文件

# hotkey_qiehuanlianzhao 方法用于切换连招,并保存更改。
def hotkey_qiehuanlianzhao(self):
    dir_ = os.path.join(state.PATH_TASK, "切换连招" + str(int(time.time())) + str(random.randint(10, 100)))
    if not os.path.exists(dir_):
        os.makedirs(dir_)
        # 创建 ConfigParser 对象
        config = configparser.ConfigParser()
        # 尝试读取新创建的任务目录中的 jiaoben.ini 文件
        config.read(os.path.join(dir_, "jiaoben.ini"))
        self.add_xuanlianzhao(dir_, config)  # 添加连招选择到系统
        self.save_ini(dir_, self.datas[-1])  # 保存数据到 ini 文件

# hotkey_addtaskfuben 方法用于添加副本任务到指定目录。
def hotkey_addtaskfuben(self):
    dir_ = os.path.join(state.PATH_TASK, "任务" + str(int(time.time())) + str(random.randint(10, 100)))
    if not os.path.exists(dir_):
        os.makedirs(dir_)
        # 创建 ConfigParser 对象
        config = configparser.ConfigParser()
        # 尝试读取新创建的任务目录中的 jiaoben.ini 文件
        config.read(os.path.join(dir_, "jiaoben.ini"))
        self.add_taskfuben(dir_, config)  # 添加副本任务到系统
        self.save_ini(dir_, self.datas[-1])  # 保存数据到 ini 文件

# hotkey_opentaskdir 方法用于打开任务目录。
def hotkey_opentaskdir(self):
    os.startfile(os.path.abspath(state.PATH_TASK))  # 使用startfile方法打开文件夹

# hotkey_selecttaskdir 方法用于让用户选择一个任务目录,并更新状态。
def hotkey_selecttaskdir(self):
    # 弹出通用对话框选择文件夹
    source_folder = QFileDialog.getExistingDirectory(self, "选择任务文件夹", state.PATH_TASK)
    if source_folder == "":
        return
    state.PATH_TASK = source_folder
    self.add_tool_item(state.PATH_TASK)
    state.PACKS_TASK += "#@@#" + state.PATH_TASK
    self.save_ini_seting()
    self.update_tasks()
    logger.info(f"成功设置{state.PATH_TASK}为当前任务文件夹")

# hotkey_setlianzhao 方法用于设置连招脚本。
def hotkey_setlianzhao(self):
    # 弹出一个文件选择对话框来选择连招脚本
    temp_path, ok = QFileDialog.getOpenFileName(self, "连招脚本", state.PATH_JIAOBEN, "脚本文件 (*.txt)")
    if ok:
        _, state.LIANZHAO = os.path.split(temp_path)
        dir_ = os.path.join(state.PATH_JIAOBEN, state.LIANZHAO)
        try:
            shutil.copy(temp_path, dir_)  # 复制脚本文件到指定路径
        except Exception as e:
            pass
        logger.info("选择连招脚本成功!")
        self.save_ini_seting()

# hotkey_addlianzhao 方法用于添加连招(通过录制或者从文件中选择)。
def hotkey_addlianzhao(self):
    # 弹出一个选择弹窗,选项为录制还是从文件中选择
    msgBox = QMessageBox(self)
    msgBox.setWindowTitle("配置连招")  # 设置消息框标题
    msgBox.setIcon(QMessageBox.Information)

    msgBox.setText("当前连招:" + state.LIANZHAO + "\n请选择一个配置方式:")
    msgBox.addButton("录制", QMessageBox.AcceptRole)
    msgBox.addButton("回放", QMessageBox.ApplyRole)
    msgBox.addButton("文件中选择", QMessageBox.RejectRole)
    result = msgBox.exec_()
    if result == QMessageBox.AcceptRole:
        try:
            text, ok = QInputDialog.getText(self, '提示', '请输入脚本名:', text=state.LIANZHAO)
            if not ok or text == "":
                return
            if text[-4:] != ".txt":
                state.LIANZHAO = text + ".txt"
            else:
                state.LIANZHAO = text
            logger.info("可以开始录制了,按F8开始/停止")
            self.sg.mysig_tishi.emit("可以开始录制了,按F8开始/停止")
            state.状态_是否禁止录制 = False
            state.状态_是否开始录制 = False

            state.录制_脚本文本 = ""
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否禁止录制#@@#假"), auto.loop)
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否开始录制#@@#假"), auto.loop)
            asyncio.run_coroutine_threadsafe(send_to_client(-1, f"全局脚本名#@@#{state.LIANZHAO.replace('.txt','')}"), auto.loop)
            hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
            asyncio.run_coroutine_threadsafe(send_to_client(-1, f"全局hwnd#@@#{hwnd}"), auto.loop)
            self.timer_luzhi_lianzhao.start(200)
        except Exception as e:
            pass
    elif result == QMessageBox.RejectRole:
        if state.状态_是否回放中 == True:
            return
        if not os.path.exists(state.PATH_JIAOBEN):
            os.makedirs(state.PATH_JIAOBEN)
        state.状态_是否回放中 = True
        state.状态_循环开关 = True
        jiaoben = os.path.abspath(os.path.join(state.PATH_JIAOBEN, state.LIANZHAO))
        message = f"解析脚本#@@#{jiaoben}"
        asyncio.run_coroutine_threadsafe(send_to_client(-1, message), auto.loop)
        hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
        set_window_activate(hwnd)
        asyncio.run_coroutine_threadsafe(send_to_client(-1, "脚本执行#@@#1"), auto.loop)
        self.timer_huifang.start(200)
    elif result == QMessageBox.Warning:
        self.hotkey_setlianzhao()  # 如果选择了警告按钮,则重新设置连招

额,太多了,后面我们执行到哪里写哪里吧

5、非主窗口函数和类

vi main.py

def extract_number(folder_name):
    numbers = re.findall(r'\d+', folder_name)
    return int(numbers[0]) if numbers else float('inf')
class FormShow(QDockWidget, Ui_DockWidget):
    def __init__(self, parent=None):
        super(QDockWidget, self).__init__(parent)
        self.parent=parent
        self.setParent(parent)
        self.setupUi(self)
        self.set_ui()
        #self.timer = QTimer()
        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)
    def set_ui(self):
        pass
    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):
        state.开关_是否展预测结果 = False
        self.parent.action_isShow.setChecked(state.开关_是否展预测结果)
    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())
class FormYunFileList(QFrame, Ui_form_yunfilelist,YunPan):
    def __init__(self):
        super().__init__()
        YunPan.__init__(self)
        self.set_ui()
        self.setupUi(self)
        self.setWindowIcon(QIcon("datas/logo.png"))
        self.setWindowTitle('懒人群友云端资源 感谢零度可乐提供云端支持')  # 标题
        self.setWindowFlags(Qt.WindowStaysOnTopHint)
        self.resize(int(910*ratio), int(700*ratio))
        self.g_box = QGridLayout()
        self.container_widget = QWidget()  # 创建一个中间部件  为了可以让g_布局超过窗口大小
        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)
        self.sa_main.setWidget(self.container_widget)  # 将中间部件设置为QScrollArea的子部件
        # 获取纵向滚动条控件
        vertical_scrollbar = self.findChild(QScrollArea)
        self.v_scrollbar = vertical_scrollbar.verticalScrollBar()
        self.row = 0
        self.column = -1
        # 所有数据
        self.datas = []
        self.login(username="lanren",password="lanrenai2024")
        # 创建一个计时器,用于延迟布局
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)  # 设置为单次触发
        self.timer.timeout.connect(self.update_layout)
        self.connect_set()
        self.ing=True
        # 创建一个计时器,用于延迟布局
        self.timer1 = QTimer(self)

        self.timer1.timeout.connect(self.update_init)
        self.timer1.start(200)

        self.lb_ing=QLabel("加载中请稍等...",self)
        self.lb_ing.setStyleSheet("""
        font: 75 50pt "微软雅黑";
    color: rgb(255, 0, 0);
        """)
        self.lb_ing.resize(500,100)
    def update_init(self):
        if not self.ing:
            self.updatefilelist()
            self.lb_ing.close()
            self.timer1.stop()
    def set_ui(self):
        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()))
    def resizeEvent(self, event):

        super().resizeEvent(event)
        # 每当用户调整窗口大小时,启动计时器
        self.timer.start(300)  # 500毫秒后触发timeout信号
    def connect_set(self):
        self.tabWidget.currentChanged.connect(self.currentChanged_tabWidget)
    def currentChanged_tabWidget(self,index):
        self.updatefilelist(keys=self.tabWidget.tabText(index))
    def update_layout(self):
        try:
            # 获取主窗口的宽度
            width = self.width()
            # 计算每行可以容纳的组件数量


            num_per_row = (width ) // (280 * ratio)  # 假设每个组件的宽度为200

            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 update(self):
        self.ing=True
        self.file_all=[]
        self.file_all = self.get_file_all(isclose=True)

        self.file_all = list(map(lambda x: {"name": x['name'], "sign": x['sign'], "dir": x['dir'],
                                       "url": x['raw_url'], "modified": x['modified']}, self.file_all))

        self.file_all = sorted(self.file_all, key=lambda x: datetime.strptime(x['modified'].split("+")[0].split(".")[0],
                                                                              "%Y-%m-%dT%H:%M:%S"),
                               reverse=True)

        self.ing = False
    def updatefilelist(self,keys=""):
        try:
            if keys=="全部":
                keys=""

            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)


            for item in self.file_all:

                if keys in item[ "dir"].split("/")[-3] or keys=="":
                    self.add_yun_file(data=item)
        except:
            pass
    def add_yun_file(self,data={}):
        '''
        添加云文件显示
        :return:
        '''
        # 根据导入的文件
        # 获取主窗口的宽度
        # 获取主窗口的宽度
        width = self.width()
        # 计算每行可以容纳的组件数量
        num_per_row = (width )  // (280* ratio)  # 假设每个组件的宽度为200
        if num_per_row < 1:
            num_per_row = 1
        self.column += 1
        if self.column == num_per_row:
            self.column = 0
            self.row += 1
        f_item = FormItemYun()
        w = int(300* ratio)
        h = int(180* ratio)
        f_item.setMinimumSize(int((w + 13)* ratio), h)
        f_item.setMinimumSize(w, h)
        f_item.setMaximumSize(w, h)
        f_item.setObjectName("frame_cont")
        f_item.raise_()
        f_item.setStyleSheet("""
                               #frame_cont:hover {
                                   border: 1px solid red;
                               }
                               #frame_cont {
                                    background-color: rgba(0, 0, 0, 0);
                               }
                               """)
        f_item.bt_down.clicked.connect(lambda: webbrowser.open(data["url"]))
        f_item.led_name.setText(data["name"])
        f_item.led_author.setText(data["dir"].split("/")[-2][:-6])
        f_item.led_time.setText(data["modified"].split(".")[0].replace("T", " "))

        data["f_item"] = f_item
        self.datas.append(data)
        self.g_box.addWidget(f_item, self.row, self.column)


class FormM(QFrame, Ui_form_m):
    def __init__(self, parent=None):
        super(QFrame, self).__init__()
        self.parent=parent
        self.setupUi(self)
        self.set_ui()
        self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)

        self.setWindowIcon(QIcon("datas/logo.png"))
        self.setWindowTitle('选择模型')  # 标题
        self.bt_save.clicked.connect(self.onn_bt_save)
        onnx_file_names = []

        # 遍历文件夹中所有文件和子文件夹
        for root, dirs, files in os.walk(".\\datas"):
            for file in files:
                # 检查文件是否以 .onnx 结尾
                if file.endswith('.onnx'):
                    # 如果是 .onnx 文件,则将其路径加入列表
                    file_name = os.path.splitext(file)[0]
                    onnx_file_names.append(file_name)

        self.cbb_m.addItems(onnx_file_names)
        self.cbb_m.setCurrentText(state.WEIGHTS.split('/')[-1].split('.')[0])
        print("1111",state.WEIGHTS.split('/')[-1].split('.')[0])
    def set_ui(self):
        pass
    def onn_bt_save(self):

        state.WEIGHTS='./datas/'+self.cbb_m.currentText()+".onnx"
        state.IMGSIZE_WIDTH=int(self.cbb_m.currentText().split("_")[-1])
        state.IMGSIZE_HEIGHT = int(self.cbb_m.currentText().split("_")[-1])
        self.parent.close()


class FormItemYun(QFrame, Ui_formitemyun):
    def __init__(self, parent=None):
        super(QFrame, self).__init__(parent)
        self.setupUi(self)
        self.set_ui()
        # self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)
    def set_ui(self):
        pass

这里开始包含了好几个ui文件,我们直接把ui目录覆盖成原项目的

6、stitchimages.py

lanrentools/stitchimages.py

# -*- coding: utf-8 -*-
import os
import cv2
import numpy as np
# pip install opencv-contrib-python
class  StitchImages:

    def __init__(self,):
        '''
        全景图合成类
        '''
        pass
    def stitch_images(self,image_paths,out_path="",isShow=False):
        # 创建 Stitcher 对象
        stitcher = cv2.Stitcher_create()
        images = [cv2.imdecode(np.fromfile(file=path, dtype=np.uint8), cv2.IMREAD_COLOR) for path in image_paths]
        # 调用 Stitcher 进行拼接
        status, stitched_image = stitcher.stitch(images)
        # 检查拼接是否成功
        if status == cv2.Stitcher_OK:
            # 保存拼接后的全景图
            cv2.imwrite(out_path, stitched_image)

            print('全景图拼接成功,并已保存为 '+out_path)

        else:
            print('全景图拼接失败')
            return False
        if isShow:
            cv2.imshow('Panorama', stitched_image)
            cv2.waitKey(0)
            cv2.destroyAllWindows()
        return True
    def get_image_paths(self,dir="./"):
        image_paths=[]
        #遍历一个文件夹 ['.png','.jpg','.bmp']找出符合这个的文件加入到image_paths中
        for root, dirs, files in os.walk(dir):
            for file in files:
                if file.endswith('.png') or file.endswith('.jpg') or file.endswith('.bmp'):
                    image_paths.append(os.path.join(root, file))
        return image_paths
if __name__ == '__main__':
    si=StitchImages()
    image_paths=si.get_image_paths("./datas/img")
    si.stitch_images(image_paths,"./datas/max_map/max_map.png")

7、yunpan

vi yunpan.py

import time

import requests
import json

class YunPan():
   def __init__(self):
      self.token=""
      self.url=""
   def login(self,username="",password=""):
      return {}
   def get_file_list(self,dir_home="鸣潮AI"):
      
      return []
      return []
   def get_file_get(self,file_name=""):
      return {}
   def get_file_all(self,dir_="原神AI",file_data=[],isclose=False):
      '''
      递归遍历所有的文件
      :param dir_:目录
      :param file_data: 上一次的数据
      :param isclose:用来强制重置数据的 防止重复
      :return:
      '''
      
      file_data=[]


main全量代码

# -*- coding: utf-8 -*-
try:
    import asyncio
    import functools
    import os.path
    from datetime import datetime
    import configparser
    import re
    import shutil
    import time
    import threading
    import webbrowser
    import pyautogui
    from qtpy import QtWidgets
    from logger_module import logger
    from lanrentools.moni import *
    import auto
    import sys
    import state
    from wayfinding import *
    from PyQt5.Qt import *
    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    from ui.formitemjiaoben import Ui_formitemjiaoben
    from ui.guanjitishi import ShutdownConfirmationDialog
    from ui.main import Ui_mainWindow
    from ui.formitem import Ui_formitem
    from ui.formitemfuben import Ui_formitemfuben
    from ui.formshow import Ui_DockWidget
    from ui.yunfilelist import Ui_form_yunfilelist
    from ui.formitemyun import Ui_formitemyun
    from ui.formitemxuanjue import Ui_formitemxuanjue
    from ui.formitemlianzhao import Ui_formitemlianzhao
    from ui.dialogchuansong import Ui_dialogchuansong
    from ui.formm import Ui_form_m
    from PyQt5.QtWidgets import QMessageBox
    from lanrentools.stitchimages import *
    from yunpan import YunPan
    from jianchaupdate import get_var_data, get_updatetxt
except:
    logger.error(traceback.format_exc())


def extract_number(folder_name):
    numbers = re.findall(r'\d+', folder_name)
    return int(numbers[0]) if numbers else float('inf')

class MySignal(QObject):
    mySignal = pyqtSignal(int, str)  # 定义自定义信号,并指定信号参数类型
    mysig_shutdown = pyqtSignal()
    mysig_mouse_through = pyqtSignal(bool)
    mysig_tishi = pyqtSignal(str)
    mysig_show_xunlu = pyqtSignal()
    mysig_show_yolov = pyqtSignal()
    mysig_dingwei=pyqtSignal(int)
    mysig_next_pack=pyqtSignal()
class WrappedTextToolButton(QToolButton):
    def __init__(self, text, parent=None):
        super().__init__(parent)
        self.setText(text)

    def sizeHint(self):
        size_hint = super().sizeHint()
        font_metrics = self.fontMetrics()
        width = max(font_metrics.width(self.text()), 100)  # 最小宽度为 100 像素
        height = font_metrics.heightForWidth(width)
        size_hint.setWidth(width)
        size_hint.setHeight(height)
        return size_hint
class DialogChuansong(QDialog, Ui_dialogchuansong):
    def __init__(self, parent=None,idex=-1):
        super(QDialog, self).__init__(parent)
        self.idex=idex


        self.setupUi(self)
        self.set_ui()
        # 移除标题栏的问号按钮
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        # 过滤滚轮事件 防止误触
        self.cbb_address.installEventFilter(self)
        self.set_cbb_items()
        self.bt_luzhi.clicked.connect(self.onn_bt_luzhi)
        self.bt_huifang.clicked.connect(self.onn_bt_huifang)
        self.bt_wenjianxuan.clicked.connect(self.onn_bt_wenjianxuan)
        self.cbb_address.currentIndexChanged.connect(self.onn_cbb_address)
        self.clb_jiaocheng.clicked.connect(
            lambda: webbrowser.open("https://www.bilibili.com/video/BV124421U7GN/"))
        # self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)
    def set_ui(self):
        pass
    def eventFilter(self,obj, event):
        if isinstance(obj, QComboBox) and event.type() == QEvent.Wheel and not obj.view().isVisible():
            return True  # 拦截鼠标滚轮事件
        return False
    def set_cbb_items(self):
        #self.cbb_address .clear()
        #遍历文件夹下的所有png文件
        # 定义要遍历的文件夹路径
        folder_path =state.PATH_ADDRESS

        # 遍历文件夹及其子文件夹中的所有文件
        for root, dirs, files in os.walk(folder_path):
            for file in files:
                # 检查文件扩展名是否为.png
                if file.endswith('.png'):
                    # 打印PNG文件的完整路径
                    file_name = os.path.splitext(file)[0]
                    if file_name[-1]!="2":
                        self.cbb_address.addItem(file_name)
    def onn_bt_luzhi(self):
        # 获取窗口句柄
        hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
        rect = win32gui.GetWindowRect(hwnd)
        # 设定截图区域的左上角坐标 (x, y) 和右下角坐标 (x, y)
        left, top, right, bottom = 1,979,120,1074  # 替换成你实际的区域坐标
        dituchilun_img = cv2.imdecode(np.fromfile(file="./datas/地图齿轮.png", dtype=np.uint8), cv2.IMREAD_UNCHANGED)
        if self.cbb_address.currentIndex() != 0:
            big_img = screenshot(hwnd, left, top, right, bottom, None)
            res = template_matching(big_img, dituchilun_img, mask=None)

            if res==[]:
                QMessageBox.information(self, "提示", "请先打开地图 后再操作")
                #弹出信息框 提示先打开地图
                return
        if ctypes.windll.user32.GetForegroundWindow() != hwnd:
            # 激活hwnd
            hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
            set_window_activate(hwnd)
            time.sleep(0.1)

        if self.cbb_address.currentIndex()!=0:
            logger.info("稍等 正在自动选择区域...")
            self.parent().sg.mysig_tishi.emit("稍等 正在自动选择区域...")
            if not self.parent().autoSelectAddress(self.cbb_address.currentText()):
                return
        logger.info("可以开始录制拖动地图过程了,按F8开始/停止")
        self.parent().sg.mysig_tishi.emit("可以开始录制拖动地图过程了,按F8开始/停止")
        state.状态_是否禁止录制 = False
        state.状态_是否开始录制 = False
        state.录制_当前任务索引 = self.idex
        state.录制_脚本文本 = ""
        state.录制_当前脚本名 = self.parent().datas[self.idex]["name"]
        asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否开始录制#@@#假"), auto.loop)
        asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否禁止录制#@@#假"), auto.loop)
        asyncio.run_coroutine_threadsafe(send_to_client(-1, f"全局脚本名#@@#传送-{state.录制_当前脚本名}"), auto.loop)
        hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
        asyncio.run_coroutine_threadsafe(send_to_client(-1, f"全局hwnd#@@#{hwnd}"), auto.loop)
        self.parent().timer_luzhi_chuansong.start(200)
        self.close()
    def onn_bt_huifang(self):

        if state.状态_是否回放中 == True:
            return
        dir_ = os.path.join(state.PATH_TASK, self.parent().datas[self.idex]["name"])
        if not os.path.exists(dir_):
            os.makedirs(dir_)

        # 获取窗口句柄
        hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
        rect = win32gui.GetWindowRect(hwnd)
        # 设定截图区域的左上角坐标 (x, y) 和右下角坐标 (x, y)
        left, top, right, bottom = 1, 979, 120, 1074  # 替换成你实际的区域坐标
        dituchilun_img = cv2.imdecode(np.fromfile(file="./datas/地图齿轮.png", dtype=np.uint8),
                                      cv2.IMREAD_UNCHANGED)
        big_img = screenshot(hwnd, left, top, right, bottom, None)
        res = template_matching(big_img, dituchilun_img, mask=None)

        if res == []:
            QMessageBox.information(self, "提示", "请先打开地图 后再操作")
            # 弹出信息框 提示先打开地图
            return
        if ctypes.windll.user32.GetForegroundWindow() != hwnd:
            # 激活hwnd
            hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
            set_window_activate(hwnd)
            time.sleep(0.1)

        if self.cbb_address.currentIndex() != 0:
            logger.info("正在自动选择区域...")
            self.parent().sg.mysig_tishi.emit("正在自动选择区域...")
            if not self.parent().autoSelectAddress(self.cbb_address.currentText()):
                return


        logger.info("回放脚本中! 按F9停止")
        self.parent().sg.mysig_tishi.emit("回放脚本中! 按F9停止")

        state.状态_循环开关 = True
        state.状态_是否回放中 = True
        jiaoben = os.path.abspath(os.path.join(dir_, self.parent().datas[self.idex]["chuansong"]))
        message = f"解析脚本#@@#{jiaoben}"
        asyncio.run_coroutine_threadsafe(send_to_client(-1, message), auto.loop)
        hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
        set_window_activate(hwnd)
        asyncio.run_coroutine_threadsafe(send_to_client(-1, "脚本执行#@@#1"), auto.loop)
        self.parent().timer_huifang.start(200)
        self.close()
    def onn_bt_wenjianxuan(self):

        # 弹出一个有分组框的窗口
        temp_path, ok = QFileDialog.getOpenFileName(self, "传送脚本", "", "脚本文件 (*.txt)")
        if ok:
            dir_ = os.path.join(state.PATH_TASK, self.parent().datas[self.idex]["name"])
            if not os.path.exists(dir_):
                os.makedirs(dir_)

                # 并且将jiaoben.ini文件也填入数据然后生成
            # 将图片复制到指定目录
            path = dir_ + "/传送脚本.txt"
            shutil.copy(temp_path, path)
            self.parent().datas[self.idex]["chuansong"] = "传送脚本.txt"
            self.parent().datas[self.idex]["f_item"].bt_chuansong.setProperty("OK_chuansong", True)
            logger.info(f"导入传送脚本成功:{path}")
            self.parent().sg.mysig_tishi.emit(f"导入传送脚本成功:{path}")
            self.parent().datas[self.idex]["f_item"].bt_chuansong.setStyleSheet("""
                                                            #bt_chuansong[OK_chuansong="true"] {
                                                            color: rgb(237,182,43);
                                                            border-color: rgb(237,182,43);
                                                            }
                                                         """)
            self.parent().save_ini(dir_, self.parent().datas[self.idex])
            self.close()
    def onn_cbb_address(self,index):
        self.parent().datas[self.idex]['cbb_address']=self.cbb_address.currentText()

class FrameItem(QFrame, Ui_formitem):
    def __init__(self, parent=None):
        super(QFrame, self).__init__(parent)
        self.setupUi(self)
        self.set_ui()
        self.is_zd=False
        w = int(item_width * ratio)
        h = int(item_height_min * ratio)
        self.setMinimumSize(w + int(1 * ratio), h)
        self.setMaximumSize(w, h)
        # self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)
    def set_ui(self):
        pass

    def mousePressEvent(self, event):
        if not self.is_zd:
            self.is_zd=not self.is_zd
            w = int(item_width * ratio)
            h = int(item_height * ratio)
            self.setMinimumSize(w + int(1* ratio), h)
            self.setMaximumSize(w, h)
            self.bt_map.setVisible(True)
            self.bt_lujing.setVisible(True)
            self.bt_chuansong.setVisible(True)
            self.bt_moban.setVisible(True)
            self.bt_moban_maodian.setVisible(True)
            self.bt_start.setVisible(True)
            self.cb_wakuang.setVisible(True)
            self.cb_caiji.setVisible(True)
            self.cb_daguai.setVisible(True)
            self.bt_del.setVisible(True)
        else:
            self.is_zd = not self.is_zd
            w = int(item_width * ratio)
            h = int(item_height_min * ratio)
            self.setMinimumSize(w + int(1* ratio), h)
            self.setMaximumSize(w, h)
            self.bt_map.setVisible(False)
            self.bt_lujing.setVisible(False)
            self.bt_chuansong.setVisible(False)
            self.bt_moban.setVisible(False)
            self.bt_moban_maodian.setVisible(False)
            self.bt_start.setVisible(False)
            self.cb_wakuang.setVisible(False)
            self.cb_caiji.setVisible(False)
            self.cb_daguai.setVisible(False)
            self.bt_del.setVisible(False)
class FrameItemFuBen(QFrame, Ui_formitemfuben):
    def __init__(self, parent=None):
        super(QFrame, self).__init__(parent)
        self.setupUi(self)
        self.set_ui()
        self.is_zd=False
        w = int(item_width * ratio)
        h = int(item_height_min * ratio)
        self.setMinimumSize(w + int(1 * ratio), h)
        self.setMaximumSize(w, h)
        # self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)

    def set_ui(self):
        pass

    def mousePressEvent(self, event):
        if not self.is_zd:
            self.is_zd=not self.is_zd
            # 在这里添加鼠标进入时的逻辑
            w = int(item_width * ratio)
            h = int(item_height * ratio)
            self.setMinimumSize(w + int(1* ratio), h)
            self.setMaximumSize(w, h)
            self.bt_chuansong.setVisible(True)
            self.bt_moban.setVisible(True)
            self.bt_moban_maodian.setVisible(True)
            self.bt_start.setVisible(True)
            self.bt_del.setVisible(True)
            self.cb_isfanxiang.setVisible(True)
            self.led_cishu.setVisible(True)
            self.label.setVisible(True)
        else:
            self.is_zd = not self.is_zd
            w = int(item_width * ratio)
            h = int(item_height_min * ratio)
            self.setMinimumSize(w + int(1 * ratio), h)
            self.setMaximumSize(w, h)
            self.bt_chuansong.setVisible(False)
            self.bt_moban.setVisible(False)
            self.bt_moban_maodian.setVisible(False)
            self.bt_start.setVisible(False)
            self.bt_del.setVisible(False)
            self.cb_isfanxiang.setVisible(False)
            self.led_cishu.setVisible(False)
            self.label.setVisible(False)
class FrameItemJiaoBen(QFrame, Ui_formitemjiaoben):
    def __init__(self, parent=None):
        super(QFrame, self).__init__(parent)
        self.setupUi(self)
        self.set_ui()
        self.is_zd=False
        w = int(item_width * ratio)
        h = int(item_height_min * ratio)
        self.setMinimumSize(w + int(1 * ratio), h)
        self.setMaximumSize(w, h)
        # self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)

    def set_ui(self):
        pass
    def mousePressEvent(self, event):
        if not self.is_zd:
            self.is_zd=not self.is_zd
            # 在这里添加鼠标进入时的逻辑
            w = int(item_width* ratio)
            h = int(item_height* ratio)


            self.setMinimumSize(w + int(1* ratio), h)
            self.setMaximumSize(w, h)
            self.bt_start.setVisible(True)
            self.bt_jiaoben.setVisible(True)
            self.bt_chuansong.setVisible(True)
            self.bt_moban_maodian.setVisible(True)
            self.bt_moban.setVisible(True)
            self.bt_start.setVisible(True)
            self.bt_del.setVisible(True)
            self.cb_auto_f.setVisible(True)
        else:
            self.is_zd = not self.is_zd
            w = int(item_width * ratio)
            h = int(item_height_min * ratio)
            self.setMinimumSize(w + int(1* ratio), h)
            self.setMaximumSize(w, h)
            self.bt_start.setVisible(False)
            self.bt_jiaoben.setVisible(False)
            self.bt_chuansong.setVisible(False)
            self.bt_moban_maodian.setVisible(False)
            self.bt_moban.setVisible(False)
            self.bt_start.setVisible(False)
            self.bt_del.setVisible(False)
            self.cb_auto_f.setVisible(False)
class FrameItemXuanJue(QFrame, Ui_formitemxuanjue):
    def __init__(self, parent=None):
        super(QFrame, self).__init__(parent)
        self.setupUi(self)
        self.set_ui()
        self.is_zd=False
        w = int(item_width * ratio)
        h = int(item_height_min * ratio)
        self.setMinimumSize(w + int(1 * ratio), h)
        self.setMaximumSize(w, h)
        # self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)
        #过滤滚轮事件 防止误触
        self.cbb_1.installEventFilter(self)
        self.cbb_2.installEventFilter(self)
        self.cbb_3.installEventFilter(self)
        self.cbb_4.installEventFilter(self)
    def eventFilter(self,obj, event):
        if isinstance(obj, QComboBox) and event.type() == QEvent.Wheel and not obj.view().isVisible():
            return True  # 拦截鼠标滚轮事件
        return False
    def set_ui(self):
        pass
    def mousePressEvent(self, event):
        if not self.is_zd:
            self.is_zd=not self.is_zd
            # 在这里添加鼠标进入时的逻辑
            w = int(item_width * ratio)
            h = int(item_height * ratio)
            self.setMinimumSize(w + int(1* ratio), h)
            self.setMaximumSize(w, h)
            self.bt_start.setVisible(True)
            self.cbb_1.setVisible(True)
            self.cbb_2.setVisible(True)
            self.cbb_3.setVisible(True)
            self.cbb_4.setVisible(True)
            self.lb_zhanchang.setVisible(True)
            self.led_main.setVisible(True)
            self.bt_del.setVisible(True)
        else:
            self.is_zd = not self.is_zd
            w = int(item_width * ratio)
            h = int(item_height_min * ratio)
            self.setMinimumSize(w + int(1* ratio), h)
            self.setMaximumSize(w, h)
            self.bt_start.setVisible(False)
            self.cbb_1.setVisible(False)
            self.cbb_2.setVisible(False)
            self.cbb_3.setVisible(False)
            self.cbb_4.setVisible(False)
            self.lb_zhanchang.setVisible(False)
            self.led_main.setVisible(False)
            self.bt_del.setVisible(False)
class FrameItemLianZhao(QFrame, Ui_formitemlianzhao):
    def __init__(self, parent=None):
        super(QFrame, self).__init__(parent)
        self.setupUi(self)
        self.set_ui()
        self.is_zd=False
        w = int(item_width * ratio)
        h = int(item_height_min * ratio)
        self.setMinimumSize(w + int(1 * ratio), h)
        self.setMaximumSize(w, h)
        # self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)
        #过滤滚轮事件 防止误触
        self.cbb_lianzhao.installEventFilter(self)

    def eventFilter(self,obj, event):
        if isinstance(obj, QComboBox) and event.type() == QEvent.Wheel and not obj.view().isVisible():
            return True  # 拦截鼠标滚轮事件
        return False
    def set_ui(self):
        pass
    def mousePressEvent(self, event):
        if not self.is_zd:
            self.is_zd=not self.is_zd
            # 在这里添加鼠标进入时的逻辑
            w = int(item_width * ratio)
            h = int(item_height * ratio)
            self.setMinimumSize(w + int(1* ratio), h)
            self.setMaximumSize(w, h)
            self.bt_start.setVisible(True)
            self.cbb_lianzhao.setVisible(True)
            self.bt_del.setVisible(True)
        else:
            self.is_zd = not self.is_zd
            w = int(item_width * ratio)
            h = int(item_height_min * ratio)
            self.setMinimumSize(w + int(1* ratio), h)
            self.setMaximumSize(w, h)
            self.bt_start.setVisible(False)
            self.cbb_lianzhao.setVisible(False)
            self.bt_del.setVisible(False)
class FormShow(QDockWidget, Ui_DockWidget):
    def __init__(self, parent=None):
        super(QDockWidget, self).__init__(parent)
        self.parent=parent
        self.setParent(parent)
        self.setupUi(self)
        self.set_ui()
        #self.timer = QTimer()
        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)
    def set_ui(self):
        pass
    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):
        state.开关_是否展预测结果 = False
        self.parent.action_isShow.setChecked(state.开关_是否展预测结果)
    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())
class FormItemYun(QFrame, Ui_formitemyun):
    def __init__(self, parent=None):
        super(QFrame, self).__init__(parent)
        self.setupUi(self)
        self.set_ui()
        # self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)
    def set_ui(self):
        pass
class FormYunFileList(QFrame, Ui_form_yunfilelist,YunPan):
    def __init__(self):
        super().__init__()
        YunPan.__init__(self)
        self.set_ui()
        self.setupUi(self)
        self.setWindowIcon(QIcon("datas/logo.png"))
        self.setWindowTitle('懒人群友云端资源 感谢零度可乐提供云端支持')  # 标题
        self.setWindowFlags(Qt.WindowStaysOnTopHint)
        self.resize(int(910*ratio), int(700*ratio))
        self.g_box = QGridLayout()
        self.container_widget = QWidget()  # 创建一个中间部件  为了可以让g_布局超过窗口大小
        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)
        self.sa_main.setWidget(self.container_widget)  # 将中间部件设置为QScrollArea的子部件
        # 获取纵向滚动条控件
        vertical_scrollbar = self.findChild(QScrollArea)
        self.v_scrollbar = vertical_scrollbar.verticalScrollBar()
        self.row = 0
        self.column = -1
        # 所有数据
        self.datas = []
        self.login(username="lanren",password="lanrenai2024")
        # 创建一个计时器,用于延迟布局
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)  # 设置为单次触发
        self.timer.timeout.connect(self.update_layout)
        self.connect_set()
        self.ing=True
        # 创建一个计时器,用于延迟布局
        self.timer1 = QTimer(self)

        self.timer1.timeout.connect(self.update_init)
        self.timer1.start(200)

        self.lb_ing=QLabel("加载中请稍等...",self)
        self.lb_ing.setStyleSheet("""
        font: 75 50pt "微软雅黑";
    color: rgb(255, 0, 0);
        """)
        self.lb_ing.resize(500,100)
    def update_init(self):
        if not self.ing:
            self.updatefilelist()
            self.lb_ing.close()
            self.timer1.stop()
    def set_ui(self):
        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()))
    def resizeEvent(self, event):

        super().resizeEvent(event)
        # 每当用户调整窗口大小时,启动计时器
        self.timer.start(300)  # 500毫秒后触发timeout信号
    def connect_set(self):
        self.tabWidget.currentChanged.connect(self.currentChanged_tabWidget)
    def currentChanged_tabWidget(self,index):
        self.updatefilelist(keys=self.tabWidget.tabText(index))
    def update_layout(self):
        try:
            # 获取主窗口的宽度
            width = self.width()
            # 计算每行可以容纳的组件数量


            num_per_row = (width ) // (280 * ratio)  # 假设每个组件的宽度为200

            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 update(self):
        self.ing=True
        self.file_all=[]
        self.file_all = self.get_file_all(isclose=True)

        self.file_all = list(map(lambda x: {"name": x['name'], "sign": x['sign'], "dir": x['dir'],
                                       "url": x['raw_url'], "modified": x['modified']}, self.file_all))

        self.file_all = sorted(self.file_all, key=lambda x: datetime.strptime(x['modified'].split("+")[0].split(".")[0],
                                                                              "%Y-%m-%dT%H:%M:%S"),
                               reverse=True)

        self.ing = False
    def updatefilelist(self,keys=""):
        try:
            if keys=="全部":
                keys=""

            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)


            for item in self.file_all:

                if keys in item[ "dir"].split("/")[-3] or keys=="":
                    self.add_yun_file(data=item)
        except:
            pass
    def add_yun_file(self,data={}):
        '''
        添加云文件显示
        :return:
        '''
        # 根据导入的文件
        # 获取主窗口的宽度
        # 获取主窗口的宽度
        width = self.width()
        # 计算每行可以容纳的组件数量
        num_per_row = (width )  // (280* ratio)  # 假设每个组件的宽度为200
        if num_per_row < 1:
            num_per_row = 1
        self.column += 1
        if self.column == num_per_row:
            self.column = 0
            self.row += 1
        f_item = FormItemYun()
        w = int(300* ratio)
        h = int(180* ratio)
        f_item.setMinimumSize(int((w + 13)* ratio), h)
        f_item.setMinimumSize(w, h)
        f_item.setMaximumSize(w, h)
        f_item.setObjectName("frame_cont")
        f_item.raise_()
        f_item.setStyleSheet("""
                               #frame_cont:hover {
                                   border: 1px solid red;
                               }
                               #frame_cont {
                                    background-color: rgba(0, 0, 0, 0);
                               }
                               """)
        f_item.bt_down.clicked.connect(lambda: webbrowser.open(data["url"]))
        f_item.led_name.setText(data["name"])
        f_item.led_author.setText(data["dir"].split("/")[-2][:-6])
        f_item.led_time.setText(data["modified"].split(".")[0].replace("T", " "))

        data["f_item"] = f_item
        self.datas.append(data)
        self.g_box.addWidget(f_item, self.row, self.column)
class FormM(QFrame, Ui_form_m):
    def __init__(self, parent=None):
        super(QFrame, self).__init__()
        self.parent=parent
        self.setupUi(self)
        self.set_ui()
        self.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint | Qt.WindowStaysOnTopHint)

        self.setWindowIcon(QIcon("datas/logo.png"))
        self.setWindowTitle('选择模型')  # 标题
        self.bt_save.clicked.connect(self.onn_bt_save)
        onnx_file_names = []

        # 遍历文件夹中所有文件和子文件夹
        for root, dirs, files in os.walk(".\\datas"):
            for file in files:
                # 检查文件是否以 .onnx 结尾
                if file.endswith('.onnx'):
                    # 如果是 .onnx 文件,则将其路径加入列表
                    file_name = os.path.splitext(file)[0]
                    onnx_file_names.append(file_name)

        self.cbb_m.addItems(onnx_file_names)
        self.cbb_m.setCurrentText(state.WEIGHTS.split('/')[-1].split('.')[0])
        print("1111",state.WEIGHTS.split('/')[-1].split('.')[0])
    def set_ui(self):
        pass
    def onn_bt_save(self):

        state.WEIGHTS='./datas/'+self.cbb_m.currentText()+".onnx"
        state.IMGSIZE_WIDTH=int(self.cbb_m.currentText().split("_")[-1])
        state.IMGSIZE_HEIGHT = int(self.cbb_m.currentText().split("_")[-1])
        self.parent.close()
class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super().__init__()
        self.set_ui()
        self.setupUi(self)
        self.setWindowIcon(QIcon("datas/logo.png"))
        self.setWindowTitle(f"懒人原神AI{state.版本号}  F8暂停 F9停止 F10标记")
        self.resize(state.WINDOW_WIDTH, state.WINDOW_HEIGHT)
        self.move(state.WINDOW_LEFT, state.WINDOW_TOP)

        self.g_box = QGridLayout()
        self.container_widget = QWidget()  # 创建一个中间部件  为了可以让g_布局超过窗口大小
        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)
        self.sa_main.setWidget(self.container_widget)  # 将中间部件设置为QScrollArea的子部件

        # 获取纵向滚动条控件
        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.datas = []
        # 创建一个计时器,用于延迟布局
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)  # 设置为单次触发
        self.timer.timeout.connect(self.update_layout)
        self.connect_set()
        #加载任务包列表
        self.load_task_packs()
        self.show_tool_item(state.PATH_TASK)

        self.timer_luzhi = QTimer(self)
        self.timer_luzhi.timeout.connect(self.timeout_luzhi)

        self.timer_luzhi_chuansong = QTimer(self)
        self.timer_luzhi_chuansong.timeout.connect(self.timeout_luzhi_chuansong)
        self.timer_luzhi_lianzhao = QTimer(self)
        self.timer_luzhi_lianzhao.timeout.connect(self.timeout_luzhi_lianzhao)

        self.timer_huifang = QTimer(self)
        self.timer_huifang.timeout.connect(self.timeout_huifang)

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

        # 设置状态栏文本
        self.statusbar.showMessage('本工具仅在QQ群789467094中免费分享!欢迎使用懒人原神AI!')
        #禁止截图
        #set_window_display_affinity(int(self.winId()))
        # self.toolBar.setMovable(True)
        # self.toolBar.setFloatable(True)
        # self.toolBar.setAllowedAreas(Qt.AllToolBarAreas)
    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 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)
                        else:
                            # 锄地任务
                            self.add_task(item_path, config)
            except Exception:
                logger.info(f"请选择任务文件夹,目前没有这个文件夹{state.PATH_TASK}" )
    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.data=[]
        # 每当用户调整窗口大小时,启动计时器
        self.timer.start(300)  # 500毫秒后触发timeout信号
    def timeout_luzhi(self):
        if  state.录制_脚本文本!="":
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否禁止录制#@@#真"), auto.loop)
            state.状态_是否禁止录制 = True
            dir_ = os.path.join(state.PATH_TASK, self.datas[state.录制_当前任务索引]["name"])
            if not os.path.exists(dir_):
                os.makedirs(dir_)
            # 并且将jiaoben.ini文件也填入数据然后生成
            path = dir_ + "/脚本.txt"
            with open(path, "w", encoding="gbk",newline='') as f:
                f.write(state.录制_脚本文本)
            self.datas[state.录制_当前任务索引]["jiaoben"] = "脚本.txt"
            self.datas[state.录制_当前任务索引]["f_item"].bt_jiaoben.setProperty("OK_jiaoben", True)
            logger.info(f"导入脚本成功:{path}")
            self.sg.mysig_tishi.emit(f"导入脚本成功:{path}")
            self.datas[state.录制_当前任务索引]["f_item"].bt_jiaoben.setStyleSheet("""
                                                                                    #bt_jiaoben[OK_jiaoben="true"] {
                                                                                    color: rgb(237,182,43);  
                                                                                    border-color: rgb(237,182,43); 
                                                                                    }
                                                                                 """)
            state.录制_脚本文本 = ""
            self.save_ini(dir_, self.datas[state.录制_当前任务索引])
            self.timer_luzhi.stop()
    def timeout_luzhi_chuansong(self):
        if state.录制_脚本文本 != "":
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否禁止录制#@@#真"), auto.loop)
            state.状态_是否禁止录制 = True
            dir_ = os.path.join(state.PATH_TASK, self.datas[state.录制_当前任务索引]["name"])
            if not os.path.exists(dir_):
                os.makedirs(dir_)
            # 并且将jiaoben.ini文件也填入数据然后生成
            path = dir_ + "/传送脚本.txt"
            with open(path, "w", encoding="gbk", newline='') as f:
                f.write(state.录制_脚本文本)
            self.datas[state.录制_当前任务索引]["chuansong"] = "传送脚本.txt"
            self.datas[state.录制_当前任务索引]["f_item"].bt_chuansong.setProperty("OK_chuansong", True)
            logger.info(f"导入脚本成功:{path}")
            self.sg.mysig_tishi.emit(f"导入脚本成功:{path}")
            self.datas[state.录制_当前任务索引]["f_item"].bt_chuansong.setStyleSheet("""
                                                                                       #bt_chuansong[OK_chuansong="true"] {
                                                                                       color: rgb(237,182,43);  
                                                                                       border-color: rgb(237,182,43); 
                                                                                       }
                                                                                    """)
            state.录制_脚本文本 = ""
            self.save_ini(dir_, self.datas[state.录制_当前任务索引])
            self.timer_luzhi_chuansong.stop()
    def timeout_luzhi_lianzhao(self):
        if  state.录制_脚本文本!="":
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否禁止录制#@@#真"), auto.loop)
            state.状态_是否禁止录制 = True
            dir_ = os.path.abspath(state.PATH_JIAOBEN)
            if not os.path.exists(dir_):
                os.makedirs(dir_)
            # 并且将jiaoben.ini文件也填入数据然后生成
            path = os.path.join(dir_, state.LIANZHAO)
            with open(path, "w", encoding="gbk",newline='') as f:
                f.write(state.录制_脚本文本)
            state.录制_脚本文本 = ""
            logger.info("录制并选择连招脚本成功!")
            self.sg.mysig_tishi.emit("录制并选择连招脚本成功!")
            self.save_ini_seting()
            self.timer_luzhi_lianzhao.stop()
    def timeout_huifang(self):
        if state.状态_循环开关 == False:
            state.状态_需重新传送 = False
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否回放#@@#假"), auto.loop)
            logger.info("回放结束1")
            self.sg.mysig_tishi.emit("回放结束1")
            self.timer_huifang.stop()
            return
        if state.状态_是否回放中== False:
            logger.info("回放结束2")
            self.sg.mysig_tishi.emit("回放结束2")
            self.timer_huifang.stop()
    def update_layout(self):
        try:
            # 获取主窗口的宽度
            width =self.centralWidget().width()
            # 计算每行可以容纳的组件数量
            num_per_row = (width ) // (self.column_step * ratio)  # 假设每个组件的宽度为200
            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 connect_set(self):
        '''
        绑定信号
        :return:
        '''

        self.sg = MySignal()
        state. QT_信号=self.sg
        self.sg.mysig_shutdown.connect(self.show_shutdown_dig)
        self.sg.mysig_mouse_through.connect(self.set_mouse_through)
        self.sg.mysig_tishi.connect(self.set_tishi)
        self.sg.mysig_next_pack.connect(self.next_pack)

        self.sg.mysig_show_xunlu.connect(self.show_xunlu)
        self.sg.mysig_show_yolov.connect(self.show_yolov)
        self.sg.mysig_dingwei.connect(self.dingwei)



        self.menu = self.menuBar()
        # 创建一个顶级菜单
        self.menu_file = self.menu.addMenu("文件")
        # 创建一个动作
        self.action_addtask = QAction("新增-AI锄地任务-大世界寻路打怪", self)
        self.action_addtask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_1))
        self.action_addtask.triggered.connect(self.hotkey_addtask)
        self.menu_file.addAction(self.action_addtask)

        # 创建一个动作
        self.action_addtaskfuben = QAction("新增-AI副本任务-任意副本需要录制传送", self)
        self.action_addtaskfuben.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_2))
        self.action_addtaskfuben.triggered.connect(self.hotkey_addtaskfuben)
        self.menu_file.addAction(self.action_addtaskfuben)

        # 创建一个动作
        self.action_addtaskjiaoben = QAction("新增-脚本回放任务-适合采集/挖矿/晶蝶/等等", self)
        self.action_addtaskjiaoben.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_3))
        self.action_addtaskjiaoben.triggered.connect(self.hotkey_addtaskjiaoben)
        self.menu_file.addAction(self.action_addtaskjiaoben)

        # 创建一个动作
        self.action_qiejue = QAction("新增-切换角色任务", self)

        self.action_qiejue.triggered.connect(self.hotkey_qiejue)
        self.menu_file.addAction(self.action_qiejue)

        # 创建一个动作
        self.action_qiehuanlianzhao = QAction("新增-切换连招任务", self)
        self.action_qiehuanlianzhao.triggered.connect(self.hotkey_qiehuanlianzhao)
        self.menu_file.addAction(self.action_qiehuanlianzhao)

        # 创建一个动作
        self.action_importtask = QAction("导入视觉任务", self)
        self.action_importtask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_4))
        self.action_importtask.triggered.connect(self.hotkey_importtask)
        self.menu_file.addAction(self.action_importtask)

        self.action_opentaskdir = QAction("打开任务文件夹", self)
        self.action_opentaskdir.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_5))
        self.action_opentaskdir.triggered.connect(self.hotkey_opentaskdir)
        self.menu_file.addAction(self.action_opentaskdir)

        self.action_selecttaskdir = QAction("导入/选择任务包", self)
        self.action_selecttaskdir.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_6))
        self.action_selecttaskdir.triggered.connect(self.hotkey_selecttaskdir)
        self.menu_file.addAction(self.action_selecttaskdir)

        self.action_setlianzhao = QAction("选择连招脚本", self)
        self.action_setlianzhao.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_7))
        self.action_setlianzhao.triggered.connect(self.hotkey_setlianzhao)
        self.menu_file.addAction(self.action_setlianzhao)

        self.action_addlianzhao = QAction("录制/编辑连招", self)
        self.action_addlianzhao.triggered.connect(self.hotkey_addlianzhao)
        self.menu_file.addAction(self.action_addlianzhao)

        # 创建一个顶级菜单
        self.menu_ck = self.menu.addMenu("选择")
        # 创建一个动作
        self.action_all_ck = QAction("全部选中", self)
        self.action_all_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_8))
        self.action_all_ck.triggered.connect(self.hotkey_all_ck)
        self.menu_ck.addAction(self.action_all_ck)

        self.action_all_not_ck = QAction("全部不选", self)
        self.action_all_not_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_9))
        self.action_all_not_ck.triggered.connect(self.hotkey_all_not_ck)
        self.menu_ck.addAction(self.action_all_not_ck)

        self.action_all_fan_ck = QAction("全部反选", self)
        self.action_all_fan_ck.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_0))
        self.action_all_fan_ck.triggered.connect(self.hotkey_all_fan_ck)
        self.menu_ck.addAction(self.action_all_fan_ck)


        self.action_keys_ack = QAction("选中包含某个关键词的", self)
        self.action_keys_ack.triggered.connect(self.hotkey_keys_ack)
        self.menu_ck.addAction(self.action_keys_ack)

        self.action_num_ck = QAction("选中包含某个区间数字的", self)
        self.action_num_ck.triggered.connect(self.hotkey_num_ck)
        self.menu_ck.addAction(self.action_num_ck)

        self.action_find = QAction("查找并定位到包含某个关键字的任务", self)
        self.action_find.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F))
        self.action_find.triggered.connect(self.hotkey_find)
        self.menu_ck.addAction(self.action_find)



        # 创建一个顶级菜单
        self.menu_run = self.menu.addMenu("操作")
        # 创建一个动作
        self.action_runall = QAction("启动选中任务", self)
        self.action_runall.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F1))
        self.action_runall.triggered.connect(self.hotkey_runall)
        self.menu_run.addAction(self.action_runall)

        self.action_deltask = QAction("删除选中任务", self)
        self.action_deltask.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_F2))
        self.action_deltask.triggered.connect(self.hotkey_deltask)
        self.menu_run.addAction(self.action_deltask)

        self.action_refresh = QAction("保存任务并刷新顺序", self)
        self.action_refresh.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        self.action_refresh.triggered.connect(self.save)
        self.menu_run.addAction(self.action_refresh)

        # 创建一个动作
        self.action_kuang = QAction("选中任务-是否勾选-矿", self)
        self.action_kuang.setCheckable(True)
        self.action_kuang.setChecked(False)
        self.action_kuang.triggered.connect(self.hotkey_kuang)
        self.action_kuang.setChecked(True)
        self.menu_run.addAction(self.action_kuang)

        # 创建一个动作
        self.action_hua = QAction("选中任务-是否勾选-花", self)
        self.action_hua.setCheckable(True)
        self.action_hua.setChecked(False)
        self.action_hua.triggered.connect(self.hotkey_hua)
        self.action_hua.setChecked(True)
        self.menu_run.addAction(self.action_hua)

        # 创建一个动作
        self.action_guai = QAction("选中任务-是否勾选-怪", self)
        self.action_guai.setCheckable(True)
        self.action_guai.setChecked(False)
        self.action_guai.triggered.connect(self.hotkey_guai)
        self.action_guai.setChecked(True)
        self.menu_run.addAction(self.action_guai)

        # 创建一个动作
        self.action_run_times = QAction(f"设置:当前任务包 执行次数:{self.run_times}", self)
        self.action_run_times.triggered.connect(self.hotkey_run_times)
        self.menu_run.addAction(self.action_run_times)

        # 创建一个顶级菜单
        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.action_isShowCmd = QAction("是否显示控制台", self)
        self.action_isShowCmd.triggered.connect(self.hotkey_isShowCmd)
        self.action_isShowCmd.setCheckable(True)
        self.action_isShowCmd.setChecked(True)
        self.menu_view.addAction(self.action_isShowCmd)

        # 创建一个顶级菜单
        self.menu_yun= self.menu.addMenu("云端")
        # 创建一个动作
        self.action_yunduanlist= QAction("懒人群友云端资源", self)
        self.action_yunduanlist.triggered.connect(self.hotkey_yunduanlist)

        self.menu_yun.addAction(self.action_yunduanlist)

        # 创建一个动作
        self.action_yunduanup1 = QAction("分享-副本打怪任务", self)
        self.action_yunduanup1.triggered.connect( lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/viwvNEP8c"))
        self.menu_yun.addAction(self.action_yunduanup1)

        self.action_yunduanup2 = QAction("分享-打怪锄地任务", self)
        self.action_yunduanup2.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/GjM0zwWAw"))
        self.menu_yun.addAction(self.action_yunduanup2)

        self.action_yunduanup3 = QAction("分享-回放脚本任务", self)
        self.action_yunduanup3.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/9eGN71WCG"))
        self.menu_yun.addAction(self.action_yunduanup3)

        self.action_yunduanup4 = QAction("分享-收集材料任务", self)
        self.action_yunduanup4.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/vWDkt4QRB"))
        self.menu_yun.addAction(self.action_yunduanup4)

        self.action_yunduanup5 = QAction("分享-连招脚本任务", self)
        self.action_yunduanup5.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/DVa5G18rL"))
        self.menu_yun.addAction(self.action_yunduanup5)

        self.action_yunduanup6 = QAction("分享-其它资源分享", self)
        self.action_yunduanup6.triggered.connect(
            lambda: webbrowser.open("https://nas.qizhiqiang.com:5001/sharing/3ucsnfSr5"))
        self.menu_yun.addAction(self.action_yunduanup6)


        # 创建一个顶级菜单
        self.menu_tools = self.menu.addMenu("工具")

        # 创建一个动作
        self.action_stitchimg = QAction("合成全景大图", self)
        self.action_stitchimg.triggered.connect(self.hotkey_stitchimg)
        self.menu_tools.addAction(self.action_stitchimg)

        # 创建一个顶级菜单
        self.menu_setting = self.menu.addMenu("设置")
        # 创建一个动作
        self.action_runstartwith = QAction("启动改为从这开始", self)
        self.action_runstartwith.setCheckable(True)
        self.action_runstartwith.setChecked(False)
        self.menu_setting.addAction(self.action_runstartwith)


        # 创建一个动作
        self.action_nextpack = QAction("是否自动继续下一个任务包", self)
        self.action_nextpack.setCheckable(True)
        self.action_nextpack.setChecked(False)
        self.action_nextpack.triggered.connect(self.hotkey_nextpack)
        if state.ON_NEXTPACK == 0:
            self.action_nextpack.setChecked(False)
        else:
            self.action_nextpack.setChecked(True)
        self.menu_setting.addAction(self.action_nextpack)

        # 创建一个动作
        self.action_jixing = QAction("是否任务完成后领取纪行奖励", self)
        self.action_jixing.triggered.connect(self.hotkey_jixing)
        self.action_jixing.setCheckable(True)
        if state.ON_JIXING == 0:
            self.action_jixing.setChecked(False)
        else:
            self.action_jixing.setChecked(True)
        self.menu_setting.addAction(self.action_jixing)
        # 创建一个动作
        self.action_shutdown = QAction("是否任务完成后关机", self)
        self.action_shutdown.triggered.connect(self.hotkey_shutdown)
        self.action_shutdown.setCheckable(True)
        if state.ON_SHUTDOWN == 0:
            self.action_shutdown.setChecked(False)
        else:
            self.action_shutdown.setChecked(True)
        self.menu_setting.addAction(self.action_shutdown)

        self.action_lianzhaobujiance = QAction("是否强制把连招搓完", self)
        self.action_lianzhaobujiance.triggered.connect(self.hotkey_lianzhaobujiance)
        self.action_lianzhaobujiance.setCheckable(True)
        if state.ON_LIANZHAOBUJIANCE == 0:
            self.action_lianzhaobujiance.setChecked(False)
        else:
            self.action_lianzhaobujiance.setChecked(True)
        self.menu_setting.addAction(self.action_lianzhaobujiance)

        # 创建一个动作
        self.action_weights = QAction(f"设置AI模型 当前: {state.WEIGHTS.split('/')[-1].split('.')[0]}", self)
        self.action_weights.triggered.connect(self.hotkey_weights)
        self.menu_setting.addAction(self.action_weights)

        # 创建一个动作
        self.action_timeout = QAction(f"设置打怪超时 阈值:{state.TIMEOUT_DAGUAI}秒", self)
        self.action_timeout.triggered.connect(self.hotkey_timeout)

        self.menu_setting.addAction(self.action_timeout)



        # 创建一个顶级菜单
        self.menu_help = self.menu.addMenu("帮助")
        # 创建一个动作
        self.action_about = QAction("关于", self)

        self.action_about.triggered.connect(
            lambda: QMessageBox.information(self, "作者", "python懒人智能 仅供技术研究!请勿用于非法用途否则后果自负!"))
        self.menu_help.addAction(self.action_about)

        # 创建一个动作
        self.action_kaiyuan = QAction("开源地址", self)

        self.action_kaiyuan.triggered.connect(lambda: webbrowser.open("https://gitee.com/LanRenZhiNeng/lanren-genshin-impact-ai"))
        self.menu_help.addAction(self.action_kaiyuan)

        # 创建一个动作
        self.action_zanzhu = QAction("赞助入群", self)

        self.action_zanzhu.triggered.connect(
            lambda: webbrowser.open("http://w.kami.vip/s/FSUtd45z"))
        self.menu_help.addAction(self.action_zanzhu)

        # 创建一个动作
        self.action_jiaocheng = QAction("教程合集", self)
        self.action_jiaocheng.triggered.connect(
            lambda: webbrowser.open("https://www.bilibili.com/video/BV1aS421w7i1"))
        self.menu_help.addAction(self.action_jiaocheng)
        # 创建右键弹出菜单
        menu = QMenu(self)
        menu.addAction(self.action_selecttaskdir)
        # 将菜单关联到工具栏上
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.toolBar.customContextMenuRequested.connect(lambda pos: menu.exec_(self.toolBar.mapToGlobal(pos)))

    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 show_tool_item(self,dir_):
        self.save()
        state.PATH_TASK = dir_
        self.save_ini_seting()
        self.update_tasks()
        self.change_tool_show_style(dir_)
        logger.info(f"成功设置{state.PATH_TASK}为当前任务文件夹")
    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_
        logger.info(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 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 get_next_task(self):
        # 获取工具栏上的所有动作
        actions_list = self.toolBar.actions()
        length=len(actions_list)
        if length<=0:
            return None
        # 遍历处理每个动作
        idex=0

        for i,action in enumerate(actions_list) :
            # 在这里对每个动作进行处理
            bt_item = action.defaultWidget()
            if state.PATH_TASK == bt_item.toolTip().replace("/", "\\").split("\n")[0]:
                idex=i
                break

        # 如果
        if idex<length-1:
            bt_item = actions_list[idex+1].defaultWidget()

            return bt_item.toolTip().replace("/", "\\").split("\n")[0]
        else:
            return None








    def show_shutdown_dig(self):
        self.dialog = ShutdownConfirmationDialog(self)
        self.dialog.show()
    def set_mouse_through(self, bool):
        set_mouse_through(int(self.winId()), bool)
        if bool:
            self.setWindowOpacity(0.9)
        else:
            self.setWindowOpacity(1)
    def set_tishi(self, txt):
        self.statusbar.showMessage(txt)
        if state.开关_是否展预测结果:
            self.fromshow.setWindowTitle(txt)
    def next_pack(self):
        self.show_tool_item(state.PATH_TASK)
        self.hotkey_runall()
    def show_xunlu(self):
        if state.开关_是否展预测结果:
            if type(state.图片_找图) == bool:
                return


            # 加载大图
            big_img_bk = state.图片_找图

            # 将OpenCV图像转换为Qt中的QImage
            height, width, channel = big_img_bk.shape
            bytesPerLine = 3 * width
            qImg = QImage(big_img_bk.data, width, height, bytesPerLine, QImage.Format_BGR888)
            pixmap = QPixmap.fromImage(qImg)

            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):

        if state.开关_是否展预测结果:
            if type(state.图片_YOLOV) == bool:
                return
            img1 = QImage(state.图片_YOLOV.data, state.图片_YOLOV.shape[1], state.图片_YOLOV.shape[0],QImage.Format_BGR888)
            pixmap1 = QPixmap.fromImage(img1)
            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())
            self.fromshow.lb_yolov.setPixmap(pixmap1)
    def dingwei(self,idex):
        try:
            self.datas[idex]["f_item"].is_zd = False
            self.datas[idex]["f_item"].mousePressEvent(None)
            self.v_scrollbar.setValue(self.datas[idex]["f_item"].y())

        except Exception as err:
            print("dingwei",err)
            pass



    def set_ui(self):
        # 设置主题样式为 Flatwhite
        # 创建 QtitanRibbon 实例
        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()))
    def tanChu_img(self, imgpath):
        '''
        弹出图片
        :param imgpath:
        :return:
        '''
        # ----------------------
        try:
            return f'''<img src='{imgpath}' > '''
        except Exception as err:
            return str(err)
    def add_task(self, dir_, config):
        '''
        添加任务
        :return:
        '''
        # 根据导入的文件
        # 获取主窗口的宽度
        width = self.centralWidget().width()
        # 计算每行可以容纳的组件数量
        num_per_row = (width ) // (self.column_step * ratio)  # 假设每个组件的宽度为200

        if num_per_row < 1:
            num_per_row = 1
        self.column += 1
        if self.column == num_per_row:
            self.column = 0
            self.row += 1
        # 加载ini配置文件

        f_item = FrameItem()

        f_item.setObjectName("frame_cont")
        f_item.raise_()
        f_item.setStyleSheet("""
                               #frame_cont:hover {
                                   border: 1px solid red;
                               }
                               #frame_cont {
                                    background-color: rgba(0, 0, 0, 0);
                               }
                               """)
        d = {}
        dir_ = dir_.replace("/", "\\")
        if dir_[-1]=="\\":
            dir_=dir_[:-1]
        d["type"] = "1"
        try:
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        except:
            # 添加一个名为 'seting' 的配置节
            config.add_section('seting')
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        d["name"] = config.get('seting', 'name', fallback=dir_.split("\\")[-1]).strip()
        d["map"] = config.get('seting', 'map', fallback='')
        d["lujing"] = config.get('seting', 'lujing', fallback='')
        d["chuansong"] = config.get('seting', 'chuansong', fallback='')
        d["chuansongmoban"] = config.get('seting', 'chuansongmoban', fallback='')
        d["maodianmoban"] = config.get('seting', 'maodianmoban', fallback='')
        d["cb_is_checked"] = config.get('seting', 'cb_is_checked', fallback='True')
        d["cbb_address"] = config.get('seting', 'cbb_address', fallback='手动录制')
        d["cb_wakuang"] = config.get('seting', 'cb_wakuang', fallback='False')
        d["cb_caiji"] = config.get('seting', 'cb_caiji', fallback='False')
        d["cb_daguai"] = config.get('seting', 'cb_daguai', fallback='True')
        f_item.bt_map.setProperty("OK_map", d["map"] != "")
        f_item.bt_lujing.setProperty("OK_lujing", d["lujing"] != "")
        f_item.bt_chuansong.setProperty("OK_chuansong", d["chuansong"] != "")
        f_item.bt_moban.setProperty("OK_chuansongmoban", d["chuansongmoban"] != "")
        f_item.bt_moban_maodian.setProperty("OK_maodianmoban", d["maodianmoban"] != "")
        f_item.bt_map.setObjectName("bt_map")
        f_item.bt_lujing.setObjectName("bt_lujing")
        f_item.bt_chuansong.setObjectName("bt_chuansong")
        f_item.bt_moban.setObjectName("bt_moban")
        f_item.bt_moban_maodian.setObjectName("bt_moban_maodian")
        f_item.led_name.setText(d["name"])
        f_item.bt_map.setStyleSheet("""
                        #bt_map[OK_map="true"] {
                        color: rgb(237,182,43);  /* 边框颜色为灰色 */
                        border-color: rgb(237,182,43);  /* 边框颜色为灰色 */
                        }
                     """)
        f_item.bt_lujing.setStyleSheet("""
                                #bt_lujing[OK_lujing="true"] {
                                color: rgb(237,182,43); 
                                border-color: rgb(237,182,43); 
                                }
                             """)
        f_item.bt_chuansong.setStyleSheet("""
                                                #bt_chuansong[OK_chuansong="true"] {
                                                color: rgb(237,182,43);  
                                                border-color: rgb(237,182,43); 
                                                }
                                             """)
        f_item.bt_moban.setStyleSheet("""
                                                #bt_moban[OK_chuansongmoban="true"] {
                                                color: rgb(237,182,43); 
                                                border-color: rgb(237,182,43); 
                                                }
                                             """)
        f_item.bt_moban_maodian.setStyleSheet("""
                                                        #bt_moban_maodian[OK_maodianmoban="true"] {
                                                        color: rgb(237,182,43); 
                                                        border-color: rgb(237,182,43); 
                                                        }
                                                     """)



        if d["cb_is_checked"] == "True":
            f_item.cb_is_checked.setChecked(True)
        else:
            f_item.cb_is_checked.setChecked(False)


        if d["cb_wakuang"] == "True":
            f_item.cb_wakuang.setChecked(True)
        else:
            f_item.cb_wakuang.setChecked(False)

        if d["cb_caiji"] == "True":
            f_item.cb_caiji.setChecked(True)
        else:
            f_item.cb_caiji.setChecked(False)

        if d["cb_daguai"] == "True":
            f_item.cb_daguai.setChecked(True)
        else:
            f_item.cb_daguai.setChecked(False)



        idex = len(self.datas)

        #f_item.led_name.editingFinished.connect(self.save)
        f_item.bt_map.clicked.connect(functools.partial(self.clickd_bt_map, idex))
        f_item.bt_lujing.clicked.connect(functools.partial(self.clickd_bt_lujing, idex))
        f_item.bt_chuansong.clicked.connect(functools.partial(self.clickd_bt_chuansong, idex))
        f_item.bt_moban.clicked.connect(functools.partial(self.clickd_bt_moban, idex))
        f_item.bt_moban_maodian.clicked.connect(functools.partial(self.clickd_bt_moban_maodian, idex))
        f_item.bt_start.clicked.connect(functools.partial(self.clickd_bt_start, idex))
        f_item.bt_del.clicked.connect(functools.partial(self.clickd_bt_del, idex))

        f_item.bt_map.setVisible(False)
        f_item.bt_lujing.setVisible(False)
        f_item.bt_chuansong.setVisible(False)
        f_item.bt_moban.setVisible(False)
        f_item.bt_moban_maodian.setVisible(False)
        f_item.bt_start.setVisible(False)
        f_item.bt_del.setVisible(False)
        f_item.cb_wakuang.setVisible(False)
        f_item.cb_caiji.setVisible(False)
        f_item.cb_daguai.setVisible(False)

        f_item.bt_map.setToolTip(self.tanChu_img(dir_ + "/" + d["map"]))
        f_item.bt_lujing.setToolTip(self.tanChu_img(dir_ + "/" + d["lujing"]))
        f_item.bt_moban.setToolTip(self.tanChu_img(dir_ + "/" + d["chuansongmoban"]))
        f_item.bt_moban_maodian.setToolTip(self.tanChu_img(dir_ + "/" + d["maodianmoban"]))

        d["f_item"] = f_item
        self.datas.append(d)
        self.g_box.addWidget(f_item, self.row, self.column)
    def add_taskfuben(self, dir_, config):
        '''
        添加任务
        :return:
        '''
        # 根据导入的文件
        # 获取主窗口的宽度
        width = self.centralWidget().width()
        # 计算每行可以容纳的组件数量
        num_per_row = (width) // (self.column_step * ratio)  # 假设每个组件的宽度为200

        if num_per_row < 1:
            num_per_row = 1
        self.column += 1
        if self.column == num_per_row:
            self.column = 0
            self.row += 1
        f_item = FrameItemFuBen()
        f_item.setObjectName("frame_cont")
        f_item.raise_()
        f_item.setStyleSheet("""
                               #frame_cont:hover {
                                   border: 1px solid red;
                               }
                               #frame_cont {
                                    background-color: rgba(0, 0, 0, 0);
                               }
                               """)
        d = {}
        d["type"] = "2"
        dir_ = dir_.replace("/", "\\")
        if dir_[-1]=="\\":
            dir_=dir_[:-1]
        try:
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        except:
            # 添加一个名为 'seting' 的配置节
            config.add_section('seting')
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        d["name"] = config.get('seting', 'name', fallback=dir_.split("\\")[-1]).strip()
        d["cb_isfanxiang"] = config.get('seting', 'cb_isfanxiang', fallback='False')
        d["led_cishu"] = config.get('seting', 'led_cishu', fallback='99')
        d["chuansong"] = config.get('seting', 'chuansong', fallback='')
        d["cbb_address"] = config.get('seting', 'cbb_address', fallback='手动录制')
        d["chuansongmoban"] = config.get('seting', 'chuansongmoban', fallback='')
        d["maodianmoban"] = config.get('seting', 'maodianmoban', fallback='')
        d["cb_is_checked"] = config.get('seting', 'cb_is_checked', fallback='True')
        f_item.bt_chuansong.setProperty("OK_chuansong", d["chuansong"] != "")
        f_item.bt_moban.setProperty("OK_chuansongmoban", d["chuansongmoban"] != "")
        f_item.bt_moban_maodian.setProperty("OK_maodianmoban", d["maodianmoban"] != "")
        f_item.bt_chuansong.setObjectName("bt_chuansong")
        f_item.bt_moban.setObjectName("bt_moban")
        f_item.bt_moban_maodian.setObjectName("bt_moban_maodian")
        f_item.led_name.setText(d["name"])
        f_item.led_cishu.setText(d["led_cishu"])
        f_item.bt_chuansong.setStyleSheet("""
                                                #bt_chuansong[OK_chuansong="true"] {
                                                color: rgb(237,182,43);  
                                                border-color: rgb(237,182,43); 
                                                }
                                             """)
        f_item.bt_moban.setStyleSheet("""
                                                #bt_moban[OK_chuansongmoban="true"] {
                                                color: rgb(237,182,43); 
                                                border-color: rgb(237,182,43); 
                                                }
                                             """)
        f_item.bt_moban_maodian.setStyleSheet("""
                                                        #bt_moban_maodian[OK_maodianmoban="true"] {
                                                        color: rgb(237,182,43); 
                                                        border-color: rgb(237,182,43); 
                                                        }
                                                     """)

        if d["cb_is_checked"] == "True":
            f_item.cb_is_checked.setChecked(True)
        else:
            f_item.cb_is_checked.setChecked(False)

        if d["cb_isfanxiang"] == "True":
            f_item.cb_isfanxiang.setChecked(True)
        else:
            f_item.cb_isfanxiang.setChecked(False)

        idex = len(self.datas)
        #f_item.led_name.editingFinished .connect(self.save)
        f_item.bt_chuansong.clicked.connect(functools.partial(self.clickd_bt_chuansong, idex))
        f_item.bt_moban.clicked.connect(functools.partial(self.clickd_bt_moban, idex))
        f_item.bt_moban_maodian.clicked.connect(functools.partial(self.clickd_bt_moban_maodian, idex))
        f_item.bt_start.clicked.connect(functools.partial(self.clickd_bt_start, idex))
        f_item.bt_del.clicked.connect(functools.partial(self.clickd_bt_del, idex))

        f_item.bt_chuansong.setVisible(False)
        f_item.bt_moban.setVisible(False)
        f_item.bt_moban_maodian.setVisible(False)
        f_item.bt_start.setVisible(False)
        f_item.bt_del.setVisible(False)
        f_item.cb_isfanxiang.setVisible(False)
        f_item.led_cishu.setVisible(False)
        f_item.label.setVisible(False)


        f_item.bt_moban.setToolTip(self.tanChu_img(dir_ + "/" +d["chuansongmoban"]))
        f_item.bt_moban_maodian.setToolTip(self.tanChu_img(dir_ + "/" +d["maodianmoban"] ))

        d["f_item"] = f_item
        self.datas.append(d)
        self.g_box.addWidget(f_item, self.row, self.column)
    def add_taskjiaoben(self, dir_, config):
        '''
        添加脚本任务
        :return:
        '''
        # 根据导入的文件
        # 获取主窗口的宽度
        width = self.centralWidget().width()
        # 计算每行可以容纳的组件数量
        num_per_row = (width ) // (self.column_step * ratio)  # 假设每个组件的宽度为200

        if num_per_row < 1:
            num_per_row = 1
        self.column += 1
        if self.column == num_per_row:
            self.column = 0
            self.row += 1
        # 加载ini配置文件
        f_item = FrameItemJiaoBen()
        f_item.setObjectName("frame_cont")
        f_item.raise_()
        f_item.setStyleSheet("""
                               #frame_cont:hover {
                                   border: 1px solid red;
                               }
                               #frame_cont {
                                    background-color: rgba(0, 0, 0, 0);
                               }
                               """)
        d = {}
        d["type"] = "3"
        dir_ = dir_.replace("/", "\\")
        if dir_[-1]=="\\":
            dir_=dir_[:-1]
        try:
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        except:
            # 添加一个名为 'seting' 的配置节
            config.add_section('seting')
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        d["name"] = config.get('seting', 'name', fallback=dir_.split("\\")[-1]).strip()
        d["cb_auto_f"] = config.get('seting', 'cb_auto_f', fallback='True')
        d["chuansong"] = config.get('seting', 'chuansong', fallback='')
        d["cbb_address"] = config.get('seting', 'cbb_address', fallback='手动录制')
        d["jiaoben"] = config.get('seting', 'jiaoben', fallback='')
        d["chuansongmoban"] = config.get('seting', 'chuansongmoban', fallback='')
        d["maodianmoban"] = config.get('seting', 'maodianmoban', fallback='')
        d["cb_is_checked"] = config.get('seting', 'cb_is_checked', fallback='True')
        f_item.bt_chuansong.setProperty("OK_chuansong", d["chuansong"] != "")
        f_item.bt_jiaoben.setProperty("OK_jiaoben", d["jiaoben"] != "")
        f_item.bt_moban.setProperty("OK_chuansongmoban", d["chuansongmoban"] != "")
        f_item.bt_moban_maodian.setProperty("OK_maodianmoban", d["maodianmoban"] != "")
        f_item.bt_chuansong.setObjectName("bt_chuansong")
        f_item.bt_moban.setObjectName("bt_moban")
        f_item.bt_moban_maodian.setObjectName("bt_moban_maodian")
        f_item.led_name.setText(d["name"])

        f_item.bt_jiaoben.setStyleSheet("""
                                                       #bt_jiaoben[OK_jiaoben="true"] {
                                                       color: rgb(237,182,43);  
                                                       border-color: rgb(237,182,43); 
                                                       }
                                                    """)

        f_item.bt_chuansong.setStyleSheet("""
                                                #bt_chuansong[OK_chuansong="true"] {
                                                color: rgb(237,182,43);  
                                                border-color: rgb(237,182,43); 
                                                }
                                             """)
        f_item.bt_moban.setStyleSheet("""
                                                #bt_moban[OK_chuansongmoban="true"] {
                                                color: rgb(237,182,43); 
                                                border-color: rgb(237,182,43); 
                                                }
                                             """)
        f_item.bt_moban_maodian.setStyleSheet("""
                                                        #bt_moban_maodian[OK_maodianmoban="true"] {
                                                        color: rgb(237,182,43); 
                                                        border-color: rgb(237,182,43); 
                                                        }
                                                     """)

        if d["cb_is_checked"] == "True":
            f_item.cb_is_checked.setChecked(True)
        else:
            f_item.cb_is_checked.setChecked(False)
        if d["cb_auto_f"] == "True":
            f_item.cb_auto_f.setChecked(True)
        else:
            f_item.cb_auto_f.setChecked(False)



        idex = len(self.datas)

        f_item.bt_jiaoben.clicked.connect(functools.partial(self.clickd_bt_jiaoben, idex))
        f_item.bt_chuansong.clicked.connect(functools.partial(self.clickd_bt_chuansong, idex))
        f_item.bt_moban.clicked.connect(functools.partial(self.clickd_bt_moban, idex))
        f_item.bt_moban_maodian.clicked.connect(functools.partial(self.clickd_bt_moban_maodian, idex))
        f_item.bt_start.clicked.connect(functools.partial(self.clickd_bt_start, idex))
        f_item.bt_del.clicked.connect(functools.partial(self.clickd_bt_del, idex))
        d["f_item"] = f_item

        f_item.bt_start.setVisible(False)
        f_item.bt_jiaoben.setVisible(False)
        f_item.bt_chuansong.setVisible(False)
        f_item.bt_moban_maodian.setVisible(False)
        f_item.bt_moban.setVisible(False)
        f_item.bt_start.setVisible(False)
        f_item.bt_del.setVisible(False)
        f_item.cb_auto_f.setVisible(False)

        f_item.bt_moban.setToolTip(self.tanChu_img(dir_ + "/" + d["chuansongmoban"]))
        f_item.bt_moban_maodian.setToolTip(self.tanChu_img(dir_ + "/" + d["maodianmoban"]))

        self.datas.append(d)
        self.g_box.addWidget(f_item, self.row, self.column)
    def add_xuanjue(self, dir_, config):
        '''
        添加脚本任务
        :return:
        '''
        # 根据导入的文件
        # 获取主窗口的宽度
        width = self.centralWidget().width()
        # 计算每行可以容纳的组件数量
        num_per_row = (width) // (self.column_step * ratio)  # 假设每个组件的宽度为200
        if num_per_row < 1:
            num_per_row = 1
        if num_per_row < 1:
            num_per_row = 1
        self.column += 1
        if self.column == num_per_row:
            self.column = 0
            self.row += 1
        # 加载ini配置文件
        f_item = FrameItemXuanJue()
        f_item.setObjectName("frame_cont")
        f_item.raise_()
        f_item.setStyleSheet("""
                                #frame_cont:hover {
                                    border: 1px solid red;
                                }
                                #frame_cont {
                                     background-color: rgba(0, 0, 0, 0);
                                }
                                """)
        d = {}
        d["type"] = "4"
        dir_ = dir_.replace("/", "\\")
        if dir_[-1] == "\\":
            dir_ = dir_[:-1]
        try:
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        except:
            # 添加一个名为 'seting' 的配置节
            config.add_section('seting')
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        d["name"] = config.get('seting', 'name', fallback=dir_.split("\\")[-1]).strip()
        d["chuansong"] =''
        d["cb_is_checked"] = config.get('seting', 'cb_is_checked', fallback='True')
        d["cbb_1"] = config.get('seting', 'cbb_1', fallback='早柚')
        d["cbb_2"] = config.get('seting', 'cbb_2', fallback='班尼特')
        d["cbb_3"] = config.get('seting', 'cbb_3', fallback='钟离')
        d["cbb_4"] = config.get('seting', 'cbb_4', fallback='香菱')
        d["led_main"] = config.get('seting', 'led_main', fallback='4')

        if d["cb_is_checked"] == "True":
            f_item.cb_is_checked.setChecked(True)
        else:
            f_item.cb_is_checked.setChecked(False)


        idex = len(self.datas)

        f_item.bt_start.clicked.connect(functools.partial(self.clickd_bt_start, idex))
        f_item.bt_del.clicked.connect(functools.partial(self.clickd_bt_del, idex))
        f_item.led_main.setText(d["led_main"])
        f_item.led_name.setText(d["name"])

        self.set_cbb_items(f_item.cbb_1)
        self.set_cbb_items(f_item.cbb_2)
        self.set_cbb_items(f_item.cbb_3)
        self.set_cbb_items(f_item.cbb_4)
        self.set_cbb_item(f_item.cbb_1, d["cbb_1"])
        self.set_cbb_item(f_item.cbb_2, d["cbb_2"])
        self.set_cbb_item(f_item.cbb_3, d["cbb_3"])
        self.set_cbb_item(f_item.cbb_4, d["cbb_4"])


        f_item.cbb_1.setVisible(False)
        f_item.cbb_2.setVisible(False)
        f_item.cbb_3.setVisible(False)
        f_item.cbb_4.setVisible(False)
        f_item.lb_zhanchang.setVisible(False)
        f_item.led_main.setVisible(False)
        f_item.bt_del.setVisible(False)
        f_item.bt_start.setVisible(False)
        d["f_item"] = f_item

        self.datas.append(d)
        self.g_box.addWidget(f_item, self.row, self.column)
    def add_xuanlianzhao(self, dir_, config):
        '''
        添加脚本任务
        :return:
        '''
        # 根据导入的文件
        # 获取主窗口的宽度
        width = self.centralWidget().width()
        # 计算每行可以容纳的组件数量
        num_per_row = (width) // (self.column_step * ratio)  # 假设每个组件的宽度为200
        if num_per_row < 1:
            num_per_row = 1
        if num_per_row < 1:
            num_per_row = 1
        self.column += 1
        if self.column == num_per_row:
            self.column = 0
            self.row += 1
        # 加载ini配置文件
        f_item = FrameItemLianZhao()
        f_item.setObjectName("frame_cont")
        f_item.raise_()
        f_item.setStyleSheet("""
                                #frame_cont:hover {
                                    border: 1px solid red;
                                }
                                #frame_cont {
                                     background-color: rgba(0, 0, 0, 0);
                                }
                                """)
        d = {}
        d["type"] = "5"
        dir_ = dir_.replace("/", "\\")
        if dir_[-1] == "\\":
            dir_ = dir_[:-1]
        try:
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        except:
            # 添加一个名为 'seting' 的配置节
            config.add_section('seting')
            config.set('seting', 'name', dir_.split("\\")[-1].strip())
        d["name"] = config.get('seting', 'name', fallback=dir_.split("\\")[-1]).strip()
        d["chuansong"] = ''
        d["cb_is_checked"] = config.get('seting', 'cb_is_checked', fallback='True')
        d["cbb_lianzhao"] = config.get('seting', 'cbb_lianzhao', fallback='')
        if d["cb_is_checked"] == "True":
            f_item.cb_is_checked.setChecked(True)
        else:
            f_item.cb_is_checked.setChecked(False)

        idex = len(self.datas)

        f_item.bt_start.clicked.connect(functools.partial(self.clickd_bt_start, idex))
        f_item.bt_del.clicked.connect(functools.partial(self.clickd_bt_del, idex))
        folder_path = state.PATH_JIAOBEN
        f_item.led_name.setText(d["name"])
        # 遍历文件夹及其子文件夹中的所有文件
        for root, dirs, files in os.walk(folder_path):
            for file in files:
                # 检查文件扩展名是否为.png
                if file.endswith('.txt'):
                    # 打印PNG文件的完整路径
                    file_name = os.path.splitext(file)[0]
                    f_item.cbb_lianzhao.addItem(file_name)

        f_item.cbb_lianzhao.setCurrentText(d["cbb_lianzhao"] )

        f_item.bt_start.setVisible(False)
        f_item.cbb_lianzhao.setVisible(False)
        f_item.bt_del.setVisible(False)
        d["f_item"] = f_item

        self.datas.append(d)
        self.g_box.addWidget(f_item, self.row, self.column)
    def returnPressed_name(self, idex):
        try:
            if self.datas[idex]["f_item"].led_name.text() == self.datas[idex]["name"]:
                return
            dir_ = os.path.join(state.PATH_TASK, self.datas[idex]["f_item"].led_name.text()).strip()
            if self.datas[idex]["name"] != "":
                dir_old = os.path.join(state.PATH_TASK, self.datas[idex]["name"])
                if not os.path.exists(dir_old):
                    dir_old = None
            else:
                dir_old = None

            if not os.path.exists(dir_):
                if dir_old != None:
                    try:
                        os.rename(dir_old, dir_)
                        self.datas[idex]["name"] = self.datas[idex]["f_item"].led_name.text()
                        logger.info(f'重命名成功{self.datas[idex]["name"]}')


                    except:
                        QMessageBox.information(self, "提示", "重命名失败!请检查是不是有特殊符号或者文件夹已经存在了")
                        self.datas[idex]["f_item"].led_name.setText(self.datas[idex]["name"])
                else:
                    try:
                        os.makedirs(dir_)
                        self.datas[idex]["name"] = self.datas[idex]["f_item"].led_name.text()
                        logger.info(f'重命名成功{self.datas[idex]["name"]}')


                    except:
                        QMessageBox.information(self, "提示", "重命名失败!请检查是不是有特殊符号或者文件夹已经存在了")
                        self.datas[idex]["f_item"].led_name.setText(self.datas[idex]["name"])
        except Exception as err:

            QMessageBox.information(self, "提示", "重命名失败!"+str(err))
            self.datas[idex]["f_item"].led_name.setText(self.datas[idex]["name"])
    def clickd_bt_map(self, idex):
        temp_path, ok = QFileDialog.getOpenFileName(self, "选择地图", "", "图片文件 (*.png)")
        if ok:
            dir_ = os.path.join(state.PATH_TASK, self.datas[idex]["name"])

            if not os.path.exists(dir_):
                os.makedirs(dir_)

                # 并且将jiaoben.ini文件也填入数据然后生成
            # 将图片复制到指定目录
            path = dir_ + "/地图.png"
            shutil.copy(temp_path, path)
            self.datas[idex]["map"] = "地图.png"
            self.datas[idex]["f_item"].bt_map.setProperty("OK_map", True)
            self.datas[idex]["f_item"].bt_map.setStyleSheet("""
                                    #bt_map[OK_map="true"] {
                                    color: rgb(237,182,43);  /* 边框颜色为灰色 */
                                    border-color: rgb(237,182,43);  /* 边框颜色为灰色 */
                                    }
                                 """)
            logger.info(f"导入地图成功:{path}" )

            self.save_ini(dir_, self.datas[idex])
    def clickd_bt_jiaoben(self, idex):

        #弹出一个选择弹窗 选项为  录制还是文件中选择
        msgBox = QMessageBox(self)
        msgBox.setWindowTitle("请选择一个配置方式")  # 设置消息框标题
        msgBox.setIcon(QMessageBox.Information)
        msgBox.setText("技巧:尽量少用鼠标转动镜头\n可以用键盘方向键配合鼠标中键进行转向")
        msgBox.addButton("录制", QMessageBox.AcceptRole)
        msgBox.addButton("回放", QMessageBox.ApplyRole)
        msgBox.addButton("文件中选择", QMessageBox.RejectRole)
        result = msgBox.exec_()
        if result == QMessageBox.AcceptRole:
            logger.info("可以开始录制了,按F8开始/停止")
            self.sg.mysig_tishi.emit("可以开始录制了,按F8开始/停止")
            state.状态_是否禁止录制 = False
            state.状态_是否开始录制 = False
            state.录制_当前任务索引=idex
            state.录制_脚本文本=""
            state.录制_当前脚本名=self.datas[idex]["name"]
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否禁止录制#@@#假"), auto.loop)
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否开始录制#@@#假"), auto.loop)
            asyncio.run_coroutine_threadsafe(send_to_client(-1, f"全局脚本名#@@#{state.录制_当前脚本名}"), auto.loop)
            hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
            asyncio.run_coroutine_threadsafe(send_to_client(-1, f"全局hwnd#@@#{hwnd}"), auto.loop)
            self.timer_luzhi.start(200)
        elif result == QMessageBox.RejectRole:
            if state.状态_是否回放中==True:
                return
            dir_ = os.path.join(state.PATH_TASK, self.datas[idex]["name"])
            if not os.path.exists(dir_):
                os.makedirs(dir_)
            state.状态_是否回放中=True
            state.状态_循环开关 = True
            jiaoben = os.path.abspath(os.path.join(dir_, self.datas[idex]["jiaoben"]))
            message = f"解析脚本#@@#{jiaoben}"
            asyncio.run_coroutine_threadsafe(send_to_client(-1, message), auto.loop)
            hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
            set_window_activate(hwnd)
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "脚本执行#@@#1"), auto.loop)
            self.timer_huifang.start(200)

        elif result == QMessageBox.Warning:
            # 弹出一个有分组框的窗口
            temp_path, ok = QFileDialog.getOpenFileName(self, "脚本", "", "脚本文件 (*.txt)")
            if ok:
                dir_ = os.path.join(state.PATH_TASK, self.datas[idex]["name"])
                if not os.path.exists(dir_):
                    os.makedirs(dir_)
                # 并且将jiaoben.ini文件也填入数据然后生成
                path = dir_ + "/脚本.txt"
                shutil.copy(temp_path, path)
                self.datas[idex]["jiaoben"] = "脚本.txt"
                self.datas[idex]["f_item"].bt_jiaoben.setProperty("OK_jiaoben", True)
                logger.info(f"导入脚本成功:{path}")
                self.sg.mysig_tishi.emit(f"导入脚本成功:{path}")
                self.datas[idex]["f_item"].bt_jiaoben.setStyleSheet("""
                                                                        #bt_jiaoben[OK_jiaoben="true"] {
                                                                        color: rgb(237,182,43);  
                                                                        border-color: rgb(237,182,43); 
                                                                        }
                                                                     """)
                self.save_ini(dir_, self.datas[idex])
    def clickd_bt_chuansong(self, idex):

        dl_chuansong=DialogChuansong(self,idex)
        dl_chuansong.cbb_address.setCurrentText(self.datas[idex]['cbb_address'])
        dl_chuansong.exec_()
    def clickd_bt_moban(self, idex):
        temp_path, ok = QFileDialog.getOpenFileName(self, "传送模板图片", "", "图片文件 (*.png)")
        if ok:
            dir_ = os.path.join(state.PATH_TASK, self.datas[idex]["name"])
            if not os.path.exists(dir_):
                os.makedirs(dir_)

                # 并且将jiaoben.ini文件也填入数据然后生成
            # 将图片复制到指定目录
            path = dir_ + "/传送模板.png"
            shutil.copy(temp_path, path)
            self.datas[idex]["chuansongmoban"] = "传送模板.png"
            self.datas[idex]["f_item"].bt_moban.setProperty("OK_chuansongmoban", True)
            self.datas[idex]["f_item"].bt_moban.setStyleSheet("""
                                                            #bt_moban[OK_chuansongmoban="true"] {
                                                            color: rgb(237,182,43); 
                                                            border-color: rgb(237,182,43); 
                                                            }
                                                         """)
            self.save_ini(dir_, self.datas[idex])
            self.sg.mysig_tishi.emit(f"导入传送模板成功:{path}")
            logger.info(f"导入传送模板成功:{path}" )
    def clickd_bt_moban_maodian(self, idex):
        temp_path, ok = QFileDialog.getOpenFileName(self, "锚点模板图片", "", "图片文件 (*.png)")
        if ok:
            dir_ = os.path.join(state.PATH_TASK, self.datas[idex]["name"])
            if not os.path.exists(dir_):
                os.makedirs(dir_)
                # 并且将jiaoben.ini文件也填入数据然后生成
            # 将图片复制到指定目录
            path = dir_ + "/锚点模板.png"
            shutil.copy(temp_path, path)
            self.datas[idex]["maodianmoban"] = "锚点模板.png"
            self.datas[idex]["f_item"].bt_moban_maodian.setProperty("OK_maodianmoban", True)
            self.datas[idex]["f_item"].bt_moban_maodian.setStyleSheet("""
                                                            #bt_moban_maodian[OK_maodianmoban="true"] {
                                                            color: rgb(237,182,43); 
                                                            border-color: rgb(237,182,43); 
                                                            }
                                                         """)
            self.save_ini(dir_, self.datas[idex])
            logger.info(f"导入锚点模板成功:{path}" )
            self.sg.mysig_tishi.emit(f"导入锚点模板成功:{path}")
    def clickd_bt_start(self, idex):

        global atys
        hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
        if hwnd == 0:
            logger.info("错误:请先开游戏!")
            self.sg.mysig_tishi.emit("错误:请先开游戏!")
            return

        left, top, right, bottom = win32gui.GetClientRect(hwnd)
        width = right - left
        height = bottom - top
        if width != 1920 or height != 1080:
            logger.info("错误:游戏分辨率不对!请确保游戏分辨率是1920x1080  建议重新设置分辨率")
            self.sg.mysig_tishi.emit("错误:游戏分辨率不对!请确保游戏分辨率是1920x1080  建议重新设置分辨率")
            return
        self.save()

        def run(idex):

            ret = False
            self.sg.mysig_mouse_through.emit(True)
            state.计次_传送重试次数 = 0
            state.状态_全局暂停 = False
            self.datas[idex]['f_item'].cb_is_checked.setChecked(True)
            for rt in range(self.run_times):
                if self.action_runstartwith.isChecked() :
                    logger.info(f"任务包:{state.PATH_TASK} {rt+1}/{self.run_times}")



                while idex < len(self.datas):
                    if state.状态_检测中:
                        time.sleep(1)
                        continue
                    if self.datas[idex]['f_item'].cb_is_checked.isChecked():
                        ret = self.run(idex)

                        if state.状态_循环开关 == False:
                            break
                        if ret == False:
                            if state.状态_需重新传送 == True:
                                state.计次_传送重试次数 += 1
                                if state.计次_传送重试次数 >= 5:
                                    state.计次_传送重试次数 = 0
                                    logger.info("传送重试次数过多,放弃该任务!")
                                else:
                                    logger.info(f"传送重试{state.计次_传送重试次数}")
                                    time.sleep(2)
                                    continue
                            else:
                                break
                    if self.action_runstartwith.isChecked()==False:
                        break
                    state.计次_传送重试次数 = 0
                    idex += 1
                if self.action_runstartwith.isChecked() == False:
                    break
                if state.状态_循环开关 == False:
                    break
                idex=0

            if state.状态_循环开关 != False:
                if self.action_runstartwith.isChecked():
                    #切下一个任务包 继续
                    next_tas=self.get_next_task()
                    if state.ON_NEXTPACK==1 and next_tas!=None:
                        logger.info("切下一个任务包!")
                        state.PATH_TASK=next_tas
                        self.sg.mysig_mouse_through.emit(False)
                        self.sg.mysig_next_pack.emit()
                        return
            if ret == True and state.ON_JIXING == 1:
                aty.run_jixing()
            if ret == True and state.ON_SHUTDOWN == 1:
                self.sg.mysig_shutdown.emit()
            self.sg.mysig_mouse_through.emit(False)
            state.状态_循环开关 = False

        t = threading.Thread(target=run, args=(idex,))
        if state.python_var>9:
            t.daemon=True
        else:
            t.setDaemon(True)
        t.start()
    def run(self, idex):
        global  aty

        if not state.状态_YOLOV:
            logger.info("还在启动相关服务中..请稍等")
            return False
        dir_ = os.path.join(state.PATH_TASK, self.datas[idex]["name"])
        txt = "执行:"+ self.datas[idex]["name"] + "任务"
        logger.info(txt)
        self.sg.mysig_tishi.emit(txt)
        self.sg.mysig_dingwei.emit(idex)
        if not os.path.exists(dir_):
            logger.info("没有找到任务文件夹,请先设定任务")
            self.sg.mysig_tishi.emit("没有找到任务文件夹,请先设定任务")
            return False
        if state.状态_已经有寻路了:
            logger.info("请勿重复启动!已经有任务在运行了")
            self.sg.mysig_tishi.emit("请勿重复启动!已经有任务在运行了")
            # 弹出提示,不要重复开
            return False
        state.计数_没找到任何目标 = 0
        state.计数_没找到怪物 = 0
        state.状态_在爬墙 = False
        state.状态_需重新传送 = False
        state.状态_循环开关 = True
        state.状态_传送中 = True
        hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
        message = f"全局hwnd#@@#{hwnd}"
        asyncio.run_coroutine_threadsafe(send_to_client(-1, message), auto.loop)
        if self.datas[idex]["chuansong"]!="":#如果没有录传送,那就不传送了

            if ctypes.windll.user32.GetForegroundWindow() != hwnd:
                # 激活hwnd
                hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
                set_window_activate(hwnd)
                time.sleep(0.1)

            # 设定截图区域的左上角坐标 (x, y) 和右下角坐标 (x, y)
            left, top, right, bottom = 1, 979, 120, 1074  # 替换成你实际的区域坐标
            rect = win32gui.GetWindowRect(hwnd)
            w_p, h_p = (rect[2] - rect[0]) - 1920, (rect[3] - rect[1]) - 1080
            p_left = rect[0] + w_p
            p_top = rect[1] + h_p

            dituchilun_img = cv2.imdecode(np.fromfile(file="./datas/地图齿轮.png", dtype=np.uint8),
                                          cv2.IMREAD_UNCHANGED)
            big_img = screenshot(hwnd, left, top, right, bottom, None)
            res = template_matching(big_img, dituchilun_img, mask=None)
            if res==[]:

                kkk = aty.处理异常情况(hwnd,0,0,1920,1080,p_left,p_top)
                if kkk == 0:
                    logger.info("在意外界面 超时!")
                    time.sleep(3)
                    state.状态_需重新传送 = False
                    state.状态_已经有寻路了 = False
                    return False
                elif kkk == -1:
                    logger.info("全军覆没了!")
                    time.sleep(3)
                    state.状态_需重新传送 = True
                    state.状态_已经有寻路了 = False
                    return False
                if self.datas[idex]['cbb_address'] != "手动录制":
                    pyautogui.keyDown("M")
                    time.sleep(0.2)
                    pyautogui.keyUp("M")
                    time.sleep(2)
                    logger.info("按下M 打开地图")
            if self.datas[idex]['cbb_address'] != "手动录制":
                logger.info("正在自动选择区域...")
                if not self.autoSelectAddress(self.datas[idex]['cbb_address'],isrun=True):
                    logger.info("选择区域失败在意外界面!")

                    state.状态_需重新传送 = False
                    state.状态_已经有寻路了 = False
                    return False



            # 运行传送脚本动作
            jiaoben = os.path.abspath(os.path.join(dir_, self.datas[idex]["chuansong"]))
            ret = auto.atys.run_chuansongjiaoben(jiaoben,self.datas[idex]['cbb_address'])

            if ret == False:
                logger.info("执行传送脚本!失败")
                return False

            # 传送模板 点击
            chuansong_path = os.path.join(dir_, self.datas[idex]['chuansongmoban'])
            maodian_path = os.path.join(dir_, self.datas[idex]['maodianmoban'])
            ret = ysam.run_chuansong(chuansong_path, maodian_path)
            if ret == False:
                logger.info("识别传送点击!失败")
                return False
        else:
            logger.info("没发现传送脚本,不传送")
        state.状态_传送中 = False
        state.计数_没找到任何目标 = 0
        state.计数_没找到怪物 = 0
        state.计数_连招次数 = 0

        state.状态_已经有寻路了 = True
        if self.datas[idex]["type"] == "2":
            return aty.run_fuben(int(self.datas[idex]['f_item'].led_cishu.text()),
                                 self.datas[idex]['f_item'].cb_isfanxiang.isChecked())

        elif self.datas[idex]["type"] == "3":
            return aty.run_jiaoben(os.path.abspath(os.path.join(dir_, self.datas[idex]["jiaoben"])),
                                 self.datas[idex]['f_item'].cb_auto_f.isChecked())
        elif self.datas[idex]["type"] == "4":
            names=[
                f"{state.PATH_JUESE}/{self.datas[idex]['f_item'].cbb_1.itemData(self.datas[idex]['f_item'].cbb_1.currentIndex())}.png",
                f"{state.PATH_JUESE}/{self.datas[idex]['f_item'].cbb_2.itemData(self.datas[idex]['f_item'].cbb_2.currentIndex())}.png",
                f"{state.PATH_JUESE}/{self.datas[idex]['f_item'].cbb_3.itemData(self.datas[idex]['f_item'].cbb_3.currentIndex())}.png",
                f"{state.PATH_JUESE}/{self.datas[idex]['f_item'].cbb_4.itemData(self.datas[idex]['f_item'].cbb_4.currentIndex())}.png"
            ]
            return aty.run_huanjue(names,self.datas[idex]['f_item'].led_main.text())
        elif self.datas[idex]["type"] == "5":
            lianzhao_path=self.datas[idex]['f_item'].cbb_lianzhao.currentText()+".txt"
            state.状态_需重新传送 = False
            state.状态_已经有寻路了 = False
            if lianzhao_path!="":
                state.LIANZHAO=lianzhao_path
                logger.info(f"切换连招脚本: {lianzhao_path}  成功")
                return True
            else:
                return False

        else:
            t2 = threading.Thread(target=aty.run_fight,args=(self.datas[idex]['f_item'].cb_wakuang.isChecked(),self.datas[idex]['f_item'].cb_caiji.isChecked(),self.datas[idex]['f_item'].cb_daguai.isChecked()))
            if state.python_var > 9:
                t2.daemon = True
            else:
                t2.setDaemon(True)

            t2.start()
            try:
                image_path = os.path.join(dir_, self.datas[idex]['map'])
                image_path_barrier = os.path.join(dir_, self.datas[idex]['lujing'])
                return ysam.run_playback(image_path_barrier, image_path,self.datas[idex]['f_item'].cb_wakuang.isChecked(),self.datas[idex]['f_item'].cb_caiji.isChecked())
            except:
                state.状态_需重新传送 = False
                state.状态_已经有寻路了 = False
                return False
    def clickd_bt_del(self, idex):

        dir_ = os.path.join(state.PATH_TASK, self.datas[idex]["name"])
        try:
            # 删除整个文件夹
            shutil.rmtree(dir_)
            logger.info(f"文件夹 {dir_} 已被删除")
            self.update_tasks()

        except Exception as e:
            self.update_tasks()
            logger.info(f"删除文件夹时出现错误:{e}")
    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 closeEvent(self, event):
        self.save()
        app.quit()
    def clickd_bt_lujing(self, idex):
        dir_ = os.path.join(state.PATH_TASK, self.datas[idex]["name"])
        if not os.path.exists(dir_):
            state.状态_全局暂停 = True
            QMessageBox.information(self, "提示", "没有找到任务文件夹,请先设定任务")
            return False
        if state.状态_已经有寻路了:
            # 弹出提示,不要重复开
            QMessageBox.information(self, "提示", "已经有在运行的AI了,请先关闭!")
            return False
        state.状态_全局暂停 = True
        state.状态_循环开关 = True
        QMessageBox.information(self, "开始录制了", "请控制角色去你的目的地,它会自己记录路线")
        self.datas[idex]['lujing'] = "路径.png"
        image_path = os.path.join(dir_, self.datas[idex]['map'])
        image_path_lujing = os.path.join(dir_, self.datas[idex]['lujing'])
        self.datas[idex]["f_item"].bt_lujing.setProperty("OK_lujing", True)
        self.datas[idex]["f_item"].bt_lujing.setStyleSheet("""
                                                    #bt_lujing[OK_lujing="true"] {
                                                    color: rgb(237,182,43); 
                                                    border-color: rgb(237,182,43); 
                                                    }
                                                 """)
        t = threading.Thread(target=ysam.run_rec, args=(image_path, image_path_lujing))
        if state.python_var>9:
            t.daemon=True
        else:
            t.setDaemon(True)
        t.start()
        self.save_ini(dir_, self.datas[idex])

        return True
    def save_ini(self, dir_, d):
        try:
            # 创建 ConfigParser 对象
            config = configparser.ConfigParser()
            # 添加节和键-值对
            if d["type"] == "2":
                config['seting'] = {
                    'type': d["type"],
                    'name': d["name"],
                    'cb_isfanxiang': d["f_item"].cb_isfanxiang.isChecked(),
                    'led_cishu': d["f_item"].led_cishu.text(),
                    'chuansong': d["chuansong"],
                    'cbb_address': d['cbb_address'],
                    'chuansongmoban': d["chuansongmoban"],
                    'maodianmoban': d["maodianmoban"],
                    'cb_is_checked': d["f_item"].cb_is_checked.isChecked()
                }
            elif d["type"] == "3":
                config['seting'] = {
                    'type': d["type"],
                    'name': d["name"],
                    'cb_auto_f': d["f_item"].cb_auto_f.isChecked(),
                    'jiaoben': d["jiaoben"],
                    'chuansong': d["chuansong"],
                    'cbb_address': d['cbb_address'],
                    'chuansongmoban': d["chuansongmoban"],
                    'maodianmoban': d["maodianmoban"],
                    'cb_is_checked': d["f_item"].cb_is_checked.isChecked()
                }
            elif d["type"] == "4":
                config['seting'] = {
                    'type': d["type"],
                    'name': d["name"],
                    'chuansong': d["chuansong"],
                    'cb_is_checked': d["f_item"].cb_is_checked.isChecked(),
                    'cbb_1':d["f_item"].cbb_1.itemData(d["f_item"].cbb_1.currentIndex()),
                    'cbb_2': d["f_item"].cbb_2.itemData(d["f_item"].cbb_2.currentIndex()),
                    'cbb_3': d["f_item"].cbb_3.itemData(d["f_item"].cbb_3.currentIndex()),
                    'cbb_4': d["f_item"].cbb_4.itemData(d["f_item"].cbb_4.currentIndex()),
                    "led_main":d["f_item"].led_main.text()

                }
            elif d["type"] == "5":
                config['seting'] = {
                    'type': d["type"],
                    'name': d["name"],
                    'chuansong': d["chuansong"],
                    'cb_is_checked': d["f_item"].cb_is_checked.isChecked(),
                    'cbb_lianzhao':d["f_item"].cbb_lianzhao.currentText(),
                }

            else:
                config['seting'] = {
                    'type': d["type"],
                    'name': d["name"],
                    'map': d["map"],
                    'lujing': d["lujing"],
                    'chuansong': d["chuansong"],
                    'cbb_address': d['cbb_address'],
                    'chuansongmoban': d["chuansongmoban"],
                    'maodianmoban': d["maodianmoban"],
                    'cb_is_checked': d["f_item"].cb_is_checked.isChecked(),
                    'cb_wakuang': d["f_item"].cb_wakuang.isChecked(),
                    'cb_caiji': d["f_item"].cb_caiji.isChecked(),
                    'cb_daguai': d["f_item"].cb_daguai.isChecked()

                }
            # 写入配置到 INI 文件
            with open(os.path.join(dir_, "jiaoben.ini"), 'w') as configfile:
                config.write(configfile)
        except:
            pass
    def hotkey_importtask(self):
        # 弹出通用对话框选择文件夹
        source_folder = QFileDialog.getExistingDirectory(self, "选择文件夹")
        if source_folder == "":
            return

        destination_folder = os.path.join(state.PATH_TASK, source_folder.split('/')[-1])
        if not os.path.exists(destination_folder):
            os.makedirs(destination_folder)
        else:
            QMessageBox.information(self, "提示", "已经有这个名字的任务了,请重命名后再试")
            return

        logger.info("导入任务 "+destination_folder)
        # 将整个文件夹的内容全部复制到test文件夹
        # 获取源文件夹中所有项的列表
        items = os.listdir(source_folder)

        # 循环处理列表中的每个项
        for item in items:
            # 构建源文件/文件夹的完整路径
            source = os.path.join(source_folder, item)
            # 构建目标文件/文件夹的完整路径
            destination = os.path.join(destination_folder, item)
            # 如果该项为文件,则使用shutil.copy()函数复制文件
            if os.path.isfile(source):
                shutil.copy(source, destination)
            # 如果该项为文件夹,则递归调用该函数复制文件夹
            elif os.path.isdir(source):
                shutil.copytree(source, destination)

        self.update_tasks()

    #以复制
    def hotkey_addtask(self):
        try:
            dir_ = os.path.join(state.PATH_TASK, "任务" + str(int(time.time())) + str(random.randint(10, 100)))
            if not os.path.exists(dir_):
                os.makedirs(dir_)
                # 创建 ConfigParser 对象
                config = configparser.ConfigParser()
                # 加载 INI 文件
                config.read(os.path.join(dir_, "jiaoben.ini"))
                config.read(os.path.join(dir_, "jiaoben.ini"))
                self.add_task(dir_, config)
                self.save_ini(dir_, self.datas[-1])
        except:
            pass
    def hotkey_addtaskjiaoben(self):
        dir_ = os.path.join(state.PATH_TASK, "任务" + str(int(time.time())) + str(random.randint(10, 100)))
        if not os.path.exists(dir_):
            os.makedirs(dir_)
            # 创建 ConfigParser 对象
            config = configparser.ConfigParser()
            # 加载 INI 文件
            config.read(os.path.join(dir_, "jiaoben.ini"))
            self.add_taskjiaoben(dir_, config)
            self.save_ini(dir_, self.datas[-1])
    def hotkey_qiejue(self):
        dir_ = os.path.join(state.PATH_TASK, "切换角色" + str(int(time.time())) + str(random.randint(10, 100)))
        if not os.path.exists(dir_):
            os.makedirs(dir_)
            # 创建 ConfigParser 对象
            config = configparser.ConfigParser()
            # 加载 INI 文件
            config.read(os.path.join(dir_, "jiaoben.ini"))
            self.add_xuanjue(dir_, config)
            self.save_ini(dir_, self.datas[-1])
    def hotkey_qiehuanlianzhao(self):
        dir_ = os.path.join(state.PATH_TASK, "切换连招" + str(int(time.time())) + str(random.randint(10, 100)))
        if not os.path.exists(dir_):
            os.makedirs(dir_)
            # 创建 ConfigParser 对象
            config = configparser.ConfigParser()
            # 加载 INI 文件
            config.read(os.path.join(dir_, "jiaoben.ini"))
            self.add_xuanlianzhao(dir_, config)
            self.save_ini(dir_, self.datas[-1])
    def hotkey_addtaskfuben(self):
        dir_ = os.path.join(state.PATH_TASK, "任务" + str(int(time.time())) + str(random.randint(10, 100)))
        if not os.path.exists(dir_):
            os.makedirs(dir_)
            # 创建 ConfigParser 对象
            config = configparser.ConfigParser()
            # 加载 INI 文件
            config.read(os.path.join(dir_, "jiaoben.ini"))
            self.add_taskfuben(dir_, config)
            self.save_ini(dir_, self.datas[-1])
    def hotkey_opentaskdir(self):
        os.startfile(os.path.abspath(state.PATH_TASK))  # 使用startfile方法打开文件夹
    def hotkey_selecttaskdir(self):
        # 弹出通用对话框选择文件夹
        source_folder = QFileDialog.getExistingDirectory(self, "选择任务文件夹", state.PATH_TASK)
        if source_folder == "":
            return
        state.PATH_TASK = source_folder
        self.add_tool_item(state.PATH_TASK)
        state.PACKS_TASK+="#@@#"+state.PATH_TASK
        self.save_ini_seting()
        self.update_tasks()
        logger.info(f"成功设置{state.PATH_TASK}为当前任务文件夹")
    def hotkey_setlianzhao(self):
        # 弹出一个有分组框的窗口
        temp_path, ok = QFileDialog.getOpenFileName(self, "连招脚本", state.PATH_JIAOBEN, "脚本文件 (*.txt)")
        if ok:
            _, state.LIANZHAO = os.path.split(temp_path)
            dir_ = os.path.join(state.PATH_JIAOBEN, state.LIANZHAO)
            try:
                shutil.copy(temp_path, dir_)
            except:
                pass
            logger.info("选择连招脚本成功!")
            self.save_ini_seting()
    def hotkey_addlianzhao(self):


        # 弹出一个选择弹窗 选项为  录制还是文件中选择
        msgBox = QMessageBox(self)
        msgBox.setWindowTitle("配置连招")  # 设置消息框标题
        msgBox.setIcon(QMessageBox.Information)

        msgBox.setText("当前连招:" + state.LIANZHAO+"\n请选择一个配置方式:" )
        msgBox.addButton("录制", QMessageBox.AcceptRole)
        msgBox.addButton("回放", QMessageBox.ApplyRole)
        msgBox.addButton("文件中选择", QMessageBox.RejectRole)
        result = msgBox.exec_()
        if result == QMessageBox.AcceptRole:
            try:
                text, ok = QInputDialog.getText(self, '提示', '请输入脚本名:',text=state.LIANZHAO)
                if not ok:
                    return
                if text=="":
                    return
                elif text[-4:]!=".txt":
                    state.LIANZHAO=text+".txt"
                else:
                    state.LIANZHAO = text
                logger.info("可以开始录制了,按F8开始/停止")
                self.sg.mysig_tishi.emit("可以开始录制了,按F8开始/停止")
                state.状态_是否禁止录制 = False
                state.状态_是否开始录制 = False

                state.录制_脚本文本 = ""
                asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否禁止录制#@@#假"), auto.loop)
                asyncio.run_coroutine_threadsafe(send_to_client(-1, "是否开始录制#@@#假"), auto.loop)
                asyncio.run_coroutine_threadsafe(send_to_client(-1, f"全局脚本名#@@#{state.LIANZHAO.replace('.txt','')}"), auto.loop)
                hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
                asyncio.run_coroutine_threadsafe(send_to_client(-1, f"全局hwnd#@@#{hwnd}"), auto.loop)
                self.timer_luzhi_lianzhao.start(200)
            except:
                pass
        elif result == QMessageBox.RejectRole:
            if state.状态_是否回放中 == True:
                return
            if not os.path.exists(state.PATH_JIAOBEN):
                os.makedirs(state.PATH_JIAOBEN)
            state.状态_是否回放中 = True
            state.状态_循环开关 = True
            jiaoben = os.path.abspath(os.path.join(state.PATH_JIAOBEN,state.LIANZHAO ))
            message = f"解析脚本#@@#{jiaoben}"
            asyncio.run_coroutine_threadsafe(send_to_client(-1, message), auto.loop)
            hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
            set_window_activate(hwnd)
            asyncio.run_coroutine_threadsafe(send_to_client(-1, "脚本执行#@@#1"), auto.loop)
            self.timer_huifang.start(200)
        elif result == QMessageBox.Warning:
            self.hotkey_setlianzhao()



    def save_ini_seting(self):
        try:
            # 创建 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()),
                'ON_SHUTDOWN': str(state.ON_SHUTDOWN),
                'ON_JIXING': str(state.ON_JIXING),
                'ON_NEXTPACK':str(state.ON_NEXTPACK),
                '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 hotkey_all_ck(self):
        for item in self.datas:
            item['f_item'].cb_is_checked.setChecked(True)
    def hotkey_all_not_ck(self):
        for item in self.datas:
            item['f_item'].cb_is_checked.setChecked(False)
    def hotkey_all_fan_ck(self):
        for item in self.datas:
            item['f_item'].cb_is_checked.setChecked(not item['f_item'].cb_is_checked.isChecked())
    def hotkey_runall(self):
        global  atys
        hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
        if hwnd == 0:
            logger.info("错误:请先开游戏!")
            return

        left, top, right, bottom = win32gui.GetClientRect(hwnd)
        width = right - left
        height = bottom - top
        if width!=1920 or height!=1080:
            logger.info("错误:游戏分辨率不对!请确保游戏分辨率是1920x1080  建议重新设置分辨率")
            return

        self.save()
        def run():
            self.sg.mysig_mouse_through.emit(True)
            #运行 N 次
            ret = False
            for rt in range(self.run_times):
                logger.info(f"任务包:{state.PATH_TASK} {rt+1}/{self.run_times}")

                idex = 0

                state.计次_传送重试次数 = 0
                state.状态_全局暂停 = False

                while idex < len(self.datas):
                    if state.状态_检测中:
                        time.sleep(1)
                        continue
                    if self.datas[idex]['f_item'].cb_is_checked.isChecked():
                        ret = self.run(idex)

                        if state.状态_循环开关 == False:
                            break
                        if ret == False:
                            if state.状态_需重新传送 == True:
                                state.计次_传送重试次数 += 1
                                if state.计次_传送重试次数 >= 5:
                                    state.计次_传送重试次数 = 0
                                    logger.info("传送重试次数过多,放弃该任务!")
                                else:
                                    logger.info(f"传送重试{state.计次_传送重试次数}" )
                                    time.sleep(2)
                                    continue
                            else:
                                break
                    state.计次_传送重试次数 = 0
                    idex += 1
                if state.状态_循环开关 == False:
                    break
            if state.状态_循环开关 != False:
                # 切下一个任务包 继续
                next_tas = self.get_next_task()
                if state.ON_NEXTPACK == 1 and next_tas != None:
                    state.PATH_TASK = next_tas
                    logger.info("切下一个任务包!")

                    self.sg.mysig_next_pack.emit()
                    self.sg.mysig_mouse_through.emit(False)
                    return
            if ret == True and state.ON_JIXING == 1:
                aty.run_jixing()
            if ret == True and state.ON_SHUTDOWN == 1:
                self.sg.mysig_shutdown.emit()
            self.sg.mysig_mouse_through.emit(False)
            state.状态_循环开关 = False

        t = threading.Thread(target=run)
        if state.python_var>9:
            t.daemon=True
        else:
            t.setDaemon(True)
        t.start()
    def hotkey_keys_ack(self):
        text, ok = QInputDialog.getText(self, '提示', '请输入关键字:', text="狗粮")
        if not ok:
            return
        if text == "":
            return

        for item in self.datas:
            if text in item['f_item'].led_name.text():
                item['f_item'].cb_is_checked.setChecked(True)
    def hotkey_num_ck(self):
        text, ok = QInputDialog.getText(self, '提示', '请输入包含某数字的区间:', text="0-100")
        if not ok:
            return
        if text == "":
            return
        try:
            min_, main_=list(map(int, text.split("-")))
        except:
            return
        for item in self.datas:
            if main_>= extract_number(item['f_item'].led_name.text())>=min_:
                item['f_item'].cb_is_checked.setChecked(True)
    def hotkey_find(self):
        text, ok = QInputDialog.getText(self, '提示', '请输入要定位的任务关键字:', text="绝缘")
        if not ok:
            return
        if text == "":
            return
        for idex,item in enumerate(self.datas) :
            if text in item['f_item'].led_name.text():
                self.dingwei(idex)
    def hotkey_deltask(self):
        for idex, item in enumerate(self.datas):
            if item['f_item'].cb_is_checked.isChecked():
                self.clickd_bt_del(idex)
    def hotkey_isShow(self):
        state.开关_是否展预测结果= self.action_isShow.isChecked()
        if self.action_isShow.isChecked():
            # 判断窗口是否存在
            if not hasattr(self, "fromshow"):
                self.fromshow = FormShow(self)
                self.addDockWidget(Qt.TopDockWidgetArea, self.fromshow)

            self.fromshow.show()

        else:
            if hasattr(self, "fromshow"):
                self.fromshow.close()
    def hotkey_isShowCmd(self):

        show_hide_window(hwnd_cmd,self.action_isShowCmd.isChecked())
    def hotkey_yunduanlist(self):
        self.formyunfilelist = FormYunFileList()
        threading.Thread(target=self.formyunfilelist.update).start()
        self.formyunfilelist.show()
        self.formyunfilelist.lb_ing.show()
        self.formyunfilelist.lb_ing.move(self.formyunfilelist.width()-self.formyunfilelist.lb_ing.width(),self.formyunfilelist.height()-self.formyunfilelist.lb_ing.height())
    def hotkey_shutdown(self):
        if self.action_shutdown.isChecked():
            state.ON_SHUTDOWN = 1
        else:
            state.ON_SHUTDOWN = 0

        self.save_ini_seting()
    def hotkey_timeout(self):
        try:
            text, ok = QInputDialog.getText(self, '超时阈值', '请输入打怪超时阈值 单位秒:\n注意最低不能小于60秒', text=str(state.TIMEOUT_DAGUAI))
            if not ok:
                return
            if text == "":
                return

            if int(text)<60:
                state.TIMEOUT_DAGUAI=60
            else:
                state.TIMEOUT_DAGUAI = int(text)
            self.action_timeout.setText(f"设置打怪超时 阈值:{state.TIMEOUT_DAGUAI}秒")
            logger.info("设置打怪超时阈值为:"+str(state.TIMEOUT_DAGUAI))
            self.save_ini_seting()
        except:
            pass
    def hotkey_weights(self):
        try:
            #创建一个窗口 里面有两个单选框

            self.fm_m= FormM(self)
            self.fm_m.show()




            # self.action_timeout.setText(f"设置打怪超时 阈值:{state.TIMEOUT_DAGUAI}秒")
            # logger.info("设置打怪超时阈值为:"+str(state.TIMEOUT_DAGUAI))
            # self.save_ini_seting()
        except:
            pass
    def hotkey_run_times(self):
        try:
            text, ok = QInputDialog.getText(self, '执行次数', f'当前任务包:{state.PATH_TASK}\n请输入执行次数:', text=str(self.run_times))
            if not ok:
                return
            if text == "":
                return

            if int(text)<1:
                self.run_times=1
            else:

                self.run_times= int(text)

            self.action_run_times.setText(f"设置:当前任务包 执行次数:{self.run_times}")
            logger.info(f"设置:当前任务包 执行次数:{self.run_times}")

            # 创建 ConfigParser 对象
            config_main = configparser.ConfigParser()
            # 添加节和键-值对
            config_main['seting'] = {
                "run_times": str(self.run_times),
                }
            # 写入配置到 INI 文件
            with open( os.path.join(state.PATH_TASK, "细节参数.ini"), 'w') as configfile:
                config_main.write(configfile)

        except:
            pass
    def hotkey_lianzhaobujiance(self):
        if self.action_lianzhaobujiance.isChecked():
            state.ON_LIANZHAOBUJIANCE = 1
        else:
            state.ON_LIANZHAOBUJIANCE = 0

        self.save_ini_seting()
    def hotkey_jixing(self):
        if self.action_jixing.isChecked():
            state.ON_JIXING = 1
        else:
            state.ON_JIXING = 0

        self.save_ini_seting()
    def hotkey_nextpack(self):
        if self.action_nextpack.isChecked():
            state.ON_NEXTPACK = 1
        else:
            state.ON_NEXTPACK = 0

        self.save_ini_seting()
    def hotkey_stitchimg(self):
        # 弹出通用对话框选择文件夹
        source_folder = QFileDialog.getExistingDirectory(self, "选择文件夹", "./datas/img")
        if source_folder == "":
            return
        si = StitchImages()
        image_paths = si.get_image_paths(source_folder)
        ret = si.stitch_images(image_paths, "./datas/max_map/max_map.png", True)
        if not ret:
            QMessageBox.information(self, "提示", "合成全景图失败,检查一下是不是每张图都有相交的地方")
    def hotkey_guai(self):

        for item in self.datas:
            if item['f_item'].cb_is_checked.isChecked():

                if item["type"] == "1":
                    item['f_item'].cb_daguai.setChecked(self.action_guai.isChecked())
    def hotkey_kuang(self):
        for item in self.datas:
            if item['f_item'].cb_is_checked.isChecked():
                if item["type"] == "1":
                    item['f_item'].cb_wakuang.setChecked(self.action_kuang.isChecked())
    def hotkey_hua(self):
        for item in self.datas:
            if item['f_item'].cb_is_checked.isChecked():

                if item["type"] == "1":
                    item['f_item'].cb_caiji.setChecked(self.action_hua.isChecked())
    def set_cbb_items(self,cbb):
        cbb .clear()
        #遍历文件夹下的所有png文件
        # 定义要遍历的文件夹路径
        folder_path =state.PATH_JUESE

        # 遍历文件夹及其子文件夹中的所有文件
        for root, dirs, files in os.walk(folder_path):
            for file in files:
                # 检查文件扩展名是否为.png
                if file.endswith('.png'):
                    # 打印PNG文件的完整路径
                    file_name = os.path.splitext(file)[0]
                    cbb.addItem("",file_name)
        # 获取下拉列表的视图部件
        view = cbb.view()

        # 设置特定子项的工具提示和相应的图片
        for index in range(cbb.count()):
            file_name = cbb.itemData(index)
            image_path = f"{folder_path}/{file_name}.png"
            if image_path:
                item = view.model().item(index, 0)
                pixmap = QPixmap(image_path)
                item.setIcon(QIcon(pixmap))
                # item.setToolTip(image_path)
        cbb.setIconSize(QSize(int(40*ratio), int(50*ratio)))  # 设置图标大小为40x40像素
    def set_cbb_item(self,cbb, name):
        # 设置特定子项的工具提示和相应的图片
        for index in range(cbb.count()):
            file_name = cbb.itemData(index)
            if file_name==name:
                cbb.setCurrentIndex(index)
    def autoSelectAddress(self,address_name="蒙德",isrun=False):



        img_filens=[cv2.imdecode(np.fromfile(file=state.PATH_ADDRESS+address_name+".png", dtype=np.uint8), cv2.IMREAD_UNCHANGED),
                    cv2.imdecode(np.fromfile(file=state.PATH_ADDRESS+address_name+"2.png", dtype=np.uint8), cv2.IMREAD_UNCHANGED)]
        # 获取窗口句柄
        hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE)  # 替换成你实际的窗口句柄
        rect = win32gui.GetWindowRect(hwnd)
        w_p, h_p = (rect[2] - rect[0]) - 1920, (rect[3] - rect[1]) - 1080
        # 设定截图区域的左上角坐标 (x, y) 和右下角坐标 (x, y)


        #点左下角的星星
        mouse_move( rect[0] + w_p + 1840,  rect[1] + w_p + 1020)
        time.sleep(0.1)
        mouse_left_down()
        time.sleep(0.2)
        mouse_left_up()

        left, top, right, bottom = 1285, 75, 1916, 1043  # 替换成你实际的区域坐标
        p_left = rect[0] + w_p + left
        p_top = rect[1] + h_p + top
        max_confidence_value = 0
        max_res = {}
        for i in range(4):
            time.sleep(0.5)
            big_img = screenshot(hwnd, left, top, right, bottom, None)
            for item_img in img_filens:
                res = template_matching(big_img, item_img, mask=None)
                if res!=[]:
                    max_confidence_dict = max(res, key=lambda x: x["confidence"])
                    if max_confidence_dict["confidence"]>max_confidence_value:
                        max_res=max_confidence_dict
                        max_confidence_value = max_confidence_dict["confidence"]
            if max_res !={}:
                break

        if max_res=={}:
            logger.info("没找到对应地址的按钮,注意不要乱动鼠标!")
            if not isrun:
                self.sg.mysig_tishi.emit("没找到对应地址的按钮,注意不要乱动鼠标!")
            return False

        mouse_move(p_left + max_res['result'][0], p_top + max_res['result'][1])
        time.sleep(0.1)
        mouse_left_down()
        time.sleep(0.2)
        mouse_left_up()

        return True


if __name__ == '__main__':
    try:

        if ctypes.windll.shell32.IsUserAnAdmin():
            hwnd_cmd = find_child_window_handle(0, "ConsoleWindowClass", "YuanShenAi")
            if hwnd_cmd == 0:
                hwnd_cmd = find_child_window_handle(0, "ConsoleWindowClass", "懒人原神")
            vardata = get_var_data()
            if vardata != False:
                updatetxt = get_updatetxt()
                print(updatetxt)
                print("当前版本号:" + state.版本号)

                if float(vardata[1]) > float(state.版本号):
                    print(
                        "如果更新失败手动下更新包手动覆盖: https://gitee.com/LanRenZhiNeng/lanren-genshin-impact-ai/releases")
                    var = input(f"发现更新的版本 v{vardata[1]} 是否需要更新? (输入yes or no  默认更新)\n")
                    if var == "":
                        var = "yes"
                    if var.lower() != "no":
                        update_process = subprocess.Popen(f'update.exe "{vardata[0]}.exe" "{vardata[2]}"',
                                                          creationflags=subprocess.CREATE_NEW_CONSOLE)
                        time.sleep(1)
                        sys.exit()
            # 运行需要管理员权限的代码
            kernel32 = ctypes.windll.kernel32
            kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), 128)
            os.environ['PNG_IGNORE_WARNINGS'] = '1'

            # 在事件循环中创建一个任务对象并加入事件循环
            aty = main()  # 启动yolov服务

            ysam = YunShenAutoMap()  # 启动寻路类
            app = QApplication(sys.argv)  # 初始化Qt应用
            ratio = screen_width / 2560  # 分辨率比例
            # 设置全局字体大小
            # 计算字体大小
            base_font_size = 13
            # 基准字体大小,适合1920*1080分辨率
            new_font_size = int(base_font_size * ratio)
            font = QFont("Arial", new_font_size)

            # 子控件的宽度
            item_width=320
            item_height=240
            item_height_min = 60
            window_main = MainWindow()
            window_main.show()
            sys.exit(app.exec_())  # 监听消息不关闭
        else:
            # 如果不是管理员,则请求以管理员权限重新运行程序
            ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
    except Exception as err:
        if str(err).find("sys.exit")==-1:

            logger.error(traceback.format_exc())

未完待续

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不要在这些场景中使用LLM或生成式AI

虽然但是&#xff0c;LLM并不是AI的全部&#xff0c;并不是所有的AI应用场景都适合生成式AI。 在某些用例中&#xff0c;应避免或极其谨慎地使用LLM和GenAI&#xff0c;二者可能并非最佳解决方案。 1. 高风险决策 LLM和生成式AI不适合做出可能对现实世界产生重大影响的高风险…

别人做谷歌seo为什么流量比你多?

如果你确认你的网站技术层面没有问题&#xff0c;那其实无非就是两方面&#xff0c;关键词没选好和用户体验不够好&#xff0c;不要妄想一步登天&#xff0c;选那些看起来搜索量很大的热门关键词&#xff0c;这种属于大家都在做&#xff0c;竞争是非常激烈的&#xff0c;在你的…

华宇TAS应用中间件斩获2024鲲鹏应用创新大赛北京赛区总决赛二等奖!

近日&#xff0c;以“数智未来 因你而来”为主题的创客北京2024鲲鹏应用创新大赛华鲲振宇北京赛区总决赛在北京鲲鹏联合创新中心圆满举办&#xff0c;华宇TAS应用中间件凭借产品竞争力、产品兼容性、技术领先性等优势脱颖而出&#xff0c;斩获鲲鹏原生开发赛道&#xff08;泛政…

AI为云游戏带来的革新及解决方案:深度技术剖析与未来展望

近期&#xff0c;科技巨头埃隆马斯克与热门国产游戏《黑神话&#xff1a;悟空》的互动&#xff0c;再次引发了公众对AI技术在游戏产业中应用的关注。马斯克&#xff0c;作为特斯拉和SpaceX的掌门人&#xff0c;不仅在科技领域引领风骚&#xff0c;其个人兴趣也广泛涉猎&#xf…

关于使用Mybatis-Plus 自动填充功能失效问题

关于使用Mybatis-Plus 自动填充功能失效问题 关于使用Mybatis-Plus 自动填充功能失效 首先遇到的第一个问题 自动填充失败 或被填充为NULL 原因&#xff1a;字段类型 与 填充类型 不一致导致 解决方法&#xff1a;将类型替换成一致的类型 全部为Date 或 LocalDateTime 即可解…

828华为云征文 | 使用华为云X实例部署图数据库Virtuoso并存储6500万条大数据的完整过程与性能测评

前言 在大数据时代&#xff0c;图数据库以其强大的关系处理能力在复杂网络、社交媒体分析、知识图谱等领域得到了广泛应用。而在云计算的蓬勃发展下&#xff0c;使用云服务器进行图数据库的部署与管理变得更加方便高效。本篇文章将详细介绍如何在华为云X实例上部署开源图数据…

CANFD和CAN最主要的区别

随着汽车电子的高速发展&#xff0c;车内信息的急剧增多&#xff0c;传统的CAN总线的数据传输能力已经很难满足车辆ECU的数据传输需求了&#xff0c;此时CANFD就应运而生了。 CANFD和CAN最主要的区别就是CANFD的ID段和数据段能够以不同的速率传输数据&#xff0c;这就保证了即…

【大模型专栏—进阶篇】语言模型创新大总结——“后起之秀”

大模型专栏介绍 &#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本文为大模型专栏子篇&#xff0c;大模型专栏将持续更新&#xff0c;主要讲解大模型从入门到实战打怪升级。如有兴趣&#xff0c;欢迎您的阅读。 &#x1f4…

Prompt最佳实践|指定任务步骤,让ChatGPT不懵逼

在OpenAI的官方文档中已经提供了[Prompt Enginerring]的最佳实践&#xff0c;目的就是帮助用户更好的使用ChatGPT 编写优秀的提示词我一共总结了9个分类&#xff0c;本文讲解第4个分类&#xff1a;指定任务步骤 提供更多的细节要求模型扮演角色使用分隔符指定任务步骤提供样例…

e冒泡排序---复杂度O(X^2)

排序原理: 1.比较相邻的元素。如果前一个元素比后一个元素大&#xff0c;就交换这两个元素的位置。 2.对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大值, public class 冒泡排序 {public static void main(String[] args) {I…

点亮第一盏LED灯 4): stm32CubeMX配置时钟

嵌入式入门&#xff0c;继续点亮第一盏LED灯&#xff0c;在Stm32CubeMX这个图形界面&#xff0c;一共是需要配置2个地方&#xff0c;1是GPIO引脚&#xff0c;2是时钟&#xff0c;上一篇文章已经将引脚PC13配置为输出引脚&#xff0c;这个引脚需要输出的是低电平&#xff0c;这篇…

这才几天,京东又又又又又又加薪了!

京东 今天的最新消息&#xff0c;京东又又又又又加薪了。 距离我们 京东宣布大幅上调校招薪资 的推文发布才一周多点的时间&#xff0c;京东又宣布加薪了。 好家伙&#xff0c;算上这次&#xff0c;光 2024 年京东就已经宣布了 6 次调薪了&#xff1a; 2024 年初&#xff0c;京…

多文件多子目录makefile

这里写目录标题 1 makefile原理2 MakeFile步骤3 多文件多子目录Makefile实例4 总结附录一&#xff1a;常用Bash指令附录二&#xff1a;常用批处理变量附录三&#xff1a;常用makefile指令 1 makefile原理 编译过程是将高级语言&#xff08;如C、C等&#xff09;源代码转换为可…

如何利用数字化智慧法务管理平台,提升企业合规与治理水平?

在当今这个日新月异的时代&#xff0c;企业管理正面临着前所未有的挑战与机遇。随着数字化浪潮的汹涌澎湃&#xff0c;企业治理水平的提升已不再是简单的管理升级&#xff0c;而是需要借助科技的力量&#xff0c;实现智慧化、精细化的管理。而智慧法务管理平台&#xff0c;正是…

电子电路产业园废水处理与资源回收的创新实践

随着电子产品的普及和技术革新步伐的加快&#xff0c;电子电路制造业已成为推动现代科技发展的关键力量之一。然而&#xff0c;随之而来的环保问题不容忽视。电镀工艺作为电子电路生产中的一个核心环节&#xff0c;其产生的含镍废水处理成为了企业必须面对的重要课题。本文将探…

【组件】前端js HEIC/HEIF 转换为JPEG、PNG或GIF格式 苹果格式

【组件】前端js HEIC/HEIF 转换为JPEG、PNG或GIF格式 Heic2any: Client-side conversion of HEIC/HEIF image files to JPEG,PNG, or GIF in the browser.https://alexcorvi.github.io/heic2any/#demo GitHub - alexcorvi/heic2any: Converting HEIF/HEIF image formats to PN…

redis 中缓存 百万级别表的查询数据 出错:Query execution was interrupted

项目背景&#xff1a;项目需要 首检合格率 这个结果&#xff0c;但是sql执行非常慢&#xff0c;就想着使用redis来优化接口的速度。现在我需要将数据库查询结果存储到redis&#xff0c;但是就是这一小步&#xff0c;也非常困难。我是用定时任务来实现上面的目的。 Component S…

基于android studio开发的仿QQ聊天软件源代码+数据库+实验报告

安卓客户端基于java 编程语言 在android studio 环境中开发。 内部图片资源很大一部分是反编译手机QQapp 获得的。 服务器端技术路线 聊天系统服务器基于Java Socket网络编程和并发编程、多线程技术、jdbc实现。 通过哈希表&#xff08;hashmap&#xff09;存储来自每一个向客…

读书笔记:《程序员修炼之道——从小工到专家》

前言 此书有两个版本&#xff0c;我读的是第一版&#xff0c;大学时买了略略翻过&#xff0c;当时太懵懂无法理解书中提出的观点&#xff0c;看了也记不得&#xff0c;感觉比较适用于有过1~2个项目工作经验的同学&#xff0c;初学者不一定能看得懂&#xff0c;工作之后看&…

学习通、智慧职教刷课脚本

&#x1f410;个人主页 可惜已不在 &#x1f40b;可以分享给身边有需要的人&#x1f436; &#x1f409;有用的话就留下一个三连吧&#x1f63c; 目录 一.安装 脚本运行器 篡改猴 - Microsoft Edge Addons 二.安装脚本 三.扩展 一.安装 脚本运行器 安装浏览器 Microsoft E…