【学写LibreCAD】1 LibreCAD主程序
一、源码
- 头文件:
#ifndef MAIN_H
#define MAIN_H#include<QStringList>#define STR(x) #x
#define XSTR(x) STR(x)/*** @brief handleArgs* @param argc cli argument counter from main()* @param argv cli arguments from main()* @param argClean a list of indices to be ignored* @return*/
QStringList handleArgs(int argc, char** argv, const QList<int>& argClean);/*** @brief LCReleaseLabel return a label for the current release based on LC_VERSION in src.pro* @return "Release Candidate" - if LC_VERSION contains rc;* "BETA" - if LC_VERSION contains beta* "ALPHA" - if LC_VERSION contains alpha*/
QString LCReleaseLabel();#endif
程序文件:
#include <clocale>#include <QApplication>
#include <QByteArray>
#include <QDebug>
#include <QFileInfo>
#include <QMessageBox>
#include <QPainter>
#include <QPixmap>
#include <QSettings>
#include <QSplashScreen>#include "console_dxf2pdf.h"
#include "console_dxf2png.h"
#include "lc_application.h"
#include "main.h"
#include "qc_applicationwindow.h"
#include "qg_dlginitial.h"
#include "rs_debug.h"
#include "rs_fontlist.h"
#include "rs_patternlist.h"
#include "rs_settings.h"
#include "rs_system.h"namespace{void restoreWindowGeometry(QC_ApplicationWindow& appWin, QSettings& settings);
// update splash for alpha/beta names)void updateSplash(const std::unique_ptr<QSplashScreen>& splash);
}
/*** Main. 创建应用程序窗口。*/// fixme - sand - refactor and split to several specialized functions
int main(int argc, char** argv){QT_REQUIRE_VERSION(argc, argv, "5.2.1"); //确保 LibreCAD 在 Qt 5.2.1 或更高版本上运行//检查前两个参数,以决定我们是要将librecad作为控制台dxf2pdf还是dxf2png工具运行。在Linux上,我们可以创建一个指向librecad可执行文件的链接,并将其命名为dxf2pdf。因此,我们可以运行以下任一操作://librecad dxf2pdf[选项]...//或者只是:dxf2pdf[选项]...for (int i = 0; i < qMin(argc, 2); i++) {QString arg(argv[i]);if (i == 0) {arg = QFileInfo(QFile::decodeName(argv[i])).baseName();}if (arg.compare("dxf2pdf") == 0) {return console_dxf2pdf(argc, argv);}if (arg.compare("dxf2png") == 0 || arg == "dxf2svg") {return console_dxf2png(argc, argv);}}RS_DEBUG->setLevel(RS_Debug::D_WARNING);LC_Application app(argc, argv);QCoreApplication::setOrganizationName("LibreCAD");QCoreApplication::setApplicationName("LibreCAD");QCoreApplication::setApplicationVersion(XSTR(LC_VERSION));RS_Settings::init(app.organizationName(), app.applicationName());QGuiApplication::setDesktopFileName("librecad.desktop");QSettings settings; // fixme - direct invocation of settingsbool first_load = settings.value("Startup/FirstLoad", 1).toBool();const QString lpDebugSwitch0("-d"),lpDebugSwitch1("--debug") ;const QString help0("-h"), help1("--help");bool allowOptions=true;QList<int> argClean;for (int i=0; i<argc; i++){QString argstr(argv[i]);if(allowOptions&&QString::compare("--", argstr)==0){allowOptions=false;continue;}if (allowOptions && (help0.compare(argstr, Qt::CaseInsensitive)==0 ||help1.compare(argstr, Qt::CaseInsensitive)==0 )){qDebug()<<"Usage: librecad [command] <options> <dxf file>";qDebug()<<"";qDebug()<<"Commands:";qDebug()<<"";qDebug()<<" dxf2pdf\tRun librecad as console dxf2pdf tool. Use -h for help.";qDebug()<<" dxf2png\tRun librecad as console dxf2png tool. Use -h for help.";qDebug()<<" dxf2svg\tRun librecad as console dxf2svg tool. Use -h for help.";qDebug()<<"";qDebug()<<"Options:";qDebug()<<"";qDebug()<<" -h, --help\tdisplay this message";qDebug()<<" -d, --debug <level>";qDebug()<<"";RS_DEBUG->print( RS_Debug::D_NOTHING, "possible debug levels:");RS_DEBUG->print( RS_Debug::D_NOTHING, " %d Nothing", RS_Debug::D_NOTHING);RS_DEBUG->print( RS_Debug::D_NOTHING, " %d Critical", RS_Debug::D_CRITICAL);RS_DEBUG->print( RS_Debug::D_NOTHING, " %d Error", RS_Debug::D_ERROR);RS_DEBUG->print( RS_Debug::D_NOTHING, " %d Warning", RS_Debug::D_WARNING);RS_DEBUG->print( RS_Debug::D_NOTHING, " %d Notice", RS_Debug::D_NOTICE);RS_DEBUG->print( RS_Debug::D_NOTHING, " %d Informational", RS_Debug::D_INFORMATIONAL);RS_DEBUG->print( RS_Debug::D_NOTHING, " %d Debugging", RS_Debug::D_DEBUGGING);exit(0);}if (allowOptions&& (argstr.startsWith(lpDebugSwitch0, Qt::CaseInsensitive) ||argstr.startsWith(lpDebugSwitch1, Qt::CaseInsensitive) )){argClean<<i;// to control the level of debugging output use --debug with level 0-6, e.g. --debug3// for a list of debug levels use --debug?// if no level follows, the debugging level is setargstr.remove(QRegularExpression("^"+lpDebugSwitch0));argstr.remove(QRegularExpression("^"+lpDebugSwitch1));char level;if(argstr.size()==0){if(i+1<argc){if(QRegularExpression(R"(\d*)").match(argv[i+1]).hasMatch()){++i;qDebug()<<"reading "<<argv[i]<<" as debugging level";level=argv[i][0];argClean<<i;} else {level = '3';}}else {level = '3'; //default to D_WARNING}}else {level = argstr.toStdString()[0];}switch(level){case '?' : {RS_DEBUG->print(RS_Debug::D_NOTHING, "possible debug levels:");RS_DEBUG->print(RS_Debug::D_NOTHING, " %d Nothing", RS_Debug::D_NOTHING);RS_DEBUG->print(RS_Debug::D_NOTHING, " %d Critical", RS_Debug::D_CRITICAL);RS_DEBUG->print(RS_Debug::D_NOTHING, " %d Error", RS_Debug::D_ERROR);RS_DEBUG->print(RS_Debug::D_NOTHING, " %d Warning", RS_Debug::D_WARNING);RS_DEBUG->print(RS_Debug::D_NOTHING, " %d Notice", RS_Debug::D_NOTICE);RS_DEBUG->print(RS_Debug::D_NOTHING, " %d Informational", RS_Debug::D_INFORMATIONAL);RS_DEBUG->print(RS_Debug::D_NOTHING, " %d Debugging", RS_Debug::D_DEBUGGING);return 0;}case '0' + RS_Debug::D_NOTHING : {RS_DEBUG->setLevel(RS_Debug::D_NOTHING);break;}case '0' + RS_Debug::D_CRITICAL : {RS_DEBUG->setLevel(RS_Debug::D_CRITICAL);break;}case '0' + RS_Debug::D_ERROR : {RS_DEBUG->setLevel(RS_Debug::D_ERROR);break;}case '0' + RS_Debug::D_WARNING : {RS_DEBUG->setLevel(RS_Debug::D_WARNING);break;}case '0' + RS_Debug::D_NOTICE : {RS_DEBUG->setLevel(RS_Debug::D_NOTICE);break;}case '0' + RS_Debug::D_INFORMATIONAL : {RS_DEBUG->setLevel(RS_Debug::D_INFORMATIONAL);break;}case '0' + RS_Debug::D_DEBUGGING : {RS_DEBUG->setLevel(RS_Debug::D_DEBUGGING);break;}default : {RS_DEBUG->setLevel(RS_Debug::D_DEBUGGING);break;}}}}RS_DEBUG->print("param 0: %s", argv[0]);QFileInfo prgInfo( QFile::decodeName(argv[0]) );QString prgDir(prgInfo.absolutePath());RS_SYSTEM->init(app.applicationName(), app.applicationVersion(), XSTR(QC_APPDIR), prgDir);// parse command line arguments that might not need a launched program:QStringList fileList = handleArgs(argc, argv, argClean);QString unit = settings.value("Defaults/Unit", "Invalid").toString();// show initial config dialog:if (first_load){RS_DEBUG->print("main: show initial config dialog..");QG_DlgInitial di(nullptr);QPixmap pxm(":/main/intro_librecad.png");di.setPixmap(pxm);if (di.exec()) {unit = LC_GET_ONE_STR("Defaults", "Unit", "None");}RS_DEBUG->print("main: show initial config dialog: OK");}auto splash = std::make_unique<QSplashScreen>();bool show_splash = settings.value("Startup/ShowSplash", 1).toBool();if (show_splash){updateSplash(splash);app.processEvents();RS_DEBUG->print("main: splashscreen: OK");}RS_DEBUG->print("main: init fontlist..");RS_FONTLIST->init();RS_DEBUG->print("main: init fontlist: OK");RS_DEBUG->print("main: init patternlist..");RS_PATTERNLIST->init();RS_DEBUG->print("main: init patternlist: OK");RS_DEBUG->print("main: loading translation..");settings.beginGroup("Appearance");QString lang = settings.value("Language", "en").toString();QString langCmd = settings.value("LanguageCmd", "en").toString();settings.endGroup();RS_SYSTEM->loadTranslation(lang, langCmd);RS_DEBUG->print("main: loading translation: OK");RS_DEBUG->print("main: creating main window..");QC_ApplicationWindow& appWin = *QC_ApplicationWindow::getAppWindow();
#ifdef Q_OS_MACapp.installEventFilter(&appWin);
#endifRS_DEBUG->print("main: setting caption");appWin.setWindowTitle(app.applicationName());RS_DEBUG->print("main: show main window");settings.beginGroup("Defaults");if( !settings.contains("UseQtFileOpenDialog")) {
#ifdef Q_OS_LINUX// on Linux don't use native file dialog// because of case insensitive filters (issue #791)settings.setValue("UseQtFileOpenDialog", QVariant(1));
#elsesettings.setValue("UseQtFileOpenDialog", QVariant(0));
#endif}settings.endGroup();if (!first_load) {restoreWindowGeometry(appWin, settings);}bool maximize = settings.value("Startup/Maximize", 0).toBool();if (maximize || first_load) {appWin.showMaximized();}else {appWin.show();}RS_DEBUG->print("main: set focus");appWin.setFocus();RS_DEBUG->print("main: creating main window: OK");if (show_splash){RS_DEBUG->print("main: updating splash");splash->raise();splash->showMessage(QObject::tr("Loading..."),Qt::AlignRight|Qt::AlignBottom, Qt::black);RS_DEBUG->print("main: processing events");qApp->processEvents();RS_DEBUG->print("main: updating splash: OK");}// Set LC_NUMERIC so that entering numeric values uses . as the decimal separatorsetlocale(LC_NUMERIC, "C");RS_DEBUG->print("main: loading files..");
#ifdef Q_OS_MAC// get the file list from LC_ApplicationfileList << app.fileList();
#endif// reopen files that we open during last close of application// we'll reopen them if no explicit files to open are provided in command linebool reopenLastFiles;QString lastFiles;QString activeFile;LC_GROUP("Startup");{reopenLastFiles = LC_GET_BOOL("OpenLastOpenedFiles");lastFiles = LC_GET_STR("LastOpenFilesList", "");activeFile = LC_GET_STR("LastOpenFilesActive", "");bool checkForNewVersion = LC_GET_BOOL("CheckForNewVersions", true);if (reopenLastFiles && fileList.isEmpty() && !lastFiles.isEmpty()) {foreach(const QString &filename, lastFiles.split(";")) {if (!filename.isEmpty() && QFileInfo::exists(filename))fileList << filename;}}bool files_loaded = false;for (QStringList::Iterator it = fileList.begin(); it != fileList.end(); ++it) {if (show_splash) {splash->showMessage(QObject::tr("Loading File %1..").arg(QDir::toNativeSeparators(*it)),Qt::AlignRight | Qt::AlignBottom, Qt::black);qApp->processEvents();}appWin.slotFileOpen(*it);files_loaded = true;}if (reopenLastFiles) {appWin.activateWindowWithFile(activeFile);}RS_DEBUG->print("main: loading files: OK");if (!files_loaded) {appWin.slotFileNewNew();}if (show_splash) {splash->finish(&appWin);splash.release();}if (checkForNewVersion) {appWin.checkForNewVersion();}}LC_GROUP_END();if (first_load)settings.setValue("Startup/FirstLoad", 0);RS_DEBUG->print("main: entering Qt event loop");QCoreApplication::processEvents();int return_code = app.exec();RS_DEBUG->print("main: exited Qt event loop");// Destroy the singletonQC_ApplicationWindow::getAppWindow().reset();return return_code;
}/*** Handles command line arguments that might not require a GUI.** @return list of files to load on startup.*/
QStringList handleArgs(int argc, char** argv, const QList<int>& argClean){RS_DEBUG->print("main: handling args..");QStringList ret;bool doexit = false;for (int i=1; i<argc; i++) {if(argClean.indexOf(i)>=0) continue;if (!QString(argv[i]).startsWith("-")){QString fname = QDir::toNativeSeparators(QFileInfo(QFile::decodeName(argv[i])).absoluteFilePath());ret.append(fname);}else if (QString(argv[i])=="--exit"){doexit = true;}}if (doexit) {exit(0);}RS_DEBUG->print("main: handling args: OK");return ret;
}QString LCReleaseLabel(){QString version{XSTR(LC_VERSION)};QString label;const std::map<QString, QString> labelMap = {{"rc", QObject::tr("Release Candidate")},{"beta", QObject::tr("BETA")},{"alpha", QObject::tr("ALPHA")}};for (const auto& [key, value]: labelMap) {if (version.contains(key, Qt::CaseInsensitive)) {label=value;break;}}return label;
}namespace {void restoreWindowGeometry(QC_ApplicationWindow& appWin, QSettings& settings){settings.beginGroup("Geometry");auto geometryB64 = settings.value("/WindowGeometry").toString().toUtf8();auto geometry = QByteArray::fromBase64(geometryB64, QByteArray::Base64Encoding);if (!geometry.isEmpty()) {appWin.restoreGeometry(geometry);} else {// fallbackint windowWidth = settings.value("WindowWidth", 1024).toInt();int windowHeight = settings.value("WindowHeight", 1024).toInt();int windowX = settings.value("WindowX", 32).toInt();int windowY = settings.value("WindowY", 32).toInt();appWin.resize(windowWidth, windowHeight);appWin.move(windowX, windowY);}settings.endGroup();}// Update Splash image to show "ALPHA", "BETA", and "Release Candidate"
QPixmap getSplashImage(const std::unique_ptr<QSplashScreen>& splash, const QString& label);
// Update Splash Screenvoid updateSplash(const std::unique_ptr<QSplashScreen>& splash){if (splash == nullptr)return;QString label = LCReleaseLabel();if (label.isEmpty())return;QPixmap splashImage = getSplashImage(splash, label);splash->setPixmap(splashImage);splash->setAttribute(Qt::WA_DeleteOnClose);splash->show();splash->showMessage(QObject::tr("Loading.."),Qt::AlignRight|Qt::AlignBottom, Qt::black);}// Update Splash image to show "ALPHA", "BETA", and "Release Candidate"QPixmap getSplashImage(const std::unique_ptr<QSplashScreen>& splash, const QString& label){if (splash == nullptr)return {};QPixmap pixmapSplash(":/main/splash_librecad.png");QPainter painter(&pixmapSplash);const double factorX = pixmapSplash.width()/542.;const double factorY = pixmapSplash.height()/337.;painter.setPen(QColor(255, 0, 0, 128));QRectF labelRect{QPointF{280.*factorX, 130.*factorY}, QPointF{480.*factorX, 170.*factorY}};QFont font;font.setPixelSize(int(labelRect.height()) - 2);painter.setFont(font);painter.drawText(labelRect,Qt::AlignRight, label);return pixmapSplash;}
}
二、代码介绍
- Qt 版本检查
QT_REQUIRE_VERSION(argc, argv, "5.2.1");
确保应用程序运行在 Qt 5.2.1 或更高版本上。
- 控制台模式检测
for (int i = 0; i < qMin(argc, 2); i++) {// 检查是否为 dxf2pdf/dxf2png 命令if (arg.compare("dxf2pdf") == 0) return console_dxf2pdf(...);if (arg.compare("dxf2png") == 0) return console_dxf2png(...);
}
检测是否以命令行工具模式运行,用于文件格式转换(如 PDF/PNG/SVG)。
- 应用程序初始化
LC_Application app(argc, argv);
QCoreApplication::setOrganizationName("LibreCAD");
// ... 其他应用程序设置 ...
RS_Settings::init(...);
-
创建 Qt 应用程序对象。
-
设置组织和应用程序的元数据。
-
初始化持久化设置系统。
- 命令行参数处理
QStringList fileList = handleArgs(argc, argv, argClean);
处理以下参数:
- 调试级别控制(-d/–debug)。
- 帮助信息输出(-h/–help)。
- 要打开的文件路径。
- 特殊命令(如 --exit)。
- 首次运行配置
if (first_load) {QG_DlgInitial di(nullptr);// 显示初始配置对话框
}
- 如果是第一次运行,显示初始设置对话框。
- 设置默认单位和其他基本偏好。
- 启动画面设置
auto splash = std::make_unique<QSplashScreen>();
updateSplash(splash); // 添加版本标签(如 ALPHA/BETA 等)
- 创建并自定义启动画面。
- 使用 getSplashImage() 添加版本标签。
- 资源初始化
RS_FONTLIST->init(); // 字体
RS_PATTERNLIST->init(); // 图案
RS_SYSTEM->loadTranslation(...); // 本地化
- 加载 CAD 所需的资源。
- 设置多语言支持。
- 主窗口创建
QC_ApplicationWindow& appWin = *QC_ApplicationWindow::getAppWindow();
restoreWindowGeometry(appWin, settings);
- 使用单例模式创建主应用程序窗口。
- 从设置中恢复窗口的几何状态。
- 文件处理
// 如果配置了,重新打开上次的文件
if (reopenLastFiles) fileList = lastFiles.split(";"); // 加载命令行指定的文件
for (QString file : fileList) appWin.slotFileOpen(file);
- 处理命令行指定的文件以及“重新打开上次文件”的功能。
- 如果没有指定文件,则创建新文档。
- 事件循环与清理
int return_code = app.exec();
// ... 清理 ...
return return_code;
- 启动 Qt 事件循环。
- 在退出时进行适当的清理。
- 在关闭时保存设置。
关键架构特性
- 单例模式:用于主应用程序窗口(QC_ApplicationWindow::getAppWindow())。
- 工厂模式:用于字体和图案资源的初始化。
- 命令分发:同时支持 GUI 和命令行模式。
- 持久化:使用 QSettings 保存窗口几何状态和偏好设置。
- 国际化:通过翻译文件支持多语言。
重要的辅助函数
- handleArgs():处理命令行参数。
- restoreWindowGeometry():从设置中恢复窗口状态。
- updateSplash():自定义启动画面,添加版本信息。
- LCReleaseLabel():确定版本类型(如 Alpha/Beta 等)。
总结
这段代码展示了一个成熟的 Qt 应用程序结构,具有清晰的职责分离:
- 初始化:应用程序和资源的初始化。
- 资源管理:字体、图案和本地化资源的加载。
- UI 设置:主窗口和启动画面的创建与配置。
- 命令行处理:支持命令行模式和文件加载。
通过良好的架构设计和模块化实现,LibreCAD 的主程序能够高效地处理多种运行场景,并为用户提供一致的使用体验。
相关文章:
【学写LibreCAD】1 LibreCAD主程序
一、源码 头文件: #ifndef MAIN_H #define MAIN_H#include<QStringList>#define STR(x) #x #define XSTR(x) STR(x)/*** brief handleArgs* param argc cli argument counter from main()* param argv cli arguments from main()* param argClean a list…...
Android Studio超级详细讲解下载、安装配置教程(建议收藏)
博主介绍:✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神,答疑解惑、坚持优质作品共享。本人是掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战,深受全网粉丝喜爱与支持✌有…...
CDN与群联云防护的技术差异在哪?
CDN(内容分发网络)与群联云防护是两种常用于提升网站性能和安全的解决方案,但两者的核心目标和技术实现存在显著差异。本文将从防御机制、技术架构、适用场景和代码实现等方面详细对比两者的区别,并提供可直接运行的代码示例。 一…...
故障诊断 | Matlab实现基于DBO-BP-Bagging多特征分类预测/故障诊断
故障诊断 | Matlab实现基于DBO-BP-Bagging多特征分类预测/故障诊断 目录 故障诊断 | Matlab实现基于DBO-BP-Bagging多特征分类预测/故障诊断分类效果基本介绍模型描述DBO-BP-Bagging蜣螂算法优化多特征分类预测一、引言1.1、研究背景和意义1.2、研究现状1.3、研究目的与方法 二…...
Linux-SaltStack配置
文章目录 SaltStack配置 🏡作者主页:点击! 🤖Linux专栏:点击! ⏰️创作时间:2025年02月24日20点51分 SaltStack配置 SaltStack 中既支持SSH协议也支持我们的一个客户端 #获取公钥(…...
内网渗透测试-Vulnerable Docker靶场
靶场来源: Vulnerable Docker: 1 ~ VulnHub 描述:Down By The Docker 有没有想过在容器中玩 docker 错误配置、权限提升等? 下载此 VM,拿出您的渗透测试帽并开始使用 我们有 2 种模式: - HARD:这需要您将 d…...
云计算如何解决延迟问题?
在云计算中,延迟(latency)指的是从请求发出到收到响应之间的时间间隔。延迟过高可能会严重影响用户体验,特别是在需要实时响应的应用中,如在线游戏、视频流、金融交易等。云计算服务如何解决延迟问题,通常依…...
飞书webhook监控业务系统端口
钉钉告警没有额度了,替代方案使用企业微信或者是飞书,以下脚本是飞书为例 监控ping也就是活动主机 #!/bin/bash # IP Ping 监控脚本 date$(date "%Y-%m-%d %H:%M:%S") # 根据实际情况修改飞书 Webhook 地址 webhook"https://open.feish…...
电脑键盘知识
1、键盘四大功能区 1. 功能区 2. 主要信息输入区 3. 编辑区 4. 数字键盘区 笔记本电脑键盘的功能区,使用前需先按Fn键 1.1、功能区 ESC:退出 F1:显示帮助信息 F2:重命名 F4:重复上一步操作 F5:刷新网页 …...
Oracle23版本 创建用户 报 00959和65096错误解决办法
00959错误解决办法,用户名必须已 c##或者C##开头 65096错误解决办法,创建用户名时去掉DEFAULT TABLESPACE smallrainTablespace这个属性 附上oracle 23版本创建表空间和用户语句; sqlplus sys as sysdba CREATE TABLESPACE smallrainOrac…...
SAP-ABAP:使用ST05(SQL Trace)追踪结构字段来源的步骤
ST05 是 SAP 提供的 SQL 跟踪工具,可以记录程序运行期间所有数据库操作(如 SELECT、UPDATE、INSERT)。通过分析跟踪结果,可以精准定位程序中结构字段对应的数据库表。 步骤1:激活ST05跟踪 事务码 ST05 → 点击 Activa…...
《深度学习实战》第3集:循环神经网络(RNN)与序列建模
第3集:循环神经网络(RNN)与序列建模 引言 在深度学习领域,处理序列数据(如文本、语音、时间序列等)是一个重要的研究方向。传统的全连接网络和卷积神经网络(CNN)难以直接捕捉序列中…...
winfrom的progressBar 鼠标移上去显示 进度条的时间
需求描述: 播放IPC摄像头(海康、大华)的录像回放,视频窗口下方有个进度条,能显示当前录像播放的进度,点击进度条能将视频跳转到指定的时间点继续播放... 现在需要再进度条上显示视频的时间,用来…...
如何在WordPress网站中查看移动版本—快速预览与自定义设置
在WordPress网站的构建过程中,确保网站在移动端的显示效果至关重要。毕竟,随着越来越多的用户通过手机访问互联网,一个优化良好的移动版网站将直接影响用户的留存率和访问体验。 如果你是WordPress网站的所有者,本文将向你介绍如…...
wordpress按分类ID调用最新、推荐、随机内容
在WordPress中,可以通过自定义查询(WP_Query)来按分类ID调用最新、推荐(自定义字段或标签)、随机内容。以下是一些示例代码,帮助你实现这些功能。 1. 按分类ID调用最新内容 以下代码可以调用指定分类ID下的最新文章: <?php // 设置分类…...
excel单、双字节字符转换函数(中英文输入法符号转换)
在Excel中通常使用函数WIDECHAR和ASC来实现单、双字节字符之间的转换。其中 WIDECHAR函数将所有的字符转换为双字节,ASC函数将所有的字符转换为单字节 首先来解释一下单双字节的含义。单字节一般对应英文输入法的输入,如英文字母,英文输入法…...
能不能用Ai来开发出一款APP?很早就想过能不能用Ai来开发出一款APP?
现在AI这么流行,长青很早就想过能不能用Ai来开发出一款APP? 然后从1月份开始长青就开始着手用AI写一款音乐app,参考了落雪音乐的开发技术栈,长青这里也准备用ReactNative去写。 首先声明一点,长青本身不会开发app的&a…...
lattice hdl实现spi接口
在lattice工具链中实现SPI接口通常涉及以下步骤: 定义硬件SPI接口的管脚。配置SPI时钟和模式。编写SPI主机或从机的控制逻辑。 展示了如何在Lattice工具链中使用HDL语言(例如Verilog)来配置SPI接口: lattice工程 顶层:spi_slave_top.v `timescale 1ns/ 1ps module spi_…...
超过DeepSeek、o3,Claude发布全球首个混合推理模型,并将完成新一轮35亿美元融资...
Anthropic于2025年2月25日发布全球首个“混合推理”AI模型Claude 3.7 Sonnet,并在融资层面取得重大进展,计划完成35亿美元的新一轮融资,估值将达615亿美元。以下是核心信息整理: 技术突破:双思维模型与代码能力 1. 混合…...
AI如何通过大数据分析提升制造效率和决策智能化
人工智能(AI)与大数据技术的融合,不仅重新定义了生产流程,更让企业实现了从“经验驱动”到“数据智能驱动”的跨越式升级。 从“模糊经验”到“精准洞察” 传统制造业依赖人工经验制定生产计划,但面对复杂多变的市…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
