如何在 Delphi 10.2 Tokyo 中实现以下目标:我需要 Delphi 不仅自动设置大图标,还自动设置每个窗口的大图标和小图标。对于某些表单和 TApplication,我需要有机会在运行时更改图标。我希望无需修改即可完成此操作VCL.Forms.pas
(小图标显示在窗口标题栏中,位于窗口标题左侧)。
中有一个功能TCustomForm
:
function GetIconHandle: HICON;
不幸的是,Delphi 只设置了大图标句柄,例如,这里有一个引用VCL.Forms.pas
:
SendMessage(Handle, WM_SETICON, ICON_BIG, GetIconHandle);
如您所见,上面的代码只设置了大图标句柄,但我还需要设置小图标句柄,因为我使用的 .ICO 文件包含不同的大小图标图像。
让我简要总结一下大图标和小图标之间的区别,因为即使是 Microsoft 文档也几乎没有提及它。以下是主要区别:
小图标图像显示在窗口标题栏上。
如果任务栏较粗,则在 Windows 任务栏(通常位于屏幕底部)中显示大图标图像;当您按 Alt+Tab 时,也会显示大图标图像。
有关大小图标的更多信息,请参阅https://blog.barthe.ph/2009/07/17/wmseticon/ 。
Delphi 通过仅设置大窗口句柄,有效地淘汰了替代图像,以在窗口标题上显示较小的图标。如果只给出大图标而不给出小图标,Windows 会将图像从大图标重新采样到小图标,质量会变差,并且会丢失更小、更简单的图像的主要思想。
请参阅由sanyok提供的示例图片。左列,标记为 v7.4.16 是使用代码编译的程序的屏幕截图,该代码设置了ICON_BIG
和ICON_SMALL
. 右列,标记为 v7.4.16.22 是来自同一程序的屏幕截图,它没有明确设置小图标和大图标,而只是分配TIcon
给一个表单,然后 Delphi 使用其标准代码只分配大图标,因此 Windows 标题栏中的图像由 Windows 从大图标调整大小。您可能会看到由于标准的 Delphi 行为,质量变得多么糟糕。
过去,我将接口部分的GetIconHandleVCL.Forms.pas
从静态更改为虚拟,将其更改function
为procedure
并添加两个参数:
procedure GetIconHandle(var Big, Small: HICON); virtual;
因此 VCL.Forms.pas 中的后续代码如下所示:
var
Big, Small: HICON;
begin
[...]
GetIconHandle(Big, Small);
SendMessage(Handle, WM_SETICON, ICON_BIG, LParam(Big));
SendMessage(Handle, WM_SETICON, ICON_SMALL, LParam(Small));
[...]
是否可以在不修改的情况下轻松完成此操作VCL.Forms.pas
?
我确实通过修改 VCL 单元在 Delphi 2007 中解决了该问题,但由于以下原因,我无法再修改 Delphi 10.20 Tokyo 中的 VCL 单元:
VCL 单元编译,但是,当我编译我的应用程序时,我得到“内部错误:AV0047C6C7-R000004CC-0”,不管目标目标(Win32/Win64;调试/发布),请参阅https://quality.embarcadero。 com/browse/RSP-18455 - 错误号(地址)的第一部分不同,但第二部分 - R000004CC-0 - 始终相同。
我必须手动将(TObject)添加到不从任何类继承的每个类中;否则我会生成一个在基类中找不到的
Create
错误Destroy
。在以前版本的 Delphi 中,简单地编写class
没有任何祖先隐式继承它TObject
,但是当我dcc32
使用dcc32 -Q -M -$D- -$M+
命令行选项从命令行编译代码时,会发生此错误,Create
或者Destroy
在基类中找不到此错误。
这是我过去加载图标的方式:
procedure LoadIconPair(var Big, Small: hIcon; AName: PChar);
begin
if Win32MajorVersion < 4 then
begin
Big := LoadIcon(hInstance, AName);
Small := 0;
end
else
begin
Big := LoadImage(hInstance, AName, IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
Small := LoadImage(hInstance, AName, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
end;
end;
此代码可以进一步改进:硬编码大小的 32x32 和 16x16 可以更改,如https://blog.barthe.ph/2009/07/17/wmseticon/GetSystemMetrics(SM_CXICON)
建议的那样,对于
GetSystemMetrics(SM_CYICON)
大图标GetSystemMetrics(SM_CXSMICON)
和GetSystemMetrics(SM_CYSMICON)
对于小图标。
因此,每个表单本质上都是调用LoadIconPair
然后通过覆盖的procedure GetIconHandle(var Big, Small: HICON); override;
.
所以问题如下:
是否可以让 Delphi 轻松设置小图标和大图标而无需修改
VCL.Forms.pas?
(这是主要问题) - 对于某些表单和 TApplication,我需要有机会在运行时更改图标-时间。;如果没有,如何在 Delphi 10.2 Tokyo 下将修改后的源 VCL 单元添加到您的应用程序中,其中修改了单元的接口部分?是否有任何说明或官方指南?如果有人设法做到这一点,你是如何做到的?您是否从 GUI IDE 编译它们?还是使用命令行 dcc32/dcc64?还是使用 msbuild?还是其他?您是否还必须手动将(TObject)添加到不从任何类继承的类中以避免
Create
或Destroy
在基类中找不到错误?
更新#1:在 VCL.Forms.pas 设置后再次设置图标不是一个完整的解决方案:我们还必须注意应用程序图标,而不仅仅是表单图标;除此之外,VCL.Forms.pas 无论如何都会设置图标,但只有ICON_BIG
,我们必须再次设置图标,这次设置大小。您是否知道我们如何修补 VCL.Forms.pas 以在设置ICON_SMALL
大图标时添加设置,所以我们只修补该implementation
部分,并会调用一些消息,甚至 WM_USER+N 来请求图标句柄表单,我们的 TForm 的后代将实现这个消息处理程序?
更新 #2: TApplication 和 TForm 在图标方面具有相似的接口,但 TApplication 是 TComponent 的后代,它们没有窗口句柄,并且分别没有消息处理程序。我们可以用 TForm 做的,我们不能用 TApplication 做。
更新#3:我已经实施了一个解决方案,它混合了kobik在他的帖子中提出的建议和Sertac Akyuz在他后来的帖子中提出的建议。还要感谢在评论中做出贡献的其他人。我已经编译了程序并将其提供给了 beta 测试人员,他们已经确认问题已得到解决,图标现在看起来不错,并且通过计时器更改图标在 TApplication 中的图标动画也可以正常工作。谢谢你们!