0

绘制图层是指用户可以手动绘制线条、圆形或其他形状的图层。普通层是指 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 是一个编辑框,我在其中显示创建/选择的图层索引(用于调试)

  • 正如您在上面看到的,如果我保留Selection:=BB然后RBLayer:=nildrawingLayer 只能移动和调整大小,所以这不是一个好的解决方案,因为我想在这个特定图层中使用我的鼠标事件来绘制。
  • 如果我仅RBLayer:=nil在保留的同时进行评论,Selection:=BB则绘图层不再可移动,但我无法选择绘图层的其他图层。我只能访问顶层(最后添加的PNG层)

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

当我单击绘图层(或以其他方式选择它,例如在列表框或其他东西中)时,我该如何做到这一点,drawingLayer 将无法移动,但我的绘图鼠标事件会启动?在这一切期间,我可以随时离开drawingLayer,并选择其他图层来移动和玩耍。所以基本上我需要一个特定的层不要像其他层一样。

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

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

其余代码(如setSelection和)大部分取自 graphics32 库的图层示例RBResizinglayerMouseDown

编辑

为了测试你的想法layerOptions,我做了以下事情:

1.开始一个新的测试项目,上面有一个ImgView,还有一个按钮

2.在创建时我使用了和以前一样的代码

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 的建议,我需要能够禁用所有图层的鼠标事件,并为特定图层启用鼠标事件,然后在完成编辑后,我需要能够重新启用鼠标事件对于所有图层,但我猜我做错了。

4

1 回答 1

0

以下项目影响鼠标事件

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

  • Layers.MouseListener (TCustomLayer)。在左键 MouseDown 和 MouseUp 之间“捕获”鼠标事件的层。引用中的“捕获”,因为它没有按照 Windows 上下文中的理解捕获鼠标。

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

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

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

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

此处提供有关使用图层的更多信息

编辑

要管理 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)。

于 2015-02-22T13:15:46.397 回答