yolo自动化项目实例解析(六)自建UI(主窗口、预览窗口)

前面我们大致把各个代码块梳理出来了,但是还是不知道从那块开始,我们这里主要先通过ui页面的元素去推理整个执行过程,我们首先需要知道ui功能里面有那些组件

qt设计师基础控件

Qt Designer 是一个图形界面设计工具,用于创建 Qt 应用程序的用户界面。它提供了丰富的控件(也称为窗口部件或widgets)来构建各种类型的用户界面

类型 窗口部件 说明
基础控件 QLabel 显示静态文本或图像
基础控件 QPushButton 用户可以点击的按钮
基础控件 QLineEdit 单行文本输入框
基础控件 QTextEdit 多行文本编辑器
基础控件 QCheckBox 复选框,用户可以选择或取消选择
基础控件 QRadioButton 单选按钮,用于一组互斥的选择项
基础控件 QComboBox 下拉列表框,用户可以从列表中选择一项
基础控件 QSlider 滑块控件,用于数值的选择范围
基础控件 QSpinBox/QDoubleSpinBox 数字输入框,用户可以输入整数或浮点数
基础控件 QProgressBar 进度条,显示任务完成的进度
基础控件 QToolButton 工具按钮,常用于工具栏上,支持弹出菜单
基础控件 QGraphicsView 图形视图,用于显示复杂的图形场景
布局管理器 QVBoxLayout 垂直布局管理器,用于管理控件的垂直排列
布局管理器 QHBoxLayout 水平布局管理器,用于管理控件的水平排列
布局管理器 QGridLayout 网格布局管理器,用于将控件放置在网格单元格中
布局管理器 QFormLayout 表单布局管理器,用于创建标签和控件成对出现的布局
布局管理器 QStackedLayout 堆叠布局管理器,用于堆叠多个控件,一次只显示一个
容器 QWidget 最基础的窗口部件,可以包含其他控件
容器 QFrame 带边框的容器,可以设置不同的样式
容器 QGroupBox 带标题的框架,常用于分组控件
容器 QTabWidget 带标签页的容器,允许用户在多个页面之间切换
容器 QScrollArea 滚动区域,当内容超过显示区域时提供滚动条
容器 QDockWidget 码头窗口,通常用于显示附加信息或工具
对话框 QMessageBox 提示信息对话框,用于显示警告、错误等消息
对话框 QFileDialog 文件对话框,用于选择文件或目录
对话框 QColorDialog 颜色选择对话框,用于选取颜色
对话框 QFontDialog 字体选择对话框,用于选取字体
其他 QMenuBar 菜单栏,通常位于窗口顶部
其他 QToolBar 工具栏,通常包含一些快捷按钮
其他 QStatusBar 状态栏,显示临时的消息

我们打开窗口的时候会发现中间有一块显示大屏,如下

我们先看看怎么实现这个大屏显示,打开qt设计师

新建项目目录

我们先不在原本的项目上找,先根据已有的信息参考源代码进行推断

一、添加主窗口

1、主窗口、窗口大小、标题

1、打开Qt Designer。
2、选择"文件" > "新建",创建一个新的Qt Designer文档。
3、在"选择类"对话框中,选择QMainWindow作为基础类,并命名为mainWindow。

4、添加布局,layouts--Horizontal layouts--- 添加后选择类名右键--布局--水平布局,然后将我们刚才添加的Horizontal layouts删除
5、设置窗口大小(geometry关键字)为800x600像素,并设置窗口标题(windowTitle)为 "主页"

2、添加工具栏、移除菜单栏

3、组件重命名

mainWindow
centralwidget
sa_main
scrollAreaWidgetContents
sb_main
toolBar

这里我们给布局内的各个元素重命名后,我们在ui转py会转换为各个关键字方便使用

4、布局重命名

我们上面临时用了下布局样式这里可能叫_2什么的,修改为下图

5、工具栏调整到侧边

6、添加动作、ui转py

#动作文本名称如下
Save_All 
Add_Mode 
Add_Script

ui转换

pyuic5 -o main.py main.ui

代码

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

# Form implementation generated from reading ui file 'main.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.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.sa_main = QtWidgets.QScrollArea(self.centralwidget)
        self.sa_main.setWidgetResizable(True)
        self.sa_main.setObjectName("sa_main")
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 762, 551))
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        self.sa_main.setWidget(self.scrollAreaWidgetContents)
        self.horizontalLayout.addWidget(self.sa_main)
        mainWindow.setCentralWidget(self.centralwidget)
        self.sb_main = QtWidgets.QStatusBar(mainWindow)
        self.sb_main.setObjectName("sb_main")
        mainWindow.setStatusBar(self.sb_main)
        self.toolBar = QtWidgets.QToolBar(mainWindow)
        self.toolBar.setObjectName("toolBar")
        mainWindow.addToolBar(QtCore.Qt.LeftToolBarArea, self.toolBar)
        self.actionSave_All = QtWidgets.QAction(mainWindow)
        self.actionSave_All.setObjectName("actionSave_All")
        self.actionAdd_Mode = QtWidgets.QAction(mainWindow)
        self.actionAdd_Mode.setObjectName("actionAdd_Mode")
        self.actionAdd_Script = QtWidgets.QAction(mainWindow)
        self.actionAdd_Script.setObjectName("actionAdd_Script")

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

    def retranslateUi(self, mainWindow):
        _translate = QtCore.QCoreApplication.translate
        mainWindow.setWindowTitle(_translate("mainWindow", "主页"))
        self.toolBar.setWindowTitle(_translate("mainWindow", "toolBar"))
        self.actionSave_All.setText(_translate("mainWindow", "Save_All "))
        self.actionAdd_Mode.setText(_translate("mainWindow", "Add_Mode "))
        self.actionAdd_Script.setText(_translate("mainWindow", "Add_Script"))

7、打开主窗口

import ctypes
import sys

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QDockWidget, QMainWindow, QApplication

import state
from ui.show import Ui_DockWidget
from ui.main import Ui_mainWindow





class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)  # 设置UI布局
        self.retranslateUi(self)  # 重新翻译UI组件的文字




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

    #初始化QT应用
    app = QApplication(sys.argv)
    ratio = screen_width / 2560  # 分辨率比例


    # 设置全局字体大小  计算字体大小
    base_font_size = 13
    # 基准字体大小,适合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_())  # 监听消息不关闭

8、设置主窗口样式

class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)  # 设置UI布局
        self.retranslateUi(self)  # 重新翻译UI组件的文字

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

    #设置主窗口样式
    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()))

9、滚动可扩展窗口

class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):


    。。。

        #sa_main是我们之前定义的QScrollArea 也就是滚动条类型的容器
        #我们在滚动条布局sa_main内放了一个普通部件QWidget()  ,self.sa_main.setWidget(self.container_widget)
        #这样一来,如果普通部件内的数据超出了显示范围,就能通过滚动条查看了
        self.g_box = QGridLayout()
        #创建了一个普通的窗口部件(QWidget),这个部件将用于包含所有的子控件,并且可以独立于其父窗口进行尺寸调整,为了可以让g_布局超过窗口大小
        self.container_widget = QWidget()  # 创建一个中间部件
        self.container_widget.setLayout(self.g_box)  # 将网格布局设置给中间部件
        self.g_box.setAlignment(Qt.AlignTop | Qt.AlignLeft)  # 布局 左上对齐
        self.g_box.setContentsMargins(0, 0, 0, 0)  # 边距
        self.g_box.setAlignment(Qt.AlignTop)
        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.statusbar = self.statusBar()

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

10、延迟布局更新

当窗口尺寸变化或其他条件满足时(例如计时器触发),重新计算并更新网格布局中的控件位置,使其适应当前窗口的大小

class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):


     。。。



        # 所有数据
        self.datas = []
        # 创建一个计时器,用于延迟布局
        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

11、全量代码

import ctypes
import sys

from PyQt5.QtCore import Qt, QTimer, QObject, pyqtSignal
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QDockWidget, QMainWindow, QApplication, QGridLayout, QWidget, QScrollArea

from ui.show import Ui_DockWidget
from ui.main import Ui_mainWindow





class MainWindow(QMainWindow, Ui_mainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)  # 设置UI布局
        self.retranslateUi(self)  # 重新翻译UI组件的文字

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

        # self.setWindowIcon(QIcon("datas/logo.png"))  设置图标
        self.setWindowTitle(f" 修改主页标题")
        self.resize(640, 900)  # 窗口的长宽
        self.move(0, 300)  # 窗口的起点位置


        #sa_main是我们之前定义的QScrollArea 也就是滚动条类型的容器
        #我们在滚动条布局sa_main内放了一个普通部件QWidget()  ,self.sa_main.setWidget(self.container_widget)
        #这样一来,如果普通部件内的数据超出了显示范围,就能通过滚动条查看了
        self.g_box = QGridLayout()
        #创建了一个普通的窗口部件(QWidget),这个部件将用于包含所有的子控件,并且可以独立于其父窗口进行尺寸调整,为了可以让g_布局超过窗口大小
        self.container_widget = QWidget()  # 创建一个中间部件
        self.container_widget.setLayout(self.g_box)  # 将网格布局设置给中间部件
        self.g_box.setAlignment(Qt.AlignTop | Qt.AlignLeft)  # 布局 左上对齐
        self.g_box.setContentsMargins(0, 0, 0, 0)  # 边距
        self.g_box.setAlignment(Qt.AlignTop)
        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.statusbar = self.statusBar()

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




        # 所有数据
        self.datas = []
        # 创建一个计时器,用于延迟布局
        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__':
    # 获取屏幕宽度和高度
    screen_width = ctypes.windll.user32.GetSystemMetrics(0)
    screen_height = ctypes.windll.user32.GetSystemMetrics(1)

    #初始化QT应用
    app = QApplication(sys.argv)
    ratio = screen_width / 2560  # 分辨率比例


    # 设置全局字体大小  计算字体大小
    base_font_size = 13
    # 基准字体大小,适合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预览窗口

QDockWidget 码头窗口,通常用于显示附加信息或工具

1、预览窗口定义

1、新建项目-窗口部件--QDockWidget (483X565)

2、添加两个label 大小480 X 270 ,设置样式表

3、添加按钮 修改按钮文本 + -

#寻路标签背景颜色为黑色
background-color: rgb(0, 0, 0);



#标签背景颜色为灰色
background-color: rgb(20, 20, 20);

这里图里搞错了,yolo那个label应该设置为background-color: rgb(20, 20, 20);

2、组件名称修改

DockWidget
dockWidgetContents
bt_jia
bt_jian
lb_xunlu
lb_yolov

3、label最大尺寸修改

寻路

yolo

4、调整各个组件前后台

jia 和jian调整为前台

xunlu和yolo调整到后台

(直接右键组件--放到前面/放到后面)

5、ui转py

pyuic5 -o show.py show.ui

py代码

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

# Form implementation generated from reading ui file 'show.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_DockWidget(object):
    def setupUi(self, DockWidget):
        DockWidget.setObjectName("DockWidget")
        DockWidget.resize(483, 565)
        self.dockWidgetContents = QtWidgets.QWidget()
        self.dockWidgetContents.setObjectName("dockWidgetContents")
        self.lb_xunlu = QtWidgets.QLabel(self.dockWidgetContents)
        self.lb_xunlu.setGeometry(QtCore.QRect(0, 0, 480, 270))
        self.lb_xunlu.setMinimumSize(QtCore.QSize(0, 0))
        self.lb_xunlu.setMaximumSize(QtCore.QSize(16777215, 16777215))
        self.lb_xunlu.setStyleSheet("background-color: rgb(0, 0, 0);")
        self.lb_xunlu.setText("")
        self.lb_xunlu.setObjectName("lb_xunlu")
        self.lb_yolov = QtWidgets.QLabel(self.dockWidgetContents)
        self.lb_yolov.setGeometry(QtCore.QRect(0, 270, 480, 270))
        self.lb_yolov.setMinimumSize(QtCore.QSize(480, 270))
        self.lb_yolov.setMaximumSize(QtCore.QSize(1920, 1080))
        self.lb_yolov.setStyleSheet("background-color: rgb(20, 20, 20);")
        self.lb_yolov.setText("")
        self.lb_yolov.setObjectName("lb_yolov")
        self.bt_jia = QtWidgets.QPushButton(self.dockWidgetContents)
        self.bt_jia.setGeometry(QtCore.QRect(30, 40, 31, 28))
        self.bt_jia.setObjectName("bt_jia")
        self.bt_jian = QtWidgets.QPushButton(self.dockWidgetContents)
        self.bt_jian.setGeometry(QtCore.QRect(60, 40, 31, 28))
        self.bt_jian.setObjectName("bt_jian")
        self.lb_yolov.raise_()
        self.lb_xunlu.raise_()
        self.bt_jia.raise_()
        self.bt_jian.raise_()
        DockWidget.setWidget(self.dockWidgetContents)

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

    def retranslateUi(self, DockWidget):
        _translate = QtCore.QCoreApplication.translate
        DockWidget.setWindowTitle(_translate("DockWidget", "DockWidget"))
        self.bt_jia.setText(_translate("DockWidget", "+"))
        self.bt_jian.setText(_translate("DockWidget", "-"))

三、主窗口添加子窗口

1、添加自定义信号

class MySignal(QObject):

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

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

2、添加预览窗口显示类

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):
        self.parent.action_isShow.setChecked(False)

    def resizeEvent(self, event):
        if self.width() >= self.lb_yolov.width() + self.lb_xunlu.width():
            self.lb_yolov.move(self.lb_xunlu.width(), 0)
        else:
            self.lb_yolov.move(0, self.lb_xunlu.height())

3、主窗口 添加 预览窗口显示

    def connect_set(self):


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





    #打开预测窗口
    def hotkey_isShow(self):
        # 尝试创建悬浮窗口实例
        if not hasattr(self, "fromshow"):
            self.fromshow = FormShow(self)  # 创建悬浮窗口实例
            print(111111)
            self.addDockWidget(Qt.TopDockWidgetArea, self.fromshow)  # 添加悬浮窗口到主窗口

4、添加信号槽

    # 绑定信号槽
    def connect_set(self):
        ...


        #添加信号
        self.sg = MySignal()
        #绑定信号槽
        self.sg.mysig_show_xunlu.connect(self.show_xunlu)  #寻路
        self.sg.mysig_show_yolov.connect(self.show_yolov)  #推理

5、添加信号槽及对应函数

这里先偷个懒,直接使用本地图片显示上去,后续整晚之后在加具体功能

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

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

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

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

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

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

6、发送信号

我们在init中定义一个新的定时器,每5s触发on_timer_timeout函数,然后会发送mysig_show_xunlu和mysig_show_yolov信号,信号槽接收到后,触发show_xunlu 和show_yolov 函数,去显示图片

    def __init__(self):

        。。。

        # 绑定信号槽
        self.connect_set()

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

    def on_timer_timeout(self):
        # 每隔一段时间自动显示图片
        #emit() 方法用于发送信号
        self.sg.mysig_show_xunlu.emit()
        self.sg.mysig_show_yolov.emit()

然我们后面使用的时候不会这么草率的发送信号,而是通过循环截取地图,和屏幕中yolo推理当前屏幕图片进行显示的

7、全量代码

import ctypes
import sys

# 导入PyQt5模块
from PyQt5.QtCore import Qt, QTimer, QObject, pyqtSignal
from PyQt5.QtGui import QFont, QImage, QPixmap, QKeySequence
from PyQt5.QtWidgets import QDockWidget, QMainWindow, QApplication, QGridLayout, QWidget, QScrollArea, QAction

# 导入UI文件生成的类
from ui.show import Ui_DockWidget
from ui.main import Ui_mainWindow

class MySignal(QObject):

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # 绑定信号槽
        self.connect_set()

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

    def on_timer_timeout(self):
        # 每隔一段时间自动显示图片
        self.sg.mysig_show_xunlu.emit()
        self.sg.mysig_show_yolov.emit()
    # 绑定信号槽
    def connect_set(self):
        # 创建一个顶级菜单
        self.menu = self.menuBar()
        self.menu_view = self.menu.addMenu("视图")

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

    # 显示主窗口
    window_main.show()

    # 监听消息不关闭
    sys.exit(app.exec_())
相关推荐
极客先躯13 分钟前
高级java每日一道面试题-2024年9月26日-运维篇[分布式篇]-如何保证每个服务器的时间都是同步的?
linux·运维·分布式·面试·时间同步·网络时间协议(ntp)·精密时间协议(ptp)
C_eeking38 分钟前
Linux终端简介
linux·运维·microsoft
Jumbuck_101 小时前
以Flask为基础的虾皮Shopee“曲线滑块验证码”识别系统部署
后端·python·深度学习·yolo·flask·密码学
不止会JS1 小时前
Docker精讲:基本安装,简单命令及核心概念
运维·docker·容器
被制作时长两年半的个人练习生1 小时前
【docker】debian中配置docker(2024年9月)
运维·docker·容器
zhangxueyi1 小时前
国产OpenEuler与Centos全面之比较
linux·运维·服务器·centos
q9085447031 小时前
centos磁盘逻辑卷LVM创建
linux·运维·centos
阿利同学1 小时前
草莓病虫害数据集1000张分5类 草莓植株黑斑病、草莓灰霉菌病、正常草莓、草莓粉霉菌病、草莓橡胶病
yolo·获取qq1309399183·草莓数据集
P.H. Infinity1 小时前
【Docker】01-Docker常见指令
运维·docker·容器
The Open Group2 小时前
企业数字化转型的架构框架选择:多框架对比与TOGAF的应用深度解析
大数据·运维·人工智能·分布式·微服务·架构·数字化转型