Python——桌面摄像头软件(附源码+打包)

news2024/9/24 3:25:44

目录

一、前言

二、桌面摄像头软件

2.1、下载项目

2.2、功能介绍

三、打包工具(nuitka)

 四、项目文件复制(我全部合到一个文件里面了)

五、结语


一、前言

看见b站的向军大叔用electron制作了一个桌面摄像头软件

但是,我不怎么熟悉前端,自己就用pyside6简单制作一个

二、桌面摄像头软件

2.1、下载项目

软件下载地址:(下载后,双击即可运行——60MB左右)

https://wwm.lanzout.com/ibIEL1q0xt8d
密码:eg34

工程文件下载地址:

camera-python.zip - 蓝奏云

启动项目:

# 下载包
pip install -r requirements.txt

# 运行项目
python main.py

2.2、功能介绍

启动后,会自动打开默认摄像头

基础操作

左键长按:拖拽移动

滚轮上下滑动:放大和缩小摄像头画面

右键设置操作

选择边框颜色(rgb格式)

选择摄像头(自由切换)

窗口变形(正方形窗口和圆形窗口的切换)

隐藏

退出

系统托盘(可右键选择隐藏或出现,以及退出)

三、打包工具(nuitka)

 Python——Windows使用Nuitka2.0打包(保姆级教程)-CSDN博客

我的打包命令:

 

nuitka --mingw64 --show-progress --standalone --disable-console --enable-plugin=pyside6 --plugin-enable=numpy --onefile --remove-output --windows-icon-from-ico=logo.ico camera.py

 四、项目文件复制(我全部合到一个文件里面了)

# -*- coding: utf-8 -*-
# @Author : pan
import time
import cv2
import numpy as np

from PySide6.QtCore import (Qt, QTimer, QPropertyAnimation, QEasingCurve,
                            QParallelAnimationGroup, QThread, QMutex,
                            Signal, Slot, QCoreApplication, QDate, QDateTime,
                            QLocale, QMetaObject, QObject, QPoint, QRect,
                            QSize, QTime, QUrl, QAbstractAnimation, QEvent)
from PySide6.QtGui import (QPixmap, QPainter, QColor, QFontMetrics, QPen,
                           QWheelEvent, QCursor, QAction, QImage, QPainterPath,
                           QBrush, QConicalGradient, QFont, QFontDatabase,
                           QGradient, QIcon, QKeySequence, QLinearGradient,
                           QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QWidget, QLabel, QMenu, QDialog,
                               QVBoxLayout, QLineEdit, QPushButton, QMessageBox,
                               QInputDialog, QFrame, QHBoxLayout, QLayout,
                               QSizePolicy, QSpacerItem, QSystemTrayIcon)



# 提示组件
class Toast(QWidget):
    def __init__(
        self,
        text: str,
        duration: int = 3000,
        parent: QWidget = None,
    ):
        super().__init__(parent)
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setAttribute(Qt.WA_TranslucentBackground, True)
        self.duration = duration

        label = QLabel(self)
        label.setText(text)
        label.setStyleSheet("""
            background-color: rgba(60, 179, 113, 0.8);
            color: white;
            font-size: 16px;
            padding: 12px;
            border-radius: 4px;
        """)
        label.setAlignment(Qt.AlignCenter)

        fm = QFontMetrics(label.font())
        width = fm.boundingRect(text).width() + 80

        # 高度与宽度
        label.setFixedWidth(width)
        label.setFixedHeight(40)

        self.setGeometry(*self.calculatePosition(label.sizeHint()))



        self.fadeIn()

        self.animationTimer = QTimer()

        self.animationTimer.timeout.connect(self.fadeOut)
        self.animationTimer.start(self.duration)

    def calculatePosition(self, sizeHint):
        if self.parent() is not None:
            # 如果存在父窗口,计算使Toast窗口相对于父窗口居中的位置
            x = self.parent().width() / 2 - sizeHint.width()/2
            y = 10

        else:
            # 如果没有父窗口,计算使Toast窗口相对于屏幕居中的位置
            desktopRect = QApplication.primaryScreen().availableGeometry()
            x = (desktopRect.width() - sizeHint.width()) // 2
            y = (desktopRect.height() - sizeHint.height()) // 2
        return x, y, sizeHint.width(), sizeHint.height()

    def fadeIn(self):
        # 创建并设置淡入动画
        fadeInAnimation = QPropertyAnimation(self, b"windowOpacity", self)
        fadeInAnimation.setStartValue(0)
        fadeInAnimation.setEndValue(1)
        fadeInAnimation.setDuration(500)
        fadeInAnimation.finished.connect(lambda: print('加载成功'))
        # 启动淡入动画
        fadeInAnimation.start()

        print('in')

    # 淡出动画
    def fadeOut(self):
        print('out')
        # 停止计时器
        self.animationTimer.stop()
        # 断开计时器的超时信号与当前方法的连接
        self.animationTimer.timeout.disconnect(self.fadeOut)

        # 创建并设置并行动画组
        self.parallelAnimation = QParallelAnimationGroup()

        # 创建并设置不透明度动画
        self.opacityAnimation = QPropertyAnimation(self, b"windowOpacity")
        self.opacityAnimation.setStartValue(1.0)
        self.opacityAnimation.setEndValue(0.0)
        self.opacityAnimation.setDuration(500)

        # 创建并设置位置动画
        self.yAnimation = QPropertyAnimation(self, b"geometry")
        targetY = self.y() - 10
        self.yAnimation.setStartValue(self.geometry())
        self.yAnimation.setEndValue(self.geometry().translated(0, targetY))
        self.yAnimation.setDuration(500)
        self.yAnimation.setEasingCurve(QEasingCurve.OutCubic)

        # 将动画添加到并行动画组中
        self.parallelAnimation.addAnimation(self.opacityAnimation)
        self.parallelAnimation.addAnimation(self.yAnimation)

        # 连接并行动画组的完成信号与关闭窗口的槽
        self.parallelAnimation.finished.connect(self.close)

        # 启动动画组
        self.parallelAnimation.start(QAbstractAnimation.DeleteWhenStopped)


    def paintEvent(self, event):
        painter = QPainter(self)
        painter.fillRect(self.rect(), QColor(0, 0, 0, 0))

    def mousePressEvent(self, event):
        pass

# 弹窗 输入框
class Ui_InputColor(QWidget):
    textEntered = Signal(str)  # 定义一个带有字符串参数的信号

    def __init__(self):
        super().__init__()
        self.drag_position = None


    def setupUi(self, Form):

        Form.setObjectName("Form")  # 直接设置对象名称
        Form.resize(200, 70)

        # 设置背景颜色和透明度
        Form.setWindowFlags(Qt.FramelessWindowHint)  # 设置无边框窗口
        Form.setAttribute(Qt.WA_TranslucentBackground)  # 设置窗口透明

        self.bg_gray = QFrame(Form)
        self.bg_gray.setObjectName(u"bg_gray")
        self.bg_gray.setGeometry(QRect(0, 0, 200, 65))
        self.bg_gray.setStyleSheet(u".QFrame{\n"
"	background-color: rgb(234,236,243);\n"
"	border-radius:5px;\n"
"}")
        self.bg_gray.setFrameShape(QFrame.StyledPanel)
        self.bg_gray.setFrameShadow(QFrame.Raised)
        self.verticalLayout_3 = QVBoxLayout(self.bg_gray)
        self.verticalLayout_3.setSpacing(0)
        self.verticalLayout_3.setObjectName(u"verticalLayout_3")
        self.verticalLayout_3.setContentsMargins(10, 11, 4, 11)
        self.verticalLayout_2 = QVBoxLayout()
        # 设置右侧边距为5px
        self.verticalLayout_2.setContentsMargins(0, 0, 7, 0)

        self.verticalLayout_2.setObjectName(u"verticalLayout_2")
        self.window_top = QHBoxLayout()
        self.window_top.setSpacing(10)
        self.window_top.setObjectName(u"window_top")
        self.window_top.setSizeConstraint(QLayout.SetFixedSize)
        self.window_top.setContentsMargins(0, 0, 0, 0)
        self.text_title = QLabel(self.bg_gray)
        self.text_title.setObjectName(u"text_title")
        self.text_title.setStyleSheet(u"    font-size: 9pt;\n"
"    font-family: \"\u5fae\u8f6f\u96c5\u9ed1\";\n"
"    color: #333;\n"
"font-weight: bold;")

        self.window_top.addWidget(self.text_title)

        self.h_spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)

        self.window_top.addItem(self.h_spacer)

        self.btn_min = QPushButton(self.bg_gray)
        self.btn_min.setObjectName(u"btn_min")
        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.btn_min.sizePolicy().hasHeightForWidth())
        self.btn_min.setSizePolicy(sizePolicy)
        self.btn_min.setMaximumSize(QSize(10, 10))
        self.btn_min.setStyleSheet(u"QPushButton {\n"
"    background-color: #07BB2C;\n"
"    border: 2px solid #07BB2C;\n"
"    color: #3498db;\n"
"    padding: 1px;\n"
"    border-radius: 5px;\n"
"}\n"
" \n"
"QPushButton:hover {\n"
"    background-color: #09ED3A;\n"
"    color: #ffffff;\n"
"}")

        self.window_top.addWidget(self.btn_min)

        self.btn_max = QPushButton(self.bg_gray)
        self.btn_max.setObjectName(u"btn_max")
        self.btn_max.setMaximumSize(QSize(10, 10))
        self.btn_max.setStyleSheet(u"QPushButton {\n"
"    background-color: #FFB206;\n"
"    border: 2px solid #FFB206;\n"
"    color: #3498db;\n"
"    padding: 1px;\n"
"    border-radius: 5px;\n"
"}\n"
" \n"
"QPushButton:hover {\n"
"    background-color: #FFC033;\n"
"    color: #ffffff;\n"
"}")

        self.window_top.addWidget(self.btn_max)

        self.btn_stop = QPushButton(self.bg_gray)
        self.btn_stop.setObjectName(u"btn_stop")

        self.btn_stop.clicked.connect(self.hide)  # 关联关闭窗口事件

        self.btn_stop.setMaximumSize(QSize(10, 10))
        self.btn_stop.setStyleSheet(u"\n"
"\n"
"QPushButton {\n"
"    background-color: #EE514A;\n"
"    border: 2px solid #EE514A;\n"
"    color: #3498db;\n"
"    padding: 1px;\n"
"    border-radius: 5;\n"
"}\n"
" \n"
"QPushButton:hover {\n"
"    background-color: #F1756F;\n"
"    color: #ffffff;\n"
"}")

        self.window_top.addWidget(self.btn_stop)


        self.verticalLayout_2.addLayout(self.window_top)

        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.lineEdit = QLineEdit(self.bg_gray)
        self.lineEdit.setObjectName(u"lineEdit")

        self.horizontalLayout.addWidget(self.lineEdit)

        self.b_submit = QPushButton(self.bg_gray)

        self.b_submit.clicked.connect(self.emitSignal)  # 点击按钮时连接到发射信号的方法

        self.b_submit.setObjectName(u"b_submit")
        self.b_submit.setMinimumSize(QSize(0, 0))
        self.b_submit.setStyleSheet(u"            QPushButton {\n"
"                border-style: solid;\n"
"                border-width: 2px;\n"
"                border-radius: 15px;\n"
"                border-color: rgb(88, 180, 107);\n"
"                font-size: 7pt;\n"
"                font-weight: bold;\n"
"                padding: 2px;\n"
"                background-color: rgb(88, 180, 107);\n"
"                color: rgb(255, 255, 255);\n"
"            }\n"
"            QPushButton:hover {\n"
"                border-color: rgb(100, 100, 100);\n"
"                background-color: rgb(183, 255, 189);\n"
"				color: rgb(88, 180, 107);\n"
"            }\n"
"            QPushButton:pressed {\n"
"                border-color: rgb(42, 42, 42);\n"
"                background-color: rgb(160, 255, 163);\n"
"				color: rgb(88, 180, 107);\n"
"            }")

        self.horizontalLayout.addWidget(self.b_submit)


        self.verticalLayout_2.addLayout(self.horizontalLayout)


        self.verticalLayout_3.addLayout(self.verticalLayout_2)


        self.retranslateUi(Form)

        QMetaObject.connectSlotsByName(Form)
    # setupUi

    @Slot()
    def emitSignal(self):
        text = self.lineEdit.text()
        self.textEntered.emit(text)  # 发射信号,并传递lineEdit中的文本

    def retranslateUi(self, Form):
        Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
        self.text_title.setText(QCoreApplication.translate("Form", u"\u8bf7\u8f93\u5165\u8272\u53f7", None))
        self.btn_min.setText("")
        self.btn_max.setText("")
        self.btn_stop.setText("")
        self.lineEdit.setPlaceholderText(QCoreApplication.translate("Form", u"255,255,255", None))
        self.b_submit.setText(QCoreApplication.translate("Form", u"\u786e\u8ba4", None))
    # retranslateUi
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_position = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
            event.accept()

    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton and self.drag_position:
            self.move(event.globalPosition().toPoint() - self.drag_position)
            event.accept()

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_position = None
            event.accept()


# 摄像头检测类
class Camera:
    def __init__(self, cam_preset_num=5):
        self.cam_preset_num = cam_preset_num

    def get_cam_num(self):
        cnt = 0
        devices = []
        for device in range(0, self.cam_preset_num):
            stream = cv2.VideoCapture(device, cv2.CAP_DSHOW)
            grabbed = stream.grab()
            stream.release()
            if not grabbed:
                continue
            else:
                cnt = cnt + 1
                devices.append(device)
        return cnt, devices

# 摄像头线程
class CameraThread(QThread):
    change_pixmap_signal = Signal(np.ndarray)

    def __init__(self, device_id=0):
        super().__init__()
        self.device_id = device_id
        self.is_paused = False
        self.mutex = QMutex()
        self.exiting = False
        self.cap = None

    def run(self):
        self.cap = cv2.VideoCapture(self.device_id)
        while not self.exiting:
            self.mutex.lock()
            if not self.is_paused:
                ret, frame = self.cap.read()
                if ret:
                    self.change_pixmap_signal.emit(frame)
                else:
                    break
            self.mutex.unlock()

        self.cap.release()
        self.cap = None

    def set_device_id(self, device_id):
        self.device_id = device_id

    def pause(self):
        self.mutex.lock()
        self.is_paused = True
        self.mutex.unlock()

    def resume(self):
        self.mutex.lock()
        self.is_paused = False
        self.mutex.unlock()

    def stop(self):
        self.exiting = True
        self.wait()

    def set_device_id(self, device_id):
        self.device_id = device_id

    def stop(self):
        self.exiting = True

# 主窗口
class MyWindow(QWidget):

    def __init__(
            self,
            text: str,
            parent: QWidget = None,
    ):
        super().__init__(parent)
        # 设置窗口属性
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setAttribute(Qt.WA_TranslucentBackground, True)

        # 窗口大小
        self.size = 200
        self.color = "255,255,255"

        self.window_shape = 0  # 0是圆

        # 子线程
        self.camera_thread = CameraThread()
        self.camera_thread.change_pixmap_signal.connect(self.image_data_slot)
        self.camera_thread.start()

        self.select_camera = False
        self.input_color_window = None

        # 创建标签并设置样式
        self.label = QLabel(self)
        self.label.setText(text)
        self.reset_style()  # 样式刷新
        self.label.setAlignment(Qt.AlignCenter)
        # 设置标签尺寸
        self.label.setAlignment(Qt.AlignCenter)
        self.label.setFixedSize(self.size, self.size)  # 设置标签的宽度和高度

        # 设置窗口位置
        self.setGeometry(*self.calculatePosition(self.label.sizeHint()))

        self.fadeIn()

    def fadeIn(self):
        # 创建并设置淡入动画
        fadeInAnimation = QPropertyAnimation(self, b"windowOpacity", self)
        fadeInAnimation.setStartValue(0)
        fadeInAnimation.setEndValue(1)
        fadeInAnimation.setDuration(500)
        fadeInAnimation.finished.connect(lambda: print('窗口 加载成功'))
        # 启动淡入动画
        fadeInAnimation.start()

    # 出现在屏幕居中的位置
    def calculatePosition(self, sizeHint):
        desktopRect = QApplication.primaryScreen().availableGeometry()
        x = (desktopRect.width() - sizeHint.width()) // 2
        y = (desktopRect.height() - sizeHint.height()) // 2
        return x, y, sizeHint.width(), sizeHint.height()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.fillRect(self.rect(), QColor(0, 0, 0, 0))

    def image_data_slot(self, image_data):

        if self.select_camera is True:
            self.label.clear()
            self.label.setText('请重新选择摄像头')
            return

        self.image = cv2.cvtColor(image_data, cv2.COLOR_BGR2RGB)
        height, width, channel = self.image.shape
        bytesPerLine = 3 * width
        image = QImage(self.image.data, width, height, bytesPerLine, QImage.Format_RGB888)

        # 将图片先裁剪为正方形
        width = image.width()
        height = image.height()
        size = min(width, height)
        square_image = image.copy((width - size) // 2, (height - size) // 2, size, size)

        # 计算缩放比例
        new_size = self.size - 10
        label_size = self.label.sizeHint()
        scaled_image = square_image.scaled(new_size, new_size, Qt.KeepAspectRatio)

        # 将 QImage 转换为 QPixmap
        pixmap = QPixmap.fromImage(scaled_image)

        # 创建一个圆形路径
        path = QPainterPath()
        path.addEllipse(0, 0, new_size, new_size)

        # 创建一个与 scaled_image 大小相同的的 QPixmap
        result_pixmap = QPixmap(new_size, new_size)
        result_pixmap.fill(Qt.transparent)

        # 在 result_pixmap 上绘制圆形图像
        painter = QPainter(result_pixmap)
        if self.window_shape == 0:
            painter.setClipPath(path)  # 设置裁剪路径
        painter.setRenderHint(QPainter.Antialiasing)  # 设置抗锯齿
        painter.drawPixmap(0, 0, pixmap)  # 绘制原始图像

        painter.end()
        # 在 label 上显示圆形图像
        self.label.setPixmap(result_pixmap)

    def reset_style(self, flag=1):
        try:
            if flag == 0:
                r = 0
            else:
                r = self.size / 2
            self.label.setStyleSheet(f"""
            font-family: Arial, sans-serif; /* 设置字体 */
            font-size: 12pt; /* 设置字体大小 */

            background-color: rgb({self.color}); /* 设置背景颜色为红色 */
            padding: 0px; 
            border-radius: {r}; /* 设置圆角大小为宽度的一半 */
                    """)
        except Exception as e:
            print(e)


    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_position = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
            event.accept()

        # 右键 打开菜单
        if event.button() == Qt.RightButton:

            menu = QMenu(self)
            set_color_action = menu.addAction("设置边框色")
            set_camera_action = menu.addAction("选择摄像头")
            set_camera_shape = menu.addAction('圆形窗口') if self.window_shape == 1 else menu.addAction('正方形窗口')
            set_hide_action = menu.addAction("隐藏")
            set_quit_action = menu.addAction("退出")
            # 修改 exec_ 弃用警告
            action = menu.exec(self.mapToGlobal(event.position().toPoint()))


            if action == set_color_action:
                # 打开窗口 Ui_InputColor
                self.open_input_color_window()
            # 获取目前所有摄像头的设备号,然后把设备号弄成一个菜单,让用户选择
            if action == set_camera_action:
                self.select_camera = True

                # 如果有摄像头在运行
                if self.camera_thread.cap is not None:
                    # 这里给我绘制一个标签,等待2s再消失
                    self.toast = Toast("正在关闭摄像头中", 1000, self)
                    self.toast.show()
                    time.sleep(1)
                    self.camera_thread.stop()  # 停止摄像头播放
                    return

                # 检测摄像头可用设备,把设备号弄成一个菜单,让用户选择
                # 获取本地摄像头数量
                _, cams = Camera().get_cam_num()
                popMenu = QMenu()
                popMenu.setFixedWidth(110)
                popMenu.setStyleSheet('''
                    QMenu {
                    font-size: 9px;
                    font-family: "Microsoft YaHei UI";
                    font-weight: light;
                    color:white;
                    padding-left: 5px;
                    padding-right: 5px;
                    padding-top: 4px;
                    padding-bottom: 4px;
                    border-style: solid;
                    border-width: 0px;
                    border-color: rgba(255, 212, 255, 255);
                    border-radius: 3px;
                    background-color: rgba(16,155,226,50);
                    }''')
                for cam in cams:
                    action = QAction(f'{cam} 号摄像头')
                    popMenu.addAction(action)
                pos = QCursor.pos()
                action = popMenu.exec(pos)

                # 设置摄像头来源
                if action:
                    str_temp = ''
                    selected_stream_source = str_temp.join(filter(str.isdigit, action.text()))  # 获取摄像头号,去除非数字字符
                    self.toast = Toast(f"摄像头设备是:{selected_stream_source}", 1000, self)
                    self.toast.show()
                    self.select_camera = False

                    self.camera_thread = CameraThread()
                    self.camera_thread.device_id = int(selected_stream_source)
                    self.camera_thread.change_pixmap_signal.connect(self.image_data_slot)
                    self.camera_thread.start()

            # 切换窗口
            if action == set_camera_shape:
                #
                if self.window_shape == 1:
                    self.window_shape = 0 # 切换为圆形
                    self.reset_style()  # 切换为圆形


                else:
                    self.window_shape = 1
                    self.reset_style(flag=0)  # 背景 变成正方形
            # 隐藏
            if action == set_hide_action:
                self.hide()

            # 退出
            if action == set_quit_action:
                self.close()


    # 颜色设置
    def colorEntered(self, text):
        print(1)
        # TODO 数据处理
        self.color = text
        self.reset_style()
        self.input_color_window.hide()

    #  打开窗口 Ui_InputColor
    def open_input_color_window(self):
        if self.input_color_window is None:  # 只有当窗口对象尚未创建时才创建它
            self.input_color_window = Ui_InputColor()
            self.input_color_window.setupUi(self.input_color_window)
            self.input_color_window.setWindowFlag(Qt.FramelessWindowHint)  # 设置窗口标志:隐藏窗口边框
            self.input_color_window.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)  # 设置窗口标志位

            self.input_color_window.textEntered.connect(self.colorEntered)  # 连接子窗口的信号和父窗口的槽

        # 窗口显示在父窗口的中心
        self.input_color_window.move(
            self.x() + (self.width() - self.input_color_window.width()) / 2,
            self.y() + (self.height() - self.input_color_window.height()) / 2
        )
        self.input_color_window.show()

    def mouseMoveEvent(self, event):

        # 左键 移动创建
        if event.buttons() == Qt.LeftButton:
            self.move(event.globalPosition().toPoint() - self.drag_position)
            event.accept()

    def mouseReleaseEvent(self, event):
        self.drag_position = None

    # 窗口大小变换
    def row_event(self, up=0, down=0):
        self.size = self.size + up
        self.size = self.size - down
        if self.window_shape == 1:
            self.reset_style(flag=0)  # 背景 变成正方形
        else:
            self.reset_style()  # 切换为圆形

        self.label.setFixedSize(self.size, self.size)  # 设置标签的宽度和高度
        self.setFixedSize(self.size, self.size)

    def event(self, event):
        if event.type() == QWheelEvent.Wheel:
            # 阻止默认的滚动行为
            event.ignore()

            # 获取滚动方向和距离
            delta = event.angleDelta().y() / 120

            # 根据滚动方向和距离执行相应操作
            if delta < 0:
                # 向下滚动(触发两次 因为背景上有bug
                self.row_event(down=1)
                self.row_event(down=1)
            else:
                # 向上滚动(触发两次 因为背景上有bug
                self.row_event(up=1)
                self.row_event(up=1)

            return True
        return super().event(event)


if __name__ == "__main__":
    app = QApplication([])

    # 创建系统托盘图标
    tray_icon = QSystemTrayIcon(QIcon("logo.jpg"), parent=app)
    tray_icon.setToolTip("Camera By Pan")

    # 创建并设置托盘图标的右键菜单
    menu = QMenu()
    show_action = menu.addAction("出现")     # 让window窗口出现
    hide_action = menu.addAction("隐藏")     # 让window窗口隐藏
    exit_action = menu.addAction("退出")
    tray_icon.setContextMenu(menu)
    # 显示托盘图标
    tray_icon.show()

    window = MyWindow("Camera Software By Pan")
    # 使窗口不在任务栏出现
    window.setWindowFlags(window.windowFlags() | Qt.Tool)  # 或者使用 Qt.SubWindow,根据你的需求和测试结果选择
    # 注意:
    # 使用Qt.Tool标志会使得窗口不在任务栏显示,这对于某些辅助工具或临时窗口是有用的。
    # 然而,这种改变也可能影响窗口的关闭行为和资源管理,尤其是在与系统托盘图标交互的上下文中。
    # 这导致我在关闭子窗口的时候,会导致程序崩溃!!!
    # 这导致我在关闭子窗口的时候,会导致程序崩溃!!!
    # 这导致我在关闭子窗口的时候,会导致程序崩溃!!!

    window.show()

    # 连接信号到槽函数
    exit_action.triggered.connect(app.quit)
    show_action.triggered.connect(window.show)
    hide_action.triggered.connect(window.hide)

    app.exec()


五、结语

  • 如果你有任何问题,欢迎在评论区留言,我会尽快回复。
  • 很久没有碰pyside6,而且学的很浅显,写了屎山代码
  • 目前只能保证功能实现,里面还有一些小bug
  • 但是不影响正常使用,就这样吧~

PS:其实我只是想自己拿来用用

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

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

相关文章

【应用多元统计分析】--多元数据的直观表示(R语言作图)

例1.2 为了研究全国31个省、市、自治区2018年城镇居民生活消费的分布规律&#xff0c;根据调查资料做区域消费类型划分。 指标&#xff1a; 食品x1&#xff1a;人均食品支出(元/人) 衣着x2&#xff1a;人均衣着商品支出(元/人) 居住x3&#xff1a;人均居住支出(元/人) 生活x4…

ssh无法直接登入Linux超级用户root(23/3/3更新)

说明&#xff1a;不允许ssh用超级用户的身份登入是为了安全性&#xff0c;如果只是学习使用对安全性没啥要求可以按以下操作解除限制 以普通用户登录到服务器后&#xff0c;执行以下命令以编辑 SSH 服务器配置文件 /etc/ssh/sshd_config sudo nano /etc/ssh/sshd_config 此时会…

二极管原理及典型应用电路、三极管基本结构及类型状态

目录 二极管原理及典型应用电路 二极管的工作原理 二极管保护电路 二极管整流电路 二极管稳压电路 三极管基本结构及类型状态 三极管基本结构和类型 三极管的 3 种工作状态 二极管原理及典型应用电路 如下图&#xff0c;二极管长成这样。它们通常有一个黑色圆柱体&am…

【大厂AI课学习笔记NO.60】(13)模型泛化性的评价

我们学习了过拟合和欠拟合&#xff0c;具体见我的文章&#xff1a;https://giszz.blog.csdn.net/article/details/136440338 那么今天&#xff0c;我们来学习模型泛化性的评价。 泛化性的问题&#xff0c;我们也讨论过了&#xff0c;那么如何评价模型的泛化性呢&#xff1f; …

论文精读--GPT3

不像GPT2一样追求zero-shot&#xff0c;而换成了few-shot Abstract Recent work has demonstrated substantial gains on many NLP tasks and benchmarks by pre-training on a large corpus of text followed by fine-tuning on a specific task. While typically task-agnos…

二十四、剖析 ArrayDeque

文章目录 剖析 ArrayDeque3.1 循环数组3.2 构造方法3.3 从尾部添加 addLast(E)3.4 从头部添加 addFirst(E)3.5 从头部和尾部删除3.6 查看长度 size()3.7 检查给定元素是否存在3.8 toArray3.9 ArrayDeque 特点分析 剖析 ArrayDeque 本文为书籍《Java编程的逻辑》1和《剑指Java&…

Unity UGUI之Slider基本了解

在Unity中&#xff0c;Slider&#xff08;滑动条&#xff09;是一种常用的用户界面控件之一&#xff0c;允许用户通过拖动滑块来选择一个数值。常常应用于调节数值&#xff08;如调节音量、亮度、游戏难度等&#xff09;、设置选项等。 以下是Slider的基本信息和用法: 1、创建…

Neoverse CSS N3:实现市场领先能效的最快途径

区分老的架构 从云到边缘&#xff0c;Arm Neoverse 提供无与伦比的性能、效率、设计灵活性和 TCO 优势&#xff0c;正在颠覆传统基础设施芯片。 我们看到云和超大规模服务运营商正在推动更高的计算密度。随着 128 核心 CPU 设计上市&#xff08;Microsoft Cobalt、阿里巴巴 Y…

工作微信统一管理(还带监管功能)

1.会话页面(可统一管理多个微信号、聚合聊天、手动搜索添加好友、通过验证请求、查看好友的朋友圈等) 2.聊天历史(可查看 所有聊天记录&#xff0c;包括手机.上撤回、删除的消息) 3.群发助手(可以一 -次群发多个好友和群&#xff0c;还可以选择定时发送&#xff0c;目前还在内测…

postman传参与返回值切换为左右显示的操作

目录 第一步 点击“Settings”&#xff0c;在下拉框选择“Settings” 第二步 在默认打开的General页面&#xff0c;参照下图改动两处 第一步 点击“Settings”&#xff0c;在下拉框选择“Settings” 第二步 在默认打开的General页面&#xff0c;参照下图改动两处 附上修改后…

Mysql深入学习 基础篇 Ss.02 详解四类SQL语句

我亲爱的对手&#xff0c;亦敌亦友&#xff0c;但我同样希望你能成功&#xff0c;与我一起&#xff0c;站在人生的山顶上 ——24.3.1 一、DDL 数据定义语言 1.DDL —— 数据库操作 查询 查询所有数据库 show databases; 查询当前数据库 select database(); 创建 create databa…

Linux:kubernetes(k8s)部署CNI网络插件(4)

在上一章进行了node加入master Linux&#xff1a;kubernetes&#xff08;k8s&#xff09;node节点加入master主节点&#xff08;3&#xff09;-CSDN博客https://blog.csdn.net/w14768855/article/details/136420447?spm1001.2014.3001.5501 但是他们显示还是没准备好 看一下…

linux安全--DNS欺骗,钓鱼网站搭建

目录 一&#xff0c;实验准备 首先让client能上网 1&#xff09;实现全网互通&#xff0c;实现全网互通过程请看 2&#xff09;SNAT源地址转换 3&#xff09;部署DHCP服务 4)配置DHCP服务 5&#xff09;启动服务 6&#xff09;安装DNS服务 7&#xff09;DNS配置 8)启动DNS…

数据结构c版(3)——排序算法

本章我们来学习一下数据结构的排序算法&#xff01; 目录 1.排序的概念及其运用 1.1排序的概念 1.2 常见的排序算法 2.常见排序算法的实现 2.1 插入排序 2.1.1基本思想&#xff1a; 2.1.2直接插入排序&#xff1a; 2.1.3 希尔排序( 缩小增量排序 ) 2.2 选择排序 2.2…

Java两周半速成之路(第九天)

一.Object类 1.概述&#xff1a; Object类&#xff1a;是java中所有的类共同的父类 1、观察包所属后发现&#xff0c;Object类属于java.lang包下的类&#xff0c;今后使用的时候&#xff0c;不需要进行导包 2.构造方法 Object() 无参构造方法 3.Object类的成员方法 (1)…

C语言数组作为函数参数

有两种情形&#xff1b; 一种是数组元素作为函数实参&#xff1b;一种是数组名作为函数参数&#xff1b; 新建一个VC6单文档工程&#xff1b; void printshz(int , CDC* , int , int ); double getav(int a[5]); ...... void CShzcshView::OnDraw(CDC* pDC) {CShzcshDoc* pDo…

pycharm 自定义TODO类注释以及其高亮颜色

大体介绍 使用自定义TODO是为了方便看&#xff0c;并且快速定位到位置 上面是为了进行标记&#xff0c;下面是让哪些标记可以过滤掉&#xff08;自定义过滤规则&#xff09;&#xff0c;从而在pycharm下面的TODO可以显示并过滤 如何设置&#xff1f; Setting-Preferences-Ed…

华为配置攻击检测功能示例

配置攻击检测功能示例 组网图形 图1 配置攻击检测功能示例组网图 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件 业务需求 企业用户通过WLAN接入网络&#xff0c;以满足移动办公的最基本需求。且在覆盖区域内移动发生漫游时&#xff0c;不影响用户的业务使用。…

AutoSar PWM配置详解

背景 芯片:AURIX TC3xx 软件:Vector DaVinci CFG(简称达芬奇) 目标:配置AURIX TC3xx的P34.4脚为30HZ的PWM输出 配置过程 1.AUTOSAR架构 下图显示了PWM在AUTOSAR架构中的位置&#xff0c;在MCAL区。 2.Port模块配置 主要配置Port的输出模式与输出类型。 查看手册 配置P…