Под слоем рисования я подразумеваю слой, на котором пользователь может вручную рисовать линии, круги или другие фигуры. И под нормальными слоями я подразумеваю слои, описанные в примере со слоями Graphics32 (слои, которые можно перемещать или изменять размер во время выполнения с помощью событий мыши). Поэтому у меня возникают трудности с объединением этих двух типов слоев. В моем тестовом проекте на данный момент я предполагаю, что у меня есть только один слой рисования и несколько слоев PNG. Итак, в моем проекте я установил свойства ImgView32 в OnFormCreate, например:
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, чтобы не усложнять вопрос. Скажу только, что он использует событие onMouseDown (layerMouseDown), отличное от того, которое используется в DrawingLayer), а 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, в котором я отображаю созданный/выбранный индекс слоя (для отладки)
- Как вы можете видеть выше, если я оставлю
Selection:=BB
иRBLayer:=nil
, тогда DrawingLayer можно будет перемещать и изменять только размер, поэтому это не очень хорошее решение, поскольку я хочу использовать события мыши в этом конкретном слое для рисования. Если я прокомментирую только
RBLayer:=nil
, сохранив при этомSelection:=BB
, тогда DrawingLayer больше не будет перемещаться, но я не смогу выбрать другие слои, которые находятся под DrawingLayer. Я могу получить доступ только к верхнему слою (последний добавленный слой PNG)Если я прокомментирую
Selection:=BB
, я не смогу выбрать другие слои с помощью мыши. Итак, в моем случае я объявил 2 слоя PNG перед моим DrawingLayer и один после него. Во время выполнения я могу выбрать только последний слой (тот, что «над» DrawingLayer). Так что это тоже не решение.
Как я могу сделать так, чтобы когда я нажимаю на слой рисования (или выбираю его иным образом, например, в списке или что-то в этом роде), DrawingLayer не будет перемещаться, но мои события рисования с помощью мыши сработают? И все это время я могу уйти от DrawingLayer, когда захочу, и выбрать другие слои, чтобы перемещаться и играть с ними. Так что в основном мне нужен определенный слой, чтобы НЕ вести себя как другие слои.
Чего я хочу добиться, так это классического поведения, подобного Photoshop или Paint.net, с использованием Graphics32. И это очень сбивает с толку, как на самом деле работают эти свойства слоя.
Пока я разобрался, как рисовать (линии, круги, прямоугольники) на прозрачном слое динамически (используя события мыши). Так что у меня может быть слой рисования. Рисование происходит в моих событиях DrLayerMouseDown
, DrLayerMouseUp
, DrLayerMouseMove
, DrLayerPaint
. Но я не могу понять, как объединить такой слой рисования с обычными слоями с подвижным/изменяемым размером.
Остальной код (например, setSelection
, RBResizing
и layerMouseDown
) в основном взят из примера слоев библиотеки 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;
...
ожидая, что он станет нечувствительным к событиям мыши. Но слой по-прежнему подвижен, а не нечувствителен к мыши. Так вроде ничего и не делал
Так что я не думаю, что это поможет мне использовать эту опцию, если только я не делаю это неправильно. Итак, при создании слоя эта опция, похоже, не работает. Но если я отключу события мыши для всех слоев, один за другим, как в следующем EDIT, тогда слой рисования отключится (события мыши).
ИЗМЕНИТЬ
Также я попробовал другой тестовый проект, та же идея: то же самое onCreate, и onButtonClick я добавляю 3 слоя (используя пример библиотеки Layers), каждый из которых содержит изображение (на этот раз без слоя рисования, чтобы упростить его). Затем я добавил новую кнопку, при нажатии на которую выполняется следующий код:
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, мне нужно иметь возможность отключать события мыши для всех слоев и включать события мыши для определенного слоя, а затем, когда редактирование завершено, мне нужно иметь возможность снова включить события мыши для всех слоев, но я думаю, что я делаю это неправильно.