Как правильно отобразить комбинированное изображение в компоненте Delphi `tstringgrid` - PullRequest
1 голос
/ 25 апреля 2020

У меня есть игровая программа, которая требует, чтобы пользователь выбирал из 50+ изображений для размещения на сетке игрового поля 9x9 с timage в каждой позиции. Для пользователя, чтобы разместить изображения, я предоставляю tstringgrid, который отображает различные изображения от timagelist. Фактические изображения представляют собой графические символы c, созданные в формате .png с прозрачными областями, чтобы при отображении отображался фоновый цвет родительского изображения. Изображение, выбранное из tstringgrid, корректно отображается на компонентах игрового поля timage, но не в «tstringgrid». tstringgrid отображает прозрачные области изображения черным цветом, что неприглядно и делает многие символы нечитаемыми.

Я использовал следующий код для загрузки tstringgrid:

procedure TImageForm.FormCreate(Sender: TObject);
var
  r, c, n : Integer;
  img:TImage;
begin
  //assign a value to each cell to connect with imagelist.
  //see StringGrid1DrawCell
  img := timage.Create(nil);
  try
    n := -1;
    with StringGrid1 do begin
      for r := 0 to RowCount - 1 do begin
        for c:= 0 to ColCount - 1 do  begin
          inc(n);
          Cells[c,r] := IntToStr(n);
          ImageList1.GetBitmap(n, img.Picture.Bitmap);
//          ImageList1.AddMasked(Img.Picture.Bitmap, clBlack);
        end;
      end;
    end;
  finally
    img.Free;
  end;
end;

Что мне нужно сделать, так это пересмотреть растровое изображение, полученное из списка, до его отображения.

Я пытаюсь сделать это следующим образом:

procedure TForm1.FillBkgd (bmp : tbitmap;clr : tcolor);
//which is the imagelist index for the image
var
  bmp1  : tbitmap;

begin
  bmp1 := tbitmap.create;

  try
     bmp1.Width := 50;
     bmp1.Height := 50;

     with Bmp1.Canvas do begin
      Brush.Color := clr;  //stringgrid1.color;
      Brush.Style := bsSolid;
      FillRect(rect(0,0,50, 50));
     end;

     bmp1.Canvas.Draw(0,0, bmp);
     bmp:= bmp1;
  finally
    bmp1.free;

  end;
end;

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
{https://www.youtube.com/watch?v=LOEP312NzsE}
var
  bmp : tbitmap;
  s : string;
  aCanvas: TCanvas;
  n : integer;
begin
  inherited;

  if not Assigned (Imagelist1) then   //or (Arow = 0) or (aCol in [0,5])
    exit;
  bmp := tbitmap.create;
  try
    s := (Sender as TStringGrid).Cells [aCol, ARow];
    // Draw ImageX.Picture.Bitmap in all Rows in Col 1
    aCanvas := (Sender as TStringGrid).Canvas;
    // Clear current cell rect
    aCanvas.FillRect(Rect);
    // Draw the image in the cell
    n := strtoInt (s);
    ImageList1.GetBitmap(n, Bmp);

    FillBkgd (bmp,clRed); //stringgrid.color

    aCanvas.StretchDraw(Rect,bmp);

  finally

  end;
end;

Мои попытки объединить изображение символа с цветной фон до помещения его в сетку не удалось. Мне неясно, не удается ли мне создать цветное растровое изображение solid или я не присоединяю изображение к фону успешно.

1 Ответ

3 голосов
/ 25 апреля 2020

Функция FillBkgd имеет большие проблемы с качеством кода.

     bmp:= bmp1;
  finally
    bmp1.free;    
  end;

Все переменные объекта являются указателями. Объекты bmp и bmp1 указывают на одну область памяти, которую вы освобождаете. Это приводит к нарушению доступа. Вам повезло, что указатель не возвращается из функции. Функция FillBkgd не работает. Чтобы получить результат, вы можете использовать bmp.Assign(bmp1);.

Я вижу много перерисовки изображения в ImageList (рисуем в Bmp, рисуем в Bmp1, рисуем ACanvas). После первого преобразования прозрачность информации теряется. Поэтому в этот момент необходимо изменить цвет фона.

s := (Sender as TStringGrid).Cells [aCol, ARow];
// Draw ImageX.Picture.Bitmap in all Rows in Col 1
aCanvas := (Sender as TStringGrid).Canvas;
// Clear current cell rect
aCanvas.FillRect(Rect);
// Draw the image in the cell
n := strtoInt (s);

//new lines
bmp.Canvas.Brush.Color := clRed;
bmp.Canvas.FillRect(TRect.Create(0, 0, ImageList1.Width, ImageList1.Height));
//new lines
ImageList1.GetBitmap(n, Bmp);

//deleted lines
//FillBkgd (bmp,clRed); //stringgrid.color

aCanvas.StretchDraw(Rect,bmp);

И не забудьте заполнить finally, чтобы освободить bmp.

...