【问题标题】:Blurred Delphi Form Icon in Windows 7 TaskbarWindows 7 任务栏中的模糊 Delphi 窗体图标
【发布时间】:2012-02-04 17:38:02
【问题描述】:

我有一个包含 2 个表单的应用程序,每个表单和应用程序都有单独的图标。在 Form1BitBtn1.Click 上,Form2 显示为非模态,在 Form1BitBtn2.Click 上,Form1 已关闭。在 Form2BitBtn1.Click 上 Form2 已关闭并且 Form2BitBtn2.Click Form1 已关闭。它工作正常。但问题是在 Windows 7 任务栏中 Form1 图标是模糊的,另一个问题是当 Form2 使用 Form1BitBtn1 显示时。单击应用程序仅显示 Form1 图标而不显示 Form2 图标。 请帮帮我。

这里是我的项目文件的下载链接是“http://hotfile.com/dl/140219264/04ce49c/Delphi_XE2_Form_Handler.7z.html

我的代码如下:

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.

【问题讨论】:

  • 请编辑您的问题以包含一个屏幕截图或显示您所问内容的内容。 “Windows 7 任务栏中模糊的 Delphi 表单图标”很难从模糊的描述和一些完全不相关的代码中理解,您希望人们编译和运行以便甚至(也许)知道您在问什么。这里的人们想要提供帮助,但您需要实际解释您想要帮助的内容才能使其成为可能。 :)(而且您发布的代码仅在几个事件中重复了几件事;它们都是 DoubleBuffered := True/Font.Color := <something> 无缘无故地完成。)
  • 澄清一下,DoubleBuffered := True 可以在 Object Inspector 中完成一次(甚至可以在 FormCreate 中完成一次),并且每隔一段时间就会浪费精力它。在您在这里提出的任何问题的范围内,更改 Font.Color 都是没有意义的(无论是什么,它都与字体颜色更改无关)。没有任何代码适用于与应用程序或窗口图标相关的任何问题。
  • @Koushik - 尽管您发布了所有代码,但这个问题是否与 this one 重复?
  • @Sertac 在我看来非常像。令人欣慰的是,您的分析和我的分析在很大程度上是一致的。
  • @David - 是的,现在我确定接受了。确实如此!..

标签: delphi delphi-xe2


【解决方案1】:

我知道如何解决这个问题……而且很简单。 不要为 Form1.Icon 提供图标。

中提供您的图标信息

项目>选项>应用程序>应用程序图标设置>加载 图标。

请务必为您的图标选择最佳分辨率。

运行应用程序和 shazan!

【讨论】:

  • 此答案未解决所提出的问题。特别是在被问到的问题中,提问者明确指出“我有一个具有 2 个表单的应用程序,每个表单和应用程序都有单独的图标。”换言之,所提出的解决方案根本不适用。 TForm.IconTApplication.Icon 出现不同行为的原因是,当您使用 IDE 设置图标时,您最终会在 TForm.Icon 中看到一个小图标,在 TApplication.Icon 中看到一个大图标。
【解决方案2】:

在我看来,这里发生的事情是由于 VCL 框架中的设计缺陷造成的。底层 windows 框架为每个顶级窗口维护不是一个,而是两个图标。这些图标通过窗口类(参见WNDCLASSEX)或通过WM_SETICON 消息与窗口相关联。

VCL 框架总是通过ICON_BIG 调用WM_SETICON,因此只分配了大图标。对于 Windows 7,大图标用于任务栏,小图标用于窗口标题栏。在具有较小任务栏的早期版本的 Windows 上,任务栏上使用了小图标。对于 100% 字体缩放,大图标为 32 像素,小图标为 16 像素。对于大字体,所需的图标大小会发生变化。

现在,如果一个应用程序只提供了一个所需的图标,当系统需要绘制没有提供的图标大小时,系统会缩放提供的图标。如果您只提供一个大图标,通常,生成的缩放小图标看起来不错。如果您只提供一个小图标,那么缩放会困难得多,通常会发生小图标(显示在标题栏上)看起来不错,但大图标是像素化的。

事实上,发生在你身上的都不是这些问题。 VCL 代码意味着您始终为 Windows 指定大图标。但是,您显然提供了一个小图标,几乎可以肯定是 16 像素。这与使用 ICON_SMALL 调用 WM_SETICON 的结果相同,并且 32px 图标是像素化的。

最简单的解决方案是在Form.IconApplication.Icon 中使用32px 图标,无论您在哪里设置图标。这在大部分时间都可以正常工作。

但是,如果您的应用程序曾经在激活字体缩放的情况下运行,那么您将再次遇到像素化问题。通过字体缩放,可以增加两个图标的大小。为了正确处理此问题,您必须向底层 Windows 框架提供正确大小的图标。如果你不这样做,就会有像素化。您可以致电GetSystemMetrics了解图标大小。

SmallIconSize := GetSystemMetrics(SM_CXSMICON);
LargeIconSize := GetSystemMetrics(SM_CXICON);

现在通常只提供一个大图标并依靠内置的缩放来生成小图标就足够了。如果您真的关心视觉效果,您当然应该使用专门为如此小尺寸准备的图标。缩小到 16px 的 32px 图标在视觉上不会像熟练的视觉设计师制作的 16px 图标那样有效。要使 VCL 使用您提供的小图标,需要额外的工作。具体来说,您需要为ICON_SMALL 发送WM_SETICON。在我的代码库中,我这样做了,实际上完全避免使用TForm.Icon,并为两种图标大小调用WM_SETICON。为了获得正确执行此操作所需的细粒度控制,VCL 机制只会进行干预。

【讨论】:

  • +1 同意。如有必要,最好提供一个大图标(32x32 或 48x48)并让窗口按比例缩小而不是同时提供这两者,让 VCL 错误地选择小图标。
  • 我想知道一个带有额外“LargeIcon”属性的自定义 TForm 后代在一个人的工具箱中是否会是一件好事。那么 TForm.Icon 内置的不稳定行为就不再重要了。
  • @WarrenP 事实上,您需要一个 SmallIcon 属性!
【解决方案3】:

我的最佳猜测是您的表单图标大小为 16x16,并且正在从 16x16 拉伸到大约 48x48,导致您称之为“模糊外观”,但这是输入时的标准 Windows 行为(您表单或应用程序)的分辨率非常低。

图标在同一个 .ico 文件中可以有多种分辨率。因此,请将您当前的图标替换为同时具有 16x16、32x32 和 48x48 尺寸的图标。然后窗口将能够显示正确的全分辨率图像。用于 Windows 的现代图标还可以包括一些较大的 Vista/Win7 图标,尺寸高达 256x256。 更新 OP 报告该图标已经具有所有正确的大小,并且从此处的其他答案中确实可以看出,正如 David 在他的回答中提到的那样,您遇到了 VCL 内部处理问题。

简而言之,Windows 这样做是因为您无法避免它。它是模糊或像素化的选择。 windows 内的“stretchdraw”代码会导致模糊,正是为了避免在不模糊时出现块状外观。

【讨论】:

  • 我添加了截图。请帮帮我。
  • 我的项目已经有 16x16、32x32 和 48x48 尺寸的图标了。
  • 据我所知,Delphi 只设置小图标,并没有提供设置大图标的内置方法
  • @Warren 虽然 .ico 文件可以包含多个图像,但 TIconHICON 的松散包装,它是单个图像。显然正在发生的事情是一个 16 像素的图标被放大了。但在我看来,最好的解决方案并非易事,而且 VCL 的设计存在根本缺陷。据我所知,WinForms 也是这样做的。这一切对我来说似乎有点垃圾。
  • @David - VCL 发送带有 ICON_BIG 的 WM_SETICON,但它传递了小图标的句柄。整个事情都是错的..
【解决方案4】:

TL;DR 版本:不要将Icon 属性设置为通过从包含多个图标大小的 Win32 资源加载获得的值以外的任何值。例如,仅使用TIcon.LoadFromResourceName。如果您在表单设计器中设置 Icon 属性,则只会使用一种图标大小,从而导致缩放工件。

多年来,VCL 一直不支持具有多种图标大小的图标图形的概念:TIcon 始终被认为是一个单一的图形,而不是一组不同尺寸和分辨率的图形。这仍然是正确的,并且在 VCL 中可能不容易纠正一个设计问题。

VCL 将通过WM_SETICON 消息设置表单图标。 VCL 总是将wParam 设置为ICON_BIG:对VCL 源的检查表明它在设置图标时从不使用ICON_SMALL。此外,WNDCLASSEX 结构的hIconhIconSm 成员变量在创建窗口类时始终为NULL。因此,很明显 VCL 甚至从未尝试设置小图标。通常,如果一个应用程序从不设置小图标,Windows 会将大图标调整为小尺寸,这非常难看。但是,该规则有一个重要的例外。

请注意,Windows 资源文件的ICON 资源实际上将存储所谓的图标组,它是原始.ico 文件中的一组单独的图标图像。 LoadIcon API 声明只会加载 32x32 的大图标。然而,这实际上并不完全正确。 Windows 本身似乎维护了HICON 和原始资源之间的链接,因此如果需要其他大小的图标,Windows 可以根据需要去加载它们。

这个事实没有很好的记录,但是在 MSDN 中有一个地方说明了这个事实:WNDCLASSEX structurehIconSm 变量:

与窗口类关联的小图标的句柄。如果该成员为NULL,则系统在hIcon成员指定的图标资源中搜索合适大小的图标作为小图标使用。

因此,即使 VCL 不能通过公共 TForm.Icon 类正确支持小图标(例如,通过在设计时从属性编辑器中分配它),仍然可以使用其中之一使事情正常工作两种方法:

  • 不设置TForm.Icon 属性(无图标)。在这种情况下,表单将从TApplication.Icon 获取图标。它的默认值来自应用程序的MAINICON 资源。来自TApplication.Create

    FIcon := TIcon.Create;
    FIcon.Handle := LoadIcon(MainInstance, 'MAINICON');
    
  • 如果不想使用应用默认图标,可以在运行时加载不同的图标资源;在 C++ 中:

    myForm->Icon->LoadFromResourceName(FindHInstance(...), L"OtherResource");
    

因此,VCL 提供了对小图标的基本支持,因为它支持从资源加载图标,而 Windows 支持从从资源加载的大图标加载小图标。

如果您使用 VCL 样式,请在此处查看我对相关错误的回答: https://stackoverflow.com/a/35067909/562766

【讨论】:

    猜你喜欢
    • 2011-02-06
    • 2012-05-05
    • 2011-04-29
    • 1970-01-01
    • 2023-04-02
    • 2011-08-03
    • 2012-11-07
    • 2010-11-01
    • 2011-10-31
    相关资源
    最近更新 更多