news 2026/10/31 14:02:11

Qt QLabel行距调整实战:基于QTextDocument实现LineSpacingLabel

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt QLabel行距调整实战:基于QTextDocument实现LineSpacingLabel

简介:一份针对Qt控件行间距调节的示例工程,覆盖QLabel、QTextBrowser与QTextEdit三种典型控件的文本排版控制,面向使用Visual Studio 2017与Qt 5.14.2进行桌面应用开发、常被默认行距困扰的程序员。压缩包内共44个文件,既包含cpp/h源代码、ui界面、qrc资源等工程核心文件,也含有sln/vcxproj工程配置、exe可执行程序及调试所需的pdb,整体大小26.37MB,按VS2017解决方案组织,便于直接打开、编译与运行。目前已有1363人学习浏览,这一热度直观反映出文本行间距调节在Qt开发中的普遍需求。工程对QLabel采用setStyleSheet设置line-height实现行距,对QTextBrowser和QTextEdit则通过QTextDocument的setDefaultBlockFormat与行高因子调整段落垂直间距;代码中结合了字体大小设置与行高因子配合,读者可对照实际界面理解Qt的富文本布局机制和两种设置方式的适用边界。对于希望精细控制界面文本疏密、提升阅读体验的Qt开发者,这是一份可直接落地参考的样例代码。

1. 为什么QLabel的行距让你调不动?先给结论,别急着改源码

QLabel是Qt桌面界面里最常用的文本控件,但当你需要把多行文字行距稍微拉开一点时,会发现这个东西比想象中难调:QSS里没有line-height属性,setText里塞\n只换行不改间距,调用setWordWrap(true)后行与行之间贴得紧紧实实。我收到过不少与QtLabelLineSpacing问题相关的小伙伙伴,都是因为一段产品文案在PhotoShop里排得挺好,搬到Qt界面里就变成一团“压缩饼干”。QtLabelLineSpacing.zip就是用来解决这个问题的:它围绕QLabel的行距设置做了可复现的完整方案,核心是一个LineSpacingLabel控件,让你直接设置行距像素或百分比。适合用Qt Widgets做桌面工具、工业上位机界面、需要多语言混排或文本预览的开发者。你在Qt Creator里新建工程、用QMake或CMake构建、部署到Windows或Ubuntu上跑,都能用上里面的思路。

2. 行距调节的三条路:HTML、QTextDocument、自绘QLabel,为什么我把宝押在QTextDocument上

2.1 先搞清楚QLabel的行距是从哪来的

QLabel并不是一个简单的“画字”控件,它内部维护了QTextDocument来渲染富文本。默认情况下,每一行的高度由QFontMetrics的lineSpacing()决定,也就是字体本身的行高。这个行高对多行文本来说通常偏小,中文里带拼音、下划线、删除线或英文里含大写字母和如“f”这样升部的字符时,行与行之间容易打架。而且QLabel对外没有直接暴露行距接口,所以你要调整它,只能从三个层面入手:一是改变文本内容,用HTML的CSS样式;二是直接操作QLabel内部的QTextDocument的QTextBlockFormat;三是完全绕开QLabel的绘制,自己用QTextDocument或QPainter画。这三种方案各有各的适用场景,下面逐个说清楚。

2.2 用富文本的line-height:改动最小,但兼容性看版本

最常见的做法是构造HTML文本。比如你要显示一句多行内容,可以这样写:

QString text("<p style=\"line-height:150%\">%1</p>"); ui->label->setText(text.arg(QStringLiteral("第一行\n第二行\n第三行")));

背后的逻辑是QLabel接受富文本时会交给QTextDocument解析,而QTextDocument支持一小部分CSS属性,line-height就是其中之一。150%的意思是行高设置为字体高度的1.5倍。这么做不用改任何类,几行就能看到效果。不过要提醒你,在这个方案里百分比的基数不是像素,而是当前字体height,不同字号下实际效果是浮动的。

如果你只需要一次性展示一段带行距的说明文字,我建议先用这个方案试试,因为它最快。但它有个问题:一旦你调用setWordWrap(true),并且让富文本自动换行,部分Qt版本,尤其是常见的Qt 5.15.2加上MSVC 2019_64编译套件,对p标签内连续换行和line-height的组合处理并不稳定,可能出现“第一段有间距,第二段又挤回去”的情况。所以这种方案顶多算是过渡,不能作为通用控件的基础。

2.3 QTextDocument与QTextBlockFormat:能精确到每一个区块的行距

真正稳定可控的做法是拿到QLabel的QTextDocument,然后对每一个文本块(block)设置格式。QTextBlockFormat有两个关键接口:

  • setLineSpacing(qreal spacing):设置当前行基线之上额外增加的间距,单位是像素。
  • setLineHeight(qreal height, int heightType):设定行高计算方式,height可以传固定像素,也可以传百分比,配合QTextBlockFormat::FixedHeight或QTextBlockFormat::ProportionalHeight使用。

这里要注意的是,QTextBlockFormat是按“块”生效的,一个回车符就是一个块。你希望全文统一行距,就得遍历文档里所有块,统一设置。代码大致是:

QTextCursor cursor(ui->label->document()); cursor.beginEditBlock(); for (QTextBlock block = cursor.document()->begin(); block.isValid(); block = block.next()) { QTextBlockFormat fmt = block.blockFormat(); fmt.setLineHeight(145, QTextBlockFormat::ProportionalHeight); QTextCursor blockCursor(block); blockCursor.setBlockFormat(fmt); } cursor.endEditBlock();

这段代码的核心逻辑是:先拿到document,从begin遍历到结尾,对每个块读取原有blockFormat,修改lineHeight后写回。注意setLineHeight有两个参数,第一个是数值,第二个是类型。ProportionalHeight用百分比表示,145表示行高是字体高度的145%;如果你想严格用像素,可以把第二个参数改成FixedHeight,然后第一个参数传具体像素值,比如24。使用beginEditBlock/endEditBlock是为了把多次块格式修改放到一个undo事务里,避免界面反复重排。

这也是我在整理QtLabelLineSpacing方案时最终选择的主要实现思路:不是每次setText后临时改document,而是把行距参数记录在Label子类里,setText时统一应用。这样后续对多段落、富文本和超链接的支持都更自然,因为QTextDocument本身就是一个完整文档模型。

2.4 自绘QLabel:什么时候才需要走上这条路

自绘方案是最后的手段。做法是让QLabel setText只保存文本,然后重写paintEvent,在内部创建一个QTextDocument,设置document的text和默认字体,并用QTextBlockFormat调整行距,再通过doc.draw()把文本画到设备上。好处是行距完全由自己控制,甚至可以做到按字形、按颜色灵活切换;坏处是你得自己处理paintEvent里的颜色、背景、边框、对齐、QSS失效等一堆问题,开发量会成倍增加,而且Qt Designer里不能直观预览。

我一般什么情况下会用自绘呢?通常是文本内容里需要混合不同字体大小,且行距要按段落切换,比如日志查看器、歌词逐行高亮这类控件。如果你只是想给QLabel加一个能设行距的封装,完全用不着自绘。所以最终推荐路线是:优先用QTextBlockFormat,把行距逻辑封装成LineSpacingLabel类,这样后续维护和扩展最省心。

3. 手工拆包:实现一个LineSpacingLabel,把QtLabelLineSpacing.zip里的核心类搬到你的工程

3.1 头文件里需要哪些成员

直接上类声明。我们需要的核心成员是行距值、行距类型、以及一个格式应用函数。

#ifndef LINESPACINGLABEL_H #define LINESPACINGLABEL_H #include <QLabel> #include <QTextBlockFormat> class LineSpacingLabel : public QLabel { Q_OBJECT public: explicit LineSpacingLabel(QWidget *parent = nullptr); // 设置额外行距(像素),比如 6,表示行之间多 6px void setLineSpacing(qreal spacingPx); // 设置行高,heightType 取 FixedHeight 或 ProportionalHeight void setLineHeight(qreal height, int heightType); // 比 QLabel::setText 多做一步格式应用 void setLabelText(const QString &text); protected: void paintEvent(QPaintEvent *event) override; QSize sizeHint() const override; private: void applyBlockFormat(); qreal m_lineSpacingPx = 0; qreal m_lineHeight = 0; int m_heightType = QTextBlockFormat::FixedHeight; }; #endif // LINESPACINGLABEL_H

成员变量说明:m_lineSpacingPx用于保存用户传进来的额外行距,m_lineHeight和m_heightType用来描述固定行高或比例行高。这两个系列可以并存,Qt在绘制时会先按lineHeight计算行高,再加上lineSpacing作为额外间距。所以实际行高 = lineHeight + lineSpacing。

这里的设计有一个细节:不重写QLabel::setText,而是提供setLabelText,避免不小心覆盖到基类行为导致QSS或属性流失。如果你确实想覆盖,也可以,但要注意在内部先调用基类setText,再调用applyBlockFormat。

3.2 源文件实现:关键在applyBlockFormat和updateGeometry

#include "LineSpacingLabel.h" #include <QTextDocument> #include <QTextBlock> #include <QTextCursor> #include <QStylePainter> #include <QStyleOptionFrame> LineSpacingLabel::LineSpacingLabel(QWidget *parent) : QLabel(parent) { setWordWrap(true); setAlignment(Qt::AlignLeft | Qt::AlignTop); } void LineSpacingLabel::setLineSpacing(qreal spacingPx) { m_lineSpacingPx = spacingPx; applyBlockFormat(); updateGeometry(); update(); } void LineSpacingLabel::setLineHeight(qreal height, int heightType) { m_lineHeight = height; m_heightType = heightType; applyBlockFormat(); updateGeometry(); update(); } void LineSpacingLabel::setLabelText(const QString &text) { QLabel::setText(text); applyBlockFormat(); updateGeometry(); } void LineSpacingLabel::applyBlockFormat() { QTextDocument *doc = document(); if (!doc) return; QTextCursor cursor(doc); cursor.beginEditBlock(); for (QTextBlock block = doc->begin(); block.isValid(); block = block.next()) { QTextBlockFormat fmt = block.blockFormat(); if (m_lineHeight > 0) fmt.setLineHeight(m_lineHeight, m_heightType); fmt.setLineSpacing(m_lineSpacingPx); QTextCursor blockCursor(block); blockCursor.setBlockFormat(fmt); } cursor.endEditBlock(); } void LineSpacingLabel::paintEvent(QPaintEvent *event) { // 沿用 QLabel 的绘制,因为基类绘制时会使用document, // 而document里的blockFormat已经更新,所以直接调用基类即可。 QLabel::paintEvent(event); } QSize LineSpacingLabel::sizeHint() const { QSize s = QLabel::sizeHint(); if (s.height() > 0) s.setHeight(s.height() + int(m_lineSpacingPx)); return s; }

这段实现里,paintEvent看起来有点多余,但我是特意保留的,因为很多人在自定义QTextDocument绘制时会卡在“改了blockFormat不刷新”上。对于QLabel,只要document里的blockFormat变了,调用update()后,QLabel自带的paintEvent会重新绘制,行距就已经生效了。但是,如果你发现没生效,那就要检查是不是文本被QLabel内部缓存了,这时可以在setText后强制写doc->markContentsDirty(0, doc->characterCount());我把它写在避坑章节里。

sizeHint的调整同样关键。QLabel在布局里计算最小高度时,不会把行距算进去,所以如果只有paintEvent生效,标签高度不够,文字会被裁掉。所以每次设置行距后,需要调用updateGeometry(),让父布局重新计算。这是很多初次照着示例改的人最容易漏掉的一步。

3.3 行距单位与混排场景的换算

参数怎么设,直接关系到最终效果。我给你的经验数值是:

  • 默认文案、按钮说明:额外行距2到4像素,或者行高110%到120%。
  • 多行段落、中文正文:行高140%到160%,阅读舒适。
  • 英文或数字为主的界面:行高120%到140%,英文本身行高够,加太多会显得松散。

留意一点:ProportionalHeight的比例是相对行内最大的字体高度计算的,不是相对像素字号。如果你的文本里有12px中文和16px英文混排,行高百分比会按最大字号跑,最后行距可能比你预想的大。这种场景别犹豫,直接用FixedHeight像素值,比如24px,更可控。还有一个常见误区是以为setLineSpacing(6)就是行间距离6像素,但实际上这是额外加在字体行高上的值,最终视觉间距会比6像素更大,因为字体行高本身还有leading。

QtLabelLineSpacing方案里,我通常会把两个接口都暴露出来:setLineSpacing用于微调,setLineHeight用于整体定比例。这样在UI上你可以用一个QSlider控制额外间距,一个QComboBox切换固定/比例行高,任何文本都能快速找到合适的行距。

4. 把QtLabelLineSpacing.zip接进你的工程:从Qt Creator到MSVC Qt 5.15.2的落地路径

4.1 在Qt Creator里把两个文件加入工程

不管你的Qt工程用的是QMake还是CMake,把LineSpacingLabel.h和LineSpacingLabel.cpp丢进源码目录,然后加入构建列表即可。QMake项目在.pro文件里这样追加:

HEADERS += LineSpacingLabel.h SOURCES += LineSpacingLabel.cpp

CMake项目则在CMakeLists.txt里追加:

set(SOURCES main.cpp MainWindow.cpp LineSpacingLabel.cpp ) set(HEADERS MainWindow.h LineSpacingLabel.h )

加入后先直接编译一次,确认没有语法错误。随后在MainWindow或你的对话框里,把需要行距的QLabel提升为LineSpacingLabel。提升控件的方法是在Qt Designer里选中Label,右键->“提升为…”,输入类名LineSpacingLabel,然后加上头文件。如果你跟我一样更喜欢纯代码写界面,那就直接:

LineSpacingLabel *label = new LineSpacingLabel(this); label->setLabelText(QStringLiteral("服务状态:运行中\n最近心跳:2025-02-18 10:23:45")); label->setLineSpacing(6); layout->addWidget(label);

插一句与Qt QML的对比:如果你是在QML里做界面,Text控件自带了lineHeight属性,处理行距很简单;但Qt Widgets里没有等价接口,所以才需要这个类。这也解释了为什么很多从QML转Widgets的开发者,一上来就四处搜QLabel行距。

slots里setLineSpacing可以绑定到一个QSpinBox,valueChanged信号触发,这样界面上一调滑块,文本行距就实时变化。实际项目中我会把setLineSpacing连接到一个QDoubleSpinBox,范围0到20,步进0.5,这样微调更细腻。

4.2 用垂直布局验证行距:一个最简单的复现命令

如果你想把验证做到位,可以创建一个临时工程,只放一个LineSpacingLabel和两个QPushButton,把按钮高度设置成默认,看label是否把布局撑开。关键验证代码如下:

auto *spin = new QSpinBox; spin->setRange(0, 20); spin->setValue(6); connect(spin, QOverload<int>::of(&QSpinBox::valueChanged), label, [label](int v){ label->setLineSpacing(v); });

逻辑说明:QSpinBox的范围是0到20像素,默认值6。每调节一档,LineSpacingLabel就会应用新的blockFormat并updateGeometry。这一步如果发现label底部文字被切掉,说明你漏了sizeHint或没有调用updateGeometry,后面避坑章节会讲。你还可以在循环里加一个QLabel显示当前文本像素高度,直观看到行距对高度的贡献。

4.3 Qt版本和编译套件的四个注意点

第一,Qt 5.15.2加MSVC 2019_64是目前桌面端很常见的一套组合,但很多人在刚下载Qt和使用QtLabelLineSpacing示例工程时,会碰到类似:-1: error: dependent '..\..\..\..\..\..\qt\5.15.2\msvc2019_64\include\qtwidgets...'的报错。这种报错通常不是代码问题,而是项目文件里的路径用了相对路径,且工程路径太长或带中文,导致Qt Creator截断依赖项。解决办法是把工程放到盘符下短路径,比如D:/code/ls,并且检查构建套件里Qt路径是否正确。

第二,Qt 6的QTextBlockFormat接口和Qt 5是兼容的,但有些富文本CSS属性在Qt 6.4以后行为更严格。如果你在Qt 6上还在用HTML的line-height方案,很可能发现百分比不生效,建议统一改用QTextBlockFormat。如果你是VS2022加Qt Solutions插件,也要注意不同Visual Studio版本的插件对Qt版本的支持差异,必要时切换MSVC或WinGW套件交叉验证。

第三,MinGW版和MSVC版混用头文件,编译会直接爆一堆链接错误。QtLabelLineSpacing里的类代码是跨编译器的,但如果你在MSVC工程里混入了MinGW编译的库,或者反过来,那么崩溃和“unresolved external symbol”就会找上门。拿到zip包后,先确认你的Qt构建套件,再决定用哪个编译器。

第四,关于qt打包,如果最后要把程序分发到别的电脑,别忘了把对应编译器的Qt运行库一起带上。用windeployqt是最省事的做法,命令是:

windeployqt D:\release\LineSpacingDemo.exe

它会把需要的Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll和platforms插件拷到exe目录。开发机跑得好,客户机器一运行就崩,往往不是行距代码的问题,而是缺平台插件。这事经常被误归因成“你的LineSpacingLabel导致崩溃”,其实和label一点关系没有。

5. 避坑记录:LabelLineSpacing使用中的5个常见症状、原因和解法

这一章写我实际调试中遇到过的问题。每一条按“现象 -> 原因 -> 解决”展开,这些坑多数是用上线后的修改时间和口碑换来的。

5.1 现象:setLineSpacing之后文本没任何变化

经常有人发代码过来,说setLineSpacing(10)明明调用了,界面纹丝不动。我排查后十有八九是以下三种情况:一是label的text是纯文本,而document里的block格式恰好没被遍历到;二是调用了setLineSpacing后又调用了setText,setText把之前的格式冲掉了;三是你用的QLabel不是LineSpacingLabel,只是普通QLabel。

原因:QLabel::setText()会重建文档,原blockFormat全丢。解决方法很简单,把setText改成setLabelText,让类内部在setText后再调用applyBlockFormat。如果你非要覆盖大法子,也可以在每次setText之后手动循环block设置。这个现象表现为“上一次设置的间距,换个文本就没了”。

5.2 现象:行距生效了,但label高度没变大,下面文字被截掉

在纯手工布局时最常见。因为QLabel的sizeHint只算字体行高,不算额外行距,所以父布局给label分配的高度不够。此时文字会被裁剪,看起来就像行距白设了。

原因:没走updateGeometry,布局系统还是按旧文本高度计算。

解决:在setLineSpacing和setLineHeight里,除了applyBlockFormat,还要调用updateGeometry()和update()。我在第3章代码里已经写过。如果你是自己实现,必须要加。另外如果用了垂直布局,让布局的sizeConstraint保持默认的QLayout::SetDefaultConstraint,不要手动把label固定死。固定高度是最容易踩坑的做法。

5.3 现象:中英文混排时,行距忽大忽小

中文显示行距正常,英文段落却特别紧;或者一行里既有中文又有数字,行距变得粗细不匀。原因是ProportionalHeight是相对行内最大字体的,如果中文字体族里数字字体和英文字体从fallback里取到不同高度,百分比行高就不稳定。

解决:这种场景把行高改成FixedHeight,比如统一设为当前字体height()的1.4倍。或者先把当前字体Metrics算出来的行高作为基准,再把基准乘以系数,在setLineHeight里传入具体像素值。更稳妥的办法是不要依赖百分比,而是自己算。

5.4 现象:Qt Designer里预览完全看不到调整效果

因为提升控件后,Qt Designer的预览进程不会真正加载你自定义类的绘制逻辑,它只会用简化渲染。这是Qt Designer自身机制的限制,不是代码问题。

解决:在UI文件里提升控件后,必须重新构建整个工程,再用Qt Creator运行模式看效果。如果你用的是动态提升(promote),还要注意designer插件没有加载你的类。别浪费时间在预览上,直接跑起来看。做界面时我用Qt Designer,但验证行距一定运行exe,这是效率最高的方式。

5.5 现象:QSS写line-height:150%不生效,界面在发布版出现奇怪换行

QSS是Qt Style Sheets的缩写,它控制控件外观,但不支持line-height。我见过有人把line-height:1.5写在setStyleSheet里,结果文本不再显示或运行期Qt崩溃,原因就是QLabel的样式表遇到未知属性时直接跳过,行为无法预期。

解决:别在QSS里调行距。实在要统一管理,就把LineSpacingLabel的行距值放在一个全局设置里,通过update()刷新。如果因为样式表导致崩溃,先检查是否使用了非法属性,删掉后再测一次。这条也算是血泪经验,我自己就在某个重构版本里这么干过,结果一启动就翻车,查了半天才发现是QSS在作怪。

以上就是我在这类行距需求中遇到过的几类典型问题。记住一个原则:凡是和文本显示相关的行为,改完格式后一定要触发updateGeometry和update,否则表现会像“没生效”。

6. 让QLabel行距随DPI自动缩放:一个能直接写进生产环境的进阶技巧

当你做完上面的封装,会发现一个隐藏问题:Windows系统缩放从100%调到150%时,QLabel的字体变大了,但行距还是固定的那6像素,视觉比例一下子变得很挤。所以我想分享一个技巧:把行距保存成“相对当前字号的比例”,每次系统DPI变化或字体变化时重新计算。

具体做法是给LineSpacingLabel增加一个事件处理:

bool LineSpacingLabel::event(QEvent *e) { if (e->type() == QEvent::FontChange || e->type() == QEvent::ApplicationFontChange || e->type() == QEvent::DpiChange) { QFontMetrics fm(font()); setLineSpacing(fm.lineSpacing() * m_scaleFactor); } return QLabel::event(e); }

其中m_scaleFactor是你定义的相对系数,比如0.15,表示额外行距是当前行高的15%。这样当界面从100%变成125%缩放时,字体高度变大,行距也跟着变大,不会出现局部拥挤。

这里要注意两点:一是QEvent::DpiChange在Qt 5.14之后才比较可靠,低版本Qt可以用自己监听WM_DPICHANGED或者重写resizeEvent处理;二是这个技巧不止用于QLabel,也可以用于QListView的item行距,但实现方式就要换到QListWidget::setSpacing,或者使用delegate的sizeHint,原理是一样的。

最后再提一个验证方法:把系统缩放调到150%,截一张图,跟100%缩放时对比行距和字号的比值。如果你看到的行距仍然占字高15%左右,说明你的写法是对的。这套做法救过我很多次,因为我以前在Qt 5.15.2的工程里也是把行距写成死像素,后来设备出厂时开了125%缩放,顿时界面文字全部叠在一起,只能连夜返工。现在我将行距参数都设计成相对比例,内部用FixedHeight配合字体高度乘系数,彻底不吃这种亏了。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 14:02:09

马尾辫怎么扎好看?从高度、流向到张力的技术拆解

马尾辫这东西&#xff0c;大家都不陌生。小时候妈妈每天早晨在镜子前帮我们扎的那根马尾&#xff0c;可能是多数人对“发型管理”的最初记忆。但真正入行做造型之后我才发现&#xff0c;越简单的发型越见真功夫。一根皮筋能扎出精神利落的通勤款&#xff0c;也能扎出慵懒随性的…

作者头像 李华
网站建设 2026/10/31 13:58:58

HTML5实现服务条款页面的技术与法律实践

1. 服务条款的基本概念与法律意义 服务条款&#xff08;Terms of Service&#xff0c;简称ToS&#xff09;是互联网服务提供商与用户之间的法律协议&#xff0c;它定义了用户使用服务时的权利、义务和行为准则。作为网站或应用程序的"宪法"&#xff0c;服务条款在数字…

作者头像 李华
网站建设 2026/10/31 13:58:51

腾讯会议API集成开发实战指南

1. 腾讯会议API集成技术文档解析 作为企业级视频会议解决方案的头部产品&#xff0c;腾讯会议开放平台提供了丰富的API接口能力&#xff0c;允许开发者将会议功能深度集成到自有系统中。这份技术文档将重点解析腾讯会议API的核心功能、集成流程及实战技巧。 我曾在多个企业数字…

作者头像 李华
网站建设 2026/10/31 13:58:18

冰面漂移中的MPC控制算法优化与实践

1. 冰面漂移中的MPC控制挑战 冰面漂移对控制算法提出了三个维度的极限要求&#xff1a;首先是极低的路面摩擦系数&#xff08;μ≈0.1-0.2&#xff09;&#xff0c;传统轮胎侧向力模型在冰面上呈现高度非线性&#xff1b;其次是车辆动力学状态的快速变化&#xff0c;漂移过程中…

作者头像 李华
网站建设 2026/10/31 13:56:42

3D旋转姿态表示:旋转矩阵、欧拉角与四元数工程避坑

上周有同学拿着一段姿态解算代码来问&#xff1a;他在编辑器面板里把某一个角度改成 30&#xff0c;模型转出来的方向跟他在代码里算的完全对不上&#xff0c;一个往左一个往右。我扫了两眼就笑了&#xff0c;这不是算错了&#xff0c;是三个约定里至少有两个没对齐——旋转顺序…

作者头像 李华
网站建设 2026/10/31 13:56:04

Paillier同态加密实现联邦学习安全聚合系统

简介&#xff1a;本资源是一套完整的毕业设计级项目源码&#xff0c;面向计算机、人工智能、通信工程等专业的本科生及初学者&#xff0c;聚焦联邦学习中关键的安全聚合问题&#xff0c;通过Paillier同态加密实现客户端本地模型参数的密文上传与服务器端安全聚合&#xff0c;兼…

作者头像 李华