• 0
PFC

TCanvas Как правильно рисовать на канве?

Вопрос

Исходно пытался нарисовать битмап на канве формы. Затем пытался нарисовать хоть что-нибудь. Все время получаю пустой экран. При этом аналогично ничего не получается и с TImage и с PaintBox. Проект на С++, Embarcadero XE7. Что я делаю не так?

SolverMXE7.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

20 ответов на этот вопрос

  • 0

В FireMonkey в отличии от VCL нельзя рисовать на канве формы в произвольном месте. Рисование должно выполняться в отведенных местах: OnPaint, Paint, Painting

Всю отрисовку на канве формы нужно выполнять в событии OnPaint.

 

В вашем случае, вам нужно рисовать в TForm.OnPaint. А в событии таймера выполнять вызов Repaint.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Спсибо за ответ. Через OnPaint действительно работает. Однако у меня пиявилось еще несколько вопросов:

 

  1. В интернете много примеров, когда рисование все же идет по нажатию кнопки. Вот например: http://docwiki.embarcadero.com/CodeExamples/XE6/en/FMXTCanvasDrawFunctions_(Delphi) (этот примечателен еще и тем, что он от самой Embarcadero) Я вижу что он для XE6, в XE7 что-то изменилось (я уже заметил, что BitmapChanged стал приватным) ? Возможно ли как-то обойти ограничение на рисование только в OnPaint?
  2. У TImage и PaintBox действительно есть метод Repaint, а вот у  формы такого метода нет. Что лучше использовать если я таки хочу рисовать на форме?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

На счет примера на DocWiki. Обратите внимание, что там идет отрисовка на канве TBitmap, а не на канве формы. На канве TBItmap можно рисовать из любого места. Главное помнить, что процесс рисования на канве в FireMonkey имеет три фазы:

  1. BeginScene - начало отрисовки
  2. Любая отрисовка на TCanvas
  3. EndScene - окончание рисования.

На счет формы, вместо Repaint у формы есть метод Invalidate.

Чтобы выполнить отрисовку в любом другом месте, можно сделать дополнительный буфер в виде TBitmap. И выполнять в любом месте отрисовку там. А в OnPaint у формы просто выводить сформированное изображение из TBitmap.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Спасибо. Ну и последний вопрос. А можно как-то отключить очистку канвы? Т.е. чтобы OnPaint рисовал новую картинку поверх старой.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Отключить нет. Форма сама определяет при помощи контролов, какие области формы нужно перерисовать. Поэтому, если нужно добиться такого эффекта, то лучше использовать опять же временный буфер. И в нем делать наложение своей картинки на старую.

Kitty понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

пытаюсь в приложении для Android просто вывести хоть какое-то изображение, но ничего не выходит. Делаю так в событии формы OnPaint:

 

      if Canvas.BeginScene then
      try
      Canvas.DrawLine(form1.ClientRect.TopLeft,form1.ClientRect.BottomRight,1);
      Canvas.DrawEllipse(Rectf(0,0,50,50),1);
      finally
      Canvas.EndScene;
      end;

 

Но выходит просто черный экран и все. Если убрать прорисовку эллипса, то риуется просто белый екран. Вообще для игры нужно вывести битмап на форму, но даже такие примитивы не выходит вывести. не могу понять почему? Больше никакого кода в проекте нет.

 

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

 

И еще вопрос. Вы ранее написали, что

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

И еще вопрос. Вы ранее написали, что можно в таймере вызывать Repaint; Но такого свойства в форме нет и в ее канве, по крайней мере RadStudio XE6 не предлагает такого варианта.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Добрый вечер,

  1. В обработчике события OnPaint не нужно вызывать BeginUpdate/EndUpdate.
  2. Вместо Repaint у формы есть Invalidate.
Kitty понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Добрый день!

Есть такая ситуация, если рисовать часто в цикле и большое изображение например на Timage, например так

 

ImageDraw.Bitmap.Canvas.BeginScene();
ImageDraw.Bitmap.Canvas.DrawBitmap(ASourceBmp,
rctCurSource,rctDest, 1);
ImageDraw.Bitmap.Canvas.EndScene();

 

То появляется эффект задержки, т.е цикл идет дальше а изображение меняется с задержкой, если цикл остановить то картинка продолжает менятся еще раз 10... Пробовал убрать прорисовку в OnPaint и вызывать событие по таймеру, но кажется эффект тотже. Пробовал рисовать на PaintBox но кажется тоже самое...

 

Сталкивался ли кто с таким? с чем это связано? Как можно рисовать напрямую, т.е рисуешь и событие отображается на экране в этот же момент...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

все верно

закончится цикл, программа исполнит рисование. 

пока программа исполняет цикл, кто будет перерисовывать экран ??

В VCL можно было вызывать в цикле Repaint для этого, тут вроде UpdateRect есть.

тут нужно в отдельном потоке готовить картинки для рисования и говорить форме Invalidate, а в OnPaint очевидно эти картинки выводить на форму

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

 

тут нужно в отдельном потоке готовить картинки для рисования и говорить форме Invalidate, а в OnPaint очевидно эти картинки выводить на форму

В общем я это понимаю, но когда работа ведется в отдельном потоке что бы что то подготовить на bmp приходится вызывать метод Synchronize, т.е он выполняется в главном потоке как я понимаю, т.е в этом же потоке в методе Synchronize я и пытаюсь рисовать на TImage.Bitmap , что достаточно удобно. Но есть проблемы первое это при активном рисование , проще говоря в цикле, похоже как возникает запаздывание прорисовки, хотя может это моя ошибка в коде...(так как там идет передача данных по сети) и вторая проблема это иногда приложение вылетает, просто без ошибки без ничего процесс в Андроиде завершается. Вот и хотел спросить у более опытных что делать.  Хотел рисовать в OnPaint но появляется какое то мерцание , поэтому рисование на битмап гораздо лучше на вид...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

В общем немного разолбрался дело не в прорисовке а в сети, тут в FMX есть какой то буфер, т.е если не вызывать метод ReadStraem какое то время, то в системе все данные накапливаются в какойто буфер, потом чтение идет из него... причем явно есть какое то граничение на размер этих данных после чего из сети данные перестают читаться и все работает как в Винде. Флаг UseNagle я отключил сразу.

Может кто с таким сталкивался? как его отключить или уменьшить

 

2 да и вторая проблема осталась, программа почему то иногда при просировке зависает или вообще вылетает непонятно

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Помогите разобраться. сделал как вы советовали, разместил отрисовку на Canvas в событии OnPaint главной формы. Для Винды все рисует нормально, а вот для Андроида пустой экран

Код

procedure TForm6.FormPaint(Sender: TObject; Canvas: TCanvas;
  const ARect: TRectF);
  var
  R: TRectF;
begin
 r:= TRectF.Create(20,20,200,200);
 Canvas.BeginScene;
 Canvas.Stroke.Color:= TAlphaColorRec.Black;
 Canvas.DrawEllipse(R,1);
 Canvas.EndScene;
end;
 
Что я сделал не так?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

на сколько помню нужно плясать от координат ARect

Попробовал вместо R подставить  ARect. Результат тот же: в Винде элипс на весь экран, а на телефоне - пусто

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Почему на мобильных платформах у меня не рисуется окружность?

Изменено пользователем Andrey Efimov
Исправил ссылку
Egorka64 понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Спасибо большое, вроде нарисовалось.

Судя по вашим ответам, вы большой спец в этой области. не могли бы посоветовать хорошую книгу или другие источники по программированию для андроид на последних Делфи. А то приходится тыкаться как слепой котенок (Делфи 7, на котором раньше программировал, сильно отличается от ХЕ8)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

 

Спасибо большое, вроде нарисовалось.

Судя по вашим ответам, вы большой спец в этой области. не могли бы посоветовать хорошую книгу или другие источники по программированию для андроид на последних Делфи. А то приходится тыкаться как слепой котенок (Делфи 7, на котором раньше программировал, сильно отличается от ХЕ8)

 

спец) он один из разработчиков Firemonkey

Изменено пользователем ZuBy
zairkz понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

 

 

Спасибо большое, вроде нарисовалось.

Судя по вашим ответам, вы большой спец в этой области. не могли бы посоветовать хорошую книгу или другие источники по программированию для андроид на последних Делфи. А то приходится тыкаться как слепой котенок (Делфи 7, на котором раньше программировал, сильно отличается от ХЕ8)

 

спец) он один из разработчиков Firemonkey

 

ну тогда особое уважение: работать и находить время на общение со слепыми котятами типа меня - это ж какая сила воли нужна

Mazzay понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!


Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.


Войти сейчас

  • Похожие публикации

    • Автор: Роман Фил
      Привет ребят, созрел такой вопрос который меня мучает ! Вобщем пытаюсь загрузить картинку по прямой слыке с сервера. Картинка не грузится, не сохраняется не отображается. 
      Конечная платформа - Андроид. Пишу на Delphi xe 10 seatle.
      Что я делаю? при нажатии на сам компонент TImage (созданный динамически), должна грузится картинка по адресу преждевременно записанное в hint (TImage) при создании вида (http://блаблабла.jpg)
      Раньше код ниже работал сейчас нет не пойму что не так. Почему стал ковырять? потому что форма встает колом при загрузке изображений.
       
      var s: string; fs: TFileStream; begin fs := TFileStream.Create(tpath.Combine(tpath.GetDownloadsPath, 'load.jpg'), fmCreate); NetHTTPClient1.Get((Sender as TImage).Hint, fs); fs.Free; (Sender as TImage).MultiResBitmap.Bitmaps[1].LoadFromFile (tpath.Combine(tpath.GetDownloadsPath, 'load.jpg')); подключал еще pas нашел на этом форуме FMX.Features.Bitmap.Helpers.pas
      (Sender as TImage).MultiResBitmap.Bitmaps[1].LoadFromUrl ((Sender as TImage).Hint); как проще сделать посоветуете чтоб и грузилось и форма не висла?
    • Автор: Anasazi
      Всем доброго времени суток. Возникла необходимость решить такую задачу: в таблице базы MySQL хранится список изображений и их URL. Необходимо получить этот список массивом. Затем загрузить изображения и поочередно с интервалом показать их в TImage.
      Понимаю, что получить список изображений правильнее при помощи PHP скрипта, но в каком виде скрип должен вернуть данные, чтобы в Delphi получить из них массив не знаю.
      Раньше для получения изображений использовал такую процедуру. Но вопрос, где хранить изображения перед демонстрацией их в TImage? Создавать несколько MemoryStream?
      procedure LoadWebImage(url: string; image: TBitmap);
      var
        idhttp : TNetHTTPClient;
        ms : TMemoryStream;
      begin
       IdHTTP := TNetHTTPClient.Create(nil);
        ms := TMemoryStream.Create;
        try
          idhttp.Get(url, ms);
          ms.Position := 0;
          image.LoadFromStream(ms);
        finally
          ms.Free;
          idhttp.Free;
        end;
      end;
    • Автор: denprox
      Доброго времени суток! Подскажите, как узнать оригинальный размер картинки, загруженной в TImage ?
    • Автор: Vizit0r
      Delphi Seattle, Android 5.0.1
      Формирую картинку через ScanLine. На выходе полученный битмап рисуется на полотне TImage, на котором перед этим был нарисован Rect.
      GlobalBitmap - формированный tbitmap.
                 with ObjectPreviewImage.Bitmap.Canvas do             begin               BeginScene;               Clear(TAlphaColorRec.White);               DRect := TRectF.Create(0, 0, GlobalBitmap.Width + 8, GlobalBitmap.Height + 8);               DrawRect(DRect, 0, 0, AllCorners,                        StealthForm.ObjectPreviewImage.AbsoluteOpacity);               DRect := TRectF.Create(0, 0, GlobalBitmap.Width, GlobalBitmap.Height);               DrawBitmap(GlobalBitmap,DRect,                  TRectF.Create(2, 2, GlobalBitmap.Width + 2, GlobalBitmap.Height + 2), 1);               EndScene;             end;  
      Проблема собственно в чем - в андроидной версии слева и внизу рамка "съедается". В Win32 версии все отлично. На прилагаемых скриншотах это четко видно.
      Документацию читал, гугл гуглил.
       
      Что я делаю не так? Или это неизвестные подводные камни андроидного рисования на полотне?
       
      P.S. Картинка одинаковая, цвет к определенной области применяется не верно. Походу тоже андроидные приколы. Но с этим я уже разберусь.
      P.P.S. Уже разобрался с цветом - под андроидом Blue и Red в пикселе надо поменять местами. А насчет канвы - не получается никак.
      P

    • Автор: Error
      *** Небольшой обмен опытом ***
      Вижу что вопросы о размере текста довольно частые, поделюсь своими наработками.
      function CalcTextSize(Text: string; Font: TFont; Size: Single = 0): TSizeF;
      Функция для расчета размера прямоугольника, занимаемого однострочным текстом.
      Параметры:
      Text - Текст Font - Шрифт с которым будет выводиться текст Size - если 0, то Font.Size будет использоваться из Font, иначе из данного параметра Исходный код:
      uses System.Types, FMX.Types, FMX.Graphics, FMX.TextLayout, System.Math, System.SysUtils; function CalcTextSize(Text: string; Font: TFont; Size: Single = 0): TSizeF; var TextLayout: TTextLayout; begin TextLayout := TTextLayoutManager.DefaultTextLayout.Create; try TextLayout.BeginUpdate; try TextLayout.Text := Text; TextLayout.MaxSize := TPointF.Create(9999, 9999); TextLayout.Font.Assign(Font); if not SameValue(0, Size) then begin TextLayout.Font.Size := Size; end; TextLayout.WordWrap := False; TextLayout.Trimming := TTextTrimming.None; TextLayout.HorizontalAlign := TTextAlign.Leading; TextLayout.VerticalAlign := TTextAlign.Leading; finally TextLayout.EndUpdate; end; Result.Width := TextLayout.Width; Result.Height := TextLayout.Height; finally TextLayout.Free; end; end;   function FontSizeForBox(Text: string; Font: TFont; Width, Height: Single; MaxFontSize: Single = cMaxFontSize): Integer;
      Функция возвращающая максимально возможный размер шрифта, для текста вписанного в заданный прямоугольник.
      Параметры:
      Text - Текст Font - Шрифт с которым будет выводиться текст Width, Height - Ширина и высота прямоугольника MaxFontSize - Максимально возможный размер шрифта Исходный код:
      uses System.Types, FMX.Types, FMX.Graphics, FMX.TextLayout, System.Math, System.SysUtils; const cMaxFontSize = 512; function FontSizeForBox(Text: string; Font: TFont; Width, Height: Single; MaxFontSize: Single = cMaxFontSize): Integer; var Size, Max, Min, MaxIterations: Integer; Current: TSizeF; begin Max := Trunc(MaxFontSize); Min := 0; MaxIterations := 20; repeat Size := (Max + Min) div 2; Current := CalcTextSize(Text, Font, Size); if ((Abs(Width - Current.Width) < 1) and (Width >= Current.Width)) and ((Abs(Height - Current.Height) < 1) and (Height >= Current.Height)) then break else if (Width < Current.Width) or (Height < Current.Height) then Max := Size else Min := Size; Dec(MaxIterations); until MaxIterations = 0; Result := Size; end; ---
      Также данные функции можно найти в этом юните
    • Автор: Satellite
      Возможно ли вывести 9-patch в Timage? Если нет, то куда можно импортировать изображение такого формата? 
    • Автор: AlexG
      Возник следующий вопрос:
      Допустим есть "сложная" форма, внешний вид которой должен быть нестандартным и на которой расположено N-ное количество компонент (исходим из того, что их много, некоторые из них - динамические, например - вывод видео с камеры).
      "Нестандартный вид" подразумевает: наличие тени у формы, измененный внешний вид, отличный от вида по умолчанию в любой ОС.
      Непосредственно вопрос звучит так.
      Какая из двух следующих реализаций будет работать быстрее (отрисовка/обновление этой формы при обновлении компонент: текста, списков, вывод видео и т.д.):
      Оба вида форм предопределяются в стиле.
      ВАРИАНТ 1.
      - Тень формы реализована в виде компонента TImage с подгруженным PNG изображением.
      - Контур формы реализован компонентом TRectangle с "окантовкой" и заливкой прямоугольника заданным цветом (все без градиентов)
      - Шапка формы реализована вторым прямоугольником TRectangle без "окантовки", но с заливкой другим цветом (без градиента)
      ВАРИАНТ 2. Вся форма задана одним объектом TStyleObject в котором в качестве свойств установлены:
      - SourceLookup - ссылка на PNG-изображение в данном стиле
      - SourceLink - создан TBitmapLink, у которого заданы свойства CapInsets и SourceRect
      Внешний вид у них будет практически одинаковый (хотя во втором случае он будет более корректным на любой ОС и при использовании любой видео-карты, чего не скажешь о первом варианте).
      Однако, интересует именно СКОРОСТЬ отрисовки в обеих случаях!
      Интересует именно теория, с точки зрения реализации самой FMX.
      З.Ы. Предполагаю, что вопрос больше к разработчикам FMX, но возможно у кого-то уже есть опыт работы с подобными задачами...
    • Автор: umkes
      Добрый день, возникла проблема при работе с TImage;
      У меня компонент TImage - imgRing и есть в TImageList. 
      Я динамически формирую Bitmap из копий картинки из TImageList и асайню его в TImage. На Windows все работает прекрасно, а на андроиде картинка все время пустая... Может кто-то подскажет, где я не прав
      //============================================================================== procedure TMainForm.DrawRing; //------------------------------------------------------------------------------ var bmp1, bmp2 : TBitmap; i : integer; str : TMemoryStream; begin bmp2 := TBitmap.Create; bmp2.Assign(ImageList.Source.Items[3].MultiResBitmap.Items[0].Bitmap); bmp1 := TBitmap.Create; bmp1.Assign(bmp2); bmp1.Width := ClientWidth + bmp2.Width * 10; i := 0; bmp1.Canvas.BeginScene(); while (i * bmp2.Width) < bmp1.Width do begin bmp1.Canvas.DrawBitmap(bmp2, RectF(0, 0, bmp2.Width, bmp2.Height), RectF(i * bmp2.Width, 0, (i + 1) * bmp2.Width, bmp2.Height), 1 ); inc(i); end{ while }; bmp1.Canvas.EndScene; str := TMemoryStream.Create; bmp1.SaveToStream(str); str.Position := 0; imgRing.BeginUpdate; imgRing.Bitmap.CreateFromStream(str); imgRing.EndUpdate; end{ procedure TMainForm.DrawRings }; Делаю такое потому-что TImage.WrapMode.Tile не подходит для моей задачи.
    • Автор: Евгений Корепов
      На незначительном количестве устройств, менее 0,1%, получаю ошибку "Bitmap size too big" при AImage.Bitmap.LoadFromStream(AMemoryStream). Подозреваю что ошибка происходит на слабых устройствах. Картинка 250х250 png. Код выполняется в основном потоке (в интернетах были упоминания что глючит эта операция в отдельном потоке на каких то версиях Delphi).
      Как предотвратить подобное? Можно как то определить максимальный размер картинки для текущего устройства? Или может дело не в свободной памяти, а в чем то еще?
    • Автор: kuldiegor
      Всем доброго времени суток! Обнаружил проблему, связанную с загрузкой изображения в TImage.
      Если загружать изображения с хард диска очень быстро, то как будто TImage не поспевает и вываливает access violation. Delphi xe7 Fire Monkey 64 bit Windows.
      val:=round(360*value/max); //узнаём какова часть байт в градусах improgressbar.Bitmap.LoadFromFile(ExtractFilePath(paramstr(0))+'Pictures\ProgressBar\'+inttostr(val)+'.png');  labprogressbar.Text:=strtool.intbytetostr(value,1)+'Б'+#$D#$A+'/'+#$D#$A+strtool.intbytetostr(max,1)+'Б'; Application.ProcessMessages; 
  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу