Nob*_*bby 7 delphi icons vcl-styles
在Windows 7 Pro 64位系统上使用Delphi XE7.如果我选择"Charcoal Dark Slate"VCL风格,那么从32x32程序图标缩小的16x16像素标题栏图标看起来并不像预期的那样.

它应该看起来像下面的小图标.如果我以16x16像素格式加载程序图标,它在标题栏中看起来不错,但由于16到32像素的放大,在任务栏中看起来很难看.
这是VCL样式的已知问题http://qc.embarcadero.com/wc/qcmain.aspx?d=106224
在Embarcadero的新版QC网站上也看到了这个问题:https://quality.embarcadero.com/browse/RSP-11572 ---自最初报道以来已经过了3年,但仍然没有修复.如果有足够的人投票支持这个问题,也许会得到一些关注.
作为解决方法,您可以将正确的16x16图标加载到表单的Icon属性中.
为了使其工作,您还必须Application.MainFormOnTaskBar := false;在您的.dpr文件中设置
但是,这会产生一些其他不良影响,因为它会禁用Windows Vista或Windows 7 Aero效果,包括实时任务栏缩略图,动态Windows,Windows Flip和Windows Flip 3D.请参阅:MainFormOnTaskBar
在任何情况下都不要更改应用程序图标大小,因为它是最糟糕的解决方案.
我终于找到了这个问题的底部,并找出了为什么没有VCL样式,并且不适用于VCL样式.
前言: 多年来,VCL一直不支持具有多种图标大小的图标图形的概念:a TIcon总是假定为单个图形 - 而不是一组具有不同尺寸和分辨率的图形.这仍然是正确的,并且在VCL中可能不容易纠正设计问题.
VCL将通过WM_SETICON消息设置表单图标.VCL始终设置wParam为ICON_BIG:对VCL源的检查显示它ICON_SMALL在设置图标时从不使用.此外,hIcon与hIconSm成员变量WNDCLASSEX结构始终是NULL创建窗口类时.因此,很明显,VCL甚至都没有试图设置一个小图标.通常情况下,如果应用程序从不设置小图标,Windows会将大图标调整为小尺寸,这非常难看.但是,该规则有一个重要的例外.
请注意,Windows资源文件的ICON资源实际上将存储所谓的图标组,该图标组是原始.ico文件中的一组单独图标图像.该LoadIconAPI指出,只有大的32x32图标将被载入.但是,这实际上并不严格.Windows本身似乎维护了HICON原始资源之间的链接,因此如果需要其他大小的图标,Windows可以根据需要加载它们.
这个事实没有详细记录,但MSDN中有一个地方陈述了这个事实: WNDCLASSEX结构,hIconSm变量:
与窗口类关联的小图标的句柄.如果此成员为NULL,系统将搜索hIcon成员指定的图标资源,以获取适当大小的图标以用作小图标.
因此,即使VCL不能通过公共TForm.Icon类正确地支持小图标(例如,通过在设计时从属性编辑器中分配它),仍然可以使用以下两种方法之一使事情正常工作:
保留未TForm.Icon设置的属性(无图标).在这种情况下,表单将从中获取图标TApplication.Icon.默认值来自应用程序的MAINICON资源.来自TApplication.Create:
FIcon := TIcon.Create;
FIcon.Handle := LoadIcon(MainInstance, 'MAINICON');
Run Code Online (Sandbox Code Playgroud)如果您不想使用应用程序默认图标,则可以在运行时加载不同的图标资源; 在C++中:
myForm->Icon->LoadFromResourceName(FindHInstance(...), L"OtherResource");
Run Code Online (Sandbox Code Playgroud)因此,VCL为小图标提供基本支持,因为它支持从资源加载图标,Windows支持从资源加载的大图标加载小图标.
问题: VCL样式显然不依赖于非客户区域的Windows默认呈现行为,例如标题栏.相反,它处理所有渲染本身.渲染中的一个任务是VCL样式必须确定要渲染的图标.事实证明,即使主VCL表单类不支持小图标 - VCL样式钩子也可以!好吧,有点.这发生在TFormStyleHook.GetIcon:
TmpHandle := THandle(SendMessage(Handle, WM_GETICON, ICON_SMALL, 0));
if TmpHandle = 0 then
TmpHandle := THandle(SendMessage(Handle, WM_GETICON, ICON_BIG, 0));
Run Code Online (Sandbox Code Playgroud)
问题是,挂钩调用WM_GETICON与ICON_SMALL和没有ICON_SMALL2.来自MSDN:
ICON_SMALL:检索窗口的小图标.
NULL因为VCL没有设置一个小图标.ICON_SMALL2:检索应用程序提供的小图标.如果应用程序未提供一个,则系统使用该窗口的系统生成图标.(强调我的)
HICON:问题是系统如何生成图标?我的实验表明,无论如何,你都会得到一个小图标:
修复: VCL需要使用ICON_SMALL2而不是ICON_SMALL每次调用WM_GETICON.(请注意,类似的代码TFormStyleHook.TMainMenuBarStyleHook.GetIcon也需要修复.)由于这是一个非常简单的修复,我希望Embarcadero尽快应用它.
解决方法: 在修复VCL之前,您必须创建自己的派生表单挂钩.不幸的是,这TFormStyleHook.GetIcon是私人的,真的很难达到.因此,我们尝试了不同的技术:改变消息处理行为WM_GETICON时wParam是ICON_SMALL如此,它反而像ICON_SMALL2.
class TFixedFormStyleHook : public TFormStyleHook
{
public:
bool PreventRecursion;
__fastcall virtual TFixedFormStyleHook(TWinControl* AControl)
: TFormStyleHook(AControl), PreventRecursion(false) {}
virtual void __fastcall WndProc(TMessage &Message)
{
if (Message.Msg == WM_GETICON && Message.WParam == ICON_SMALL &&
!PreventRecursion && this->Control &&
this->Control->HandleAllocated())
{
// Just in case some future Windows version decides to call us again
// with ICON_SMALL as response to being called with ICON_SMALL2.
PreventRecursion = true;
Message.Result = SendMessage(this->Control->Handle, WM_GETICON,
ICON_SMALL2, Message.LParam);
PreventRecursion = false;
this->Handled = true;
} else {
this->TFormStyleHook::WndProc(Message);
}
}
};
// In your WinMain function, you have to register your hook for every data
// type that VCL originally registered TFormStyleHook for:
TCustomStyleEngine::RegisterStyleHook(__classid(TForm),
__classid(TFixedFormStyleHook));
TCustomStyleEngine::RegisterStyleHook(__classid(TCustomForm),
__classid(TFixedFormStyleHook));
Run Code Online (Sandbox Code Playgroud)