I have an application having 2 Forms, each Form and Application have individual Icon. O
What is happening here is, in my view, due to a design flaw in the VCL framework. The underlying windows framework maintains not one, but two icons for each top-level window. These icons are associated with a window either via the window class (see WNDCLASSEX) or through WM_SETICON messages.
The VCL framework always calls WM_SETICON
passing ICON_BIG
and so only the large icon is assigned. For Windows 7 the large icon is used on the taskbar and the small icon is used on the window's caption bar. On earlier versions of Windows, which had smaller taskbars, the small icon was used on the taskbar. For 100% font scaling the large icon is 32px and the small icon is 16px. For large fonts, the required icon sizes change.
Now, if an application only supplies one of the required icons, the system will scale the icon provided when it needs to draw the icon size which has not been supplied. If you supply a large icon only then, generally, the resulting scaled small icon looks fine. If you supply a small icon only then it's much harder to scale and what typically happens is that the small icon (shown on the caption bar) looks fine, but the large icon is pixellated.
In fact what is happening to you is neither of these problems. The VCL code means that you are always specifying, to Windows, the large icon. However, you are clearly supplying a small icon, almost certainly 16px. This has the same result as calling WM_SETICON
with ICON_SMALL
and the 32px icon is pixellated.
The simplest solution for you is to use the 32px icon in for Form.Icon
or Application.Icon
, wherever it is that you set the icon. This will work fine for much of the time.
However, if your application ever runs with font scaling active then you will encounter pixellation again. With font scaling, both icon sizes can be increased. In order to handle this properly you must provide to the underlying Windows framework an icon of the correct size. If you don't then there will be pixellation. You can find out the icon sizes by calling GetSystemMetrics.
SmallIconSize := GetSystemMetrics(SM_CXSMICON);
LargeIconSize := GetSystemMetrics(SM_CXICON);
Now it is often sufficient just to supply a large icon and rely on the built in scaling to produce the small icon. If you really care about visuals you should of course use an icon specifically prepared for such small sizes. A 32px icon down-scaled to 16px will not be as effective visually as a 16px icon produced by a skilled visual designer. To make the VCL use the small icon you provide requires extra work. Specifically you need to send the WM_SETICON
for ICON_SMALL
. In my code base I do this and in fact avoid using TForm.Icon
at all and call WM_SETICON
for both icon sizes. In order to get the fine-grained control needed to do this right the VCL mechanisms just interfere.
My best guess is that your form icon size is 16x16 and is being stretched from 16x16 to about 48x48, resulting in what you would call "a blurry appearance" but which is the standard Windows behaviour when the input (the icon on your form or application) is very low resolution.
Icons can have multiple resolutions in the same .ico file. So please replace your current icon with one which has both 16x16, 32x32, and 48x48 sizes. THen windows will be able to show a proper full-resolution image. A modern icon for windows use could also include some larger Vista/Win7 icon sizes as high as 256x256. Update The OP reports the icon already has all the right sizes, and it does appear from the other answer here, that you are experiencing a problem with the VCL internal handling as David mentions in his answer.
In short, windows does this because you gave it no way to avoid it. It is a choice of blurry, or pixelated. The "stretchdraw" code inside windows causes blurring, precisely to avoid the blocky look you would get when you don't blur it.
TL;DR version: Don't set the Icon
property to any value other than that obtained by loading from a Win32 resource that contains multiple icon sizes. For example, only use TIcon.LoadFromResourceName
. If you set the Icon
property in the form designer, only one icon size will ever be used, resulting in scaling artifacts.
For years, VCL has not supported the concept of an icon graphic with multiple icon sizes: a TIcon
was always assumed to be one single graphic - not a set of graphics of varying dimensions and resolutions. This is still true, and a design issue probably not easy to correct in the VCL.
The VCL will set the form icon by way of the WM_SETICON message. VCL always sets wParam
to ICON_BIG
: an examination of VCL sources shows it never uses ICON_SMALL
when setting the icon. Additionally, the hIcon
and hIconSm
member variables of WNDCLASSEX
structure are always NULL
when creating the window class. Therefore, it's clear that VCL never even attempts to set a small icon. Normally, if an app never sets a small icon, Windows will resize the large icon to be the small size, which is quite ugly. However, there is an important exception to that rule.
Note that a Windows resource file's ICON resource will actually store what is known as an icon group, which is a set of the individual icon images from the original .ico
file. The LoadIcon API states that only the large 32x32 icon will be loaded. However, this is not actually strictly true. It seems that Windows itself maintains a link between an HICON
and the original resource, so that if icons of other sizes are required, Windows can go load them as needed.
This fact is not well-documented, but there is one place in MSDN that states this fact: WNDCLASSEX structure, hIconSm
variable:
A handle to a small icon that is associated with the window class. If this member is NULL, the system searches the icon resource specified by the hIcon member for an icon of the appropriate size to use as the small icon.
Therefore, even though VCL did not support small icons properly by way of the public TForm.Icon
class (e.g. by assigning it from the property editor at design time), it was still possible to get things working right using one of these two methods:
Leave the TForm.Icon
property unset (no icon). In that case, the form will get the icon from TApplication.Icon
. The default value of this comes from the application's MAINICON
resource. From TApplication.Create
:
FIcon := TIcon.Create;
FIcon.Handle := LoadIcon(MainInstance, 'MAINICON');
If you don't want to use the application default icon, you can load a different icon resource at runtime; in C++:
myForm->Icon->LoadFromResourceName(FindHInstance(...), L"OtherResource");
Therefore, VCL provides basic support for small icons, because it supports loading icons from resources, and Windows supports loading small icons from large icons that were loaded from a resource.
If you use VCL styles, see my answer to a related bug here: https://stackoverflow.com/a/35067909/562766
I know how to fix this...and it's simple. Don't provide an icon for Form1.Icon.
Provide your icon information in
Project > Options > Application > Application Icon Settings > Load Icon.
Be sure to choose the best resolution for your icon.
Run the application and shazan!