Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > GDI+, Direct2D, firemonkey и все все все


Автор: gonzales 29.5.2013, 16:56
Доброго времени суток, уважаемые форумчане!
Вопрос выбора технологии для отрисовки 2D графики. 
Необходимые функции
1. отрисовка растров с прозрачностью
2. возможность работы в альфаканалом: использовать для изображения альфаканал из стороннего файла
3. антиалайсинг
4. слои
5. поддержка windows xp

Сейчас проект реализован на GDI+, но все работает достаточно медлено. Например пересчет изображения с учетом полупрозрачной маски уменьшает производительность с 94 до 43 fps, но это полбеды. Эта отрисовка происходит во внутренний буфер, а когда я делаю repain, то есть вывожу содержимое буфера на экран, fps падает до 7-10, а это уже очень критично. 

Вопросов собственно несколько, может кто-то сталкивался.
1. можно ли выводить битмап на канву быстрее чем 
Код

graphicsGDIPlus := TGPGraphics.Create(canvas.Handle);
 graphicsGDIPlus.DrawImage(bmpcrop, TGPRectf.Create(r1.X, r1.Y, bmpcrop.GetWidth, bmpcrop.GetHeight),
            // destination rectangle
            0, 0, // upper-left corner of source rectangle
            bmpcrop.GetWidth, // width of source rectangle
            bmpcrop.GetHeight, // height of source rectangle
            UnitPixel, ImageAttributes);
repaint;


2. Можно ли каким-то образом прикрутить к GDI+ аппаратную акселерацию.

3. Можно ли использовать D2D для вывода, а GDI+ для обработки изображения одновременно

В общем, задача несколько размыта, надеюсь на Ваши мысли
Заранее спасибо

Автор: Beltar 29.5.2013, 17:54
GLScene, Asphyre Sphinx или иной движок. Сфинкс поддерживает даже DX11, а я на нем недавно вариацию Lines сделал, на полностью заполненном поле из 240 клеток с 4-хцетными градиентными шарами у меня 200+ fps тянуло, но на днях автор объявил о закрытии проекта, ссылаясь на занятость, так что неясно что с ним будет. :( D2D под XP не работает. Вообще.
Слои, я так понимаю, та же прозрачность? В Corel Photo Paint, например, такого понятия как слой вообще нет, есть просто объекты, которыые от фотошоповых слоев неотличимы.

Автор: gonzales 29.5.2013, 21:33
спасибо, покопаюсь.
а есть ли какая инфа по d2d? я так понял, что firemonkey приложения по умолчанию d2d используют.

Добавлено @ 21:43
еще вопросик, по сфинксу можете что-нибудь посоветовать, литературу, примеры
заранее спасибо
кстати, написанные приложения работают на xp?

Автор: Beltar 29.5.2013, 22:45
D2D это DirectX. Fire Monkey принципиально OpenGL иначе никакой кроссплатформенности не будет. Литература есть по DirectX, гугл решает.

По сфинксу литературы я не видел. Однако там сами исходники очень грамотно написаны и откомментированы. В простейшем случае просто берешь какой-нибудь из примеров, идущих с ним, выкидываешь, оттуда рисовку, загружаешь свои ресурсы (помимо графики он поддерживает создание упакованных ресурных и сеть) и просто вызываешь в ProcessEvent свою обработку логики, а в RenderEvent свою отрисовку. Таймер с синхронизацией там уже готовый. Если игровой подход, когда игра просто шпарит кадры насколько может, периодически вызывая обсчет логики не устраивает, то можно предельный fps ограничить и в принципе я так понимаю, просто отключить таймер и вызывать рисовку, как в GDI Refresh. Само 2D-рисование в принципе такое же, как в GDI, даже в чем-то проще, т. к. не надо 100500 свойств у канваса задавать и всякие буферные битмепы юзать, базовые примитивы есть, только есть тонкости, связанные со сбросом кеша рендеринга и просадкой fps. По крайней мере, это то, что я в простейшем 2D проекте заметил.

По GLScene ничего не скажу, но у нее есть русскоязычное сообщество.

Автор: Alexeis 30.5.2013, 08:49
Цитата(gonzales @  29.5.2013,  17:56 Найти цитируемый пост)
3. Можно ли использовать D2D для вывода, а GDI+ для обработки изображения одновременно

  D2D это будет Windows Vista+ . В XP эта технология не поддерживается официально.

Цитата(gonzales @  29.5.2013,  17:56 Найти цитируемый пост)
2. Можно ли каким-то образом прикрутить к GDI+ аппаратную акселерацию.

  Она и так там есть, как и в GDI, другое дело, какой уровень оптимизации. 

 Можно и на OpenGL сделать такой вывод, но там удобных средств нет, придется поизучать хорошо и своих преобразований чуток сделать. Зато OpenGL позволит рисовать на векторном контексте с гибким масштабированием. Но вообще и у OpenGL работа с растрами не на высоком уровне. 

Автор: gonzales 30.5.2013, 11:15
Beltar, спасибо!!!
буду пробывать


Alexeis, я писал в топике про просадку фпс при вызове repaint. Какая оптимизация еще может быть?
вот что пишут официально про d2d
Цитата

Direct2D is a hardware-accelerated, immediate-mode 2-D graphics API that provides high performance and high-quality rendering for 2-D geometry, bitmaps, and text. The Direct2D API is designed to interoperate with existing code that uses GDI, GDI+, or Direct3D.

то есть получается, что на вин7 автоматически уже используют новую систему рендеринга Direct2D, или же это надо дополнительно подключать в самом приложении и выводить уже явно через Direct2D. К сожалению такой инфы я не нашел

Автор: Beltar 30.5.2013, 12:39
Мне года 3 назад советовали GDI+. Я попробовал, оказалось, что даже медленнее, чем GDI, по крайней мере на моей задаче. DirectX и, насколько я понимаю, OpenGL напрямую для 2D-графики использовать попахивает мазохизмом, т. к. они работают с вершинами и треугольниками, а базовых примитивов для 2D-графики там нет. Т. е. или сам их делай, или юзай готовый движок.

Я так понимаю, что D2D и есть такой движок, работал бы на XP, думаю, никто бы уже на GDI не писал.

Цитата

я писал в топике про просадку фпс при вызове repaint. Какая оптимизация еще может быть?


В случае Repaint ИМХО некорректно говорить об fps. Оно ведь рисуется 1 раз и потом может не перерисовываться сколь-угодно долго. Например, ты перетащишь форму, она не будет перерисована. Касательно тормозов и оптимизаций, то можно было код привести, что оптимизировать наверняка найдется.

Цитата

то есть получается, что на вин7 автоматически уже используют новую систему рендеринга Direct2D, или же это надо дополнительно подключать в самом приложении и выводить уже явно через Direct2D. К сожалению такой инфы я не нашел


Если приложение написано в эпоху Win9X и ничего кроме GDI не знает, то и юзать оно будет только GDI. От семерки тут ничего не зависит, она рисует каждое приложение так, как приложение запрашивает.

Автор: Alexeis 30.5.2013, 13:27
Цитата(gonzales @  30.5.2013,  12:15 Найти цитируемый пост)
Alexeis, я писал в топике про просадку фпс при вызове repaint. Какая оптимизация еще может быть?
вот что пишут официально про d2d

  Драйвера видео могут оптимизировать операции с растрами даже при использовании GDI . Насколько я помню самая быстрая GDI функция для обновления SetDIBitsToDevice . 

Автор: gonzales 30.5.2013, 14:31
Beltar, пробую юзать сфикса. с подгрузкой растров из файлов я разобрался, а вот со шрифтами какая-то лажа. Сфинкс позволяет юзать системные шрифты или только с подгрузкой имиджей из своего архива?

Цитата

В случае Repaint ИМХО некорректно говорить об fps. Оно ведь рисуется 1 раз и потом может не перерисовываться сколь-угодно долго. Например, ты перетащишь форму, она не будет перерисована. Касательно тормозов и оптимизаций, то можно было код привести, что оптимизировать наверняка найдется.

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


Alexeis, спасибо за наводку, буду пробывать.

Автор: Beltar 30.5.2013, 15:14
Я так понял, что использует пререндеренные, утилита для их создания прилагается. Меня для игры вполне устроил шрифт из примера Shapes. Обычные я не пробовал.

Цитата

перерисовка произходит по mousemove с изменением параметров, поэтому приходится перерисовывать многократно.


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

Автор: gonzales 30.5.2013, 17:03
Цитата

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


так тоже пробывал, создаю битмеп, на нем отрисовываю, потом копирую на canvas. Но все равно приходится вызывать repaint, иначе не перерисовывается. Может это из-за doublebuffer:=true? Или из-за того, что отрисовка происходит не в onPaint?
Код

  bufbtm:=TBitmap.Create;
  bufbtm.Width:=width;
  bufbtm.Height:=height;
  graphicsGDIPlus := TGPGraphics.Create(bufbtm.canvas.Handle);

//отрисовка на канве битмэпа

  bitblt(canvas.Handle,0,0,width,height,bufbtm.Canvas.Handle,0,0,SrcCopy);
  bufbtm.Free;
  repaint;




Автор: Beltar 30.5.2013, 17:15
Я уже не помню, когда рисовал сразу по форме или чему-то еще, обычно делал свой контрол и у него просто перекрывал Paint. Repaint руками по идее вызывать не нужно, она сама вызывается при, например, Refresh.

Автор: Alexeis 30.5.2013, 18:15
Цитата(gonzales @  30.5.2013,  18:03 Найти цитируемый пост)
 Но все равно приходится вызывать repaint, иначе не перерисовывается. Может это из-за doublebuffer:=true? Или из-за того, что отрисовка происходит не в onPaint?

  Вполне вероятно. Лучше, если указать винде, что кусок области стал невалидным при помощи функции InvalidateRect , при этом желательно отключить очистку фона у окна. После вызова InvalidateRect винда сама вызовет OnPaint . Далее при помощи BeginPaint в обработчике OnPaint мы можем узнать какой же прямоугольник требует обновления и обновить только его. 

Автор: gonzales 30.5.2013, 21:37
Цитата

Я уже не помню, когда рисовал сразу по форме или чему-то еще, обычно делал свой контрол и у него просто перекрывал Paint. Repaint руками по идее вызывать не нужно, она сама вызывается при, например, Refresh.

конечно я тоже сделал свой)) наследник TImage. Но я не перекрывал paint а сделал свою процедуру DrawImage которую вызываю по MouseMove. Repaint или Refrash в данном случае значения не имеет. Подскажите, принципиально перекрывать Paint, есть какое-то кардинальное отличие от любой другой процедуры вызываемой  руками?
Как в таком случае должен выглядеть алгоритм перерисовки
OnMouseMove -> InvalidateRect -> OnPaint -> {отрисовка битмапа} -> SetDIBitsToDevice 

 
Цитата

Лучше, если указать винде, что кусок области стал невалидным при помощи функции InvalidateRect , при этом желательно отключить очистку фона у окна. После вызова InvalidateRect винда сама вызовет OnPaint

я правильно понимаю, что я должен вызвать InvalidateRect для всей области моего контрола и тем самым вызвать OnPaint?

Буду пробывать!

Кстати, SetDIBitsToDevice предполагает конвертацию из TBitmap в DIB, не даст ли это обратный эффект (ухудшения оптимизации)?

ЗЫ. Комрады, в любом случае спасибо, очень приятно обсуждать вопросы с нормальными людьми, ВинГрад один из немногих форумов, где можно получить реальную помощь  smile 

Автор: Beltar 30.5.2013, 23:43
Ну я примерно вот так делал. Проект на XE3, но там бэкапы файла проекта для 2007 и XE лежат, а сам компонент будет работать даже в D7, если все inline убрать.

Производительность довольно высокая. У меня на Core Duo 2.66 даже в Debug версии строит график по 10 сериям с 1 728 010 точками примерно за 0.3 сек. Это полная отрисовка с примерно 148000 вызовами LineTo для 1920х1080. А так можно возить по нему мышкой, подлагивает, но не сильно, если зона рисования меньше, то лага может и не быть. Первый вариант Lines на GDI с 240 клетками у меня без лага полностью перерисовывался по MouseMove. Ты что-то не так, похоже, делаешь.


Автор: Alexeis 31.5.2013, 10:38
Цитата(gonzales @  30.5.2013,  22:37 Найти цитируемый пост)
я правильно понимаю, что я должен вызвать InvalidateRect для всей области моего контрола и тем самым вызвать OnPaint?


  Неа, только для области под курсором. Если можно перерисовывать не все то желательно так и делать. 
Цитата(gonzales @  30.5.2013,  22:37 Найти цитируемый пост)
Кстати, SetDIBitsToDevice предполагает конвертацию из TBitmap в DIB, не даст ли это обратный эффект

  Эмм.. насколько я понимаю TBitmap это и есть DIB . По крайней мере TBitmap может быть DIB если ему установить PixelFormat . По идее, получается прямое рисование DIB на контекст безо всякого копирования.

Автор: gonzales 31.5.2013, 16:30
что то я совсем запутался, окончательно и бесповоротно((((((((
сделал я SetDIBitsToDevice все одно, пока repaint или refrash не вызову, изображение на экране не перерисовывается. 
перекрыл событие Paint для моего наследника TImage, написал банальное
Код

procedure TFrameImage.Paint;
begin
 inherited;
 showmessage('1');
end;

получаю 4 мессаджбокса, хотя процедура перерисовки DrawImage вызывалась 1 раз. Это может быть из-за того, что во время перерисовки на экране появляется вторая форма, частично закрывающая мой контрол?

Если я пишу 
Код

procedure TFrameImage.Paint;
begin
 inherited;
 DrawImage;
end;


то все навеки зависает.

Может я свойство какое у TImage не заполняю, что он так себя ведет?

Практически все реализовано как в примере AvgChart. Только там используется TCustomControl, а у меня TImage. 

убираю из функции DrawImage repaint и fps на уровне 50, но отрисовка идет не плавно а большими рывками, ставлю repaint, fps падает до 7 но отрисовка гораздо плавнее.(((




Автор: Beltar 31.5.2013, 20:04
Между TImage и TCustomControl есть одно отличие, TImage не имеет дескриптора. Я, правда, не помню сейчас, почему я использовал именно TCustomControl, а не TGraphicControl, но что-то меня там не устроило. В принципе есть еще и компонент TPaintBox, Но это тоже GraphicControl. Попробуй тоже TCustomControl заюзать.

Paint должен вызываться автоматически при любой перерисовке, разворачивание окна, закрытие его части и т. п. Я не вижу смысла вызывать методы перерисовки кроме Refresh вручную.

Как ты fps мерял? В играх средне fps измеряется из-за непрерывности цикла отрисовки, тут-то цикла нету.

Автор: gonzales 1.6.2013, 12:12
а у tcustomcontrol у меня возникли проблемы с прозрачным canvas. Изначально я и хотел сделать из TCustomControl контейнер, в который положить несколько TImage, которые будут как бы слоями с изображениями, но не смог добиться прозрачного фона. TImage уже предполагает работу с прозрачностью, поэтому я его и выбрал.
А fps меряю просто. Замеряю кол-во тактов в начале процедуры и в конце, делю на частоту процессора, получаю время работы процедуры. Ну а fps - это будет 1/время. Это конечно не средне-статистическое значение, но приблизительное представление оно дает, по крайней мере порядок величины.

Добавлено через 5 минут и 48 секунд
Цитата

Я не вижу смысла вызывать методы перерисовки кроме Refresh вручную.

как раз приходится вызывать вручную, чтобы избежать ненужных прорисовок объектов, когда из например частично перекрывают другие объекты. если я запихну процедуру отрисовки объекта в Paint то при любом перекрытии объекта он будет перерисован, хотя с ним никаких изменений не происводилось. 

Автор: Beltar 1.6.2013, 13:23
Как-то слишком сложно. Если у тебя там нет непрерывной анимации, то для замера времени будет достаточно GetTickCount. Можно Stopwatch, т. к. GetTickCount дает значения с шагом 16. Но если у тебя рисуется за 100 мс, то тебе и этой точности хватит для оценки лага. Если есть анимация, то лучше заюзать Сфинкса и не думать о таймерах, 2D-графику он тебе даже на нетбуке, скорее всего, вытащит. Избыточные вычисления, если на сотни fps шпарить будет, забирая ядро целиком можно подавить ограничением fps. Да и фотошопы вроде уже давно за счет аппаратной отрисовки живут.

Заблокировать отрисовку можно просто добавив какое-то условие в ф-ию отрисовки, или в Paint перед ее вызовом. Сам вызов Paint ты не можешь контролировать, если приложение свернули, а затем развернули, то Paint будет вызван. Но вот само условие блокировки рисовки будет весьма нетривиальным. У меня в AvgChart ручной вызов перерисовки делается только в том случае, если были изменены данные и то можно с помощью BeginUpdate перекрыть это дело.

Опиши лучше, что рисуешь и в каком порядке. Не исключено, что и саму Paint можно свести к тупому вызову BitBlt, или как она там на канвасе, Draw вроде, а сложную часть запоминать на битмепе и уже ее перерисовывать вручную, если, например, добавился объект, или был сделан ресайз контрола.

Автор: Alexeis 1.6.2013, 14:01
Цитата(gonzales @  31.5.2013,  17:30 Найти цитируемый пост)
Может я свойство какое у TImage не заполняю, что он так себя ведет?

  TImage лучше совсем не трогать по вопросам сообщений. Надежнее обращаться к окну которое лежит ниже. Я бы вообще не использовал TImage. Этот класс предназначен для статических изображений. Эффективнее выводить графику прям на окно. 

Автор: gonzales 3.6.2013, 13:22
заменил repaint на paint, отрисовка заработала на несколько порядков быстрей, НО Paint не стирает содержимое а рисует поверх. Как в перекрытом методе Paint заставить его стереть изображение?

Рисую графический фрейм для изображения. см рисунок.
создаю его на основе TImage. прописал функции mousedown, mousemove, mouseup и drawimage.

По событиям мыши производятся все координатные вычисления, затем вызывается drawimage.


Код

constructor TFrameImage.Create(aowner: Tcomponent); // конструктор
begin
inherited Create(aowner);
//создаю буферный битмап
  bufbtm:=TBitmap.Create;
  bufbtm.PixelFormat:=pf32bit;
  bufbtm.Width:=width;
  bufbtm.Height:=height;
end;

procedure TFrameImage.FrameImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
begin
//вычисляю в какую точку фрейма ткнул пользователь
//присваиваю флаг
mouseclickflag:= 
end;

procedure TFrameImage.FrameImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer);
begin
//вычисляю новую геометрию фрейма
DrawImage;
end;

procedure TFrameImage.FrameImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
begin
 mouseclickflag := clno;
 DrawImage(true, Fdpi_limit);
end;

procedure TFrameImage.DrawImage;
begin
//рисую на канве контрола или на канве буферного битмапа
graphicsGDIPlus := TGPGraphics.Create({bufbtm.}canvas.Handle);
//-----
//--функции отрисовки---
//-----
// далее необходимо обновить контрол, чтобы изображение из буфера видеокарты отобразилось на экране
Repaint; //---> просадка fps
Paint; //----> зависает
end;

procedure TFrameImage.Paint;
begin
 inherited;
 canvas.Draw(0,0,bufbtm);  //если рисую на канве буферного битмапа вывожу его на экран.
end;






Автор: gonzales 3.6.2013, 13:44
пробую внедрить флаг перерисовки, все равно канва не очищается
Код

procedure TFrameImage.Paint;
begin

 if paintflag=true then
  begin
 InValidateRect(Canvas.Handle,nil,true);
 Canvas.FillRect(Canvas.ClipRect);
 canvas.Draw(0,0,bufbtm);
 paintflag:=false;
  end;
 inherited;
end;

Автор: Beltar 3.6.2013, 14:37
А она и не будет очищаться, просто залей ее цветом фона перед рисованием.

Код

Paint; //----> зависает


Говорю же, Paint вызывается автоматически.

Должно быть

Код

procedure Paint;
begin
inherited;
DrawImage;
end;


Ты сейчас все запутываешь только. В DrawImage должно быть описано как рисовать, а не когда. Для этого программа сама когда нужно Paint вызовет.

Вот у тебя на картинке рамка, ты за нее явно тянешь. У тебя только рамка тянется или само изображение тут же перерисовывается? Если только рамка, то кто мешает хранить изображение на битмепе, перерисовывая только разметку, как у меня с графиком и делается?

Автор: gonzales 3.6.2013, 15:39
Код

Вот у тебя на картинке рамка, ты за нее явно тянешь. У тебя только рамка тянется или само изображение тут же перерисовывается? 

изображение тоже пееррисовывается.

Цитата

Ты сейчас все запутываешь только. В DrawImage должно быть описано как рисовать, а не когда.

Так у меня и описано. А когда перерисовывать решают события мыши. 

Я убрал явный вызов drawImage из событий мыши и написал
Код

procedure Paint;
begin
inherited;
DrawImage;
 Canvas.FillRect(Canvas.ClipRect);
 canvas.CopyRect(rect(0,0,width,height),bufbtm.Canvas,rect(0,0,width,height));
end;


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

Цитата

А она и не будет очищаться, просто залей ее цветом фона перед рисованием.

так я заливаю
Canvas.FillRect(Canvas.ClipRect);
и все равно не очищается.

Автор: gonzales 3.6.2013, 17:14
я не понимаю как у тебя в примере все работает
Код

procedure TAvgChart.Paint;
begin
  inherited;
Draw;  // рисование
end;

procedure TAvgChart.Draw;
var T:Cardinal;
begin
if BlockPaint then Exit;
DoBeforeReapint;
T:=GetTickCount;
DeltaX:=FMaxXValue-FMinXValue;//глобальный DeltaX, для ValueToPoint
DrawZoneX:=Width-LeftBorder-RightBorder;
DrawZoneY:=Height-TopBorder-BottomBorder;
DrawTrends;
FastRepaint;//Дорисовка
FDrawTime:=GetTickCount-T;
DoAfterRepaint;
end;

procedure TAvgChart.FastRepaint;
begin
if BlockPaint then Exit;
Canvas.Pen.Mode:=pmCopy;
if Assigned(Bmp1) then Bmp1.Free;
Bmp1:=TBitmap.Create;
Bmp1.Width:=Width;
Bmp1.Height:=Height;
Bmp1.Canvas.Draw(0,0,Bmp);
if FSetsRectangles then DrawRectangles;
DrawAxes;
DrawValueLines;
if FInSelection then DrawSelection;
Canvas.Draw(0,0,Bmp1);
end;



у тебя по paint вызывается draw, в котором сидит fastrepaint, в котором изменяется канва Canvas.Draw(0,0,Bmp1);
соответственно опять должно автоматически вызваться Paint и опять же рекурсия. Но я так понимаю, этого не происходит. Можешь объяснить, почему?

Автор: Beltar 3.6.2013, 19:32
Зачем? Paint вызывается или автоматом, когда контролу надо перерисоваться (типичный случай, разворот приложения, или изменение размеров контрола), или если контролу был сделан принудительный Refresh. Но к низкоуровневым функциям, которые переводят байты канваса в пиксели монитора она никакого отношения не имеет. У TCustomControl Paint ЕМНИП вообще пустая. Обработка мыши у меня прописана в самом контроле и вызывает только быструю упрощенную прорисовку. Попросту Paint это метод, который должен осуществлять полную прорисовку по умолчанию.

В твоем случае рисование тоже разделяется на 2 части: сами картинки и пользовательская разметка.

http://biblioteka.cc/index.php?newsid=30955 стр 75. ЕМНИП Repaint как раз и вызывает Paint.

Автор: gonzales 5.6.2013, 13:19
Цитата

Но к низкоуровневым функциям, которые переводят байты канваса в пиксели монитора она никакого отношения не имеет.

если не имеет, то я не понимаю, почему у меня все время вызывается paint, если я использую 
Код

procedure Paint;
begin
inherited;
DrawImage;
end;


получается у меня где-то в drawimage вызывается paint?

Автор: gonzales 5.6.2013, 13:48
НАШЕЛ!!!
методом научного тыка выяснил
функция Canvas.FillRect(Canvas.ClipRect); в DrawImage вызывает Paint
осталось понять, как очистить канву не используя FillRect


Автор: Beltar 5.6.2013, 15:12
А ты там брейкпойнт не ставишь, так что приложение переключается нна IDE, а потом обратно и снова рисуется?

Автор: gonzales 5.6.2013, 16:05
у меня два экрана, я вижу, что оно Paint постоянно вызывается
Код

procedure TFrameImage.Paint;
begin
 inherited Paint;
 Canvas.Brush.Style := bsClear;
 Canvas.FillRect(ClientRect);
end;

вот такой код приводит к цикличности. 

Автор: Beltar 5.6.2013, 18:00
Это проблема не заливки, а базового класса, у меня все работает именно потому что TCustomControl. При наследовании от TImage тоже загрузка проца в 100% вечным циклом. Попробуй унаследоваться от TGraphicControl, который обычно и юзают для своих компонентов, которым не надо оконного дескриптора, с ним у меня все правильно работает и ничего не виснет, а что там у TImage уже сделано смотреть надо.

Автор: gonzales 6.6.2013, 10:46
Beltar, спасибо большое! В общем и целом понятно. Буду пробывать TGraphicControl

Автор: gonzales 5.7.2013, 15:59
Beltar, прошу помощи. 
Я переделал компонент на TGraphicControl, соответственно 
Код

procedure TFrameImage.Paint;
  begin
    inherited Paint;
    DrawImage;
  end;


но заметил одну особенность, если у меня на форме несколько компонентов TFrameImage, то при изменении одного, перерисовываются все, то есть Paint срабатывает для всех, даже если они не перекрываются. Соответственно при сложных перерисовках и большом кол-ве компонентов опять имею тормоза. Как заставить перерисовываться только компонент, с которым сейчас производятся манипуляции? 
пробывал внедрять флаг needrepaint
Код

procedure TFrameImage.Paint;
  begin
    inherited Paint;
    if needrepaint=true then
    DrawImage(true, 1);
    needrepaint:=false;
  end;

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







Автор: Gwire 29.7.2013, 09:15
gonzales, я на GDI+ делал стрелочный индикатор.
И заметил интересную особенность если перерисовывать на холсте TWinControl (скажем TPanel) c размером, подогнанным под то, что собираешься рисовать,
то производительность заметно увеличивается (в сравнении, если рисовать прямо на холсте TForm)

По поводу оптимизации подумай, что у тебя статичное и рисуй его в на холсте буферного TBitmap.
B момент перерисовки просто "печатай" с помощью BitBlt(), а после дорисуй динамические элементы.
Например: В Индикаторе шкала ёмкая но статичная. Стрелка динамическая но она одна =)

Если я правильно понял у тебя графические объекты которые нужно перемещать по форме.
Здесь есть "захваченный" и "остальные". Так вот "остальные" - это статика. В TBitmap рисуешь все кроме "захваченного".
А захваченный рисуешь уже на TWinControl.

По другому еще можно  для каждого графического объекта сделать "обертку" на основе TGraphicControl, 
тогда - что и когда перерисовывать будет "думать" система. 

- - - - - -
PS: Если конечно графические объекты у тебя сами не "шевелятся".
Хотя я думаю и там можно найти статику. smile

- - - - - -
PPS: Не увидел вторые станицы, на которой рассмотрены некоторые моменты smile

Автор: Beltar 12.10.2013, 22:32
Хм-м. Похоже, что из-за TGraphicControl и перерисовка всех, он ведь своей канвы не имеет и рисуется поверх винконтрола на котором лежит. Т. е. нужен все-таки кто-то с дескриптором вроде TCustomControl.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)