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

目录

一、前言

二、桌面摄像头软件

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.mfbz.cn/a/426751.html

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

相关文章

【离散化】【 树状树状 】100246 将元素分配到两个数组中

本文涉及知识点 离散化 树状树状 LeetCode 100246 将元素分配到两个数组中 给你一个下标从 1 开始、长度为 n 的整数数组 nums 。 现定义函数 greaterCount &#xff0c;使得 greaterCount(arr, val) 返回数组 arr 中 严格大于 val 的元素数量。 你需要使用 n 次操作&#x…

Network LSA 结构简述

Network LSA主要用于描述一个区域内的网络拓扑结构&#xff0c;包括网络中的路由器和连接到这些路由器的网络。它记录了每个路由器的邻居关系、连接状态以及连接的度量值&#xff08;如带宽、延迟等&#xff09;&#xff0c;以便计算最短路径和构建路由表。display ospf lsdb n…

CentOS下安装Kafka3

kafka是分布式消息队列&#xff0c;本文讲述其在centos&#xff08;centos 7.5&#xff09;下的安装。安装过程可以参考其官方文档https://kafka.apache.org/36/documentation.html 首先在官网 https://kafka.apache.org/downloads 下载Kafka二进制文件&#xff08;官网的压缩包…

WordPress免费的远程图片本地化下载插件nicen-localize-image

nicen-localize-image&#xff08;可在wordpress插件市场搜索下载&#xff09;&#xff0c;是一款用于本地化文章外部图片的插件&#xff0c;支持如下功能&#xff1a; 文章发布前通过编辑器插件本地化 文章手动发布时自动本地化 文章定时发布时自动本地化 针对已发布的文章…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于条件风险价值的虚拟电厂参与能量及备用市场的双层随机优化》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 这篇文章的标题涉及到以下几个关键点…

数字革命的浪潮:Web3如何改变一切

随着数字技术的不断发展&#xff0c;人类社会正迎来一场前所未有的数字革命浪潮。在这个浪潮中&#xff0c;Web3技术以其去中心化、安全、透明的特性&#xff0c;正在逐渐改变着我们的生活方式、商业模式以及社会结构。本文将深入探讨Web3技术如何改变一切&#xff0c;以及其所…

【学习心得】请求参数加密的原理与逆向思路

一、什么是请求参数加密&#xff1f; 请求参数加密是JS逆向反爬手段中的一种。它是指客户端&#xff08;浏览器&#xff09;执行JS代码&#xff0c;生成相应的加密参数。并带着加密后的参数请求服务器&#xff0c;得到正常的数据。 常见的被加密的请求参数sign 它的原理和过程图…

【C语言】【洛谷】P1125笨小猴

一、个人解答 #include<stdio.h> #include<string.h>int prime(int num);int main() {char max a, min z;int maxn0, minn1000;char str[100];int num[26] { 0 };fgets(str, sizeof(str), stdin);str[strcspn(str, "\n")] \0;for (int i 0; str[i]…

ABAP - SALV 教程15 用户点击按钮交互功能

SALV增加了按钮&#xff0c;那么该怎么实现点击了按钮实现交互功能呢&#xff1f;可以通过注册事件并且在对应的method中写入相关逻辑&#xff0c;来实现点击按钮后的逻辑。通过自定义状态栏的方式添加按钮&#xff1a;http://t.csdnimg.cn/lMF16通过使用派生类的方式添加按钮&…

【MetaGPT】配置教程

MetaGPT配置教程&#xff08;使用智谱AI的GLM-4&#xff09; 文章目录 MetaGPT配置教程&#xff08;使用智谱AI的GLM-4&#xff09;零、为什么要学MetaGPT一、配置环境二、克隆代码仓库三、设置智谱AI配置四、 示例demo&#xff08;狼羊对决&#xff09;五、参考链接 零、为什么…

java学习(常用类)

一、包装类&#xff08;针对八种基本数据类型相应的引用类型--包装类. 1)包装类和基本数据类型的相互转换 装箱&#xff1a;基本类型->包装类型 拆箱&#xff1a;包装类型->基本类型 //以下是int类型和char类型演示。 public class temp1 {public static void main(St…

【Web - 框架 - Vue】随笔 - 通过CDN的方式使用VUE 2.0和Element UI

通过CDN的方式使用VUE 2.0和Element UI - 快速上手 VUE 网址 https://cdn.bootcdn.net/ajax/libs/vue/2.7.16/vue.js源码 https://download.csdn.net/download/HIGK_365/88815507测试 代码 <!DOCTYPE html> <html lang"en"> <head><meta …

C语言基础(五)——结构体与C++引用

七、结构体与C引用 7.1 结构体的定义、初始化、结构体数组 C 语言提供结构体来管理不同类型的数据组合。通过将不同类型的数据组合成一个整体&#xff0c;方便引用 例如&#xff0c;一名学生有学号、姓 名、性别、年龄、地址等属性&#xff0c;如果针对学生的学号、姓名、年龄…

VMware 虚拟机安装windows 10操作系统

先提前准备好镜像文件 1.创建新的虚拟机 2.选择自定义&#xff0c;然后下一步 v Windows 建议选择2G以上&#xff0c;下一步 选择网络地址转换&#xff08;NAT&#xff09;&#xff0c;下一步 这里可按自己的需求来分区&#xff0c;也可以安装好后再分区 选择立即重启&#xff…

【计算机毕业设计】208基于SSM的在线教育网站

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Redis高并发高可用详解

Redis高并发高可用 复制 在分布式系统中为了解决单点问题&#xff0c;通常会把数据复制多个副本部署到其他机器&#xff0c;满足故障恢复和负载均衡等需求。Redis也是如此&#xff0c;它为我们提供了复制功能&#xff0c;实现了相同数据的多个Redis 副本。复制功能是高可用Re…

Effective objective-c-- 内存管理

Effective objective-c-- 内存管理 前言理解引用计数引用计数工作原理属性存取方法中的内存管理自动释放池保留环要点 以ARC简化引用计数使用ARC时必须遵循的方法和命名规则变量的内存管理语义ARC如何清理实例变量覆写内存管理方法要点 在dealloc方法中只释放引用并解除监听要点…

【数据分享】2000~2022年中国区域MOD16A2GF V061 潜在蒸散发PET数据

各位同学们好&#xff0c;今天和大伙儿分享的是2000~2022年中国区域MOD16A2GF V061 潜在蒸散发PET数据。如果大家有下载处理数据等方面的问题&#xff0c;您可以私信或者评论。 Running, S., Mu, Q., Zhao, M., Moreno, A. (2021). MODIS/Terra Net Evapotranspiration Gap-Fil…

[JavaWeb玩耍日记]HTML+CSS+JS快速使用

目录 一.标签 二.指定css 三.css选择器 四.超链接 五.视频与排版 六.布局测试 七.布局居中 八.表格 九.表单 十.表单项 十一.JS引入与输出 十二.JS变量&#xff0c;循环&#xff0c;函数 十三.Array与字符串方法 十四.自定义对象与JSON 十五.BOM对象 十六.获取…

模型部署 - onnx 的导出和分析 -(1) - PyTorch 导出 ONNX - 学习记录

onnx 的导出和分析 一、PyTorch 导出 ONNX 的方法1.1、一个简单的例子 -- 将线性模型转成 onnx1.2、导出多个输出头的模型1.3、导出含有动态维度的模型 二、pytorch 导出 onnx 不成功的时候如何解决2.1、修改 opset 的版本2.2、替换 pytorch 中的算子组合2.3、在 pytorch 登记&…
最新文章