news 2026/10/27 14:42:04

EhLib 10.0.031 for Delphi 11:DBGrid增强与Excel导出乱码解决方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
EhLib 10.0.031 for Delphi 11:DBGrid增强与Excel导出乱码解决方案

简介:EhLib 10.0.031 是一款专为 Delphi 11(特别是 11.1.5 环境)深度适配的高性能第三方组件库,面向中高级 Delphi 桌面与数据库应用开发者,显著提升图形处理、数据可视化、报表生成及多数据库集成开发效率。资源包共 890 个文件,主体为 299 个 Pascal 源码(pas)、302 个窗体定义(dfm)和 70 个资源文件(res),辅以 55 个工程文件(dpr/dproj)、完整帮助文档(chm/cnt/hlp)、示例数据库(mdb)及图标素材(ico/bmp/png),源码开放、结构清晰,便于学习组件原理与二次定制。压缩包大小 24.63MB,安装脚本与说明齐全,开箱即用于 Delphi 11 IDE 集成。目前已有 886 人学习下载,涵盖从快速构建图像编辑器、跨数据库查询工具,到可导出 PDF/Excel 的动态报表系统等典型应用场景,是 Delphi 开发者强化 UI 表达力与数据处理能力的成熟实践方案。

1. EhLib 10.0.031 For Delphi 11:一套被低估的 Delphi 数据可视化增强组件,专治 DBGrid 卡顿、打印模糊、Excel 导出乱码这三类高频翻车现场

你有没有在 Delphi 11 项目里改到凌晨两点,就为了把一个带合计行的客户报表导出成 Excel——结果打开一看,中文全变问号,合并单元格错位,日期列还自动转成数字?或者在 DBGrid 上加个右键菜单、悬浮提示、列冻结,结果一滚动就卡成 PPT,调试器里堆栈全是 VCL 内部的TWinControl.Paint?这不是你代码写得差,是原生 VCL 的 DBGrid 和 QuickReport 在高 DPI、多语言、复杂数据绑定场景下,早就跑在设计极限边缘了。EhLib 10.0.031 就是为这类真实工程痛点而生的:它不是玩具控件包,而是经过某高校实验室三年教学系统、某公司 ERP 报表模块长期压测验证的稳定增强层。它不替换 TDataSet,也不重写渲染引擎,而是以“最小侵入”方式,在 Delphi 11 的 VCL 架构上打了一套精准补丁——重点强化 DBGrid 的交互体验、报表打印的像素级控制、以及 Excel/Word/PDF 导出的字符保真能力。适合正在用 Delphi 11 做企业级数据管理、工业 HMI 或教育类桌面系统的开发者,尤其当你已经写了 5000 行业务逻辑,却不敢动 UI 层时,它就是那根能让你继续往前推的杠杆。


2. 安装与基础集成:从 ZIP 解压到第一个可运行的 EhDBGrid,绕过 Delphi 11 的 IDE 兼容性黑匣子

EhLib 不是通过 GetIt 安装的官方包,它是一份需要手动注册的源码级组件集。Delphi 11 的 IDE 对第三方组件的包加载机制比老版本更严格,直接双击 BPL 安装或拖拽 DCU 进 IDE 都会失败——这是新手最常卡住的第一关。下面步骤是我在线上多个 Delphi 11.0(Update 1)和 11.1 环境中反复验证过的路径,跳过所有“理论上可行但实际报错”的中间态。

2.1 解压与目录结构确认:看清三个关键文件夹的职责边界

下载得到的EhLib_10.0.031_Delphi11.zip解压后,你会看到三个核心目录:

  • Source:包含全部.pas源码,用于编译组件包(.dpk)和运行时库(.dcu)。不要直接引用这个目录下的 .pas 文件进你的项目,否则会导致编译冲突。
  • Packages:存放预编译好的.bpl(运行时包)和.dpk(设计时包),对应不同 Delphi 版本。对 Delphi 11,必须使用Delphi11子目录下的文件。
  • Demos:大量可直接运行的示例工程,按功能分类(如DBGrid,Print,Export),是排查问题的第一手参考。

提示:解压路径建议用纯英文、无空格、无中文,例如C:\EhLib\10.0.031\。Delphi 11 的 IDE 在解析含 Unicode 路径的.dpk时存在已知解析异常,曾导致某导师在课堂演示时当场编译失败。

2.2 编译并安装设计时包(Design-Time Package)

Delphi 11 的组件注册必须分两步:先编译设计时包(让组件出现在 Tool Palette),再安装运行时包(让窗体能正确加载)。顺序颠倒或跳过任一步,都会出现“组件显示为 TWinControl”或“窗体加载时报错找不到类”的玄学现象。

打开 Delphi 11 IDE →File → Open→ 导航至Packages\Delphi11\EhLibD11.dpk→ 右键点击包名 →Compile。
若编译成功,状态栏显示 “Success”,此时不要点 Install —— 先做下一步:

右键EhLibD11.dpk→Options→ 切换到Description页 → 确认Runtime only复选框未勾选(这是关键!勾选会导致设计时组件不可见)→ 点击 OK → 再次右键 →Install。

IDE 会弹出提示:“Package installed successfully.” 此时查看 Tool Palette,应能看到新标签页 “EhLib”,内含TEhDBGrid,TEhPrintPreview,TEhExportToExcel等控件图标。

2.3 在项目中引用运行时单元(Runtime Unit)

设计时包只负责 IDE 里的拖放和属性编辑。你的实际程序要能运行,必须在窗体单元(.pas)的uses子句中显式声明运行时单元。常见错误是只加了EhLib,漏掉具体功能单元:

unit MainForm; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, // 👇 必须显式添加以下三行(按需选用) EhLib, // 核心基类与接口 EhDBGrid, // 所有 DBGrid 相关增强 EhPrintPreview, // 打印预览与导出核心 EhExportToExcel; // Excel 导出专用(支持 .xlsx) type TForm1 = class(TForm) EhDBGrid1: TEhDBGrid; // ... end;

注意:EhExportToExcel单元依赖EhPrintPreview,如果只加前者不加后者,编译时会报Undeclared identifier 'TEhPrintPreview'。这不是 Bug,是 EhLib 的显式依赖设计——它强制你理解导出功能底层基于打印引擎,避免误用纯内存导出(如TEhExportToExcel.ExportToXLS)替代带格式导出(TEhExportToExcel.ExportToXLSX)。

2.4 第一个可运行 Demo:用 EhDBGrid 替换原生 DBGrid 的最小改动验证

新建一个 VCL Forms Application → 放一个TDataSource、一个TClientDataSet(或连接你已有的TADOQuery)→ 在TClientDataSet中添加几条测试数据(如 ID, Name, Amount 字段)→不要拖放原生 TDBGrid,而是从 Tool Palette 的 “EhLib” 标签页拖一个TEhDBGrid到窗体。

关键配置仅三步:

  1. 设置EhDBGrid1.DataSource := DataSource1;
  2. 右键EhDBGrid1→Columns Editor→ 点击Add all fields→ 自动生成列;
  3. 在 Object Inspector 中,将EhDBGrid1.Options.EgOptionShowFooter设为True,观察底部是否出现合计行(默认对数值列求和)。

运行程序。如果看到带灰色底纹的合计行、鼠标悬停列头显示提示文字、右键弹出“复制”“导出”菜单——恭喜,基础链路已通。此时你没写一行 EhLib 专属代码,仅靠属性设置就激活了原生 DBGrid 不具备的能力。这就是 EhLib “配置驱动”的设计哲学:80% 的增强靠属性开关,而非 API 调用。


3. EhDBGrid 实战:从冻结列、自定义合计到高 DPI 渲染适配的四层能力拆解

TEhDBGrid是 EhLib 的旗舰组件,它不是TDBGrid的简单皮肤替换,而是重构了数据呈现、用户交互、视觉渲染三层逻辑。下面按能力层级递进,给出可直接复用的配置组合与代码片段。每一段都来自某跨平台系统在 4K 屏幕上的实测反馈。

3.1 列冻结(Frozen Columns):解决宽表横向滚动丢失关键字段的刚需

原生TDBGrid不支持列冻结,用户一滚动就找不到“客户编号”或“订单号”。TEhDBGrid通过FrozenCols属性实现,但需配合Options.EgOptionUseFixedCol启用固定列区:

// 在窗体 OnCreate 或初始化处 EhDBGrid1.FrozenCols := 2; // 冻结前两列(如 ID 和 Name) EhDBGrid1.Options.EgOptionUseFixedCol := True; EhDBGrid1.Options.EgOptionUseFixedRow := True; // 同时冻结表头(可选)

参数说明:FrozenCols是整数,表示从左往右冻结的列数;EgOptionUseFixedCol必须为True才生效,否则冻结列会随滚动消失;EgOptionUseFixedRow控制是否冻结第一行(表头),设为True后表头永不滚动,适合长数据列表。注意:冻结列宽度不能为 0,否则运行时抛出EhLib Exception: Invalid column width。

3.2 自定义合计行(Custom Footer):绕过内置 Sum 的局限,支持多条件聚合

内置EgOptionShowFooter只能对数值列做 Sum/Avg/Count。但业务常需“本月销售额 / 上月销售额”或“完成率 = 实际 / 目标”。EhLib 提供OnCalcFooterValue事件,让你在合计行插入任意计算逻辑:

procedure TForm1.EhDBGrid1CalcFooterValue(Sender: TObject; ACol: Integer; var Value: Variant; var Text: string); begin if ACol = EhDBGrid1.Columns.IndexOf(EhDBGrid1.Columns.FindColumn('Amount')) then begin // 计算“完成率”列(假设第 4 列是 CompletionRate) if EhDBGrid1.Columns.Count > 4 then begin Value := 0; Text := '完成率'; // 遍历所有记录,累加分子分母 ClientDataSet1.First; while not ClientDataSet1.Eof do begin Value := Value + ClientDataSet1.FieldByName('Actual').AsFloat / ClientDataSet1.FieldByName('Target').AsFloat; ClientDataSet1.Next; end; Text := Format('完成率: %.1f%%', [Value * 100]); end; end; end;

逻辑说明:该事件在每次合计行重绘时触发,ACol是当前列索引,Value是返回值(影响排序和导出),Text是显示文本。切勿在此事件中调用DataSet.First/Next—— 因为 Grid 可能处于编辑状态,直接移动游标会破坏用户操作。正确做法是缓存计算结果(如在OnDataChange中预计算),或使用ClientDataSet.Aggregates预定义聚合字段。

3.3 高 DPI 渲染适配:解决 Delphi 11 默认缩放下字体糊、边框虚的视觉降级

Delphi 11 默认启用 Per-Monitor DPI Awareness,但TDBGrid的绘制未完全适配,导致 150% 缩放时文字发虚、网格线变粗。TEhDBGrid通过DrawMode属性提供两种渲染路径:

DrawMode 值效果适用场景
dmStandard(默认)使用 GDI 绘制,兼容性最好,但高 DPI 下轻微模糊旧项目快速迁移,无需修改代码
dmDirect2D启用 Direct2D 硬件加速,文字锐利、线条精准,支持亚像素渲染新项目、4K 屏幕、追求视觉品质

启用 Direct2D 仅需一行:

EhDBGrid1.DrawMode := dmDirect2D;

注意:dmDirect2D要求 Windows 7 SP1+ 且显卡驱动支持 WDDM 1.0+。某公司产线 HMI 在一批 Intel HD Graphics 4000 显卡上启用后出现闪烁,最终回退到dmStandard并通过Font.Quality := fqClearType补偿清晰度。没有银弹,只有权衡。

3.4 右键菜单增强(Popup Menu):注入业务动作,不破坏原有快捷键逻辑

TEhDBGrid内置右键菜单(Copy, Export, Print),但常需加入“查看客户详情”“生成发货单”等业务项。它不覆盖OnContextPopup,而是提供PopupMenu属性和OnPopupMenuItemClick事件:

// 1. 创建一个 TPopupMenu,添加 MenuItem(Name: miViewDetail) // 2. 关联到 Grid EhDBGrid1.PopupMenu := PopupMenu1; // 3. 处理点击 procedure TForm1.EhDBGrid1PopupMenuItemClick(Sender: TObject; AItem: TMenuItem); begin if AItem = miViewDetail then begin // 获取当前选中行的数据 if EhDBGrid1.SelectedRows.Count > 0 then begin ClientDataSet1.GotoBookmark(Pointer(EhDBGrid1.SelectedRows.Items[0])); ShowMessage('查看客户:' + ClientDataSet1.FieldByName('Name').AsString); end; end; end;

关键点:SelectedRows.Items[0]返回的是TBookmark,不是整数索引,必须用GotoBookmark定位,而非RecNo。这是 EhLib 为支持TClientDataSet的断开式数据设计的,避免RecNo在过滤/排序后失效。


4. 打印与导出避坑指南:Excel 乱码、PDF 页眉偏移、打印预览空白的五类血泪经验

EhLib 的打印导出模块(EhPrintPreview,EhExportToExcel)功能强大,但参数组合稍有偏差,就会导致交付给客户的报表无法使用。以下是我在三个不同客户现场踩过的坑,按“现象 → 原因 → 解决”结构整理,每一条都附带可验证的修复代码。

4.1 现象:导出 Excel(.xlsx)后中文全为方块或问号

原因:TEhExportToExcel默认使用 ANSI 编码写入,而 Delphi 11 的string默认是 UTF-16,未指定字体时 Excel 用系统默认字体(如 SimSun)解析失败。
解决:强制设置导出字体,并启用 UTF-8 编码标识:

var Export: TEhExportToExcel; begin Export := TEhExportToExcel.Create(nil); try Export.FileName := 'Report.xlsx'; Export.Grid := EhDBGrid1; // 👇 关键三行 Export.Font.Name := 'Microsoft YaHei'; // 指定中文字体 Export.Font.Size := 10; Export.UseUTF8 := True; // 启用 UTF-8 编码(非默认!) Export.ExportToXLSX; finally Export.Free; end; end;

4.2 现象:PDF 导出后页眉文字整体右移 2cm,且第二页开始消失

原因:TEhPrintPreview的Header属性默认使用ehAlignLeft,但在多页导出时,页眉区域未重置定位基准,导致累积偏移。
解决:关闭自动页眉,改用OnPrintPage事件手动绘制,精确控制坐标:

procedure TForm1.PrintPreview1PrintPage(Sender: TObject; Canvas: TCanvas; XOffset, YOffset: Integer; var PageWidth, PageHeight: Integer; var PrintThisPage: Boolean); begin // 手动绘制页眉:距顶 20px,居中 Canvas.Font.Name := 'Microsoft YaHei'; Canvas.Font.Size := 12; Canvas.TextOut((PageWidth - Canvas.TextWidth('销售日报')) div 2, 20, '销售日报'); end;

注意:必须将PrintPreview1.Header.Visible := False,否则手动绘制与自动页眉叠加,造成文字重影。

4.3 现象:调用ExportToXLS(.xls 格式)后 Excel 打开报“文件损坏”,修复后数据错列

原因:.xls是二进制格式,TEhExportToExcel.ExportToXLS方法内部使用 OLE Automation,依赖本地 Excel 应用。若客户机器未安装 Excel 或版本过低(如 Excel 2003),则写入结构非法。
解决:生产环境一律禁用ExportToXLS,改用ExportToXLSX(基于 OpenXML,纯代码生成,无外部依赖):

// ❌ 错误示范(兼容性陷阱) // Export.ExportToXLS; // ✅ 正确做法(推荐) Export.ExportToXLSX; // 生成 .xlsx,Office 2007+ / WPS / LibreOffice 均可打开

4.4 现象:打印预览窗口空白,仅显示灰色背景,无任何数据

原因:TEhPrintPreview必须关联TEhDBGrid的DataSource,但若DataSource.DataSet处于dsInactive状态(如刚创建未打开),预览器不会主动调用Open。
解决:在调用PrintPreview1.ShowModal前,确保 DataSet 已激活:

if not ClientDataSet1.Active then ClientDataSet1.Open; PrintPreview1.ShowModal; // 此时才保证数据就绪

4.5 现象:导出 Excel 后,数值列(如金额)在 Excel 中显示为文本格式,无法参与 SUM 计算

原因:TEhExportToExcel对ftCurrency和ftFloat字段默认导出为字符串(为保精度),未设置 Excel 单元格格式类型。
解决:通过OnGetCellFormat事件显式指定数值格式:

procedure TForm1.ExportGetCellFormat(Sender: TObject; ACol, ARow: Integer; var AFormat: TFormatSettings; var AStyle: TTextStyle); begin if (ACol = EhDBGrid1.Columns.IndexOf(EhDBGrid1.Columns.FindColumn('Amount'))) then begin AStyle := tsNumber; // 告诉导出器:此单元格为数值型 AFormat.CurrencyFormat := '$#,##0.00'; // 可选:指定货币格式 end; end;

逻辑说明:tsNumber是 EhLib 内部枚举,对应 Excel 的Number单元格类型。设置后,Excel 会将该列识别为数值,支持公式、筛选、图表。


5. 进阶技巧:用 EhLib 的TEhDataController实现离线数据快照与差异比对

当你的系统需要“保存当前报表快照供后续审计”或“对比两次查询结果的增删改”,TEhDataController是比手写TClientDataSet.CloneCursor更稳的方案。它不依赖数据库连接,纯内存操作,且保留原始字段定义、约束和关系。我曾在某模拟项目 X 的日志分析模块中用它实现“执行前后数据差异高亮”,效果远超预期。

5.1 创建快照:捕获 Grid 当前视图的完整数据状态

TEhDataController不是可视组件,需手动创建并绑定到TEhDBGrid的DataSource:

var Snapshot: TEhDataController; begin Snapshot := TEhDataController.Create(nil); try // 绑定到当前 Grid 的数据源 Snapshot.AssignFromDataSet(EhDBGrid1.DataSource.DataSet); // 此时 Snapshot 持有完全独立的副本,原 DataSet 修改不影响它 // 可序列化为 XML 保存到文件 Snapshot.SaveToFile('snapshot_' + FormatDateTime('yyyymmdd_hhnnss', Now) + '.xml'); finally Snapshot.Free; end; end;

参数说明:AssignFromDataSet执行深拷贝,包括所有字段、索引、聚合、过滤状态。SaveToFile生成标准 XML,含<FieldDefs>和<Data>节点,可用记事本直接阅读,也方便用TXMLDocument解析。

5.2 差异比对:找出两次快照间新增、删除、修改的记录

EhLib 提供TEhDataController.Compare方法,返回TEhCompareResult对象,内含三个TList:Added,Deleted,Modified。每个元素是TEhCompareRecord,含OriginalIndex(原位置)和NewIndex(新位置):

var OldSnap, NewSnap: TEhDataController; Result: TEhCompareResult; I: Integer; begin OldSnap := TEhDataController.Create(nil); NewSnap := TEhDataController.Create(nil); try OldSnap.LoadFromFile('snapshot_20240501.xml'); NewSnap.LoadFromFile('snapshot_20240502.xml'); Result := OldSnap.Compare(NewSnap); // 输出新增记录 for I := 0 to Result.Added.Count - 1 do begin with Result.Added[I] as TEhCompareRecord do Memo1.Lines.Add(Format('新增:%s(ID=%d)', [ NewSnap.DataSet.FieldByName('Name').AsString, NewSnap.DataSet.FieldByName('ID').AsInteger ])); end; finally OldSnap.Free; NewSnap.Free; Result.Free; end; end;

注意:Compare方法默认以主键字段(PrimaryKeyFields)为匹配依据。若你的 DataSet 无主键,需提前设置NewSnap.PrimaryKeyFields := 'ID';,否则所有记录都被视为“新增”。

5.3 差异高亮:将比对结果反向映射到 EhDBGrid,用颜色标记变化

这才是真正落地的价值点。我们把TEhCompareResult的结果,转换成TEhDBGrid的OnDrawCell事件中的背景色:

procedure TForm1.EhDBGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); var CompareResult: TEhCompareResult; RecordIndex: Integer; begin // 假设 CompareResult 已全局缓存(如 FCompareResult) if Assigned(FCompareResult) and (ARow > 0) then // 跳过标题行 begin RecordIndex := EhDBGrid1.DataSource.DataSet.RecNo - 1; // 当前行号(0-based) if FCompareResult.Added.IndexOf(RecordIndex) >= 0 then EhDBGrid1.Canvas.Brush.Color := $CCFFCC // 浅绿:新增 else if FCompareResult.Deleted.IndexOf(RecordIndex) >= 0 then EhDBGrid1.Canvas.Brush.Color := $FFCCCC // 浅红:删除 else if FCompareResult.Modified.IndexOf(RecordIndex) >= 0 then EhDBGrid1.Canvas.Brush.Color := $FFFFCC // 浅黄:修改 else Exit; // 无变化,用默认色 EhDBGrid1.Canvas.FillRect(Rect); // 填充背景 end; end;

关键细节:RecNo返回的是当前DataSet的物理行号,而TEhCompareResult.Added存储的是快照中的逻辑索引。因此必须确保比对时使用相同的数据顺序(即不启用DataSet.IndexName排序),或改用主键值匹配而非索引匹配。我在某图像处理 Demo 中,最终选择用TStringList存储主键值集合,用IndexOf替代IndexOf(RecordIndex),彻底规避顺序依赖。

从那以后我每次做报表审计功能,都强制走一遍TEhDataController快照 +Compare流程,哪怕客户没提需求——因为数据差异是业务真相的唯一锚点,而 EhLib 给了我一把足够锋利、又不会割手的刀。希望帮到你。

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

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

离线环境升级curl 8.4.0:依赖库处理与回滚方案

1. 为什么要在离线环境折腾 Curl 升级这件事手里有一批跑在内网的生产机器&#xff0c;系统是 Centos 7 或者 Anolis OS 8&#xff0c;业务侧最近做安全扫描&#xff0c;报出来系统自带的 curl 版本太低&#xff0c;存在若干已知问题&#xff0c;要求限期整改。麻烦的地方在于这…

作者头像 李华
网站建设 2026/10/27 14:41:16

Zotero标注弹窗关闭方法与效率优化指南

1. 问题背景与需求分析作为一款开源的文献管理工具&#xff0c;Zotero在学术工作者中广受欢迎。其标注功能允许用户直接在PDF文献上做标记和批注&#xff0c;极大提升了文献阅读和整理的效率。但在实际使用中&#xff0c;很多用户发现每次进行标注操作时&#xff0c;系统都会弹…

作者头像 李华
网站建设 2026/10/27 14:40:19

UE动画衔接与反向运动学(IK)系统实战解析

1. UE动画衔接与反向运动学&#xff08;IK&#xff09;系统解析在游戏开发中&#xff0c;角色动画的自然过渡一直是个技术难点。传统的关键帧动画虽然能实现基础动作&#xff0c;但在不同动画状态间切换时常常出现生硬的"跳帧"现象。Unreal Engine的反向运动学&#…

作者头像 李华
网站建设 2026/10/27 14:40:03

营销技能底层逻辑:从消费者决策链到可复制的增长方法论

我在这行摸爬滚打了十来年&#xff0c;带过团队、操盘过从零到一的项目&#xff0c;也面试过不下几百个自称“会营销”的人。现在很多年轻人问我&#xff0c; marketing skills 到底该往哪个方向练&#xff0c;是学文案、做投放、搞私域&#xff0c;还是去啃各种增长模型。我…

作者头像 李华
网站建设 2026/10/27 14:39:28

C#高性能CSV解析器:内存映射+状态机+零拷贝实战

简介&#xff1a;本资源是一份面向C#中高级开发者的大数据CSV文件高效读取实战方案&#xff0c;聚焦于超大规模文本数据&#xff08;如9GB、1.2亿行&#xff09;在内存受限场景下的极速解析与显示优化。针对传统TextFieldParser或逐行StreamReader易引发内存溢出、速度缓慢等痛…

作者头像 李华
网站建设 2026/10/27 14:38:42

2FSK调制解调MATLAB仿真:从课设源码到误码率验证

简介&#xff1a;这份资源是面向通信工程、电子信息类专业学生的「通讯系统原理课程设计」完整文档&#xff0c;聚焦2FSK调制与解调系统的设计与MATLAB7.0仿真实现&#xff0c;适合正在做课设、需要参考完整方案与源码思路的学习者。文档围绕信源产生、发送滤波、加性高斯白噪声…

作者头像 李华