Delphi: 无法在面板的 Canvas 上绘图

Delphi: Can't Draw On Panel's Canvas

我正在尝试在此面板的过程中在 TPanel 的 Canvas 上绘制图像。当我在面板的 Paint 方法中执行此操作时,它工作得很好,但是当我尝试在另一个过程或构造函数中绘制 Canvas 时,没有任何反应。

这是我在 Paint Procedure 中在 Panel 的 Canvas 上绘制的方式:

procedure TFeld.Paint;
var bmp : TBitmap;
begin
  inherited;
  bmp := TBitmap.Create;
  try
    bmp.LoadFromFile('textures\ground.bmp');
    self.Canvas.Draw(0,0,bmp);
  finally
    bmp.Free;
  end;
end;

这就是我尝试在另一个程序中利用它的方式:

procedure TFeld.setUnsichtbar;
var bmp : TBitmap;
begin
  bmp := TBitmap.Create;
  try
    bmp.LoadFromFile('textures\invisible.bmp');
    self.Canvas.Draw(0,0,bmp);
  finally
    bmp.Free;
  end;
end;

但是Panel的Canvas仍然是我在Paint程序中应用的图像。

我已经尝试将绘图从 Paint 过程移至 Constructor,但没有成功。

路径也正确,切换路径,现在面板有 'invisible.bmp' 图片。

整个Class/Unit:http://pastebin.com/YhhDr1F9

知道为什么这不起作用吗?

看看你的整体 class 我假设你希望根据特定条件控制在什么时间显示哪个图像。对吗?

如果是这种情况,您需要做的第一件事就是让您的 class 有一个用于存储图像数据的字段。在上面的示例中,您仅使用 bmp 文件,因此 TBitmap 就足够了。但是,如果您使用的是其他图片类型,则可能需要使用 TPicture 字段,因为该字段允许将所有支持的图片图像加载为 TImage,您也尝试使用组件可以。

然后您更改组件的 Paint 方法以使用上述字段获取图片数据,而不是像现在这样每次都创建本地图片数据变量。
事实上,您现在所做的事情很糟糕,因为您在每次渲染组件时都强制应用程序将图像数据从文件读取到内存中。这可能会导致糟糕的性能。

最后,当您想要更改组件上显示的图片时,只需将不同的图片加载到您的图片字段中即可。

因此,通过以上更改,您的 class 应该如下所示:

type 
  TFeld=class(TPanel)
  protected
    procedure Paint;override;
    procedure BitmapChange(Sender: TObject);
  private
    zSichtbar : Boolean;
    zPosHor,zPosVer : Integer; // Position im Array
    zEinheit  : TEinheit;
    Bitmap: TBitmap; //Field for storing picture data
  public

//    hImage    : TImage;

    constructor Create(pX,pPosHor,pY,pPosVer,pHoehe,pBreite:integer;pImgPath:String;pForm:Tform); virtual;
    destructor Destroy;
    procedure ChangeImage(pImgPath: String);
  end;

...

implementation

constructor TFeld.Create(pX,pPosHor,pY,pPosVer,pHoehe,pBreite:integer;pImgPath:String;pForm:Tform);
begin
  inherited create(pForm);

  ...

  //Creater internal component for storing image data
  Bitmap := TBitmap.Create;
  //Assign proper method to Bitmaps OnChange event
  Bitmap.OnChange := BitmapChange;
  //Load initial image data
  Bitmap.LoadFromFile(pImgPath);

  ....

end;

destructor Destroy;
begin
  //We need to destroy the internal component for storing image data before 
  //we destory our own component in order to avoid memory leaks
  Bitmap.Free;
end;

procedure TFeld.Paint;
begin
  inherited;
  //Use local image field to tell the Paint method of what to render
  self.Canvas.Draw(0,0,Bitmap);
end;

procedure TFeld.BitmapChange(Sender: TObject);
begin
  //Force redrawing of the component on bitmap change
  self.Invalidate;
end;

procedure TFeld.ChangeImage(pImgPath: String);
begin
  //Load different image into image field
  Bitmap.LoadFromFile(pImgPath);
end;

编辑:添加必要的代码以在更改位图后强制重绘组件。