Delphi 如何从TCanvas中删除单个图片?

Delphi 如何从TCanvas中删除单个图片?,delphi,canvas,bitmap,delphi-xe3,Delphi,Canvas,Bitmap,Delphi Xe3,在我的表单中,有一个包含画布的透明面板(我认为它的实现在这里并不重要;有人告诉我不是这样)。我正在这个画布上绘制许多位图,使用: Panel.Canvas.Draw(Image.Left, Image.Top, Image.Picture.Bitmap, Opacity); //Image is a TImage instance //Opacity is an integer 0..255 但是,当我在图片中做一些改变时,比如重新确定尺寸或在表格周围移动,我会在面板中重新绘制它的图片。这里的

在我的表单中,有一个包含画布的透明面板(我认为它的实现在这里并不重要;有人告诉我不是这样)。我正在这个画布上绘制许多位图,使用:

Panel.Canvas.Draw(Image.Left, Image.Top, Image.Picture.Bitmap, Opacity);
//Image is a TImage instance
//Opacity is an integer 0..255
但是,当我在图片中做一些改变时,比如重新确定尺寸或在表格周围移动,我会在面板中重新绘制它的图片。这里的问题是旧的定位图像仍保留在画布上。 现在我的问题是:有一种方法可以擦除画布上的单个位图吗?如果是,会是什么?如果没有,有没有办法擦除画布上的所有内容?这样我就可以重新绘制剩余的图片

编辑:


最后,我的问题出现在我使用的透明面板上。它的
Paint
方法是伪造的,并没有使画布失效以擦除其上的控件。无论如何,问题解决了。我该怎么处理这个问题呢?

不太可能,因为画布没有记录不同的图像

但是,只需在画布上画图,就可以轻松地“清除”画布的任何部分。
这将允许您重新绘制所有剩余的图片

但是,如果有许多图片,并且用户正忙于拖动单个图片,那么这可能会非常耗时;因为这将导致对运动图像的每个微小位置改变进行大量重绘

一个选项是在调整“活动”图像时使用XOR掩码绘制该图像。然后,只需再次使用异或掩码在同一位置重新绘制即可擦除。这样做的缺点是颜色会失真,但效率很高

另一个选项是在绘制活动图片之前,复制画布的一部分。然后,您有一个简单的机制,通过在正确的位置重新绘制副本来擦除新图片


编辑:回应Guill评论的最后一个选项的详细说明: 既然我没有背景,我怎么能画出来呢?有透明的刷子吗

假设要绘制和移动图片(可能是一个蓝色矩形20x60):

  • 假设您从一块空白画布开始,
    clWhite
    background
  • 初始位置为(25,75),因此:
  • (A)首先在画布上复制(25,75)处的20x60矩形
  • 副本当然是完全白色的,但那正是你的背景
  • 现在在该位置绘制矩形
酷,第一点就完成了。现在要将矩形移动到(40,90):

  • 在(25,75)处绘制复制的图像NB完全没有透明度!在绘制蓝色矩形之前,您希望将画布恢复到(A)的状态
  • 在(40,90)处复制20x60矩形。(同样,它将是完全白色的)
  • 在(40,90)处绘制蓝色矩形
好的,到目前为止还不错,但我们的拷贝总是白色的。让我们添加第二个矩形。(这次是红色和80x10。)

  • 我们将放弃当前副本,因为我们不再希望移动蓝色矩形
  • 我们希望将红色矩形放置在(45,95)处,使其与蓝色重叠
  • (B)在(45,95)处复制80x10矩形
  • 注意,这一次副本的一部分是蓝色的,其余部分是白色的
  • 现在在(45,95)处绘制红色矩形
作为最后一步,让我们将红色矩形的大小减小到5x5:

  • 绘制复制的图像(45,95)NB同样重要的是,我们不要使用透明度,因为我们试图将绘制红色矩形的图像部分恢复到(B)中的样子
  • 在(45,95)处复制5x5矩形
  • 绘制较小的红色矩形
这是一个简单的冲洗重复过程。碰巧的是,这与Windows在移动鼠标光标时绘制鼠标光标所使用的技术相同


旁注:如果您正在绘制的图像是不规则形状,则无所谓。如果你的备份矩形完全覆盖了你正在绘制的图像,这项技术是有效的。

你的整个绘制方法是不正确的。绘制表面的窗口不记得其内容。在窗口中绘制的设计要求每个窗口在被请求时能够重新绘制自身,即当发送
WM_paint
消息时。您必须通过绘制要求您绘制的内容来响应
WM_PAINT
。您当前正在违反该规则。你需要重新设计你的程序以适应这个系统

请执行以下操作:

  • t输入框
    添加到面板中
  • OnPaint
    事件处理程序添加到执行所有绘制的绘制框中
  • 当需要强制重新绘制时,在绘制框上调用
    Invalidate
  • 就这样。请注意,此处未提及
    WM_PAINT
    。这是因为VCL为您包装了所有内容,并以更易于消化的形式呈现


    关于这个主题(以及其他许多主题)的必读读物是Petzold的经典著作《编程窗口》。

    没有办法从画布上“清除”一些东西。您只能要求面板重新绘制,例如通过调用
    panel.Invalidate
    ,下一步您将不会绘制隐藏图像。或者你可以在那个区域画些东西。你到底要做什么?我将把我的问题更新为更具体的示例。简而言之,它要求系统通过发送
    WM_PAINT
    消息重新绘制系统响应的控件,该消息通常由控件作为
    OnPaint
    事件发布。在这种情况下,你应该把所有的东西都画出来。但这不适用于面板。面板主要不用于自定义绘图。我明白了。但是在一个大循环中使用它会导致很多“闪烁”。并没有解决我的问题,因为它确实重新绘制了旧的定位图像