• 0
Maka

Нарисовать TСontrol без вывода на экран

Вопросы

Ситуация такая. Я хочу отобразит некий фрейм с кучей компонентов с использованием плавного проявления (анимация свойства Opacity)

Если анимировать на прямую, то объекты фрейма проявляются не равномерно, и вообще выглядит не красиво.

Выход: Сделать скриншот фрейма, плавно и красиво его показать, потом скрыть и на его место поместить целевой фрейм.

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

Пробовал делать MakeScreenshot в событии onPaint фрейма, и там же его скрыть сразу. Действует, но периодически получается моргание, из-за того, что фрейм все же на долю секунды появляется на экране.

Пробовал делать Repaint рекурсивно для фрейма и всех дочерних элементов перед снятием скриншота:

  procedure Repchild(aCtr: TControl);
  var
    xA: SmallInt;
  begin
    aCtr.Repaint;
    for xA := 0 to aCtr.ChildrenCount - 1 do if aCtr.Children[xA] is TControl then Repchild(Tcontrol(aCtr.Children[xA]));    
  end;

без результатно.

Подскажите, как отрисовать TContro без вывода на экран?

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


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

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

  • 0

Хороший вопрос. Отрисовка в FMX это весьма хитрая штука.

Как вариант (кривой если честно, тем не менее) - отображайте TControl вне границ экрана, тогда и MakeScreenshot корректно отработает, и мерцать на экране не будет.

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


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

и еще костыль.... подготовьте заранее картинку экрана...ее и проявляйте медленно...

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
2 минуты назад, #WAMACO сказал:

и еще костыль.... подготовьте заранее картинку экрана...ее и проявляйте медленно...

так и делаю, и вопрос в том и заключается, как ее правильно заранее подготовить

Изменено пользователем Maka

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
8 минут назад, Maka сказал:

так и делаю, и вопрос в том и заключается, как ее правильно заранее подготовить

ну так первый раз вывести "честно", снять скриншот, записать в ресурсы, распространять вместе с программой и данный скрин и проявлять медленно...

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
59 минут назад, Tumaso сказал:

Как вариант (кривой если честно, тем не менее) - отображайте TControl вне границ экрана, тогда и MakeScreenshot корректно отработает, и мерцать на экране не будет.

Возможно так и придется поступить

39 минут назад, #WAMACO сказал:

ну так первый раз вывести "честно", снять скриншот, записать в ресурсы, распространять вместе с программой и данный скрин и проявлять медленно...

Нет, не пойдет, т.к. содержимое выводимых контролов постоянно меняется, и будет чехорда из "красивых" и "некрасивых" вариантов вывода

 

40 минут назад, dnekrasov сказал:

А чем PaintTo не устраивает?

Вот, видоизменил код Ярослава Бровина для сохранения скриншота:

procedure ActionMakeScreenshotExecute(aCtr: TControl);
  var
    BitmapBuffer: TBitmap;
    SourceRect: TRectF;
  begin
    aCtr.Visible := True;
    aCtr.BringToFront;
    aCtr.Opacity := 1;
    // Фиксируем размер снимаемой области
    SourceRect := TRectF.Create(0, 0, aCtr.Width, aCtr.Height);
    // Создаем временный буфер для получения скриншота
    BitmapBuffer := TBitmap.Create(Round(SourceRect.Width), Round(SourceRect.Height));
    try
      // Переводим канву в режим отрисовки - начинаем процесс отрисовки сцены
      if BitmapBuffer.Canvas.BeginScene then
        try
          // Говорим контролу отрисовать себя в канве нашего буфера в указанной области
          aCtr.PaintTo(BitmapBuffer.Canvas, SourceRect);
        finally
          // Завершаем процесс отрисовки, заканчивая формируемую сцену
          BitmapBuffer.Canvas.EndScene;
        end;
      BitmapBuffer.SaveToFile(DateDir + 'screenshot1.png');
    finally
      FreeAndNil(BitmapBuffer);
    end;
  end;

И если мы сюда отправим еще не отрисованный контрол, то получим пустой скриншот, а последующие вызовы будут сохранять не текущее, а последнее нарисованное состояние контрола.

Или есть другой способ воспользоваться PaintTo?

Изменено пользователем Maka

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
2 часа назад, Tumaso сказал:

Как вариант (кривой если честно, тем не менее) - отображайте TControl вне границ экрана, тогда и MakeScreenshot корректно отработает, и мерцать на экране не будет.

По поводу корректности MakeScreenshot в данном сценарии  - это предположение, или личный опыт?

У меня получается так:

Отображаю нужный контрол за пределами экрана, отлавливаю OnPaint контрола, и в нем делаю MakeScreenshot.

В результате какие-то элементы попадают на скриншот (например TCharts, TRectangle, ), а какие-то нет (например кнопки, эдиты).  Эффект тени от кнопки попадает, а сама кнопка нет..  И прочие чудеса.

 

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
16 часов назад, dnekrasov сказал:

А чем PaintTo не устраивает?

И кстати. В реализации MakeScreenshot уже присутствует PaintTo

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


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

Быть может это натолкнет более опытных товарищей на какую-нибудь идею, решающую проблему:

Удалось понять, что на скриншот не попадают элементы, для которых доступна работа со стилями, и прекрасно перерисовываются элементы без стилей (Effects, Shapes)

 

Изменено пользователем Maka

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
16 минут назад, Maka сказал:

на скриншот не попадают элементы, для которых доступна работа со стилями

Попробуйте перед снятием скриншота насильно применять стиль всех для элементов.
Вызывайте для каждого контрола процедуру ApplyStyleLookup();

Изменено пользователем Barbanel

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


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

После присвоения Parent Вашему фрейму сделайте Application.ProcessMessages. Тогда MakeScreenshot должен заработать без проблем.

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
19 минут назад, Barbanel сказал:

Попробуйте перед снятием скриншота насильно применять стиль всех для элементов.
Вызывайте для каждого контрола процедуру ApplyStyleLookup();

Да, это помогло. Спасибо!

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

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

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу