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

news2024/12/23 17:17:02

前面我们大致把各个代码块梳理出来了,但是还是不知道从那块开始,我们这里主要先通过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_())

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

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

相关文章

遇到慢SQL、SQL报错,应如何快速定位问题 | OceanBase优化实践

在数据库的使用中&#xff0c;大家时常会遇到慢SQL&#xff0c;或执行出错的SQL。对于某些SQL问题&#xff0c;其错误原因显而易见&#xff0c;但也有不少情况难以直观判断。面对这类问题&#xff0c;我们应当如何应对&#xff1f;如何准确识别SQL错误的根源&#xff1f;是否需…

电脑usb接口封禁如何实现?5种禁用USB接口的方法分享!(第一种你GET了吗?)

“防患于未然&#xff0c;安全始于细节。”在信息技术飞速发展的今天&#xff0c;企业的信息安全问题日益凸显。 USB接口作为数据传输的重要通道&#xff0c;在带来便利的同时&#xff0c;也成为了数据泄露和安全风险的高发地。 因此&#xff0c;对电脑USB接口进行封闭管理&a…

WPF项目中使用Caliburn.Micro框架实现日志和主题切换

目录 一、添加Caliburn.Micro框架 二、配置Serilog日志 三、实现主题切换 Caliburn.Micro是MVVM模式的轻量级WPF框架&#xff0c;简化了WPF中的不少用法。这个框架中所有的页面控制都是通过ViewModel去实现的。 以下内容是自己在进行项目实战的同时进行记录的&#xff0c;对于…

【08】纯血鸿蒙HarmonyOS NEXT星河版开发0基础学习笔记-Scroll容器与Tabs组件

序言&#xff1a; 本文详细讲解了关于我们在页面上经常看到的可滚动页面和导航栏在鸿蒙开发中如何用Scroll和Tabs组件实现&#xff0c;介绍了Scroll和Tabs的基本用法与属性。 笔者也是跟着B站黑马的课程一步步学习&#xff0c;学习的过程中添加部分自己的想法整理为笔记分享出…

晶圆厂如何突破多网隔离实现安全稳定又快速的跨网域文件传输?

在当今数字化时代&#xff0c;晶圆厂作为高科技产业的核心&#xff0c;其生产效率和数据安全性直接影响到整个半导体行业的竞争力。晶圆厂内部网络通常被划分为多个安全域&#xff0c;如生产网络、研发网络、办公网络等&#xff0c;以确保数据安全和防止敏感信息泄露。然而&…

【RabbitMQ 项目】服务端:服务器模块

文章目录 一.编写思路二.代码实践三.服务端模块关系总结 一.编写思路 成员变量&#xff1a; muduo 库中的 TCP 服务器EventLoop 对象&#xff1a;用于主线程循环监控连接事件协议处理句柄分发器&#xff1a;用于初始化协议处理器&#xff0c;便于把不同请求派发给不同的业务处理…

大语言模型在构建UNSPSC 分类数据中的应用

UNSPSC 是联合国标准产品和服务代码。UNSPSC由联合国开发计划署&#xff08;UNDP&#xff09;和Dun & Bradstreet公司&#xff08;D & B&#xff09;于1998年联合制定&#xff0c;自2003年以来一直由GS1 US管理。GS1 US 将在 2024 年底前将 UNSPSC 的管理权移交给 UNDP…

【HarmonyOS】TaskPool非阻塞UI

TaskPool方法不会阻塞UI&#xff0c;如果做上传图片的功能加载Loading记得使用TaskPool&#xff0c;Promise、Async/Await都会阻塞UI 【引言】 发现Promise可能会阻塞UI&#xff0c;尝试使用async或await&#xff0c;但发现它们仍然会导致阻塞。后来看到chaoxiaoshu回复的Tas…

数字孪生平台,助力制造设备迈入超感知与智控新时代!

痛点剖析 当前&#xff0c;制造业面临系统分散导致的数据孤岛问题&#xff0c;严重阻碍了有效监管与统计分析&#xff1b;同时&#xff0c;设备多样化且兼容性不足&#xff0c;增加了管理难度&#xff1b;台账记录方式混乱&#xff0c;工单审批流程繁琐且效率低下&#xff1b;…

electron使用npm install出现下载失败的问题

我在使用electron进行下载时&#xff0c;经常出现一个错误。 HTTPError: Response code 404 (Not Found) for https://registry.npmmirror.com/v21.4.4/electron-v21.4.4-win32-x64.zip 这个时候需要修改一些npm的配置。使用命令npm config list -ls 滑到下面&#xff0c;找到一…

第一个maven web工程(eclipse)

1、点击file--》new--》Maven Project&#xff0c;如下&#xff1a; 2、直接next&#xff0c;如下 3、搜索web原型&#xff0c;如下 4、填写项目的坐标&#xff0c;如下 5、创建完成后&#xff0c;需要自己补一个文件夹&#xff0c;名称为java&#xff0c;如下&#xff1a; …

class 023 随机快速排序

这篇文章是看了“左程云”老师在b站上的讲解之后写的, 自己感觉已经能理解了, 所以就将整个过程写下来了。 这个是“左程云”老师个人空间的b站的链接, 数据结构与算法讲的很好很好, 希望大家可以多多支持左程云老师, 真心推荐. https://space.bilibili.com/8888480?spm_id_f…

云中红队系列 | 使用 AWS API 配置Fireprox进行 IP轮换

在渗透测试评估期间&#xff0c;某些活动需要一定程度的自动化&#xff0c;例如从 LinkedIn 等网站抓取网页以收集可用于社会工程活动、密码喷洒登录门户或测试时盲注的有效员工姓名列表网络应用程序。但是&#xff0c;从单个源 IP 地址执行这些活动可能会导致在测试期间被拦截…

【TabBar嵌套Navigation案例-新特性页面-代码位置 Objective-C语言】

一、接下来,我们来说这个新特性页面 1.首先,看一下我们的示例程序,这里改一下,加一个叹号, command + R, 好,首先啊,这里边有一个新特性页面,当我这个程序是第一次安装、第一次运行、还有呢、就是当这个应用程序更新的时候,我应该去加载这个新特性页面, 然后呢,这…

JPEG图像的DCT(Discrete Cosine Transform)变换公式代码详解

引 言 网络上图像在传输过程中为节省内存空间主要采用jpeg格式。jpeg图属于有损压缩图像的一种。在图像篡改检测过程中&#xff0c;可以利用jpeg图像的单双压缩伪影的不同而判别图像为伪造图并可以定位伪造区域。RGB图像变成jpeg图像过程中涉及从RGB图变成YCbCr图像&#xff0c…

使用离火插件yoloV8数据标注,模型训练

1. 启动 2.相关配置 2.1 data.yaml path: D:/yolo-tool/yaunshen-yolov8/YOLOv8ys/YOLOv8-CUDA10.2/1/datasets/ceshi001 train: images val: images names: [蔡徐坤,篮球] 2.2 cfg.yaml # Ultralytics YOLOv8, GPL-3.0 license # Default training settings and hyp…

物联网行业中通信断线重连现象介绍以及如何实现

01 概述 断线重连是指在计算机网络中&#xff0c;当网络连接遇到异常中断或者断开时&#xff0c;系统会自动尝试重新建立连接&#xff0c;以保证网络通信的连续性和稳定性。这是一种常见的网络通信技术&#xff0c;广泛应用于各种计算机网络场景&#xff0c;包括互联网、局域…

蓝队技能-应急响应篇Web内存马查杀Spring框架型中间件型JVM分析Class提取

知识点&#xff1a; 1、应急响应-Web框架内存马-分析&清除 2、应急响应-Web中间件内存马-分析&清除 注&#xff1a;框架型内存马与中间件内存马只要网站重启后就清除了。 目前Java内存马具体分类&#xff1a; 1、传统Web应用型内存马 Servlet型内存马&#xff1a;…

探索EasyCVR视频融合平台:在视频编解码与转码领域的灵活性优势

随着视频监控技术的飞速发展&#xff0c;各类应用场景对视频数据的处理需求日益复杂多样。从公共安全到智慧城市&#xff0c;再到工业监控&#xff0c;高效、灵活的视频处理能力成为衡量视频融合平台性能的重要标准。在众多解决方案中&#xff0c;EasyCVR视频融合平台凭借其在视…

Java面试题之JVM20问

1、说说 JVM 内存区域 这张图就是一个 JVM 运行时数据图&#xff0c;「紫色区域代表是线程共享的区域」&#xff0c;JAVA 程序在运行的过程中会把他管理的内存划分为若干个不同的数据区域&#xff0c;「每一块儿的数据区域所负责的功能都是不同的&#xff0c;他们也有不同的创建…