简介:Almediadev StyleControls VCL 5.87 是一套面向 Delphi 与 C++Builder XE2-13 Athens 开发者的 VCL 皮肤控件包,源码完全开放,适合需要为桌面应用快速构建现代化界面的中高级开发者。包内提供 100 余个控件,涵盖按钮、编辑框、表格、树形、仪表、滑块、开关等,支持经典绘图、系统主题、GDI+ 与 VCL Styles 四种模式自由切换,并可实现 Windows 10/11 亚克力模糊、按钮光效动画与 DWM 阴影等 Fluent UI 效果,同时具备 PerMonitorV2 高 DPI 适配与 DevExpress 桥接能力。资源共 187 个文件,以 pas 源码、res 资源、cpp 与 cbproj 工程文件、dpk 与 dproj 包工程为主,另有 dfm 窗体与少量说明文档,压缩包约 830KB。v5.87 新增对 Delphi 13 与 64 位 IDE 的官方支持,并改进样式菜单与高 DPI 系统对话框渲染。目前已有 48 人学习,适合用于统一第三方控件风格、扩展非客户区标题栏按钮与标签页等场景。
1. StyleControls VCL 5.87 全源码包:Delphi 老项目换皮的一条捷径
手上维护着一套跑了七八年的 Delphi 老系统,客户突然要求界面“跟上现在的审美”,按钮要圆角、面板要阴影、主题要能一键切换。你打开 VCL 默认控件面板,TButton 还是那个灰扑扑的方块,TSpeedButton 连个 hover 状态都得自己画。这时候 StyleControls VCL 5.87 FullSource 这个包就值得翻一翻了。它是一套面向 Delphi VCL 的皮肤化控件库,带完整源码,核心价值在于把按钮、面板、编辑框、菜单、滚动条这些常用控件全部重绘成可换肤的样式,并且支持从外部文件加载主题。适合两类人:一是维护遗留 VCL 项目、不想大改业务代码就想换界面的工程师;二是想研究 VCL 自绘控件架构、需要一份可编译源码参考的开发者。FullSource 意味着你能直接跟进调试、改绘制逻辑,而不是对着 DCU 猜黑匣子。
2. 把包拆开看:源码结构、编译顺序与依赖关系
2.1 目录里到底装了什么
拿到Almediadev StyleControls VCL 5.87 FullSource.7z之后,先别急着往 IDE 里拖。解压出来通常能看到几个关键目录:Source放的是全部.pas单元,Packages下按 Delphi 版本分目录存放.dpk包工程,Demos里是各控件的示例工程,Themes或Skins目录放的是预置皮肤文件。FullSource 版本和只带 DCU 的版本最大区别就在Source目录——你能看到每个控件的Paint方法是怎么写的,遇到绘制异常可以直接断点进去。
我一般会先确认三件事:包工程对应的 Delphi 版本是否和我当前用的匹配、源码里有没有引用第三方库(比如某些图形库或 PNG 支持库)、皮肤文件的格式是二进制还是文本。这三点决定了后面编译会不会翻车。
2.2 编译顺序与包依赖
StyleControls 这类控件库通常拆成运行时包(Runtime)和设计时包(Design-time)。运行时包提供控件类本身,设计时包负责在 IDE 工具栏上注册图标和属性编辑器。编译顺序不能反,必须先编译运行时包,再编译设计时包,否则 IDE 会报找不到单元。
常见做法是在 IDE 里打开Packages下对应版本的.dpk,先 Build 运行时包,再 Install 设计时包。如果你用的是较新的 Delphi 版本而包里只提供到某个旧版本的包工程,可以自己新建一个 Package,把Source目录下的单元加进去,手动指定输出路径。
// 典型运行时包工程文件片段(.dpk) package StyleControlsVCL_R; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$DEBUGINFO ON} requires rtl, vcl, vclx; contains StyleControls in '..\Source\StyleControls.pas', StyleControlsUtils in '..\Source\StyleControlsUtils.pas', StyleControlsThemes in '..\Source\StyleControlsThemes.pas', StyleControlsButtons in '..\Source\StyleControlsButtons.pas'; // 其余单元按实际文件补全 end.这段包工程的关键在requires和contains两段。requires声明依赖的 Delphi 标准包,一般至少要有rtl、vcl,如果控件涉及图形扩展可能还要加vclx或vclimg。contains列出所有要编进包里的单元,路径按你解压后的实际位置改。参数上注意{$ALIGN 8}要和主程序保持一致,否则记录类型跨包传递可能出问题。
2.3 安装后在 IDE 里验证
包 Install 成功后,IDE 控件面板上会出现一个新的页签,通常叫StyleControls或Almediadev。拖一个按钮到窗体上,如果能看到圆角样式而不是默认方块,说明运行时和设计时都装对了。这时候打开 Object Inspector,应该能看到Style、SkinData、Colors这类扩展属性。
提示:安装前先关闭所有 Delphi 实例,安装完再重新打开,否则工具栏刷新可能不完整。
3. 在真实项目里接上皮肤:从加载主题到控件替换
3.1 主题加载的两种方式
StyleControls 换肤的核心是主题数据。常见有两种加载方式:一种是在程序启动时从文件加载,另一种是把主题编译进资源。前者灵活,客户能自己换皮肤文件;后者省事,不怕文件丢失。
从文件加载的典型写法是在主窗体OnCreate里调用主题管理器的加载方法:
procedure TMainForm.FormCreate(Sender: TObject); begin // 从外部皮肤文件加载主题 scThemeManager.LoadFromFile( ExtractFilePath(Application.ExeName) + 'Themes\dark_blue.scskin' ); // 将主题应用到当前窗体及其所有子控件 scThemeManager.ApplyTo(Self); end;LoadFromFile的参数是皮肤文件的完整路径,我一般用ExtractFilePath(Application.ExeName)拼相对路径,避免硬编码。ApplyTo传入窗体对象后,会递归遍历子控件,把支持换肤的控件逐个刷新。注意如果窗体上有动态创建的控件,需要在创建之后再单独调一次ApplyTo,否则新控件还是默认样式。
3.2 控件替换的粒度控制
老项目不可能一次性把所有控件都换掉。我的做法是按窗体分批替换,先换主界面和登录框这种“脸面”,内部功能窗体保持原样。替换时把TButton换成对应的皮肤按钮类,属性名大多兼容,但有几个地方要注意:Caption一般还能用,但字体设置可能被皮肤覆盖,需要在控件的Font属性或主题配置里单独指定。
如果不想改 DFM 里的类名,也可以写一个运行时替换函数,遍历窗体上的控件,把标准类替换成皮肤类。这种做法适合窗体数量多、不想逐个改的情况,但要注意替换后事件绑定需要重新挂接。
procedure ReplaceButtonsWithSkin(AParent: TWinControl); var I: Integer; Ctrl: TControl; begin for I := AParent.ControlCount - 1 downto 0 do begin Ctrl := AParent.Controls[I]; if Ctrl is TButton then begin // 这里用皮肤按钮替换标准按钮,实际替换逻辑需按库提供的工厂方法写 // 伪代码示意:SkinButtonFactory.Replace(TButton(Ctrl)); end; if Ctrl is TWinControl then ReplaceButtonsWithSkin(TWinControl(Ctrl)); end; end;这段递归遍历的思路是:从后往前遍历控件列表,遇到TButton就替换,遇到容器控件就递归进去。从后往前是为了避免替换过程中索引错乱。实际替换时不要直接Free掉原控件再Create新的,因为原控件上挂的事件会丢,正确做法是用库提供的替换方法或者手动迁移事件属性。
3.3 皮肤文件与颜色参数的对应关系
皮肤文件里定义的是一组颜色和绘制参数,控件在绘制时按状态(正常、悬停、按下、禁用)去取对应的值。如果你要微调某个颜色,有两种途径:改皮肤文件,或者在控件级别覆盖。控件级别覆盖适合个别按钮需要突出显示的场景,比如“确认”按钮用主色调,“取消”用灰色。
| 参数类别 | 常见属性名 | 作用范围 |
|---|---|---|
| 背景色 | BackColor/FillColor | 控件主体填充 |
| 边框色 | BorderColor | 控件外框 |
| 文字色 | FontColor/TextColor | 标题文字 |
| 悬停色 | HoverColor | 鼠标悬停状态 |
| 按下色 | PressedColor | 鼠标按下状态 |
| 圆角半径 | CornerRadius | 圆角大小,单位像素 |
这张表里的属性名在不同版本里可能有细微差异,以你手上源码里的实际声明为准。我一般会先在 Demo 工程里试改,确认效果后再往正式项目里搬。
4. 避坑与排查:编译不过、皮肤不生效、字体错乱
4.1 编译报“找不到单元”或“不兼容的版本”
现象:打开包工程后 Build,提示某个.pas找不到,或者报Unit xxx was compiled with a different version of yyy。
原因:一是包工程里的单元路径没指向你实际解压的Source目录;二是之前装过同库的其他版本,DCU 缓存里残留了旧编译结果。
解决:在包工程的 Options 里检查 Unit output directory 和 Search path,确保指向当前版本的源码目录。然后删除项目目录下的.dcu文件和 IDE 的库缓存,重新 Build。如果之前装过旧版,先在 IDE 的 Install Packages 列表里把旧包卸载掉。
4.2 皮肤加载了但控件没变化
现象:代码里调了LoadFromFile和ApplyTo,但窗体上的按钮还是默认样式。
原因:最常见的是控件不是皮肤控件类,标准TButton不响应皮肤管理器的刷新。其次是ApplyTo调用的时机太早,窗体还没完全创建。
解决:确认控件是皮肤库提供的类,或者在ApplyTo之前先做控件替换。时机上把加载和应用的代码放到OnShow或OnCreate的最后,确保窗体句柄已创建。如果还是不行,检查皮肤文件路径是否正确,文件是否完整。
4.3 字体被皮肤覆盖导致显示异常
现象:换了皮肤之后,某些标签或按钮的文字变得特别小、特别大,或者中文字体变成乱码。
原因:皮肤文件里定义了默认字体,应用时覆盖了控件原有的Font设置。如果皮肤里指定的字体在你机器上不存在,系统会回退到默认字体,中文可能显示异常。
解决:在控件级别重新指定Font,或者在主题配置里把字体名称改成你系统里有的中文字体。我一般会在应用主题之后,再遍历一遍需要保持字体的控件,把Font重新赋一次值。
4.4 设计时包装了但工具栏不出现
现象:设计时包 Install 成功,但 IDE 控件面板上找不到对应页签。
原因:可能是包安装到了错误的 IDE 版本,或者工具栏页签被隐藏了。
解决:在 IDE 的 Component 菜单里找 Install Packages,确认包已勾选。然后在工具栏右键,检查是否有对应的页签被取消勾选。如果还是没有,重启 IDE 再试。
4.5 运行时包和设计时包版本不一致
现象:设计时能拖控件,但一编译运行就报错,提示类找不到或方法签名不匹配。
原因:运行时包和设计时包编译自不同版本的源码,或者其中一个没重新编译。
解决:把两个包都重新 Build 一遍,确保用的是同一份源码。如果项目里同时引用了旧版 DCU,清理所有编译产物再重来。
5. 进阶:把皮肤机制接到配置系统与 FastReport 报表
5.1 让用户自己选主题并持久化
实际交付的项目里,换肤不能只靠改代码。我一般会在设置界面放一个主题下拉框,列出Themes目录下所有皮肤文件,用户选中后立即应用,并把选择写到配置文件或注册表。下次启动时先读配置,再加载对应皮肤。
procedure TSettingsForm.LoadThemeList; var SR: TSearchRec; begin cboThemes.Items.Clear; if FindFirst(ExtractFilePath(Application.ExeName) + 'Themes\*.scskin', faAnyFile, SR) = 0 then begin repeat cboThemes.Items.Add(SR.Name); until FindNext(SR) <> 0; FindClose(SR); end; end; procedure TSettingsForm.cboThemesChange(Sender: TObject); begin if cboThemes.ItemIndex >= 0 then begin scThemeManager.LoadFromFile( ExtractFilePath(Application.ExeName) + 'Themes\' + cboThemes.Text ); scThemeManager.ApplyTo(Self); // 持久化选择,下次启动读取 SaveThemeToConfig(cboThemes.Text); end; end;FindFirst/FindNext用来枚举皮肤文件,SaveThemeToConfig是我自己封装的写配置方法,你可以用 INI 文件或注册表实现。注意应用主题后,当前设置窗体自身的控件也会被刷新,如果窗体上有预览区域,效果会即时可见。
5.2 和 FastReport VCL 报表的样式协调
很多 Delphi 项目会搭配 FastReport VCL 做报表输出。报表预览窗口是 FastReport 自己的控件,不受 StyleControls 皮肤管理器管辖。如果主界面换了深色皮肤,报表预览还是白底,视觉上会很割裂。我的做法是单独设置 FastReport 的预览窗体背景色和工具栏样式,让它和主界面主题接近。FastReport 提供了预览窗体的配置接口,可以在加载报表前设置背景色和按钮样式。这一步不是必须的,但客户对界面一致性要求高的时候,值得花时间调一下。
5.3 验证换肤是否彻底
换完皮肤后,我习惯按这个清单过一遍:主窗体所有按钮、编辑框、下拉框是否都变了;弹出对话框和消息框是否也跟随主题;动态创建的控件在创建后是否补了ApplyTo;禁用状态的控件颜色是否可读;高分屏下圆角和阴影有没有锯齿。最后一条容易被忽略,但在 4K 屏上如果皮肤绘制没做 DPI 适配,圆角会糊成一片。
从那以后我每次接老项目换肤的活,都强制先在一个独立 Demo 里把包编译通过、皮肤加载跑通,再往正式工程里搬。这样即使翻车,也只翻在 Demo 里,不会把生产代码搞乱。希望帮到你。
本文还有配套的精品资源,点击获取