基于PyQt5的图形化界面开发——自制MQTT客户端软件

news2024/11/16 5:29:18

基于 PyQt5 的图形化界面开发——自制MQTT客户端

  • 0. 前言
  • 1. 第三方库的安装及注意事项
  • 2. Editor.py
    • 2.1 配置界面效果演示:
  • 3. Publish.py
    • 3.1 消息发布界面演示
  • 4. Subcribe.py
    • 4.1 订阅消息效果演示:
  • 界面切换——main.py
  • 5. 写在最后

0. 前言

使用 PyQt5 练习写图形化界面,目标是写出一个使用MQTT协议通信的界面,包含 编辑配置、消息发布、消息订阅 三个功能。

操作系统:windows10 专业版
开发环境:Pycharm Conmunity 2022.3
Python版本:Python3.8
第三方库:PyQt5、paho

1. 第三方库的安装及注意事项

需要安装第三方库 PyQt5paho

如果你还不会安装第三方库,你可以参考我的这篇文章学习
Python第三方库安装——使用vscode、pycharm安装Python第三方库

注意!!! 工程结构必须如下:

在这里插入图片描述

2. Editor.py

编辑配置界面代码如下:

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

# Form implementation generated from reading ui file 'Editor.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# 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(641, 409)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(490, 290, 93, 28))
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(260, 100, 171, 21))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_2.setGeometry(QtCore.QRect(260, 130, 91, 21))
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(180, 100, 51, 20))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(190, 130, 51, 20))
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(170, 160, 81, 20))
        self.label_3.setObjectName("label_3")
        self.lineEdit_3 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_3.setGeometry(QtCore.QRect(260, 160, 171, 21))
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.splitter = QtWidgets.QSplitter(self.centralwidget)
        self.splitter.setGeometry(QtCore.QRect(170, 20, 279, 28))
        self.splitter.setOrientation(QtCore.Qt.Horizontal)
        self.splitter.setObjectName("splitter")
        self.pushButton_3 = QtWidgets.QPushButton(self.splitter)
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_4 = QtWidgets.QPushButton(self.splitter)
        self.pushButton_4.setObjectName("pushButton_4")
        self.pushButton_5 = QtWidgets.QPushButton(self.splitter)
        self.pushButton_5.setObjectName("pushButton_5")
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(230, 220, 131, 20))
        self.label_4.setText("")
        self.label_4.setObjectName("label_4")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 641, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "编辑配置"))
        self.pushButton.setText(_translate("MainWindow", "保存配置"))
        self.label.setText(_translate("MainWindow", "Broker"))
        self.label_2.setText(_translate("MainWindow", "Port"))
        self.label_3.setText(_translate("MainWindow", "Client ID"))
        self.pushButton_3.setText(_translate("MainWindow", "消息订阅"))
        self.pushButton_4.setText(_translate("MainWindow", "消息发布"))
        self.pushButton_5.setText(_translate("MainWindow", "编辑配置"))

2.1 配置界面效果演示:

在这里插入图片描述

点击保存配置后将生成一个config.json文件,下一次将不需要重新配置,将默认匹配填充配置文件中的字段。

注意,此时最上方的界面切换函数并没有添加切换功能

3. Publish.py

发布消息界面代码如下:

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

# Form implementation generated from reading ui file 'Publish.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# 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(641, 409)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(490, 290, 93, 28))
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(260, 100, 171, 21))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_2.setGeometry(QtCore.QRect(260, 130, 171, 21))
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(200, 100, 41, 20))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(200, 130, 51, 20))
        self.label_2.setObjectName("label_2")
        self.splitter = QtWidgets.QSplitter(self.centralwidget)
        self.splitter.setGeometry(QtCore.QRect(170, 20, 279, 28))
        self.splitter.setOrientation(QtCore.Qt.Horizontal)
        self.splitter.setObjectName("splitter")
        self.pushButton_3 = QtWidgets.QPushButton(self.splitter)
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_4 = QtWidgets.QPushButton(self.splitter)
        self.pushButton_4.setObjectName("pushButton_4")
        self.pushButton_5 = QtWidgets.QPushButton(self.splitter)
        self.pushButton_5.setObjectName("pushButton_5")
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(230, 220, 211, 20))
        self.label_4.setText("")
        self.label_4.setObjectName("label_4")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(490, 70, 93, 28))
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 641, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "消息发布"))
        self.pushButton.setText(_translate("MainWindow", "发布"))
        self.label.setText(_translate("MainWindow", "Topic"))
        self.label_2.setText(_translate("MainWindow", "Info"))
        self.pushButton_3.setText(_translate("MainWindow", "消息订阅"))
        self.pushButton_4.setText(_translate("MainWindow", "消息发布"))
        self.pushButton_5.setText(_translate("MainWindow", "编辑配置"))
        self.pushButton_2.setText(_translate("MainWindow", "连接服务器"))

3.1 消息发布界面演示

使用前需要先点击连接服务器与mqtt服务器进行连接

在这里插入图片描述

点击发布,将提示发布成功

在这里插入图片描述

使用MQTT客户端查看消息是否发布成功,如下,服务器有收到helloworld:

在这里插入图片描述
注意,此时最上方的界面切换函数并没有添加切换功能

4. Subcribe.py

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

# Form implementation generated from reading ui file '.\Subscribe.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# 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(641, 409)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(490, 290, 93, 28))
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(230, 100, 141, 21))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_2.setGeometry(QtCore.QRect(230, 140, 171, 21))
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(170, 100, 51, 20))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(170, 140, 71, 20))
        self.label_2.setObjectName("label_2")
        self.splitter = QtWidgets.QSplitter(self.centralwidget)
        self.splitter.setGeometry(QtCore.QRect(170, 20, 279, 28))
        self.splitter.setOrientation(QtCore.Qt.Horizontal)
        self.splitter.setObjectName("splitter")
        self.pushButton_3 = QtWidgets.QPushButton(self.splitter)
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_4 = QtWidgets.QPushButton(self.splitter)
        self.pushButton_4.setObjectName("pushButton_4")
        self.pushButton_5 = QtWidgets.QPushButton(self.splitter)
        self.pushButton_5.setObjectName("pushButton_5")
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(230, 220, 211, 20))
        self.label_4.setText("")
        self.label_4.setObjectName("label_4")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(490, 70, 93, 28))
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 641, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "消息发布"))
        self.pushButton.setText(_translate("MainWindow", "订阅"))
        self.label.setText(_translate("MainWindow", "Topic"))
        self.label_2.setText(_translate("MainWindow", "Receive"))
        self.pushButton_3.setText(_translate("MainWindow", "消息订阅"))
        self.pushButton_4.setText(_translate("MainWindow", "消息发布"))
        self.pushButton_5.setText(_translate("MainWindow", "编辑配置"))
        self.pushButton_2.setText(_translate("MainWindow", "连接服务器"))

订阅消息部分用到了多线程,这样做的目的是防止界面卡死,因为界面是一直在死循环中接收消息的,使用线程的好处是不会引发线程冲突,我们最后的完整代码也依旧可以自由进行界面切换。

4.1 订阅消息效果演示:

同样的需要先连接服务器,我们使用现有的MQTT客户端进行测试:

在这里插入图片描述

可以看到我们自己编写的客户端收到了消息:

在这里插入图片描述
完成子功能测试后,我们可以开始添加界面切换功能了。

界面切换——main.py

界面切换的原理其实就是在显示当前界面时,关闭或者是隐藏其他的所有界面。

例如,我们在发布消息的界面时,订阅消息和编辑配置这两个界面是隐藏起来的

上传视频有点麻烦,这里不上传演示视频了,直接上完整代码:

# code:utf-8
# Create by Maxtang
# 2023/4/21

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidgetItem
from functools import partial
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt
import time

from paho.mqtt import client as mqtt_client

import Editor
import Publish
import Subscribe

class UI_Editor(QMainWindow,Editor.Ui_MainWindow):
    def __init__(self):
        super(UI_Editor, self).__init__()
        self.setupUi(self)
        self.pushButton.clicked.connect(lambda: {self.save()})

        self.pushButton_3.clicked.connect(lambda: {self.hide(), self.change(3)})
        self.pushButton_4.clicked.connect(lambda: {self.hide(), self.change(4)})
        self.pushButton_5.clicked.connect(lambda: {self.hide(), self.change(5)})

        try:
            with open("config.json","r+") as f:
                config = eval(f.read())
                self.lineEdit.setText(config["Broker"])
                self.lineEdit_2.setText(config["Port"])
                self.lineEdit_3.setText(config["Client_ID"])
        except:
            print("[!] read config error")
            pass

    def change(self,i):
        edit = UI_Editor()
        sub = UI_Subscribe()
        pub = UI_Publish()

        if i == 3:
            sub.show()
        if i == 4:
            pub.show()
        if i == 5:
            edit.show()

    def save(self):
        try:
            Broker = self.lineEdit.text()
            Port = self.lineEdit_2.text()
            Client_ID = self.lineEdit_3.text()

            with open("config.json","w+") as f:
                f.write(str({"Broker":Broker,"Port":Port,"Client_ID":Client_ID}))
                f.close()
            self.label_4.setText("已保存配置!")
        except:
            self.label_4.setText("保存失败!")

class UI_Publish(QMainWindow,Publish.Ui_MainWindow):
    def __init__(self):
        super(UI_Publish, self).__init__()
        self.setupUi(self)
        self.pushButton.clicked.connect(lambda: {self.publish(client)})
        self.pushButton_2.clicked.connect(lambda: {self.connect()})

        self.pushButton_3.clicked.connect(lambda: {self.hide(), self.change(3)})
        self.pushButton_4.clicked.connect(lambda: {self.hide(), self.change(4)})
        self.pushButton_5.clicked.connect(lambda: {self.hide(), self.change(5)})

    def change(self,i):
        edit = UI_Editor()
        sub = UI_Subscribe()
        pub = UI_Publish()

        if i == 3:
            sub.show()
        if i == 4:
            pub.show()
        if i == 5:
            edit.show()

    def publish(self,client):
        try:
            topic = self.lineEdit.text()
            msg = self.lineEdit_2.text()

            result = client.publish(topic, msg)
            # result: [0, 1]
            status = result[0]

            if status == 0:
                print(f"Send `{msg}` to topic `{topic}`")
                self.label_4.setText("[√]发送成功")
            else:
                print(f"Failed to send message to topic {topic}")

                self.label_4.setText("[×]发送失败")
        except:
            self.label_4.setText("[!]请先连接服务器!")


    def connect(self):
        try:
            def on_connect(client, userdata, flags, rc):
                if rc == 0:
                    print("Connected to MQTT Broker!")
                else:
                    print("Failed to connect, return code %d\n", rc)

            with open("config.json", "r+") as f:
                config = eval(f.read())
                Broker = config["Broker"]
                Port = int(config["Port"])
                Client_ID = config["Client_ID"]
                print(config)
                f.close()

            global client
            client = mqtt_client.Client(Client_ID)
            client.on_connect = on_connect
            client.connect(Broker, Port)

            self.label_4.setText("[√]连接成功")

        except:
            print("[!]Connect error")
            self.label_4.setText("[×]连接失败")
            pass

class UI_Subscribe(QMainWindow,Subscribe.Ui_MainWindow):
    def __init__(self):
        from threading import Thread
        super(UI_Subscribe, self).__init__()
        self.setupUi(self)

        self.pushButton.clicked.connect(lambda: {self.subscribe(client),Thread(target=client.loop_forever).start()})
        self.pushButton_2.clicked.connect(lambda: {self.connect()})

        self.pushButton_3.clicked.connect(lambda: {self.hide(), self.change(3)})
        self.pushButton_4.clicked.connect(lambda: {self.hide(), self.change(4)})
        self.pushButton_5.clicked.connect(lambda: {self.hide(), self.change(5)})

    def change(self,i):
        edit = UI_Editor()
        sub = UI_Subscribe()
        pub = UI_Publish()

        if i == 3:
            sub.show()
        if i == 4:
            pub.show()
        if i == 5:
            edit.show()

    def subscribe(self,client):
        def on_message(client, userdata, msg):
            print("ok")
            self.lineEdit_2.setText(msg.payload.decode())
            self.label_4.setText("[√]接收成功")
            time.sleep(1)

        topic = self.lineEdit.text()

        client.subscribe(topic)
        client.on_message = on_message

        self.label_4.setText("[√]订阅成功")

    def connect(self):
        try:
            def on_connect(client, userdata, flags, rc):
                if rc == 0:
                    print("Connected to MQTT Broker!")
                else:
                    print("Failed to connect, return code %d\n", rc)

            with open("config.json", "r+") as f:
                config = eval(f.read())
                Broker = config["Broker"]
                Port = int(config["Port"])
                Client_ID = config["Client_ID"]
                print(config)
                f.close()

            global client
            client = mqtt_client.Client(Client_ID)
            client.on_connect = on_connect
            client.connect(Broker, Port)

            self.label_4.setText("[√]连接成功")
        except:
            print("[!]Connect error")
            self.label_4.setText("[×]连接失败")
            pass

app = QtWidgets.QApplication(sys.argv)
main = UI_Subscribe()
main.show()
sys.exit(app.exec_())

5. 写在最后

如果你的代码运行报错:

1. 请检查是否安装第三方库 PyQt5 和 paho
2. 工程结构是否与我一致

在这里插入图片描述

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

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

相关文章

葛兰一季度规模再度跌破900亿

一季度末管理规模再度跌破900亿元,中欧基金葛兰交出了公募主动权益基金管理规模的头把交椅。 4月22日零点刚过,葛兰在管基金悉数披露2023年一季报,从管理规模来看,一季度葛兰在管5只公募基金合计规模降至844.40亿元,较…

keep-alive 和 router-view 的使用方法(Vue3)

系列文章目录 提示:主要是介绍keep-alive 和 router-view在Vue3中的使用方法,以及适用场景!!! 文章目录 系列文章目录前言:一、router-view:1. 常规使用方法2. 非常规使用方法(插槽&…

UE5语音识别和语音合成-阿里云智能语音-短视频-翻译-文章-AI角色等

UE5智能语音 哈喽,大家好,我叫人宅,很高兴和大家一起分享本套课程,阿里云智能语音UE5版本开发。阿里云智能语音一共分为 语音合成,语音识别,什么是语音合成,它可以将您的文字转化成您设定的任何…

大数据数仓维度建模

目录 维度建模分为三种: 1、星型模型: 2、雪花模型: 3、星座模型: 模型的选择: 维度表和事实表: 维度表: 维度表特性 : 事实表: 事实表特性: 事务型…

程序员能干多久?程序员能干到多大年龄?

程序员可以工作多少年?大多数程序员认为程序员是吃青春饭的工作。编程只能干到30岁,最长可达35岁。我经常听到这样的话,都让人倍感压力。今天,我们来谈谈这个老话题...... 程序员能干多久? 根据国外的经验来说,干到…

ChatGPT 基础使用方法

文章目录 1. ChatGPT 是下一代搜索引擎2. ChatGPT 是学习助手3. ChatGPT API 简介4. ChatGPT API 身份5. 开发痛点6. 机会与前景7. Images8. Audio 1. ChatGPT 是下一代搜索引擎 根据 3 月份对 ChatGPT 的使用,我对它的理解是下一代的搜索引擎,即能够根…

【社区图书馆】读《大话数据结构溢彩加强版》

目录 书中简介: 选读原因 本书内容有哪些: 学会了什么: 书中简介: 《大话数据结构【溢彩加强版】》以一个计算机教师的教学过程为场景,讲解数据结构和相关算法的知识。全书以趣味方式来叙述,大量引用各…

无公网IP,外网远程连接MySQL数据库

哈喽~大家好,这篇来看看无公网IP,外网远程连接MySQL数据库。 文章目录 前言1. 检查mysql安装状态2. 安装配置cpolar内网穿透3. 创建tcp隧道,映射3306端口4. 公网远程连接4.1 图形化界面4.2 使用命令行远程连接 5. 配置固定tcp端口地址5.1 保留…

「计算机控制系统」6. 直接设计法

特殊类型系统的最小拍无差设计 一般系统的最小拍无差设计 最小拍控制器的工程化改进 Dahlin算法 文章目录 特殊类型系统的最小拍无差设计理论分析典型输入函数的最小拍无差系统 一般系统的最小拍无差设计有波纹最小拍无差设计无波纹最小拍无差设计 最小拍控制器的工程化改进针对…

操作HDFS文件系统常用命令(启停、创建、查看、上传、下载、追加、删除.etc)

文章目录 1 一键启停2 单进程启停3 创建文件夹4 查看指定目录下内容5 上传文件到HDFS指定目录下 linux->HDFS6 下载 HDFS ->Linux7 追加数据 linux->HDFS8 查看HDFS文件内容9 HDFS 数据删除10 网页端图形化界面11总结 跟linux命令大差不差 1 一键启停 HadoopHDFS组件…

共享锁中:Semaphore 、CyclicBarrier 、CountDownLatch的区别是什么?

目录 下面是一个使用Semaphore实现共享锁的例子: 下面是一个使用CountDownLatch实现等待一组操作完成的例子: 下面是一个使用CyclicBarrier实现等待一组线程达到某个状态后再同时执行的例子: 结论1: 结论2: 下面是…

JavaSE基础(一)—— Java环境搭建、IDEA、Java语言

【JavaSE基础回顾笔记】 JavaSE基础(一)—— Java环境搭建、IDEA、Java语言 JavaSE基础(二)—— Java语法、运算符、随机数 JavaSE基础(三)—— 分支、循环、控制关键字 JavaSE基础(四&…

Opencv+Python笔记(六)图像的平滑处理

图像在获取、传输的过程中,可能会受到干扰的影响,会产生噪声,噪声是一种出错了的信号,噪声会造成图像粗糙。 图像平滑处理的目的是去除图像中的噪声和不必要的细节,使图像更加清晰和易于分析。常用的平滑滤波器包括高斯…

无感FOC

前言 一年多前就画好了FOC的板子,后面因为各种原因耽搁了,最近又重新捡起来,准备写一下程序,首先我们要做一下FOC的理论分析。 左右手定则 左手定则用于判断导线在磁场中受力的方向: 磁感线从左手手心流入&#xff0…

前++与后++的区别?反汇编底层刨析

目录 1.只,不赋值 2.和其他运算符的结合 1.后置(i) 2.前(i) 总结 1.只,不赋值 前置和后置无区别,效果一致,i -> ii1 反汇编语言内,对a和b的操作进行观察&#…

彻底卸载Anaconda和PyCharm详细教程

目录 一、卸载Anaconda 二、 卸载PyCharm 一、卸载Anaconda 1、在开始处打开Anaconda Prompt 2、打开后,输入conda install tqdm -f命令并按回车键 conda install tqdm -f 3、之后页面会出现一个WANNING,这个我们不用在意,然后会出现一个…

GitHub新手用法详解【适合新手入门-建议收藏!!!】

目录 什么是Github,为什么使用它? 一、GitHub账号的注册与登录 二、 gitbash安装详解 1.git bash的下载与安装 2.git常用命令 3. Git 和 GitHub 的绑定 1. 获取SSH keys 2.绑定ssh密钥 三、通过Git将代码提交到GitHub 1.克隆仓库 2.测试提交代码…

ClickHouse同步MySQL数据

目录 1 概述1.1 特点1.2 使用细则 2 案例实操2.1 MySQL 开启 binlog 和 GTID 模式2.2 准备 MySQL 表和数据2.3 开启 ClickHouse 物化引擎2.4 创建复制管道2.5 修改数据2.6 删除数据2.7 删除表 1 概述 MySQL 的用户群体很大,为了能够增强数据的实时性,很多…

通过response.body()返回的json报文,直接生成对应结构体,实现数据绑定

作者:非妃是公主 专栏:《Golang》 博客地址:https://blog.csdn.net/myf_666 个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩 文章目录 序一、解决办法二、相关测试代码1. json body…

Origin选取一定间隔的数据点并作图

有些时候我们发现用origin绘制的图数据点太密,抖动太剧烈: 所以我们最好是隔几个点采样一次,方法如下。 假如我们一共有五列数据,我们再扩充六列(其中一列是放隔点采样的横坐标): 然后选中扩充…