【问题标题】:Delphi PNG image displays rectangle BUG around when move / load imageDelphi PNG图像在移动/加载图像时显示矩形BUG
【发布时间】:2014-04-15 02:45:00
【问题描述】:

在加载图像或移动图像时,png图像周围出现奇怪的矩形。

矩形在 24 位 PNG 或 jpg 中很少出现,但在 32 位 PNG 中出现问题。有谁知道是什么原因造成的? PNG是在Photoshop中创建的。我也试过 gimp 但同样的问题。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, pngimage, jpeg, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    Timer1: TTimer;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Label1: TLabel;
    procedure Timer1Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  png:TPngImage;
  rs:TResourceStream;
  ms:TMemoryStream;

implementation

{$R *.dfm}
{$R FB.RES}

procedure TForm1.Button1Click(Sender: TObject);
begin
 rs:=TResourceStream.Create(hInstance,'24bitpng',RT_RCDATA);
 png:=TPngImage.Create;
 png.LoadFromStream(rs);
 Image1.Picture.Graphic:=png;
 rs.Free;
 Label1.Caption:=Button1.Caption;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 rs:=TResourceStream.Create(hInstance,'32bitpng',RT_RCDATA);
 png:=TPngImage.Create;
 png.LoadFromStream(rs);
 Image1.Picture.Graphic:=png;
 rs.Free;
 Label1.Caption:=Button2.Caption;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
Form1.Close;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
Timer1.Enabled:=True;
Image2.Left:=0;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
DoubleBuffered:=True;  //This did the job, now no flickering around

Form1.BorderStyle:=bsnone;
Form1.Position:=poScreenCenter;
Label1.Caption:=Button1.Caption;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
    Screen.Cursor:=crSizeAll;
    ReleaseCapture;
    SendMessage(Form1.Handle, WM_SYSCOMMAND, 61458, 0) ;
    Screen.Cursor:=crDefault;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 if image2.Left<300 then
 image2.Left:=image2.Left+2
 else
 Timer1.Enabled:=False;

end;

end.

这个我试过了。

...
protected
    procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;

...

begin

procedure TForm1.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
  Message.Result := 1;
end;


end.

【问题讨论】:

  • 您只是应该通过移动 VCL 控件来制作动画!相反,在OnPaint 中使用 GDI 手动绘制。 Examples
  • 这里是源代码+编译后的二进制文件copy.com/s/FSczlwV4C0X0NEi6/FootBall-PNG.rar
  • 在表单上设置 DoubleBuffered。或者实现你自己的离屏处理。
  • 安德烈亚斯是正确的。响应WM_ERASEBKGND 渲染背景,响应WM_PAINT 渲染前景。
  • @David - 双缓冲,或者一般来说,离屏图像渲染没有错。尽管有时可能并不理想,但我认为这不是一种情况。毕竟,您不应该在终端会话中进行开球。

标签: image delphi png


【解决方案1】:

您的基本方法有缺陷。您不应该使用TImage 控件来显示动画。这些控件设计用于显示静态图像。作为一种粗略的解决方案,您可以为表单启用双重缓冲。通过将DoubleBuffered 设置为True 来执行此操作。这具有可能不受欢迎的副作用。无论如何,整个方法应该让你感到恶心。

正确的方法是将整个图像渲染到绘图表面。在理想情况下,您将拥有一个单独的窗口控件,该控件呈现背景以响应WM_ERASEBKGND,然后绘制动态内容以响应WM_PAINT。这就是我会做的。

作为更简单的中途之家,您可以使用TPaintBox 或者甚至是表单的OnPaint 处理程序。这些方法会让您绘制整个图像以响应WM_PAINT。那应该没有闪烁。如果没有,那么您可能需要使用屏幕外位图进行绘制,然后将其粘贴到绘制表面。

【讨论】:

  • 我先尝试了 WM_ERASEBKGND,但它周围有黑色背景,我需要自定义形状形式 i.imgur.com/lHL3WEq.jpg,然后我设置 DoubleBuffered:=True;现在没有闪烁
  • @Nafelem 您没有正确实现 WM_ERASEBKGND 的处理程序。您出于错误的原因拒绝了这种方法。另一方面,除非您在 Win32 方面有经验,否则您将很难走这条路。双缓冲很好,你可以忍受有点恶心。
  • 我尝试为 WM_ERASEBKGND 实现一个处理程序(上面的编辑代码)。
  • 您应该渲染背景以响应WM_ERASEBKGND。这就是我在答案中所说的。我不确定你是否真的理解我的意思。这个想法是答案的第二部分,从“正确的方法”开始就是你扔掉你现在拥有的东西。摆脱两个TImage 控件。并直接在窗口控件上绘制。
猜你喜欢
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 2010-12-06
  • 1970-01-01
  • 2016-11-26
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
相关资源
最近更新 更多