【问题标题】:Delphi Graphics32 combining normal layers with drawing layersDelphi Graphics32 将普通图层与绘图图层相结合
【发布时间】:2015-04-21 20:06:43
【问题描述】:

我所说的绘图层是指用户可以手动绘制线条、圆形或其他形状的层。普通层是指 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:=BBRBLayer:=nil,那么drawingLayer 只能移动和调整大小,所以这不是一个好的解决方案,因为我想在这个特定层中使用我的鼠标事件来绘制。
  • 如果我只评论RBLayer:=nil 而保留Selection:=BB,则drawingLayer 不再可移动,但我无法选择drawingLayer 的其他图层。我只能访问顶层(最后添加的PNG层)

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

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

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

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

其余代码(如setSelectionRBResizinglayerMouseDown)大部分取自 graphics32 库的图层示例。

编辑

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

【问题讨论】:

  • 看来我在错误的地方发表了评论,在我的回答下,对不起。无论如何,作为对您关于再次启用鼠标事件的编辑的回应。要启用使用 OR 运算符,例如在 LayerOptions := LayerOptions 或 LOB_MOUSE_EVENTS 中。图像消失是因为使用 AND 运算符时您清除了 LOB_VISIBLE 位。您应该阅读有关逻辑运算符和位域的内容。
  • 好消息:Graphics32 已于上个月(04.2017)更新

标签: delphi delphi-xe graphics32


【解决方案1】:

以下项目影响鼠标事件

  • 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 事件。

根据之前的建议,当用户进入“编辑”模式时,您可以禁用除绘图层之外的所有其他层,方法是将它们的 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)。

【讨论】:

  • 请查看我已编辑的问题
  • 我说要禁用 LOB_MOUSE_EVENTS 所有其他层,除了绘图层。另外你应该设置Selection := nil;以防万一。
  • 作为对您关于再次启用鼠标事件的编辑的回应。启用使用 OR 运算符,如LayerOptions := LayerOptions or LOB_MOUSE_EVENTS。图像消失是因为使用 AND 运算符时您清除了 LOB_VISIBLE 位。您应该阅读有关逻辑运算符和位域的内容。
  • 谢谢,等我睡一觉我会调查你的cmets,我会回复你的
  • 如果我使用你的想法,我的应用程序会崩溃。所以我添加了 2 个普通层,然后我调用了LayerMouseDisEnable(false);,然后我添加了如上所述的绘图层。但是,当我单击我的图层时,应用程序崩溃并将我指向 procedure TCustomLayer.SetVisible(Value: Boolean); 内的 GR32_layers.pas 到这一行:LayerOptions := LayerOptions or LOB_VISIBLE
猜你喜欢
  • 2015-03-18
  • 2015-04-17
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
  • 2015-04-18
  • 2015-06-28
  • 2015-06-24
  • 1970-01-01
相关资源
最近更新 更多