简介这是一份面向Delphi 12.3开发者的TRichView 18.0.1控件完整安装包直接解决在Delphi IDE中集成富文本编辑能力的痛点适用于需要处理复杂文档显示、打印与排版的应用开发场景。压缩包共收录2000个文件其中1263个cpp源文件构成核心实现188个h头文件提供接口声明109个pas单元与82个dpk/dproj、56个cbproj、11个bdsproj等工程文件覆盖从源码编译到设计期组件注册的完整链路同时附带res资源、dfm窗体模板、dcr图标、pdf文档说明等方便不同IDE版本如D2005、2006、BDS等的工程直接兼容使用。全部文件按模块与工程分目录存放结构清晰约23MB的包体便于快速下载部署。目前已有55人学习对于希望省去自行移植或调试控件的中高级Delphi程序员而言这套源码与工程可直接复用也为研究富文本排版、样式解析与文档渲染机制提供了良好的实践样本无论是快速集成还是深度定制均能从中受益。1. Delphi 12.3上解压TRichView 18.0.1之前先搞清楚这套控件解决什么问题Delphi 12.3上装TRichView 18.0.1是很多还用VCL做桌面文档产品的团队绕不开的一步。TRichView这套控件包解决的是TRichEdit满足不了的需求文档里要有表格、图片、分页、样式表还要能把内容导出成RTF或直接存进数据库。做司法文书、医院报告、保险单证的同行应该都有同感原生RichEdit在图文混排、表格编辑、打印分页这几个场景下基本是黑匣子改不动、也算不准。TRichView把文档拆成了可见的控件属性和可遍历的文档模型界面上能编辑的东西代码里都能按项访问。下面从解压安装开始一路讲到参数调整和踩坑记录适合在Delphi 12.3上用控件、但不想啃官方PDF手册的人。2. 从RAR解压到Tool Palette出现图标D12安装全流程2.1 解压后先看清包结构找到D12那个文件夹常见做法是这类控件RAR打开后根目录不是单个可执行安装程序而是一组分好类的源码和预编译文件。第一件事不是双击任何exe而是把包解压到固定目录例如C:\TRichView\然后看目录结构。TRichView的包通常包含Sources核心单元源码、Library预编译DCU和BPL、Demos示例工程以及按IDE版本划分的文件夹带有D12字样的目录就是给Delphi 12编译器准备的。解压后我会先看一眼D12目录里有没有.dpk和.dcp文件有dcp说明厂商打包时已经给你编好过没有就说明后面要用源码自己编。这一步决定了你是“装上就能用”还是“编译一次再安装”。C:\TRichView\ ├─ Sources\ # 主要.pas单元 ├─ Library\Win32\ # 预编译的dcu/dcp可能不存在 ├─ Demos\ # 官方示例 └─ D12\ # Delphi 12对应的包工程文件也可能叫D11、D10并列文件/目录名作用安装阶段需要处理Sources核心单元源码加进Library PathLibrary\Win32预编译dcu文件有的话可以直接引用没有就编译源码Demos官方示例工程用来验证安装是否成功D12Delphi 12组件的包工程打开编译并Install如果目录里同时有D11和D12不要看错。用D12目录里的包工程编译出来的是面向Delphi 12编译器的产物装到Delphi 12.3上没有问题TRichView 18.0.1发布时主要适配的是RAD Studio 12.1/12.2但Delphi 12.3的编译器仍是12.x系列这类包绝大多数能直接编过前提是Library Path和包依赖顺序没错。2.2 把Sources路径加进Library Path这一步决定能不能找到单元操作路径IDE菜单Tools Options Language Delphi Library在Library path输入框末尾用分号追加下面两个路径。保存后重启IDE让编译器缓存重新加载。C:\TRichView\Sources C:\TRichView\Sources\D12路径顺序很关键。机器上如果同时装过其他版本的TRichView要确保当前版本目录排在前面否则编译器会优先找到旧版单元编译时符号对不上报出一串没头没尾的H2443警告或Linker Error。我一般把TRichView的路径直接放在所有第三方控件的第一位省得后面排查时先怀疑路径优先级。这一步不做后面打开任何Demo都会先报“Unit not found: RichView”。这个错误非常误导人它看起来像包没装实际上只是编译器找不到源码或dcu。每次在群里看到有人发这个报错第一句先问他Library Path加了没八成都是漏在这。2.3 打开dpk编译安装从dpk到BPL/DCP路径确认没问题后按这个顺序操作File Open切换到D12目录打开包工程文件。文件名一般叫RV.dpk或RichView.dpk认.dpk后缀就行不同构建版本名字略有差异。在Project Manager里选中该节点右键Compile。先确认Target平台是Win32还是Win64Config选Release。Debug编出来的包也能用但体积大一圈运行期没有实际区别。编译通过后再点Install设计期组件会注册到Tool Palette的RichView页。如果IDE反复编译不过或者你想批量装多个包可以用命令行方式cd /d C:\TRichView\Sources\D12 C:\Program Files (x86)\Embarcadero\Studio\你的版本号目录\bin\dcc32.exe -Q -JL RichView.dpk解释一下命令行参数-Q是安静模式只输出错误不刷屏-JL告诉dcc32把dpk当作package编译产出.dcp和.bpl两个文件。文件名以实际为准D12目录里可能存在多个dpk先编基础的rv包再编扩展包顺序按包的依赖关系来。命令行适合无人值守安装和给CI用日常开发还是IDE里编译直观报错能双击跳转到具体行。2.4 安装完怎么验证新建工程拖控件、看单元引用装完别急着写业务代码先花三分钟验证。新建一个VCL工程往窗体上拖一个TRichViewEdit然后看uses子句。如果编译器能找到包uses会自动增加RichView、RVStyle这类单元名。unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, RichView, RVStyle;新增的RichView和RVStyle就是TRichView的核心单元能出现在uses里说明Library Path已经生效。接下来打开Demos目录里任何一个富文本示例编译运行一遍。能正常跑起来安装阶段就算结束了。再补一个验证按住Ctrl点击RichView单元名如果能跳到源码或dcu符号说明编译器定位的是你刚装的这份不是历史残留。3. 跑通第一个示例用TRichViewEdit实现带表格和图片的RTF编辑器3.1 最小窗体搭建一个TRichViewEdit加两个按钮安装验证通过后别直接往业务工程里塞先搭一个最小示例把TRichViewEdit的行为摸清楚。窗体上放一个TRichViewEdit、一个OpenDialog、一个SaveDialog再放两个按钮Load和SaveFormCreate里做两件事关闭纯文本模式、建立一个默认样式。procedure TForm1.FormCreate(Sender: TObject); begin // 关闭纯文本模式表格和图片才能进入文档流 RichViewEdit1.PlainText : False; // 先建一个默认正文样式避免空文档里字体不确定 RichViewEdit1.AddStyle(正文, 宋体, 10, [], clBlack, clWhite); // 把当前样式切到刚建的第0号样式 RichViewEdit1.Style : 0; RichViewEdit1.ParagraphSpace : 6; end;PlainText设为False是TRichViewEdit承载复合内容的前提设成True后文档被当成纯文本图片和表格项在界面上会显示成占位符。AddStyle的参数依次是样式名、字体名、字号、字体风格集合、前景色、背景色返回值是样式编号。Style : 0表示新输入文本默认套用第0号样式这个和TRichEdit的DefaultStyle概念类似但TRichView的样式是完整独立的文本样式对象不只是字体名。注意AddStyle返回的样式编号不保证连续删除样式后编号会变业务代码里建议用成员变量保存编号不要到处写死整数0、1、2。3.2 加载与保存RTFClear之后LoadRTFFromFile按钮的事件处理里写文件加载和保存这是每天都会用到的两个操作。加载前先Clear防止多次打开时新旧内容叠在一起。procedure TForm1.btnLoadClick(Sender: TObject); begin if OpenDialog1.Execute then begin RichViewEdit1.Clear; // LoadRTFFromFile会把RTF按段落和样式拆进文档流 RichViewEdit1.LoadRTFFromFile(OpenDialog1.FileName); Caption : 已加载: ExtractFileName(OpenDialog1.FileName); end; end; procedure TForm1.btnSaveClick(Sender: TObject); begin if SaveDialog1.Execute then // SaveRTFFromFile会把样式表、表格、图片引用写进RTF RichViewEdit1.SaveRTFFromFile(SaveDialog1.FileName); end;LoadRTFFromFile失败会抛异常实际项目里要包一层try/except给用户一个“文件格式无法识别”的提示而不是让IDE弹默认错误框。保存时如果文档里有图片RTF会默认把图片嵌入导出文件体积会比原图总和还大一点换来的是单文件可迁移。这里注意区分LoadRTFFromFile和LoadRVFFromFileRTF是给外部编辑器用的交换格式RVF是TRichView自己的格式回读更快、保真度更高但别的编辑器不认识。内部存储建议用RVF对外导出才用RTF。3.3 插入图片与表格光标处插入最常用文字编辑之外插入图片和表格是富文本编辑器最核心的两个动作。图片插入用InsertImageFromFile表格插入用AddTableEx两个方法都是插到当前光标位置。procedure TForm1.btnInsertImageClick(Sender: TObject); begin if OpenPictureDialog1.Execute then begin // InsertImageFromFile(文件名, 样式号, 插入项位置, 插入点内位置) RichViewEdit1.InsertImageFromFile( OpenPictureDialog1.FileName, 0, RichViewEdit1.CurItemNo 1, 0); RichViewEdit1.Format; end; end; procedure TForm1.btnInsertTableClick(Sender: TObject); var ColW, RowH: array of Integer; begin SetLength(ColW, 3); ColW[0] : 80; ColW[1] : 160; ColW[2] : 80; SetLength(RowH, 2); RowH[0] : 24; RowH[1] : 24; // AddTableEx列数3、行数2、列宽数组、行高数组、样式号0 RichViewEdit1.AddTableEx(3, 2, ColW, RowH, 0); RichViewEdit1.Format; end;InsertImageFromFile四个参数分别是文件路径、样式号、插入在哪一个Item之前、在Item内部偏移位置。CurItemNo是光标所在的文档项索引1表示插到光标所在项之后正好对应“在光标处插入”的直觉。调用后要手动调一次Format让控件重新计算图片占位和后续文本的换行位置。AddTableEx的列宽行高单位是像素和当前的屏幕DPI相关4K屏上如果觉得表格比预期小一半先查RichViewEdit1.Scale是不是被IDE设成了144是的话把列宽数组按96/144的比例换算回来。3.4 遍历文档结构Item层级和它的用途TRichView和普通文本编辑器的最大区别在于文档可以被程序按项遍历。这个能力是全文检索、自定义导出、按块重排版式的公共基础。用一段遍历代码把当前文档的顶层结构打印到Memo里。procedure TForm1.btnDumpClick(Sender: TObject); var i: Integer; begin Memo1.Lines.Clear; for i : 0 to RichViewEdit1.ItemsCount - 1 do begin case RichViewEdit1.GetItemStyle(i) of rvsText: Memo1.Lines.Add(Format(%d: 文本 [%s], [i, RichViewEdit1.GetItemText(i)])); rvsPicture: Memo1.Lines.Add(Format(%d: 图片, [i])); rvsTable: Memo1.Lines.Add(Format(%d: 表格, [i])); rvsBreak: Memo1.Lines.Add(Format(%d: 换行, [i])); end; end; end;GetItemStyle返回项类型枚举GetItemText只在文本项上有意义图片和表格项要取底层的Bitmap对象和TRVTableItemInfo对象。rvsText、rvsPicture、rvsTable、rvsBreak是公开枚举18.0.1里还可能遇到rvsCheckbox这类扩展类型case里没列到的类型要加Default分支处理否则导出自定义格式时会漏项。这一段遍历逻辑会出现在后面搜索、导出的所有进阶代码里建议现在就把它存成一个独立函数返回统一结构。4. 显示效果和打印都由参数说话几个必调属性4.1 样式表决定字体不是控件的Font属性决定字体新手最容易踩的误区是设RichViewEdit1.Font.Name发现文档里字体纹丝不动。TRichView的字体由StyleList里的TextStyle决定控件自身的Font属性只是没样式时的兜底进入文档流的每段文本都带着样式编号渲染时按样式里的字体信息显示。所以调整字体要走样式表的路子。procedure TForm1.FormCreate(Sender: TObject); begin // 用成员变量保存样式编号避免硬编码 FBodyStyle : RichViewEdit1.AddStyle(正文, 宋体, 10, [], clBlack, clWhite); FTitleStyle : RichViewEdit1.AddStyle(标题, 黑体, 16, [fsBold], clBlack, clWhite); end; // 工具栏点击“标题”按钮时把光标处输入文本切到标题样式 procedure TForm1.btnTitleClick(Sender: TObject); begin RichViewEdit1.Style : FTitleStyle; end;AddStyle的第三个参数是字号单位是磅和Word一致第四个参数是字体风格集合fsBold加粗、fsItalic斜体可以叠加。样式表里每个TextStyle是完整独立的修改已存在样式直接用索引访问例如RichViewEdit1.StyleList[FBodyStyle].FontName : 仿宋改完必须调Format才能刷新界面。这个设计初看比TRichEdit繁琐但好处是导出RTF时样式映射非常干净不会出现一段文本两个字体打架的情况。4.2 Scale、PageWidth、PageHeight和DPI打印与预览一致的前提屏幕上编辑态和打印态的分页计算是两套逻辑。TRichView用Scale作为整个文档的逻辑分辨率基准PageWidth和PageHeight描述打印页面的客户区像素尺寸Printing属性决定是否按分页模式重排。三者的关系不对齐就会出现屏幕上好好的、打印出来右边裁掉一截。// 96dpi下A4纸的宽高按毫米换算得到794×1123像素 RichViewEdit1.Scale : 96; RichViewEdit1.PageWidth : Round(210 / 25.4 * 96); RichViewEdit1.PageHeight : Round(297 / 25.4 * 96); RichViewEdit1.Printing : True;属性作用常见取值Scale文档逻辑分辨率96标准、144高分屏PageWidth打印页宽像素A496dpi为794PageHeight打印页高像素A496dpi为1123Printing是否按分页布局False为编辑态True为打印/预览毫米换像素的公式是毫米数除以25.4再乘DPI这段代码比写死794和1123更通用。打印前先把Scale设成打印机实际报送的DPI值再设PageWidth和PageHeight最后Printing : True并Format一次。打印完成后要把Printing切回False否则控件一直保持分页模式编辑时光标定位和滚轮滚动都会变慢。4.3 VCL和FMX两套包别把VCL代码直接搬过去TRichView同时提供VCL和FMX两个版本D12这份RAR里的VCL包对应Win32/Win64的VCL工程。FMX版本的组件名和单元名不同设计期行为差异很大字体处理、滚动容器、DPI体系几乎全部重写。如果你的项目是FMX安装阶段要选对应FMX的包硬把VCL包塞进FMX工程会直接提示Platform not supported。工程类型使用组件注意事项VCLTRichViewEdit本文章代码适用RichView页出现组件FMX组件名带FMX或独立单元字体、滚动、DPI体系都不同不能直接迁移写代码之前先看工程uses里有没有FMX.Forms有的话就别拿VCL包硬凑。FMX版和VCL版在API设计上大方向一致LoadRTFFromFile这类核心方法同名但参数细节和控件宿主环境不一样。团队里如果有人把VCL版本的代码直接复制进FMX项目编译错一般会出现在TForm、Canvas这类跨平台差异点上。4.4 多线程加载文档控件必须留在主线程TRichView不是线程安全控件任何属性读写、Format调用都必须在主线程执行。但大文档的文件读取和解析可以在工作线程里做把纯IO操作从UI线程剥离开再通过消息队列把加载动作切回主线程。核心思路是工作线程只准备流对象主线程负责真正的加载。type TDocLoadThread class(TThread) private FFilename: string; protected procedure Execute; override; public constructor Create(const AFilename: string); end; constructor TDocLoadThread.Create(const AFilename: string); begin inherited Create(False); FFilename : AFilename; end; procedure TDocLoadThread.Execute; var LStream: TMemoryStream; begin LStream : TMemoryStream.Create; try LStream.LoadFromFile(FFilename); // TThread.Queue把真正的加载调度回主线程 TThread.Queue(nil, procedure begin try FRichView.Clear; // LoadRTFFromStream解析完后文档数据和流已经分离 FRichView.LoadRTFFromStream(LStream); finally LStream.Free; end; end); except LStream.Free; raise; end; end;工作线程里只调用TMemoryStream.LoadFromFile这是纯文件IO不碰任何TRichView对象。TThread.Queue和Synchronize的区别在于Queue不等待工作线程的返回不会造成UI线程被反向阻塞在窗口销毁时也更安全。LStream的生命周期要小心正常路径下主线程的匿名方法执行完finally时释放如果Queue没被调度就进了异常分支由except里的Free兜底。业务项目里还要把加载异常通过Queue传回主线程用一个回调事件弹提示不要在匿名方法里直接ShowMessage避免窗口句柄跨线程调用。5. 我在TRichView 18.0.1上踩过的五个坑5.1 现象编译报错“Unit not found: RichView”路径全加了也不行原因Library Path里加的是Sources的上层目录而不是真正放RichView.pas的那一层或者编译器命中了机器上残留的旧版本RCU缓存。这个报错是安装问题里出现频率最高的。解决把路径精确到包含RichView.pas的目录并且排在Library Path列表的最前面。改完保存后务必重启IDEDelphi的单元搜索缓存不会在选项变更后立刻全部失效。如果机器装过旧版TRichView用Everything搜索全盘RichView相关的.dcu和.bpl把旧目录移走再试。路径加对之后打开Demos工程重新编译报错会立刻消失。5.2 现象编译通过后双击TRichViewEditIDE直接崩溃原因本机残留旧版本控件生成的.dcp/.bpl与18.0.1的DCU版本冲突。这类崩溃在Delphi 12.3上最常见于同时装过试用版、正式版或不同小版本的情况IDE加载设计期包时符号表混乱导致内存访问越界。解决先Component Install Packages找到旧版TRichView条目移除。关闭IDE删除系统目录里的TRV*.bpl和项目目录里的dcu缓存再清理注册表里残留的包项。重开IDE重新从D12目录编译安装18.0.1。装新包之前我会用Everything搜一下TRichView相关文件确认全机器只剩当前这一套源码目录这一步能省掉后面很多随机崩溃。5.3 现象打开一份带几百张图的RTF文档界面卡十几秒原因用循环逐项调用插入方法每插一项都触发一次全量Format重排复杂度是O(n²)。这是把TRichView用卡的最常见原因也是网上骂这个控件慢的主要来源。解决批量编辑期间用BeginUpdate/EndUpdate包住所有操作从文件加载一律走LoadRTFFromFile不要循环插入如果必须动态拼接文档先在线程里把项组织成内部数据再一次性SetText。按我的实测一份2000项的文档用LoadRTFFromFile打开不到1秒用循环逐项插入了9秒以上。使用习惯对了这个控件一点都不慢。5.4 现象中英文混排时中文回退到系统字体宋体怎么设都不生效原因TRichView的样式表里字体名和字符集是分离的。RTF文件里如果带着ANSI字符集标记加载时会把中文字体覆盖掉在Delphi 12.3的高分屏环境下还叠加了DPI字体缩放逻辑让表现更隐蔽。解决加载RTF后立即遍历样式表把含中文的样式显式指定字符集并重设字体名。这段逻辑要放在Load之后马上执行不要放在绘制或定时器里。var i: Integer; begin for i : 0 to RichViewEdit1.StyleList.Count - 1 do begin RichViewEdit1.StyleList[i].FontName : 宋体; RichViewEdit1.StyleList[i].FontCharset : GB2312_CHARSET; end; RichViewEdit1.Format; end;字体名和字符集必须成对设置只改FontName不改Charset导出RTF时仍可能被另一端编辑器识别成西文字体。如果客户环境里没有宋体这个循环要改成先从SystemFonts里查可用字体再决定映射到哪个中文字体写死宋体在精简版Windows上会踩坑。5.5 现象屏幕上看着正常的版式打印出来右边界裁掉一块原因屏幕编辑态的Scale和PageWidth算的是客户区尺寸而打印时走的是打印机物理分辨率不是96dpi。TRichView按Scale换算文档宽度两边DPI不一致横向溢出就把右边裁掉了。解决打印前统一设置Scale为打印机上报的DPI值PageWidth按毫米换算Printing设为True后先Format一次再打印打完恢复编辑态。另外注意TRichViewEdit自带横向滚动条滚动范围和打印范围不是一回事不能在滚动条看到最右边就当版式正常。跨系统部署时让用户在打印设置里选一次打印机程序读取DPI再算页面尺寸比固定写死A4参数可靠。如果还想裁掉多余空白可以在打印前调整边距值把左右边距显式写入PageRect。6. 老手才关注的三个进阶验证手法6.1 用RVF格式做数据库存档比RTF更可控文档需要存进数据库BLOB字段时优先考虑RVF而不是RTF。RVF是TRichView自有格式保存样式、表格、图片引用的效率比RTF高回读时不需要做样式重建跨版本兼容性也稳定。配合多层文档结构RVF流可以整体塞进ADO或FireDAC的BLOB字段。procedure TForm1.btnSaveToDBClick(Sender: TObject); var MS: TMemoryStream; begin MS : TMemoryStream.Create; try // RVF保留表格、图片引用和样式比RTF更紧凑 RichViewEdit1.SaveRVFFromStream(MS); MS.Position : 0; ADOQuery1.Edit; TBlobField(ADOQuery1.FieldByName(DocContent)).LoadFromStream(MS); ADOQuery1.Post; finally MS.Free; end; end;读取时反向操作从BLOB字段读出流再LoadRVFFromStream。要注意RVF的跨版本兼容性问题不大但从18.0.1读老版本生成的RVF文件后建议在测试计划里加一条“打开后另存一次”用新格式覆盖旧格式避免老版本格式里的边缘标记在新版本里触发异常。如果后续要做PDF导出常见搭配是iText for Delphi从RVF流读出内容再往PDF写比经过RTF中转少一层转换损耗。6.2 FindText搜索与光标定位做文书类系统全文搜索是刚需。TRichView的FindText按字符串向后查找并移动光标找到后配合MakeItemVisible处理跨页定位。搜索高亮的常见做法是先选中匹配文本再设置背景色。var Found: Boolean; StartPos: Integer; begin StartPos : RichViewEdit1.GetTextStartPos(RichViewEdit1.CurItemNo); Found : RichViewEdit1.FindText(edtSearch.Text, StartPos, True, False); if Found then RichViewEdit1.MakeItemVisible(RichViewEdit1.CurItemNo); end;FindText的参数在18.0.1里按顺序是查找文本、起始位置、是否允许部分行匹配、是否区分大小写个别小版本参数顺序有差异对照Demos目录里的Search示例核一下再集成。连续搜索时要把起始位置手动推进到当前匹配位置之后否则会永远命中同一个结果。搜索跨表格内容时表格内部的文本顶层结构不同直接用FindText可能漏掉表格单元格里的文本需要在表格项内部递归查找这块逻辑建议单独抽成函数。6.3 表格列宽和单元格合并表格操作是TRichView里最接近深水区的部分。列宽通过TRVTableItemInfo的ColWidth数组直接修改单元格合并用MergeCells方法参数是起始列、起始行、结束列、结束行。var i: Integer; Table: TRVTableItemInfo; begin for i : 0 to RichViewEdit1.ItemsCount - 1 do begin if RichViewEdit1.GetItem(i) is TRVTableItemInfo then begin Table : TRVTableItemInfo(RichViewEdit1.GetItem(i)); // 第0列列宽改为120像素再重新排版 Table.ColWidth[0] : 120; // 合并从第0行第1列开始的两行两列 Table.MergeCells(1, 0, 2, 1); RichViewEdit1.Format; Break; end; end; end;用is判断比GetItemStyle更早地拿到底层对象的真实类型这是访问表格属性的前提。MergeCells不同版本的合并后内容保留规则略有差异合并前建议先备份单元格文本必要时先清空被合并单元格再合并。列宽改完后必须Format否则界面和打印都用旧布局。合并过的表再次拆分没有直接对应的UnmergeCells反向方法要么撤销重做要么在应用层记录合并历史。做案件卷宗、报告书这类反复调整表格的界面要把表格操作包在命令模式里给用户留后悔药。我一直的习惯是每次升级Delphi都先把第三方控件全部卸干净给新版本建独立目录然后按依赖顺序逐个编译安装把每步写进项目里的INSTALL.txt。Delphi 12.3配TRichView 18.0.1这套组合第一次我也翻过车根源全是路径残留和DPI换算不是控件本身的问题。按上面的顺序装一次、跑一次Demo、再试一次打印后面基本就是顺畅的。希望帮到你。本文还有配套的精品资源点击获取