Delphi Graphics32结合了普通层和工程图层 [英] Delphi Graphics32 combining normal layers with drawing layers

查看:118
本文介绍了Delphi Graphics32结合了普通层和工程图层的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

By drawing layer I mean a layer where the user can manually draw lines, circles or other shapes. And by normal layers I mean the layers described in the graphics32 layers example (the layers that can be moved or resized at runtime using mouse events) So I am having difficulties combining these 2 types of layers. In my test project, for now, I will assume I only have one drawing layer and multiple PNG layers. So in my project I set properties for the ImgView32 in the OnFormCreate like:

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;

在此之后,单击按钮的onClick,我添加了许多层(包含透明的PNG图像).就是这样

After this, onClick of a button, I add a number of layers (containing transparent PNG images). So it's like this

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

(在这里,为了使问题简短,我不会详细说明添加PNG图层.我只会说它使用的是与drawingLayer中使用的事件不同的onMouseDown事件(layerMouseDown)),AddDrawingLayer如下所示:

(I wont elaborate here the adding of PNG layers in order to keep the question short. I will only say that it uses a different onMouseDown event (layerMouseDown) than the one used in the drawingLayer) and the AddDrawingLayer is as follows:

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,在其中显示创建/选定的图层索引(用于调试)

EdLayerIndex is a EditBox where I display the created/selected Layer index (for debugging)

  • 从上面可以看到,如果我保留Selection:=BBRBLayer:=nil,则drawingLayer只能移动并且可以调整大小,因此这不是一个好的解决方案,因为我想在此特定图层中使用Mouse事件进行绘制.
  • 如果在保持Selection:=BB的同时仅注释RBLayer:=nil,则drawingLayer不再可移动,但是我无法选择drawingLayer下 的其他图层.我只能访问顶层(最后添加的PNG层)

  • As you can see above, if I keep Selection:=BB and RBLayer:=nil then the drawingLayer is only movable and resizable, so it's not a good solution since I want to use my Mouse events in this particular layer to draw.
  • If I comment only the RBLayer:=nil while keeping Selection:=BB then the drawingLayer is not movable anymore, but I cannot select other layers that are under the drawingLayer. I can only access the top layer (the last added PNG layer)

如果我注释Selection:=BB,则无法用鼠标选择其他层.因此,在我的情况下,我在我的drawingLayer之前声明了2个png图层,在其之后声明了一个.在运行时,我只能选择最后一层("drawingLayer"上方的一层) 因此,这也不是解决方案.

If I comment the Selection:=BB then I cannot select other layers with my mouse. So in my case I declared 2 png layers before my drawingLayer and one after it. On runtime I can only select the last layer (the one 'above' the drawingLayer) So this is not a solution either.

当我单击绘图层(或在列表框之类的菜单中选择它)时,该如何操作,该drawLayer无法移动,但是我的绘图鼠标事件会启动?这一切使我可以随时离开drawingLayer并选择其他图层来移动和玩耍. 因此,基本上我需要一个特定的层来不像其他层那样工作.

How can I do it that when I click on the drawing layer (or select it otherwise, like in a listbox or something), the drawingLayer wont be movable, but my drawing Mouse Events will kick in? And all this while I can go away from the drawingLayer whenever I want and select other layers to move around and play with. So basically I need a particular layer to NOT act like the other layers.

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

What I want to achieve is having a classic Photoshop-like or paint.net like behavior using graphics32. And it is very confusing how these layer properties actually work.

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

So far I figured out how to draw (lines, circles, rectangles) on a transparent layer dynamically (using mouse events). So I can have a drawing layer. The drawing happens in my DrLayerMouseDown, DrLayerMouseUp, DrLayerMouseMove, DrLayerPaint events. But I cannot seem to understand how to combine such a drawing layer with regular movable/resizable layers.

其余代码(如setSelectionRBResizinglayerMouseDown)大部分来自graphics32库的分层示例.

The rest of the code (like setSelection, RBResizing and layerMouseDown) is mostly taken from the layers example of the graphics32 library.

编辑

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

In order to test your idea with layerOptions, I did the following:

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

1.Started a new test project with an ImgView on it, and a button

2.在创建时,我使用了与以前相同的代码

2.On create i used the same code as before

3.OnButtonClick我使用经过修改的AddDrawingLayer像这样添加了一层:

3.OnButtonClick I added ONE layer using a modified AddDrawingLayer like this:

...
    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;
...

期望它对鼠标事件不敏感.但是该层仍然可以移动,而不会对鼠标不敏感.就像我什么都没做

expecting it to become insensitive to Mouse Events. But the layer is still movable instead of being insensitive to mouse. So it's like I did not do anything

因此,除非我做错了,否则我认为它不会帮助我使用此选项 因此,在图层的onCreate上,此选项似乎不存在.但是,如果我像在下一个EDIT中那样一一禁用所有层的鼠标事件,则绘图层将被禁用(鼠标事件)

So I do not think it helps me using this option unless I am doing it wrong So onCreate of the layer, this option does not seem to stick. But if I disable mouse events for all layers, one-by-one like in the next EDIT, then the drawing layer gets disabled (mouse events)

编辑

我还尝试了另一个测试项目,想法相同:相同的onCreate和onButtonClick我添加了3个层(使用库的Layers示例),每个层都包含一个图像(为了简单起见,这次没有绘制层).然后,我添加了一个新按钮,如果单击该按钮,将执行下一个代码:

Also I tried another test project, same idea: same onCreate, and onButtonClick I add 3 layers (using the Layers example of the library) containing an image each (no drawing layer this time, to keep it simple). Then I added a new button where if you click it, the next code is executed:

  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):

My purpose was to make all layers insensitive to mouse events. I succeeded, after clicking the new button, the layers could not be selected anymore, however when I wanted to re-enable mouse events for the layers (adding a third button with the next code 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空白背景.

No error was shown, but when I tried to select a layer in order to move it ... all the images of the layers disappeared from the view... leaving me with a white background empty ImgView.

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

What am I doing wrong? In order to do what you suggested with LayerOptions, I need to be able to disable mouse events for all layers, and enable mouse events for a specific layer, and then when editing is done, I need to be able to re-enable mouse events for all layers, but I am doing it wrong I guess.

推荐答案

以下项目会影响鼠标事件

Following items affect mouse events

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

  • Layers.MouseEvents (boolean). Layers is the TLayerCollection of TCustomImage32 that manages the layers. If MouseEvents is False, mouse events are not propagated to the layers.

Layers.MouseListener(TCustomLayer). 捕获"鼠标左键MouseDown和MouseUp之间的鼠标事件的层.由于无法捕获Windows上下文中理解的鼠标,因此捕获"之所以用以定额.

Layers.MouseListener (TCustomLayer). The layer that 'captures' mouse events between left button MouseDown and MouseUp. 'Captures' in quoutes because it is not capturing the mouse as understood in Windows context.

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

Layer Option Bits. Each layer has a 32 bit LayerOptions property. The interesting bit is LOB_MOUSE_EVENTS (bit 29) which specifies whether the layer reacts to mouse events. A layer may also specify LOB_NO_CAPTURE bit (bit 27) which prevents mouse events, even if LOB_MOUSE_EVENTS is set.

层索引.将检查LOB_MOUSE_EVENTS选项位的层(从上到下,从最低到最低).找到具有此位的图层后,将在图层HitTest函数中检查X和Y坐标.如果X和Y坐标在图层位置内,则HitTest成功.内置的HitTest的结果可以在您自己的OnHitTest事件中覆盖.最后,如果图层选项不包含LOB_NO_CAPTURE位,则调用图层MouseDown事件.

Layer index. Layers are checked (in order topmost down to lowest) for LOB_MOUSE_EVENTS option bit. When a layer is found with this bit, the X and Y coordinates are checked in the layers HitTest function. If the X and Y coordinates are within the layers location HitTest succeeds. The result of built-in HitTest can be overridden in your own OnHitTest event. Finally, if the layers options does not contain the LOB_NO_CAPTURE bit, the layers MouseDown event is called.

根据先前的经验,我建议当用户进入编辑"模式时,通过将其LayerOptions设置为不包含LOB_MOUSE_EVENTS位,可以禁用除绘图层之外的所有其他层

Based on previous I suggest that when the user enters an 'edit' mode, you disable all other layers, except the drawing layer, by setting their LayerOptions to not include the LOB_MOUSE_EVENTS bit

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

有关使用图层的更多信息,请此处

Further info about using layers is available here

修改

要管理LOB_MOUSE_EVENTS,请创建例如以下内容

To manage the LOB_MOUSE_EVENTS create for example something like following

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)以启用鼠标事件.

Call this (with False) to disable mouse events in the layers just before you create the drawing layer. The drawing layer will have mouse events enabled as newly created layers have both LOB_VISIBLE and LOB_MOUSE_EVENTS set. Call again (with True) when you stop drawing to enable the mouse event.

这篇关于Delphi Graphics32结合了普通层和工程图层的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆