Python-PyQt5树莓派上位机

Python-PyQt5树莓派上位机

一个使用PythonQT设计的树莓派的上位机,功能大概如下
1.笔记本电脑与树莓派的通讯是否成功显示(给个信号显示判断是否通讯成功);
2.阈值的设置显示;
3.图像成像的显示;
4.是否发生火灾报警显示。
5.当前像素灰度值最大值和最小值显示。
6.对以上主要信息数据(时间年月日时分秒信息、阈值数据、灰度值最大值和最小值、是否发生火灾报警信息)的采集保存,用excel或txt存就行。

界面AppView.py

import sys

from PyQt5.QtWidgets import (QApplication, QWidget, QLabel, QPushButton, QLineEdit, QGroupBox, QVBoxLayout,
                             QHBoxLayout, QTextEdit)
from PyQt5.QtCore import Qt


class AppView(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # 最外层的水平布局
        hboxlayout = QHBoxLayout()

        # 最右侧的按钮以及信息显示
        rvboxlayout = QVBoxLayout()

        # 左侧的图像部分
        lvboxlayout = QVBoxLayout()

        # 创建分组框
        connection_group = QGroupBox("TCP 连接")
        threshold_group = QGroupBox("阈值设置")
        image_group = QGroupBox("图像显示")
        # interval_group = QGroupBox("时间间隔设置")
        alarm_group = QGroupBox("火灾报警状态")
        data_group = QGroupBox("数据操作")

        # 分组框布局
        connection_layout = QVBoxLayout()
        threshold_layout = QVBoxLayout()
        image_layout = QVBoxLayout()
        interval_layout = QVBoxLayout()
        alarm_layout = QVBoxLayout()
        data_layout = QVBoxLayout()

        # TCP连接部分
        self.ip_input = QLineEdit()
        self.port_input = QLineEdit()
        self.connect_button = QPushButton('连接')
        self.connection_status = QLabel('连接状态: 未连接')
        connection_layout.addWidget(QLabel('IP 地址:'))
        connection_layout.addWidget(self.ip_input)
        connection_layout.addWidget(QLabel('端口号:'))
        connection_layout.addWidget(self.port_input)
        connection_layout.addWidget(self.connect_button)
        connection_layout.addWidget(self.connection_status)
        connection_group.setLayout(connection_layout)

        # 阈值设置部分
        self.threshold_input = QLineEdit()
        self.set_threshold_button = QPushButton('设置阈值')
        self.min_max_label = QLabel('最小值: 0   最大值: 255')
        self.threshold_value_label = QLabel('当前阈值: 0')
        threshold_layout.addWidget(QLabel('阈值:'))
        threshold_layout.addWidget(self.min_max_label)  # 显示最小值和最大值
        threshold_layout.addWidget(self.threshold_input)
        threshold_layout.addWidget(self.set_threshold_button)
        threshold_layout.addWidget(self.threshold_value_label)
        threshold_group.setLayout(threshold_layout)

        # 图像显示部分
        self.image_label = QLabel('图像显示区域')
        self.image_label.setFixedSize(800, 600)
        self.image_label.setAlignment(Qt.AlignCenter)  # 图像居中显示
        self.image_label.setScaledContents(True)  # 图像缩放以填充整个 QLabel 区域
        image_layout.addWidget(self.image_label)
        # self.min_max_label = QLabel('最小值: 0   最大值: 255')
        # image_layout.addWidget(self.min_max_label)  # 显示最小值和最大值
        image_group.setLayout(image_layout)

        # 时间间隔设置部分
        # self.interval_input = QLineEdit()
        # self.set_interval_button = QPushButton('设置间隔')
        # interval_layout.addWidget(QLabel('时间间隔 (ms):'))
        # interval_layout.addWidget(self.interval_input)
        # interval_layout.addWidget(self.set_interval_button)
        # interval_group.setLayout(interval_layout)

        # 火灾报警状态
        self.alarm_status = QLabel('火灾报警状态: 无')
        alarm_layout.addWidget(self.alarm_status)
        alarm_group.setLayout(alarm_layout)

        # 数据操作部分
        self.save_button = QPushButton('保存数据')
        self.data_display = QTextEdit()
        data_layout.addWidget(self.save_button)
        data_layout.addWidget(QLabel('数据日志:'))
        data_layout.addWidget(self.data_display)
        data_group.setLayout(data_layout)

        # 添加分组框到栅格布局
        rvboxlayout.addWidget(connection_group)
        rvboxlayout.addWidget(threshold_group)
        # rvboxlayout.addWidget(interval_group)
        rvboxlayout.addWidget(alarm_group)
        rvboxlayout.addWidget(data_group)
        hboxlayout.addWidget(image_group)
        hboxlayout.addLayout(rvboxlayout)

        # 设置外层布局
        self.setLayout(hboxlayout)
        self.setWindowTitle('火灾监控系统 by WJF and PHL')
        self.resize(1200, 800)  # 调整窗口初始大小


if __name__ == '__main__':
    app = QApplication(sys.argv)
    view = AppView()
    view.show()
    sys.exit(app.exec_())

image-20240108143645838

布局大概如下

image-20240108144201361

最外面是一个QHBoxLayout水平布局将图像显示和信息显示和设置区域分成左右两部分

最右边是一个QVBoxLayout垂直布局从上到下分别是

threshold_group = QGroupBox("阈值设置")
image_group = QGroupBox("图像显示")
alarm_group = QGroupBox("火灾报警状态")
data_group = QGroupBox("数据操作")

服务器端RaspberryPiServer.py

import pickle
import socket
import struct
import threading

import cv2

class RaspberryPiServer:
    def __init__(self, host, port):
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.bind((host, port))

        self.server_socket.listen(1)
        print(f"服务器启动,监听 {host}:{port}")
        self.minthreshold = 25
        self.maxthreshold = 150
        self.isFire = True
        self.threshold = 50  # 示例阈值
        self.capture = cv2.VideoCapture(0)  # 打开默认摄像头

    def set_threshold(self, threshold):
        try:
            self.threshold = int(threshold)
            print(f'阈值已设置为: {self.threshold}')
        except ValueError:
            print('无效的阈值')

    def encode_image(self):  # 图像编码
        ret, frame = self.capture.read()
        cv2.waitKey(1)
        if ret:
            _, img_encoded = cv2.imencode('.jpg', frame)
            return img_encoded.tobytes()
        return None

    def send_data(self, client_socket):  # 发送数据
        image_data = self.encode_image()
        if image_data:
            data = {"image": image_data, "threshold": self.threshold, "isFire": self.isFire, "minthreshold": self.minthreshold, "maxthreshold": self.maxthreshold}
            packed_data = pickle.dumps(data)
            client_socket.sendall(struct.pack(">L", len(packed_data)))
            client_socket.sendall(packed_data)
            client_socket.recv(1024)  # 等待客户端确认

    def handle_client(self, client_socket):
        while True:
            try:
                # 发送图像数据
                self.send_data(client_socket)

                # 非阻塞地检查是否有来自客户端的数据
                client_socket.settimeout(0.1)  # 设置短暂超时
                try:
                    request = client_socket.recv(1024).decode()
                    if request.startswith("SET_THRESHOLD"):
                        new_threshold = request.split(":")[1]
                        self.set_threshold(new_threshold)
                except socket.timeout:
                    pass  # 没有接收到数据,继续下一次循环
            except Exception as e:
                print(f"处理客户端请求时出错: {e}")
                break
        client_socket.close()

    def start(self):
        while True:
            client_socket, addr = self.server_socket.accept()
            print(f"接收到来自 {addr} 的连接")
            threading.Thread(target=self.handle_client, args=(client_socket,)).start()

if __name__ == '__main__':
    server = RaspberryPiServer('127.0.0.1', 6958)
    server.start()

首先是构造方法

创建了TCP的Socket对象用于网络通信

设置了一些默认的阈值

创建了VideoCapture对象用于读取摄像头的图像

    def __init__(self, host, port):
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.bind((host, port))
        self.server_socket.listen(1)
        print(f"服务器启动,监听 {host}:{port}")
        self.minthreshold = 25
        self.maxthreshold = 150
        self.isFire = True
        self.threshold = 50  # 示例阈值
        self.capture = cv2.VideoCapture(0)  # 打开默认摄像头
set_threshold方法

用于设置阈值,仅仅为模拟,如果需要设置其他值可以拓展修改此方法

    def set_threshold(self, threshold):
        try:
            self.threshold = int(threshold)
            print(f'阈值已设置为: {self.threshold}')
        except ValueError:
            print('无效的阈值')
encode_image方法

用于将图像编码成字节流

    def encode_image(self):  # 图像编码
        ret, frame = self.capture.read()# 读取图像
        cv2.waitKey(1) #  延迟一毫秒
        if ret: # 读取成功
            _, img_encoded = cv2.imencode('.jpg', frame) # 编码成.jpg格式
            return img_encoded.tobytes() # 变成字节流
        return None
send_data方法

用于发送数据

def send_data(self, client_socket):  # 发送数据
    image_data = self.encode_image() # 将图片编码
    if image_data:# 如果有图片数据
        # 将图片和阈值鞥数据一起发送
        data = {"image": image_data, "threshold": self.threshold, "isFire": self.isFire, "minthreshold": self.minthreshold, "maxthreshold": self.maxthreshold}
        packed_data = pickle.dumps(data)
        client_socket.sendall(struct.pack(">L", len(packed_data)))
        client_socket.sendall(packed_data)
        client_socket.recv(1024)  # 等待客户端确认
  1. pickle.dumps(data):
    • pickle是Python中用于序列化和反序列化对象结构的模块。
    • dumps函数将Python对象(如字典、列表等)转换成字节流,以便可以通过网络发送。
    • data是需要被发送的原始数据。
  2. struct.pack(">L", len(packed_data)):
    • struct模块在Python中用于处理字节和Python基本数据类型之间的转换。
    • pack函数将Python数据(此处为数据长度)打包为结构化的二进制格式。
    • ">L"是格式字符串,表示“大端序”(网络字节序)的无符号长整型。
    • len(packed_data)是获取序列化后数据的长度。
  3. client_socket.sendall(struct.pack(">L", len(packed_data))):
    • 这里client_socket是一个TCP套接字对象,用于网络通信。
    • sendall方法用于发送数据。在这里,它发送的是打包后的数据长度信息。
  4. client_socket.sendall(packed_data):
    • 再次使用sendall方法,这次是发送实际的序列化数据。
  5. client_socket.recv(1024):
    • recv方法用于接收数据。这里指定了最大接收数据的大小为1024字节。
    • 这行代码通常用于等待并接收来自客户端的响应或确认。
handle_client方法
 def handle_client(self, client_socket):
        while True:
            try:
                # 发送图像数据
                self.send_data(client_socket)

                # 非阻塞地检查是否有来自客户端的数据
                client_socket.settimeout(0.1)  # 设置短暂超时
                try:
                    request = client_socket.recv(1024).decode() # 解码
                    if request.startswith("SET_THRESHOLD"): 
                        new_threshold = request.split(":")[1]
                        self.set_threshold(new_threshold)
                except socket.timeout:
                    pass  # 没有接收到数据,继续下一次循环
            except Exception as e:
                print(f"处理客户端请求时出错: {e}")
                break
        client_socket.close()
start方法
def start(self):
    while True:
        client_socket, addr = self.server_socket.accept()
        print(f"接收到来自 {addr} 的连接")
        threading.Thread(target=self.handle_client, args=(client_socket,)).start()

AppModel.py

import socket
import struct
import pickle
import cv2
import numpy as np

class AppModel:
    def __init__(self):
        self.client_socket = None
        self.connected = False

    def connect(self, ip, port):
        try:
            self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.client_socket.connect((ip, int(port)))
            self.connected = True
            return "连接成功"
        except Exception as e:
            return f"连接失败: {e}"

    def receiveData(self):
        try:
            data_size = struct.unpack(">L", self.client_socket.recv(4))[0]
            received_payload = b""
            remaining_size = data_size
            while remaining_size > 0:
                received_payload += self.client_socket.recv(remaining_size)
                remaining_size = data_size - len(received_payload)

            data = pickle.loads(received_payload)
            if data:
                image_data = data["image"]
                image = cv2.imdecode(np.frombuffer(image_data, np.uint8), cv2.IMREAD_COLOR)
                threshold = data["threshold"]
                isFire = data["isFire"]
                minthreshold = data["minthreshold"]
                maxthreshold = data["maxthreshold"]
                self.client_socket.sendall(b"ack")
                return image, threshold, isFire, minthreshold, maxthreshold
            return None, None, None, None, None
        except Exception as e:
            return None, None, None, None, None

    def disconnect(self):
        if self.client_socket:
            self.client_socket.close()
            self.connected = False
connect方法
def connect(self, ip, port):
        try:
            self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.client_socket.connect((ip, int(port)))
            self.connected = True
            return "连接成功"
        except Exception as e:
            return f"连接失败: {e}"
  1. def connect(self, ip, port):
    • 这是一个定义在类中的方法,self代表类的实例。
    • ipport是方法的参数,分别表示要连接的服务器的IP地址和端口号。
  2. tryexcept Exception as e:
    • 这是Python中的异常处理结构。try块中的代码是可能会引发异常的代码,而except块用于处理异常。
    • 如果try块中的代码运行出错,程序执行将跳转到except块。
  3. self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM):
    • 这行代码创建了一个新的套接字对象。
    • socket.AF_INET 表示该套接字用于IPv4地址。
    • socket.SOCK_STREAM 表示该套接字是基于流的TCP协议。
  4. self.client_socket.connect((ip, int(port))):
    • 使用connect方法来建立到指定IP地址和端口的TCP连接。
    • ip是目标服务器的IP地址,int(port)将端口号转换为整数。
  5. self.connected = True:
    • 这行代码设置一个实例变量(或称为属性)connectedTrue,通常用于表示连接已成功建立。
  6. return "连接成功":
    • 如果连接建立成功,方法返回一个字符串表示成功。

receiveData方法

def receiveData(self):
    try:
        data_size = struct.unpack(">L", self.client_socket.recv(4))[0]
        received_payload = b""
        remaining_size = data_size
        while remaining_size > 0:
            received_payload += self.client_socket.recv(remaining_size)
            remaining_size = data_size - len(received_payload)

        data = pickle.loads(received_payload)
        if data:
            image_data = data["image"]
            image = cv2.imdecode(np.frombuffer(image_data, np.uint8), cv2.IMREAD_COLOR)
            threshold = data["threshold"]
            isFire = data["isFire"]
            minthreshold = data["minthreshold"]
            maxthreshold = data["maxthreshold"]
            self.client_socket.sendall(b"ack")
            return image, threshold, isFire, minthreshold, maxthreshold
        return None, None, None, None, None
    except Exception as e:
        return None, None, None, None, None

接收数据长度

  • data_size = struct.unpack(">L", self.client_socket.recv(4))[0]
    

    :

    • self.client_socket.recv(4):从TCP套接字接收前4个字节。这四个字节通常包含了随后要接收的数据的长度。
    • struct.unpack(">L", ...):使用struct模块解析这4个字节。">L"表示使用大端序格式解析一个无符号长整型。
    • data_size存储后续数据的总字节大小。

接收数据主体

  • received_payload = b""
    • 初始化一个空字节对象received_payload,用于累积接收到的数据。
  • 循环while remaining_size > 0
    • 循环直到所有预定长度的数据被接收完毕。
  • received_payload += self.client_socket.recv(remaining_size)
    • 从套接字接收数据,追加到received_payload。每次调用recv最多接收remaining_size指定的字节数。
  • remaining_size = data_size - len(received_payload)
    • 更新剩余要接收的数据的字节数。这是为了处理TCP流式传输中可能出现的数据分片情况。

处理接收到的数据

  • data = pickle.loads(received_payload)

    • 使用pickle.loads将接收到的字节流反序列化为原始Python对象。这意味着发送方用pickle.dumps序列化了数据。
  • 提取和处理数据:

    • 如果

      data
      

      不为空,则提取数据中的字段:

      • image_data = data["image"]:提取图像数据。
      • image = cv2.imdecode(np.frombuffer(image_data, np.uint8), cv2.IMREAD_COLOR):将图像数据转换为OpenCV可处理的图像格式。
      • threshold, isFire, minthreshold, maxthreshold:提取其他相关数据。
  • self.client_socket.sendall(b"ack")

    • 发送确认消息(ack)回发送方,表示数据已成功接收。

返回值

  • return image, threshold, isFire, minthreshold, maxthreshold
    

    return None, None, None, None, None
    

    • 如果数据成功接收并处理,返回提取的值;如果出现异常或数据为空,返回一系列None

AppController.py

import sys
from datetime import datetime

from PyQt5.QtWidgets import QApplication, QMessageBox
from PyQt5.QtCore import pyqtSignal, QThread, Qt
from AppView import AppView
from AppModel import AppModel
import numpy as np
from PyQt5.QtGui import QImage, QPixmap

class DataReceiverThread(QThread):
    dataReceived = pyqtSignal(list)


    def __init__(self, model):
        super().__init__()
        self.model = model
        self.isRunning = True

    def run(self):
        while self.isRunning:
            image, threshold, isFire, minthreshold, maxthreshold = self.model.receiveData()
            if image is not None and threshold is not None:
                self.dataReceived.emit([image, threshold, isFire, minthreshold, maxthreshold])

    def stop(self):
        self.isRunning = False
        self.wait()

class AppController:
    def __init__(self, view):
        self.view = view
        self.model = AppModel()
        self.dataReceiverThread = None
        self.view.connect_button.clicked.connect(self.connectToRaspberry)
        self.view.save_button.clicked.connect(self.save_data)
        self.view.set_threshold_button.clicked.connect(self.send_threshold_to_raspberry)
        self.view.ip_input.setText("127.0.0.1")
        self.view.port_input.setText("6958")
        self.last_log_time = datetime.now()  # 初始化上次记录日志的时间
    def connectToRaspberry(self):
        ip = self.view.ip_input.text()
        port = self.view.port_input.text()
        result = self.model.connect(ip, port)
        self.view.connection_status.setText(f"连接状态: {result}")
        if result == "连接成功":
            QMessageBox.information(self.view, "连接状态", "连接成功!", QMessageBox.Ok)
            # by WJF and PHL
            QMessageBox.information(self.view, "作者", "WJF and PHL!", QMessageBox.Ok)
            self.dataReceiverThread = DataReceiverThread(self.model)
            self.dataReceiverThread.dataReceived.connect(self.updateData)
            self.dataReceiverThread.start()

    def updateData(self, receivedData: list):
        image = receivedData[0]
        threshold = receivedData[1]
        isFire = receivedData[2]
        minthreshold = receivedData[3]
        maxthreshold = receivedData[4]
        height, width, channel = image.shape
        bytesPerLine = 3 * width

        qImg = QImage(image.data, width, height, bytesPerLine, QImage.Format_RGB888).rgbSwapped()
        pixmap = QPixmap.fromImage(qImg)
        # 确定QLabel的大小
        label_size = self.view.image_label.size()

        # 调整图像大小以填充QLabel
        scaled_pixmap = pixmap.scaledToWidth(label_size.width(), Qt.SmoothTransformation)
        # 或者使用 scaledToHeight:
        # scaled_pixmap = pixmap.scaledToHeight(label_size.height(), Qt.SmoothTransformation)

        # 将调整大小后的图像设置到QLabel
        self.view.image_label.setPixmap(scaled_pixmap)
        self.view.image_label.setPixmap(pixmap)
        self.view.threshold_value_label.setText(f'当前阈值: {threshold}')
        self.view.alarm_status.setText(f'火灾报警状态: {isFire}')
        self.view.min_max_label.setText(f'最小值: {minthreshold}   最大值: {maxthreshold}')
        self.add_log_entry(threshold, isFire, minthreshold, maxthreshold)

    def add_log_entry(self, threshold, isFire, minthreshold, maxthreshold):
        current_time = datetime.now()
        if (current_time - self.last_log_time).total_seconds() > 5:  # 比如每10秒记录一次
            self.last_log_time = current_time  # 更新上次记录日志的时间

            # 获取当前日志框中的文本
            current_text = self.view.data_display.toPlainText()

            # 获取当前时间戳
            timestamp = current_time.strftime("%Y-%m-%d %H:%M:%S")

            # 创建要添加的新日志条目
            new_log_entry = (f'[{timestamp}] 当前阈值: {threshold} \n '
                             f'火灾报警状态: {isFire}\n'
                             f'最小值: {minthreshold}   最大值: {maxthreshold}\n')

            # 将新日志条目添加到当前文本后面
            self.view.data_display.setPlainText(current_text + new_log_entry)

    def save_data(self):
        # 获取文本编辑框中的文本
        data = self.view.data_display.toPlainText()
        # 获取当前时间戳来命名文件
        timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
        file_name = f"log_{timestamp}.txt"
        # 打开文件以保存数据(这里示意保存到文件)
        with open(f'./log/{file_name}', 'w') as file:
            file.write(data)

    def disconnectFromRaspberry(self):
        if self.dataReceiverThread:
            self.dataReceiverThread.stop()
        self.model.disconnect()

    def send_threshold_to_raspberry(self):
        threshold = self.view.threshold_input.text()
        if self.model.connected:
            try:
                self.model.client_socket.sendall(f"SET_THRESHOLD:{threshold}".encode())
                print(f'已发送阈值: {threshold}')
            except Exception as e:
                print(f'发送阈值失败: {e}')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    view = AppView()
    controller = AppController(view)
    view.show()
    sys.exit(app.exec_())

DataReceiverThread(数据接收线程)

  • 继承自QThread,用于在后台接收数据。
  • dataReceived = pyqtSignal(list):定义一个信号,当接收到数据时发射。
  • __init__(self, model):构造函数,接收一个模型对象(model),用于调用数据接收方法。
  • run(self):重写QThreadrun方法,在一个循环中调用模型的receiveData方法接收数据,然后通过dataReceived信号发送数据。
  • stop(self):停止线程的方法。

AppController(应用控制器)

  • __init__(self, view):构造函数,初始化视图(view),模型(model),以及数据接收线程(dataReceiverThread)。设置按钮的点击事件和初始值。
  • connectToRaspberry(self):处理连接到树莓派的逻辑,启动数据接收线程。
  • updateData(self, receivedData):接收到数据后的处理方法。更新GUI的不同部分,如图像显示和状态标签。
  • add_log_entry(self, ...):添加日志条目到文本框。
  • save_data(self):将日志数据保存到文本文件。
  • disconnectFromRaspberry(self):处理从树莓派断开连接的逻辑。
  • send_threshold_to_raspberry(self):向树莓派发送阈值设置的方法。

主程序入口

  • if __name__ == '__main__':这是Python程序的标准入口点。
  • 创建QApplicationAppView实例,并显示视图。
  • 创建AppController实例,将视图传递给控制器。
  • 启动事件循环。

run方法,在一个循环中调用模型的receiveData方法接收数据,然后通过dataReceived`信号发送数据。

  • stop(self):停止线程的方法。

AppController(应用控制器)

  • __init__(self, view):构造函数,初始化视图(view),模型(model),以及数据接收线程(dataReceiverThread)。设置按钮的点击事件和初始值。
  • connectToRaspberry(self):处理连接到树莓派的逻辑,启动数据接收线程。
  • updateData(self, receivedData):接收到数据后的处理方法。更新GUI的不同部分,如图像显示和状态标签。
  • add_log_entry(self, ...):添加日志条目到文本框。
  • save_data(self):将日志数据保存到文本文件。
  • disconnectFromRaspberry(self):处理从树莓派断开连接的逻辑。
  • send_threshold_to_raspberry(self):向树莓派发送阈值设置的方法。

主程序入口

  • if __name__ == '__main__':这是Python程序的标准入口点。
  • 创建QApplicationAppView实例,并显示视图。
  • 创建AppController实例,将视图传递给控制器。
  • 启动事件循环。

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

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

相关文章

9.建造者模式

文章目录 一、介绍二、代码三、实际使用总结 一、介绍 建造者模式旨在将一个复杂对象的构建过程和其表示分离,以便同样的构建过程可以创建不同的表示。这种模式适用于构建对象的算法(构建过程)应该独立于对象的组成部分以及它们的装配方式的…

学习笔记——C++二维数组

二维数组定义的四种方式: 1,数据类型 数组名[ 行数 ][ 列数 ]; 2,数据类型 数组名[ 行数 ][ 列数 ]{{数据1,数据2},{数据3,数据4}}; 3,数据类型 数组名[ 行数…

【计算机网络】TCP原理 | 可靠性机制分析(二)

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程、计算机网络的一点学习心得,欢迎大家在评论区交流讨论💌 T…

如何做好档案统一管理?

档案统一管理是指将一个组织或机构的所有档案资料进行集中管理和整理的一种管理方式。档案统一管理的目标是确保档案的完整性、准确性和可访问性,提高档案的利用价值和管理效率。 要做好档案统一管理,需要以下几个步骤: 1. 确定档案的分类与命…

【S32K 进阶之旅】 NXP S32K3 以太网 RMII 接口调试(2)

前言 前文介绍了 NXP S32K3 以太网 RMII 接口调试的开发环境搭建,下面开始详解软件调试步骤。没看过第一节的小伙伴请移步《【S32K 进阶之旅】 NXP S32K3 以太网 RMII 接口调试(1)》,话不多说我们直接进入正题。 lwip Stack 介绍 …

debug OpenBLAS library 和 应用示例

1. 构建openblas lib git clone gitgithub.com:OpenMathLib/OpenBLAS.git cd OpenBLAS/ 如果要安装在自定义文件夹中,可以修改 PREFIX 的定义: 将 PREFIX /opt/OpenBLAS 修改成 PREFIX ../local/ 然后构建: make -j make install 如果要…

09.面向对象进阶

面向对象进阶 在前面的章节我们已经了解了面向对象的入门知识,知道了如何定义类,如何创建对象以及如何给对象发消息。为了能够更好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程进行更为深入的了解。 property装…

OpenAI ChatGPT-4开发笔记2024-03:Chat之Tool和Tool_Call(含前function call)

Updates on Function Calling were a major highlight at OpenAI DevDay. In another world,原来的function call都不再正常工作了,必须全部重写。 function和function call全部由tool和tool_choice取代。2023年11月之前关于function call的代码都准备翘翘。 干嘛…

考公还是互联网?

来源 花了 10 小时检索,汇总的有效信息 V2EX,牛客,Google,Bing,广东省人事考试网,国家公务员局,B站,小红书,知乎,掘金,Github,公务员…

Rollup-plugin-bundle-analyzer VS Rollup-plugin-visualizer

分析和可视化Rollup打包后的文件的插件 Rollup-plugin-bundle-analyzerRollup-plugin-visualizer Rollup-plugin-bundle-analyzer和Rollup-plugin-visualizer都是用于分析和可视化Rollup打包后的文件的插件,但它们在功能和使用方式上存在一些差异。 Rollup-plugi…

低成本高回报:如何利用免版素材库提升设计品质?

免版素材库起源于互联网的发展,是指一种包含大量图片、图标、字体等创意资源的网站或平台,这些资源多为设计师和相关行业人士创作,并免费提供给用户使用。免版素材库的资源通常遵循一定的授权协议,如CC0(Creative Comm…

Python pip 常用指令

前言 Python的pip是一个强大的包管理工具,它可以帮助我们安装、升级和管理Python的第三方库。以下是一些常用的pip指令。 1. 安装第三方库 使用pip安装Python库非常简单,只需要使用pip install命令,后面跟上库的名字即可。 # 安装virtuale…

【leetcode 447. 回旋镖的数量】审慎思考与推倒重来

447. 回旋镖的数量 题目描述 给定平面上 **n **对 互不相同 的点 points ,其中 points[i] [xi, yi] 。回旋镖 是由点 (i, j, k) 表示的元组 ,其中 i 和 j 之间的距离和 i 和 k 之间的欧式距离相等(需要考虑元组的顺序)。 返回平…

加速科技ST2500 数模混合信号测试设备累计装机量突破500台!

国产数字机,测试中国芯!新年伊始,国产半导体测试设备领军企业加速科技迎来了振奋人心的一刻,ST2500 数模混合信号测试设备累计装机量突破500台!加速科技凭借其持续的创新能力、完善的解决方案能力、专业热忱的本地化服…

企业级快速开发平台可以用在什么行业?优点多吗?

应用专业的企业级快速开发平台可以带来什么效果?目前,低代码技术平台在很多领域都获得了广泛应用和推广,在实现高效率办公、流程化办公和数字化发展中扮演了非常重要的角色,具有举足轻重的作用。针对这个话题,现在将给…

外汇天眼:台北妇女轻信假投资诈骗话术,小赚1万却惨赔1500万

当今社会物价急速上涨,许多民众为了避免资产因通膨缩水,纷纷开始寻找各种能增加收入的渠道,因此投资理财日渐受到重视。 然而,诈骗集团也注意到这趋势,并且推出虚假的投资平台或方案,以各种话术行骗。 不久…

【css】快速实现鼠标悬浮变色效果

<div class"nav-item"><div class"ic-img"></div><div>切换</div> </div>.nav-item {width: 100rem;height: 45rem;line-height: 45rem;display: flex;text-align: center;justify-content: center;align-items: cent…

用python提取word中的所有图片

使用word中提取的方式图片会丢失清晰度&#xff0c;使用python写一个脚本&#xff0c;程序运行将弹出对话框选择一个word文件&#xff0c;然后在弹出一个对话框选择一个文件夹保存word中的文件。将该word中的所有图片都保存成png格式&#xff0c;并命名成image_i的样式。 程序…

go image.DecodeConfig 和image.Decode 不能同时使用吗

问题场景&#xff1a;在同时使用go image.DecodeConfig 和image.Decode获取图片信息时&#xff0c;报错提示&#xff1a; 无法读取图像配置 image: unknown format package mainimport ("fmt""github.com/golang/freetype""image""image/d…

软件压测工具有哪些功能和特点

目前市场上有许多成熟的压测工具&#xff0c;开发人员可以根据自己的项目特点和需求选择合适的工具进行压力测试。本文将介绍软件压测工具的功能和特点&#xff1a; 一、软件压测工具定义 软件压测工具是一种专门设计用于模拟大量用户并发访问系统的工具。通过模拟真实场景中的…