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;
编辑:添加必要的代码以在更改位图后强制重绘组件。
我正在尝试在此面板的过程中在 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;
编辑:添加必要的代码以在更改位图后强制重绘组件。