2

enter image description hereI have an application having 2 Forms, each Form and Application have individual Icon. On Form1BitBtn1.Click Form2 is Shown-Nonmodaly and on Form1BitBtn2.Click Form1 is closed. On Form2BitBtn1.Click Form2 is Closed and Form2BitBtn2.Click Form1 is closed. It works fine. But the problem is that in Windows 7 Taskbar the Form1 Icon is Blurred and another problem is that when Form2 is shown using Form1BitBtn1.Click the application shows only Form1 Icon but not Form2 Icon. Please help me.

Here is the download link for my project file is "http://hotfile.com/dl/140219264/04ce49c/Delphi_XE2_Form_Handler.7z.html"

My code is as below :

unit KoushikHalder01;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls,
  Vcl.ComCtrls;
type
  TForm01 = class(TForm)
    BitBtn01: TBitBtn;
    BitBtn02: TBitBtn;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormShow(Sender: TObject);
    procedure FormHide(Sender: TObject);
    procedure BitBtn01MouseEnter(Sender: TObject);
    procedure BitBtn02MouseEnter(Sender: TObject);
    procedure BitBtn01MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure BitBtn02MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure BitBtn01MouseLeave(Sender: TObject);
    procedure BitBtn02MouseLeave(Sender: TObject);
    procedure BitBtn02Click(Sender: TObject);
    procedure BitBtn01Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form01: TForm01;

implementation

{$R *.dfm}

uses KoushikHalder02;

procedure TForm01.BitBtn01Click(Sender: TObject);
begin
   Doublebuffered := True;
   Form02.Show;
   if Form01.Visible = true then Form01.BringToFront;
end;

procedure TForm01.BitBtn01MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
   BitBtn01.Font.Color :=10379745;
end;

procedure TForm01.BitBtn01MouseEnter(Sender: TObject);
begin
   BitBtn01.Font.Color :=16711825;
end;

procedure TForm01.BitBtn01MouseLeave(Sender: TObject);
begin
   BitBtn01.Font.Color :=15756035;
end;

procedure TForm01.BitBtn02Click(Sender: TObject);
begin
  Form01.Close;
end;

procedure TForm01.BitBtn02MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
   BitBtn02.Font.Color :=10379745;
end;

procedure TForm01.BitBtn02MouseEnter(Sender: TObject);
begin
   BitBtn02.Font.Color :=16711825;
end;

procedure TForm01.BitBtn02MouseLeave(Sender: TObject);
begin
   BitBtn02.Font.Color :=15756035;
end;

procedure TForm01.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   Doublebuffered := True;
end;

procedure TForm01.FormCreate(Sender: TObject);
begin
   Doublebuffered := True;
end;

procedure TForm01.FormHide(Sender: TObject);
begin
   Doublebuffered := True;
end;

procedure TForm01.FormShow(Sender: TObject);
begin
   Doublebuffered := True;
end;

end.
Koushik Halder
  • 445
  • 1
  • 9
  • 15
  • 4
    Please edit your question to include a **small** screen capture or something to show what you're asking. "Blurred Delphi form icon in windows 7 taskbar" is very hard to understand from a vague description and some totally unrelated code you expect people to compile and run in order to even (maybe) know what you're asking. People here want to help, but you need to actually explain what you want help with in order to make it possible. :) (And the code you post only repeats a couple of things in several events; they're all `DoubleBuffered := True`/`Font.Color := ` done for no reason.) – Ken White Jan 07 '12 at 03:49
  • 3
    To clarify, `DoubleBuffered := True` can be done *once* in the Object Inspector (or even once in `FormCreate`), and is wasted effort every other time you're doing it. Changing the `Font.Color` is meaningless in the scope of any question you're asking here (whatever it is, it has nothing to do with font color changes). None of the code applies to any question related to the application or window icons. – Ken White Jan 07 '12 at 03:54
  • @Koushik - Is this question a duplicate of [this one](http://stackoverflow.com/q/2621814/243614), despite all the code you posted? – Sertac Akyuz Jan 08 '12 at 15:21
  • @Sertac Looks very much to me as though it is. Reassuring to see that your analysis and mine are very largely in alignment. – David Heffernan Jan 09 '12 at 16:17
  • @David - Yeah, now I'm certain with the accept.. And indeed!.. – Sertac Akyuz Jan 09 '12 at 16:40

4 Answers4

7

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!

akjoshi
  • 15,374
  • 13
  • 103
  • 121
Wagner
  • 87
  • 2
  • 1
  • 1
    This answer does not address the question that was asked. Specifically in the question that was asked the asker clearly states that "I have an application having 2 Forms, each Form and Application have individual Icon." In other words, the solution proposed simply does not apply. The reason why you see different behaviour with `TForm.Icon` and `TApplication.Icon` is that when you set icons using the IDE, you end up with a small icon in `TForm.Icon` and a large icon in `TApplication.Icon`. – David Heffernan May 12 '14 at 09:16
6

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • +1 Agreed. If necessary, it is better to provide one large icon (32x32 or 48x48) and let windows scale that down rather than provide both, and have the VCL wrongly select the small one. – Warren P Jan 09 '12 at 15:59
  • I wonder if a custom TForm descendant with an additional "LargeIcon" property would be a nice thing to have in one's toolbox. Then the built in wonky behaviour of TForm.Icon doesn't have to matter any more. – Warren P Jan 09 '12 at 16:07
  • @WarrenP In fact what you would need to would a SmallIcon property! – David Heffernan Jan 09 '12 at 16:14
1

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

Community
  • 1
  • 1
James Johnston
  • 9,264
  • 9
  • 48
  • 76
1

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.

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • I have added screenshot. Please help me. – Koushik Halder Jan 08 '12 at 06:21
  • Already my project has both 16x16, 32x32, and 48x48 sizes Icon. – Koushik Halder Jan 08 '12 at 06:34
  • 2
    So far as I know Delphi only sets the small icon and provides no built in way to set the large icon – David Heffernan Jan 08 '12 at 08:26
  • Well, in fact it is the other way around. The VCL sends WM_SETICON passing `ICON_BIG`. It never does `ICON_SMALL`. – David Heffernan Jan 08 '12 at 11:45
  • 1
    @Warren Whilst .ico files can contain multiple images, `TIcon` is a loose wrapper for `HICON` which is a single image. Clearly what is happening is that a 16px icon is being up-scaled. But in my view the best solution is not trivial to achieve and there is a fundamental flaw in the design of the VCL. From what I can tell, WinForms does it in the same way. It all seems a bit rubbish to me. – David Heffernan Jan 08 '12 at 12:16
  • 1
    @David - The VCL sends WM_SETICON with ICON_BIG but it passes the small icon's handle. The whole thing is just wrong.. – Sertac Akyuz Jan 08 '12 at 16:41
  • @Sertac Well, it's kind of up to the programmer as to whether or not it's a big icon or a small icon. They just assign `TForm.Icon` with whatever they fancy. But yes, it's a mess. I just bypass it completely and do it myself properly! – David Heffernan Jan 08 '12 at 16:43
  • Please anyone download my project file and tell me where to rectify what. – Koushik Halder Jan 11 '12 at 13:57
  • @Koushik - As you've seen in [this question](http://stackoverflow.com/questions/8566777/animated-cursor-playing/8639751#8639751), that approach doesn't work well. If you have anything that you didn't understand in an answer, try to ask that in a comment to that answer. – Sertac Akyuz Jan 11 '12 at 21:24