当前位置: 首页 > news >正文

QT:一个TCP客户端自动连接的测试模型

版本 1:没有取消按钮

 测试效果:

缺陷:

无法手动停止

测试代码

CMakeLists.txt

cmake_minimum_required(VERSION 3.19)
project(AutoConnect LANGUAGES CXX)find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets Network)qt_standard_project_setup()qt_add_executable(AutoConnectWIN32 MACOSX_BUNDLEmain.cppwidget.hwidget.ui
)target_link_libraries(AutoConnectPRIVATEQt::CoreQt::WidgetsQt6::Network
)include(GNUInstallDirs)install(TARGETS AutoConnectBUNDLE  DESTINATION .RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)qt_generate_deploy_app_script(TARGET AutoConnectOUTPUT_SCRIPT deploy_scriptNO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})

main.cpp 

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket>
#include <QProgressDialog>
#include <QPushButton>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QTextBrowser>
#include <QMouseEvent>
#include <QLineEdit>
#include <QDebug>
#include <QMetaObject>
#include <QProgressBar>
#include <QTimer>class MyTextBrowser:public QTextBrowser
{
public:MyTextBrowser(QWidget *parent = nullptr):QTextBrowser(parent){}// QWidget interface
protected:virtual void mouseDoubleClickEvent(QMouseEvent *event) override{if(event->button() == Qt::LeftButton){this->clear();}}
};class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr): QWidget(parent){QVBoxLayout *root = new QVBoxLayout(this);QHBoxLayout *iplayout = new QHBoxLayout;QPushButton *button_connect = new QPushButton("connect",this);button_connect->setObjectName("connect");QLabel *ip_label = new QLabel("ip",this);QLabel *port_label = new QLabel("port",this);iplayout->addWidget(ip_label);iplayout->addWidget(ip_LineEdit);iplayout->addWidget(port_label);iplayout->addWidget(port_LineEdit);iplayout->addWidget(button_connect);iplayout->addStretch();root->addLayout(iplayout);root->addWidget(console,1);//设置默认的测试网络参数ip_LineEdit->setText("127.0.0.1");port_LineEdit->setText("6600");client->setObjectName("client");QMetaObject::connectSlotsByName(this);}~Widget(){}
public slots:void auto_connect(){if(client->state() == QAbstractSocket::ConnectedState){client->disconnectFromHost();client->waitForDisconnected();}//client->waitForConnected();std::shared_ptr<QProgressDialog> dialog(new QProgressDialog(this));dialog->setLabelText("");QProgressBar *bar = new QProgressBar(dialog.get());bar->setTextVisible(false);dialog->setBar(bar);dialog->setLabelText("connecting ... ");dialog->setRange(0,0);dialog->setCancelButton(nullptr);dialog->setWindowFlag(Qt::FramelessWindowHint);QMetaObject::Connection conn_accept= connect(client,&QTcpSocket::connected,dialog.get(),&QProgressDialog::accept);QMetaObject::Connection conn_rejected= connect(client,&QTcpSocket::stateChanged,dialog.get(),[this,dialog](){if(this->client->state() ==QAbstractSocket::UnconnectedState){dialog->reject();}});bool rtn = false;if(conn_accept&&conn_accept){QHostAddress ip(ip_LineEdit->text());int port = port_LineEdit->text().toInt();show_msg(QString("connect %1:%2 ...").arg(ip.toString()).arg(port));client->connectToHost(ip,port);rtn = dialog->exec();qDebug() << "rtn = " << rtn;if(rtn == true){show_msg(QString("connect %1:%2 success").arg(ip.toString()).arg(port));}else{show_msg(QString("connect %1:%2 fail").arg(ip.toString()).arg(port));}}else{qDebug() << "error";}if(conn_accept){QObject::disconnect(conn_accept);}if(conn_rejected){QObject::disconnect(conn_rejected);}if(!rtn){QTimer::singleShot(10, this, &Widget::auto_connect);}}void on_connect_clicked(){qDebug() << "clicked";auto_connect();}void on_client_connected(){QTcpSocket *c = (QTcpSocket *)sender();qDebug() << c->peerAddress() << "-" << c->peerName() << "-" << c->peerPort();show_msg(QString("connect %1:%2 ok").arg(c->peerAddress().toString()).arg(c->peerPort()));}void on_client_disconnected(){qDebug() << __func__<<__LINE__;show_msg(QString("disconnected"));QTimer::singleShot(10, this, &Widget::auto_connect);}void on_client_errorOccurred(QAbstractSocket::SocketError socketError){qDebug() << __func__<<__LINE__ << "socketError:" << socketError;}void on_client_hostFound(){qDebug() << __func__<<__LINE__;}// void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)void on_client_stateChanged(QAbstractSocket::SocketState socketState){qDebug() << __func__<<__LINE__<< "socketState:"<<socketState;}void show_msg(QString msg){console->append(msg);}void on_client_aboutToClose(){qDebug() << __func__<<__LINE__;}// void bytesWritten(qint64 bytes)// void channelBytesWritten(int channel, qint64 bytes)void on_client_channelReadyRead(int channel){qDebug() << __func__<<__LINE__<< "channel:"<<channel;}void on_client_readChannelFinished(){qDebug() << __func__<<__LINE__;}void on_client_readyRead(){qDebug() << __func__<<__LINE__;}public:QTcpSocket *client = new QTcpSocket(this);MyTextBrowser *console = new MyTextBrowser;QLineEdit *ip_LineEdit = new QLineEdit;QLineEdit *port_LineEdit = new QLineEdit;private:
};
#endif // WIDGET_H

版本 2:有取消按钮

 测试效果:

点击canel按钮后,就不会自动重连了:

 

测试代码

CMakeLists.txt

cmake_minimum_required(VERSION 3.19)
project(AutoConnect LANGUAGES CXX)find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets Network)qt_standard_project_setup()qt_add_executable(AutoConnectWIN32 MACOSX_BUNDLEmain.cppwidget.hwidget.ui
)target_link_libraries(AutoConnectPRIVATEQt::CoreQt::WidgetsQt6::Network
)include(GNUInstallDirs)install(TARGETS AutoConnectBUNDLE  DESTINATION .RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)qt_generate_deploy_app_script(TARGET AutoConnectOUTPUT_SCRIPT deploy_scriptNO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})

main.cpp 

#include "widget.h"#include <QApplication>
int MyPushButton::count = 0;
int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include <QApplication>
#include <QWidget>
#include <QTcpSocket>
#include <QProgressDialog>
#include <QPushButton>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QTextBrowser>
#include <QMouseEvent>
#include <QLineEdit>
#include <QDebug>
#include <QMetaObject>
#include <QProgressBar>
#include <QTimer>class MyTextBrowser:public QTextBrowser
{
public:MyTextBrowser(QWidget *parent = nullptr):QTextBrowser(parent){}// QWidget interface
protected:virtual void mouseDoubleClickEvent(QMouseEvent *event) override{if(event->button() == Qt::LeftButton){this->clear();}}
};
class MyPushButton:public QPushButton{Q_OBJECT
public:MyPushButton(QWidget *parent = nullptr):MyPushButton("",parent){}MyPushButton(const QString &text, QWidget *parent = nullptr):QPushButton(text,parent){MyPushButton::count++;qDebug() << __func__ << __LINE__ << " create MyPushButton:count = "  << count;}~MyPushButton(){MyPushButton::count--;qDebug() << __func__ << __LINE__ << " delete MyPushButton:count = " << count;}
public:static int count;
signals:void user_click();// QWidget interface
protected:virtual void mousePressEvent(QMouseEvent *event) override{if(event->button() == Qt::LeftButton){qDebug() << __func__ << __LINE__ << "user click";emit user_click();}}
};class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr): QWidget(parent){QVBoxLayout *root = new QVBoxLayout(this);QHBoxLayout *iplayout = new QHBoxLayout;QPushButton *button_connect = new QPushButton("connect",this);button_connect->setObjectName("connect");QLabel *ip_label = new QLabel("ip",this);QLabel *port_label = new QLabel("port",this);iplayout->addWidget(ip_label);iplayout->addWidget(ip_LineEdit);iplayout->addWidget(port_label);iplayout->addWidget(port_LineEdit);//iplayout->addWidget(button_connect);button_connect->setVisible(false);iplayout->addStretch();root->addLayout(iplayout);root->addWidget(console,1);//设置默认的测试网络参数ip_LineEdit->setText("127.0.0.1");port_LineEdit->setText("6600");client->setObjectName("client");QMetaObject::connectSlotsByName(this);QTimer::singleShot(10, this, &Widget::auto_connect);// std::shared_ptr<QProgressDialog> dialog(new QProgressDialog(this));// dialog->setCancelButton(new MyPushButton("hello",this));// qDebug() << "wait ...";// dialog.reset();// qDebug() << "byebye ...";}~Widget(){}
public slots:void auto_connect(){if(client->state() == QAbstractSocket::ConnectedState){client->disconnectFromHost();client->waitForDisconnected();}//client->waitForConnected();std::shared_ptr<QProgressDialog> dialog(new QProgressDialog(this));dialog->setLabelText("");QProgressBar *bar = new QProgressBar(dialog.get());bar->setTextVisible(false);dialog->setBar(bar);dialog->setLabelText("connecting ... ");dialog->setRange(0,0);MyPushButton *cancel_button = new MyPushButton("cancel",dialog.get());dialog->setCancelButton(cancel_button);dialog->setWindowFlag(Qt::FramelessWindowHint);QMetaObject::Connection conn_accept= connect(client,&QTcpSocket::connected,dialog.get(),&QProgressDialog::accept);QMetaObject::Connection conn_rejected= connect(client,&QTcpSocket::stateChanged,dialog.get(),[this,dialog](){if(this->client->state() ==QAbstractSocket::UnconnectedState){qDebug() << "connect error";dialog->reject();}});QMetaObject::Connection conn_cancel= connect(cancel_button,&MyPushButton::user_click,dialog.get(),[this,dialog](){qDebug() << "connect error";dialog->reject();this->m_user_cancel = true;show_msg("user cancel reconnect");});bool rtn = false;if(conn_accept&&conn_accept&&conn_cancel){QHostAddress ip(ip_LineEdit->text());int port = port_LineEdit->text().toInt();show_msg(QString("connect %1:%2 ...").arg(ip.toString()).arg(port));client->connectToHost(ip,port);rtn = dialog->exec();qDebug() << "rtn = " << rtn;if(rtn == true){show_msg(QString("connect %1:%2 success").arg(ip.toString()).arg(port));}else{show_msg(QString("connect %1:%2 fail").arg(ip.toString()).arg(port));}}else{qDebug() << "error";}if(conn_accept){QObject::disconnect(conn_accept);}if(conn_rejected){QObject::disconnect(conn_rejected);}if(conn_rejected){QObject::disconnect(conn_rejected);}if(conn_cancel){QObject::disconnect(conn_cancel);}if(!rtn){if(this->m_user_cancel == false){QTimer::singleShot(10, this, &Widget::auto_connect);}}}void on_connect_clicked(){qDebug() << "clicked";auto_connect();}void on_client_connected(){QTcpSocket *c = (QTcpSocket *)sender();qDebug() << c->peerAddress() << "-" << c->peerName() << "-" << c->peerPort();show_msg(QString("connect %1:%2 ok").arg(c->peerAddress().toString()).arg(c->peerPort()));}void on_client_disconnected(){qDebug() << __func__<<__LINE__;show_msg(QString("disconnected"));QTimer::singleShot(10, this, &Widget::auto_connect);}void on_client_errorOccurred(QAbstractSocket::SocketError socketError){qDebug() << __func__<<__LINE__ << "socketError:" << socketError;}void on_client_hostFound(){qDebug() << __func__<<__LINE__;}// void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)void on_client_stateChanged(QAbstractSocket::SocketState socketState){qDebug() << __func__<<__LINE__<< "socketState:"<<socketState;}void show_msg(QString msg){console->append(msg);}void on_client_aboutToClose(){qDebug() << __func__<<__LINE__;}// void bytesWritten(qint64 bytes)// void channelBytesWritten(int channel, qint64 bytes)void on_client_channelReadyRead(int channel){qDebug() << __func__<<__LINE__<< "channel:"<<channel;}void on_client_readChannelFinished(){qDebug() << __func__<<__LINE__;}void on_client_readyRead(){qDebug() << __func__<<__LINE__;}public:bool m_user_cancel = false;QTcpSocket *client = new QTcpSocket(this);MyTextBrowser *console = new MyTextBrowser;QLineEdit *ip_LineEdit = new QLineEdit;QLineEdit *port_LineEdit = new QLineEdit;private:
};
#endif // WIDGET_H

小结

相关文章:

QT:一个TCP客户端自动连接的测试模型

版本 1:没有取消按钮 测试效果&#xff1a; 缺陷&#xff1a; 无法手动停止 测试代码 CMakeLists.txt cmake_minimum_required(VERSION 3.19) project(AutoConnect LANGUAGES CXX)find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets Network)qt_standard_project_setup(…...

关于启动vue项目,出现:Error [ERR_MODULE_NOT_FOUND]: Cannot find module ‘xxx‘此类错误

目录 一、问题报错 二、原因分析 三、解决方法 一、问题报错 node环境变量配置有问题&#xff1a; (base) xxxM73H-15:~/VueProject/pproject-vue$ npm run dev /usr/bin/env: “node”: 没有那个文件或目录vue项目启动有问题&#xff1a; (base) xxx:~/VueProject/pproj…...

电路元件与电路基本定理

电流、电压和电功率 电流 1 定义&#xff1a; 带电质点的有序运动形成电流 。 单位时间内通过导体横截面的电量定义为电流强度&#xff0c; 简称电流&#xff0c;用符号 i 表示&#xff0c;其数学表达式为&#xff1a;&#xff08;i单位&#xff1a;安培&#xff08;A&#x…...

指针之矢:C 语言内存幽境的精准飞梭

一、内存和编码 指针理解的2个要点&#xff1a; 指针是内存中一个最小单元的编号&#xff0c;也就是地址平时口语中说的指针&#xff0c;通常指的是指针变量&#xff0c;是用来存放内存地址的变量 总结&#xff1a;指针就是地址&#xff0c;口语中说的指针通常指的是指针变量。…...

uniapp下载打开实现方案,支持安卓ios和h5,下载文件到指定目录,安卓文件管理内可查看到

uniapp下载&打开实现方案&#xff0c;支持安卓ios和h5 Android&#xff1a; 1、申请本地存储读写权限 2、创建文件夹&#xff08;文件夹不存在即创建&#xff09; 3、下载文件 ios&#xff1a; 1、下载文件 2、保存到本地&#xff0c;需要打开文件点击储存 使用方法&…...

免费干净!付费软件的平替款!

今天给大家介绍一个非常好用的电脑录屏软件&#xff0c;完全没有广告界面&#xff0c;非常的干净简洁。 电脑录屏 无广告的录屏软件 这个软件不需要安装&#xff0c;打开就能看到界面直接使用了。 软件可以全屏录制&#xff0c;也可以自定义尺寸进行录制。 录制的声音选择也非…...

软路由系统 iStoreOS 中部署 Minecraft 服务器

商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。协议(License): 知识共享署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)作者(Author): lhDream链接(URL): https://blog.luhua.site/archives/1734968846131 软路由系统 iStoreOS 中部署 Minecraft…...

第 29 章 - ES 源码篇 - 网络 IO 模型及其实现概述

前言 本文介绍了 ES 使用的网络模型&#xff0c;并介绍 transport&#xff0c;http 接收、响应请求的代码入口。 网络 IO 模型 Node 在初始化的时候&#xff0c;会创建网络模块。网络模块会加载 Netty4Plugin plugin。 而后由 Netty4Plugin 创建对应的 transports&#xff0…...

细说STM32F407单片机IIC总线基础知识

目录 一、 I2C总线结构 1、I2C总线的特点 2、I2C总线通信协议 3、 STM32F407的I2C接口 二、 I2C的HAL驱动程序 1、 I2C接口的初始化 2、阻塞式数据传输 &#xff08;1&#xff09;函数HAL_I2C_IsDeviceReady() &#xff08;2&#xff09;主设备发送和接收数据 &#…...

从头开始学MyBatis—04缓存、逆向工程、分页插件

介绍了MyBatis的缓存、逆向工程和分页插件的使用 目录 1.Mybatis的缓存 1.1MyBatis的一级缓存 1.2MyBatis的二级缓存 1.3二级缓存的相关配置 1.4MyBatis缓存查询的顺序 1.5整合第三方缓存EHCache 1.5.1添加依赖 1.5.2各jar包功能 1.5.3创建EHCache的配置文件ehcache.x…...

Artec Space Spider助力剑桥研究团队解码古代社会合作【沪敖3D】

挑战&#xff1a;考古学家需要一种安全的方法来呈现新出土的陶瓷容器&#xff0c;对比文物形状。 解决方案&#xff1a;Artec Space Spider, Artec Studio 效果&#xff1a;本项目是REVERSEACTION项目的一部分&#xff0c;旨在研究无国家社会中复杂的古代技术。研究团队在考古地…...

《探索PyTorch计算机视觉:原理、应用与实践》

《探索PyTorch计算机视觉&#xff1a;原理、应用与实践》 一、PyTorch 与计算机视觉的奇妙相遇二、核心概念解析&#xff08;一&#xff09;张量&#xff1a;计算机视觉的数据基石&#xff08;二&#xff09;神经网络&#xff1a;视觉任务的智慧大脑&#xff08;三&#xff09;…...

【C#设计模式(21)——状态模式(State Pattern)】

前言 状态模式:在对象内部发生改变时改变其行为&#xff0c;使得对象在不同的状态下具有不同的行为表现。 代码 #region 状态模式-类/// 抽象 交通灯状态public abstract class TrafficLightState{public abstract void Display();}//红灯public class RedLight : TrafficLight…...

nvm日常使用中常用命令总结

日常开发vue项目中&#xff0c;不同的项目 我们可能需要安装不同的node版本&#xff0c;但是为了方便切换node&#xff0c;我们一般会安装一个名称为nvm的工具&#xff0c;这里总结一下&#xff0c;nvm常用的命令&#xff1a; 1、为了查看可用的 Node.js 版本&#xff0c;你可…...

【数据仓库】SparkSQL数仓实践

文章目录 集成hive metastoreSQL测试spark-sql 语法SQL执行流程两种数仓架构的选择hive on spark数仓配置经验 spark-sql没有元数据管理功能&#xff0c;只有sql 到RDD的解释翻译功能&#xff0c;所以需要和hive的metastore服务集成在一起使用。 集成hive metastore 在spark安…...

PessimisticLock

想象你和你的朋友都想去图书馆借同一本非常受欢迎的小说。为了确保你们中的一位能够成功借到这本书&#xff0c;图书馆采用了悲观锁机制来管理借阅过程。 悲观锁的方式 查看书籍状态&#xff1a;当你到达图书馆并决定要借这本小说时&#xff0c;你先告诉图书管理员你想借这本…...

【Maven】属性管理

1. 属性 问题导入 定义属性有什么好处&#xff1f; 1.1 属性配置与使用 ①&#xff1a;定义属性 <!--定义自定义属性--> <properties><spring.version>5.2.10.RELEASE</spring.version><junit.version>4.12</junit.version> </prop…...

微信小程序性能优化、分包

性能优化是任何应用开发中的重要组成部分&#xff0c;尤其是在移动环境中。对于微信小程序而言&#xff0c;随着用户量的增加和应用功能的丰富&#xff0c;性能优化显得尤为关键。良好的性能不仅提升用户体验&#xff0c;还能增加用户留存率和应用的使用频率。我们将探讨如何在…...

TDengine 新功能 VARBINARY 数据类型

1. 背景 VARBINARY 数据类型用于存储二进制数据&#xff0c;与 MySQL 中的 VARBINARY 数据类型功能相同&#xff0c;VARBINARY 数据类型长度可变&#xff0c;在创建表时指定最大字节长度&#xff0c;使用进按需分配存储&#xff0c;但不能超过建表时指定的最大值。 2. 功能说明…...

【Maven】工程依赖下载失败错误解决

在使用 Maven 构建项目时&#xff0c;可能会发生依赖项下载错误的情况&#xff0c;主要原因有以下几种&#xff1a; 下载依赖时出现网络故障或仓库服务器宕机等原因&#xff0c;导致无法连接至 Maven 仓库&#xff0c;从而无法下载依赖。 依赖项的版本号或配置文件中的版本号错…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

电脑桌面太单调,用Python写一个桌面小宠物应用。

下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡&#xff0c;可以响应鼠标点击&#xff0c;并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...