Delphi Graphics32将普通图层与图层组合在一起

时间:2015-02-20 07:52:17

标签: delphi delphi-xe graphics32

通过绘制图层,我指的是用户可以手动绘制线条,圆形或其他形状的图层。通过普通图层,我指的是graphics32图层示例中描述的图层(可以使用鼠标事件在运行时移动或调整大小的图层) 所以我在组合这两种类型的层时遇到了困难。在我的测试项目中,现在,我假设我只有一个绘图层和多个PNG层。 所以在我的项目中,我在OnFormCreate中设置了ImgView32的属性,如:

procedure TForm1.FormCreate(Sender: TObject);
begin
  AWidth:= 800;
  AHeight:= 600;
  FillColor:=clWhite;

  with ImgView do
  begin
    Selection := nil;
    RBLayer := nil;
    Layers.Clear;
    Scale := 1;
    Scaled:=true;
    Bitmap.SetSize(AWidth, AHeight);
    Bitmap.DrawMode := dmTransparent;
    Bitmap.Clear(FillColor);
  end;
end;

在此之后,单击一个按钮,我添加了许多图层(包含透明的PNG图像)。所以就像这样

procedure TForm1.Button1Click(Sender: TObject);
begin
  AddPNGLayer(1);
  AddPNGLayer(2);
  AddDrawingLayer;
  AddPNGLayer(3);
end;

(我不会在这里详细说明添加PNG层以保持问题简短。我只会说它使用与drawingLayer中使用的不同的onMouseDown事件(layerMouseDown)),AddDrawingLayer如下:

procedure TForm1.AddDrawingLayer;
var
  P:TPoint;
  jumaH, JumaW, W, H: Single;
begin
  imwidth := ImgView.Bitmap.Width;
  imheight := ImgView.Bitmap.Height;

  xofx := (ImgView.ClientWidth - 17 - imwidth) div 2; // substracting the width of the scrollbar
  yofy := (ImgView.ClientHeight - 17 - imheight) div 2; // same here with height

  bm32 := TBitmap32.Create;
  bm32.DrawMode := dmTransparent;
  bm32.SetSize(ImgView.Bitmap.Width,ImgView.Bitmap.Height);
  bm32.Canvas.Pen.Width := 3;
  bm32.Canvas.Pen.Color := clBlack32;//pencolor;

  BB := TBitmapLayer.Create(ImgView.Layers);
  try
    BB.Bitmap.DrawMode := dmTransparent;
    BB.Bitmap.SetSize(imwidth,imheight);
    BB.Bitmap.Canvas.Pen.Width := 3;
    BB.Bitmap.Canvas.Pen.Color := pencolor;
    BB.Location := GR32.FloatRect(0, 0, imwidth, imheight);
    BB.Scaled := true;
    BB.Tag:=3;
////    Selection:=BB;  // if I use this then I cant draw because the entire layer is selected and the mouseDown event works as a mover/resizer
//    BB.OnMouseDown := DrLayerMouseDown;
//    BB.OnMouseUp := DrLayerMouseUp;
//    BB.OnMouseMove := DrLayerMouseMove;
//    BB.OnPaint := DrLayerOnPaint;
    RBLayer:=nil;
    EdLayerIndex.Text:=IntToStr(BB.Index);
  finally
    BB.Free;
  end;
  FDrawingLine := false;
//    swapBuffers32; // needed when mouse events are active
end;

EdLayerIndex是一个EditBox,我在其中显示创建/选择的Layer索引(用于调试)

  • 如上所示,如果我保留Selection:=BBRBLayer:=nil,那么drawingLayer只能移动并可调整大小,所以这不是一个好的解决方案,因为我想在此特定图层中使用我的鼠标事件画画。
  • 如果我在保留RBLayer:=nil时仅对Selection:=BB发表评论,那么drawingLayer不再可移动,但我无法选择 drawingLayer下的其他图层。我只能访问顶层(最后添加的PNG图层)

  • 如果我评论Selection:=BB,那么我无法用鼠标选择其他图层。所以在我的情况下,我在drawingLayer之前声明了2个png图层,在它之后声明了一个png图层。在运行时我只能选择最后一层(在drawingLayer上面') 所以这也不是解决方案。

当我点击绘图图层(或者在列表框或其他内容中选择它)时,我怎么能这样做,drawingLayer不会移动,但是我的绘图鼠标事件会启动?所有这一切,我可以随时离开drawingLayer并选择其他图层来移动和玩。 所以基本上我需要一个特定的层来不像其他层一样。

我想要实现的是使用graphics32获得类似经典Photoshop或类似paint.net的行为。这些图层属性实际上如何工作非常令人困惑。

到目前为止,我想出了如何在透明层上动态绘制(线条,圆形,矩形)(使用鼠标事件)。所以我可以有一个绘图层。该绘图发生在我的DrLayerMouseDownDrLayerMouseUpDrLayerMouseMoveDrLayerPaint事件中。但我似乎无法理解如何将这样的绘图层与常规的可移动/可调整大小的图层组合在一起。

其余代码(如setSelectionRBResizinglayerMouseDown)主要来自graphics32库的图层示例。

修改

为了使用layerOptions测试您的想法,我执行了以下操作:

1.启动一个带有ImgView的新测试项目和一个按钮

2.On create我使用了与之前相同的代码

3.OnButtonClick我使用修改后的AddDrawingLayer添加了一个图层:

...
    BB.Scaled := true;
    Selection:=BB;
    Selection.LayerOptions:=Selection.LayerOptions and (not LOB_MOUSE_EVENTS); // I also tried it with BB instead of Selection
    BB.OnMouseDown := DrLayerMouseDown;
    BB.OnMouseUp := DrLayerMouseUp;
    BB.OnMouseMove := DrLayerMouseMove;
    BB.OnPaint := DrLayerOnPaint;
...

希望它对鼠标事件不敏感。但该层仍然是可移动的,而不是对鼠标不敏感。所以就像我没有做任何事情

所以我不认为这有助于我使用此选项,除非我做错了 所以onCreate的图层,这个选项似乎并不坚持。但是,如果我为所有图层禁用鼠标事件,就像在下一个编辑中一样,那么绘图层将被禁用(鼠标事件)

修改

此外,我尝试了另一个测试项目,相同的想法:相同的onCreate和onButtonClick我添加3层(使用库的图层示例),每个图层包含一个图像(这次没有绘图层,为了保持简单)。然后我添加了一个新按钮,如果单击它,则执行下一个代码:

  for i := 0 to ImgView.Layers.Count-1 do
    (ImgView.Layers.Items[i] as TPositionedLayer).LayerOptions:= (ImgView.Layers.Items[i] as TPositionedLayer).LayerOptions and (not LOB_MOUSE_EVENTS);

我的目的是让所有图层对鼠标事件不敏感。我成功了,单击新按钮后,无法再选择图层,但是当我想为图层重新启用鼠标事件时(添加第三个按钮,下一个代码点击onClick):

  for i := 0 to ImgView.Layers.Count-1 do
    (ImgView.Layers.Items[i] as TPositionedLayer).LayerOptions:= (ImgView.Layers.Items[i] as TPositionedLayer).LayerOptions and (LOB_MOUSE_EVENTS);

没有显示任何错误,但是当我尝试选择一个图层以便移动它时......图层的所有图像都从视图中消失了......让我的白色背景为空ImgView。

我做错了什么? 为了完成您对LayerOptions的建议,我需要能够为所有图层禁用鼠标事件,并为特定图层启用鼠标事件,然后在编辑完成后,我需要能够重新启用鼠标事件对于所有图层,但我猜错了。

1 个答案:

答案 0 :(得分:0)

以下项目影响鼠标事件

  • Layers.MouseEvents(boolean)。图层是TCustomImage32的TLayerCollection,用于管理图层。如果MouseEvents为False,则鼠标事件不会传播到图层。

  • Layers.MouseListener(TCustomLayer)。在左按钮MouseDown和MouseUp之间“捕获”鼠标事件的图层。 '捕获'在quoutes中,因为它没有像Windows上下文中所理解的那样捕获鼠标。

  • 图层选项位。每个层都有一个32位的LayerOptions属性。有趣的是LOB_MOUSE_EVENTS(第29位),它指定图层是否对鼠标事件做出反应。层也可以指定LOB_NO_CAPTURE位(位27),即使设置了LOB_MOUSE_EVENTS,也会阻止鼠标事件。

  • 图层索引。对于LOB_MOUSE_EVENTS选项位,检查层(按顺序从最低到最低)。使用此位找到图层时,将在图层HitTest函数中检查X和Y坐标。如果X和Y坐标位于图层位置HitTest成功。内置HitTest的结果可以在您自己的OnHitTest事件中被覆盖。最后,如果layers选项不包含LOB_NO_CAPTURE位,则调用图层MouseDown事件。

基于之前我建议当用户进入“编辑”模式时,通过将其LayerOptions设置为不包含LOB_MOUSE_EVENTS位来禁用除绘图层之外的所有其他图层

Layer.LayerOptions := Layer.LayerOptions and (not LOB_MOUSE_EVENTS);

有关使用图层的更多信息,请访问here

修改

管理LOB_MOUSE_EVENTS创建例如以下内容

procedure TForm7.LayerMouseDisEnable(Enable: boolean);
var
  i: integer;
  Lo: cardinal;
begin
  for i := 0 to ImgView.Layers.Count-1 do
  begin
    Lo := ImgView.Layers.Items[i].LayerOptions;
    if Enable then
      ImgView.Layers.Items[i].LayerOptions := Lo or LOB_MOUSE_EVENTS
    else
      ImgView.Layers.Items[i].LayerOptions := Lo and (not LOB_MOUSE_EVENTS);
  end;
end;

调用此方法(使用False)可在创建绘图图层之前禁用图层中的鼠标事件。绘图层将启用鼠标事件,因为新创建的图层同时设置了LOB_VISIBLE和LOB_MOUSE_EVENTS。当您停止绘图以启用鼠标事件时,再次调用(使用True)。