Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.03.30;
Скачать: CL | DM;

Вниз

Мерцание при перерисовке(GDI+)   Найти похожие ветки 

 
unknowing ©   (2007-04-24 20:11) [0]

Рисую окружность с рисками через каждые 10 гр, двигаю стрелку по таймеру... И всё это сильно мерцает:(
Как от этого эффекта избавляются профессионалы??
Привожу кусок кода(строго не судить:):

procedure TMainForm.Draw(Count: Smallint);
var
 graphics   : TGPGraphics;
 Pen        : TGPPen;
 SolidBrush : TGPSolidBrush;

 R,
 X, Y,
 Xc,Yc,
 cs, SN,
 cs2, SN2 : Single;
 CountR   : Integer;

const
 dash : array[0..2] of single = (2, 20, 20);
begin

 graphics := TGPGraphics.Create(PaintBox.Canvas.Handle);
 graphics.Clear(clBlack);
 Pen := TGPPen.Create(MakeColor(0, 255, 0),2);  // салатовый
 
 graphics.SetSmoothingMode(SmoothingModeAntiAlias);  

 R :=PaintBox.Height - 80;      //диаметр окружности
 X:= (PaintBox.Width / 2)-R/2;  //координата х левого верхнего угла прямоугольника
 Y:= (PaintBox.Height / 2)-R/2 ;//координата у левого верхнего угла

 graphics.DrawEllipse(Pen, X, Y, R, R);  // окружность

 Xc := X+(R/2);  //координаты центра окружности
 Yc := Y+(R/2);

//---------------------риски румбов----------------------------
 CountR:=0;
  while CountR<360 do
    begin
           Pen.SetWidth(1);
           cs := Xc+(R/2)*cos(CountR*pi/180);  
           sn := Yc+(R/2)*sin(CountR*pi/180);  

           cs2 := Xc+(7+R/2)*cos(CountR*pi/180);  
           sn2 := Yc+(7+R/2)*sin(CountR*pi/180);  

           if frac(CountR/30) = 0 then
            begin  //параметры для толстых рисок
             Pen.SetWidth(3); //
             sn2 := Yc+(10+R/2)*sin(CountR*pi/180);  
            end;
           graphics.DrawLine(pen, cs, sn,cs2,sn2); //рисуем риску

           Inc(CountR,10);
    end;

//---------------------------------------------------------------

//---------------------движение стрелки-----------------------
           Pen.SetWidth(2);
           cs := Xc+(R/2)*cos(Count*pi/180);  
           sn := Yc+(R/2)*sin(Count*pi/180);  

           cs2 := Xc+(R/2 - 15)*cos((10+Count)*pi/180);  
           sn2 := Yc+(R/2 - 15)*sin((10+Count)*pi/180);

           graphics.DrawLine(pen, cs,sn, cs2,sn2);      //стрелка (левая)

           cs2 := Xc+(R/2- 15)*cos((-10+Count)*pi/180);  
           sn2 := Yc+(R/2- 15)*sin((-10+Count)*pi/180);  

           graphics.DrawLine(pen, cs,sn, cs2,sn2);      //стрелка (правая)
//---------------------------------------------------------------

//-----------------------базовые линии окружности-------------
 Pen.SetWidth(0.5);
 Pen.SetDashPattern(@dash, 4);
 graphics.DrawLine(Pen,Xc,Yc-R/2-15,Xc,Yc+R/2+15); //горизонтальная базовая линия окружности
 graphics.DrawLine(Pen,Xc-R/2-15,Yc,Xc+R/2+15,Yc);

//---------------------------------------------------------------
 Pen.Free;
 graphics.Free;
end; //Draw

procedure TMainForm.FormCreate(Sender: TObject);
begin
Count:=0;
end;

procedure TMainForm.Timer1Timer(Sender: TObject);
begin
INC(Count,10);
Draw(Count);
//Timer1.Interval=500;
end;


 
Fenik ©   (2007-04-24 20:28) [1]

Простейший вариант: у панели или формы, на которой лежит пэинтбокс, сделать: DoubleBuffered := true;

А лучше делать ручную буферизацию: рисовать в памяти на битмапе, с которого копировать на форму.


 
unknowing ©   (2007-04-24 20:37) [2]


> Fenik ©   (24.04.07 20:28) [1]

DoubleBuffered := true; - не помогает, к сожалению:(

> А лучше делать ручную буферизацию: рисовать в памяти на
> битмапе, с которого копировать на форму.

это как, если не секрет:) ?


 
Fenik ©   (2007-04-24 21:10) [3]

Ну есть у тебя созданный при старте битмап:
 Bmp := TBitmap.Create;
 Bmp.Width := 100;
 Bmp.Height := 100;
 и т.д.

Во время прорисовки указываешь хэндл битмапа а не пеинтбокса (если такое возможно для gdi+ никогда с ним не работал):

  graphics := TGPGraphics.Create(Bmp.Canvas.Handle);

А потом выводишь на экран, что-то вроде

  PaintBox.Canvas.Draw(0, 0, Bmp);

лучше юзать BitBlt для этого. Можно вообще прямо на форму копировать, тогда мерцать точно не будет )

Совет: 1) заготовить риски загодя, потом просто копируя их с битмапа на битмап, на котором будут стрелки рисоваться. 2) использовать try finally для уничтожения объектов.


 
Krupsky   (2007-04-24 21:38) [4]

Вся эта братия

graphics   : TGPGraphics;
Pen        : TGPPen;
SolidBrush : TGPSolidBrush;

и установки:

graphics.SetSmoothingMode(SmoothingModeAntiAlias);

должны быть заранее сделаны. Draw должна быть как можно более быстродейственной!

Рисовать нужно не в таймере, а в TPaintBox.OnPaint. А в таймере нужно вызывать перерисовку при помощи TPaintBox.Invalidate.

Попробуй так, напиши, что получилось.


 
homm ©   (2007-04-24 21:45) [5]

> А лучше делать ручную буферизацию:

Чегой то лучше? Аргументы?


 
antonn ©   (2007-04-24 23:36) [6]


> Чегой то лучше? Аргументы?

Doublebuffered:=true + тема в ОС не классическая + D7 + Манифест на форме -  дают интересные результаты на таких контролах, как TButton/TPanel:
http://antonn.ru/index.php?download=1ec64a0d_1177443306.GIF&id=fe4def6b4ca8370e6c848b091ed4bd3d (15Кб)
одного этого достаточно, чтобы делать вручную...


 
Rial ©   (2007-04-24 23:46) [7]

> [5] homm ©   (24.04.07 21:45)
> > А лучше делать ручную буферизацию:
>
> Чегой то лучше? Аргументы?

Все правильно человек советует. По идее,
любой способ, реализованный своими руками, лучше.
Т.к. понимаешь, как он работает и знаешь, что в нем не так :)
А вопросы затрат времени на написание буферизации отпадает
(цена/качество), т.к. задача это простая в общем то.


 
antonn ©   (2007-04-24 23:49) [8]


> По идее,
> любой способ, реализованный своими руками, лучше.

ну не совсем так, потому как подводные камни есть, иногда велосипед лучше не изобретать. только если у него треугольные колеса иногда, тогда да - можно самому:)


 
homm ©   (2007-04-25 00:12) [9]

> Doublebuffered:=true + тема в ОС не классическая + D7 +
> Манифест на форме -  дают интересные результаты на таких
> контролах, как TButton/TPanel:

В принцепе понятно, чего они не работают, видимо посылают WM_ERASEBACKGROUND, а при включеной даблдуфере, ВСЛ фигу возвращает :) Это конечно аргумент, но зато когда у вас на форме будет 50 компонентов графических, каждый из них будет перерисовывться отдельно, а с дабл буфером рдителя, они все отобразяться одновременно, что куда приятнее выглядит.


 
antonn ©   (2007-04-25 00:24) [10]

я вот из-за этого бага когда то потерял немало времени и нервов, стал подозревать даже невинную IPHLPAPI.DLL :))


 
unknowing ©   (2007-04-26 19:50) [11]

Представляю на Ваш суд такое решение:

Bitmap:= TGpBitmap.Create(PaintBox.Width,PaintBox.Height,2498570);
graphics := TGPGraphics.Create(Bitmap);
graphics.FillRectangle(BrushP,0,0,MFD.Width,MFD.Height);
//рисую черный квадрат во весь PaintBox
... здесь рисую окружности, риски и пр.
 
playBack :=TGPGraphics.Create(MFD.Canvas.Handle);
cBitmap:= TGPCachedBitmap.Create(bitmap, playBack);
playBack.DrawCachedBitmap(cBitmap, 0, 0);

Есть ли лучший способ очистки контекста(типа Clear(clBlack))??


 
antonn ©   (2007-04-26 23:50) [12]

есть встречный вопрос - Bitmap создается при каждом рисовании кадра?


 
Unknowing ©   (2007-04-27 18:46) [13]


> antonn ©   (26.04.07 23:50) [12]

Да, и каждый раз освобождается.


 
clickmaker ©   (2007-04-28 12:01) [14]


> [13] Unknowing ©   (27.04.07 18:46)

а почему не один раз?


 
Unknowing ©   (2007-04-28 13:48) [15]


> clickmaker ©   (28.04.07 12:01) [14]

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


 
antonn ©   (2007-04-28 14:38) [16]

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


 
Unknowing ©   (2007-04-28 21:51) [17]


> antonn ©   (28.04.07 14:38) [16]

дело в том, что в процессе работы стрелка двигается с частотой 10 Гц и всё с этой же частой перерисовывается. Если не освобождать каждый раз - коллапс... Я лучше ничего не придумал... Есть ли лучший способ?


 
antonn ©   (2007-04-28 23:36) [18]

создавать отдельно (ну при создании формы) и рисовать используя эти объекты.

для теста можно сделать так в [3], только выводить там где graphics.Free; как нибудь типа paintbox.canvas.copyrect(rect(0,0,paintbox.width,paintbox.height),bitmap.canvas, rect(0,0,bitmap.width,bitmap.height));


 
homm ©   (2007-04-29 06:08) [19]

> Ну а если он мерцает, значит достаточно часто, так почему
> бы не создать один раз нужные объекты и юзать их в процессе
> работы? а по окончании убить.

Потому что потому. Если бы все программы сразу выделяли максимальное количество памяти, которое им понадобится, было бы очень печально работать на айбиэм писи. Скажи, часто ли у тебя окна свернутые в трей находяться? Если нет — снимаю шляпу.


 
antonn ©   (2007-04-29 09:12) [20]


> Потому что потому. Если бы все программы сразу выделяли
> максимальное количество памяти, которое им понадобится,
> было бы очень печально работать на айбиэм писи. Скажи, часто
> ли у тебя окна свернутые в трей находяться? Если нет — снимаю
> шляпу.


> а по окончании убить.


 
homm ©   (2007-04-29 09:39) [21]

> [20] antonn ©   (29.04.07 09:12)

По окончании чего? Прорисовки то-ли? Дак тогда так и нужно, а если окончании раоты программы, то, нафига мне 2 метра хлама в оператвке, когда приложение свернуто в трей?


 
antonn ©   (2007-04-29 11:22) [22]

по окончании необходимости рисовать. когда приложение в трей свернулось, например...


 
homm ©   (2007-04-29 12:44) [23]

> когда приложение в трей свернулось, например...

И сколько ты таких «окончаний необходимости» готов привести? Спорим я все равно на одно больше, да назову, и что ты их все собрался отлавливать, штук так 10 различных ситуаций, когда перерисовка не нужна долгое время, и мы получаем офигенные тормаза по прошествию этого времени, потому что наш битмап ушел в своп? Какие проблемы освобождать память, когда она не понадобиться в ближайшее время? Поверь мне, даже две соседние перерисовки при 10 перерисовках в секунду— не есть «ближайшее время»


 
antonn (work)   (2007-04-29 16:25) [24]

homm, просто хочется поспорить?


 
Rial ©   (2007-04-29 17:03) [25]

> [23] homm ©   (29.04.07 12:44)

Извини конечно, но что за чушь ты несешь ?!
Тебя послушать, так тогда перед каждым выключением компьютера
надо сносить операционку, а потом ее каждое утро заново ставить. %)


 
homm ©   (2007-04-29 17:23) [26]

> homm, просто хочется поспорить?

Хочется что-бы на свете было как можно меньше кривых программ :) Другие аргументы иссякли, я так понимаяю?


> Тебя послушать, так тогда перед каждым выключением компьютера надо сносить операционку

Хм, интересно где я такое сказал… Не люблю когда мне причисляют чужие подвиги ;)


 
Vovan #2   (2007-04-29 19:52) [27]

2 homm:

Жевал бы лучше, а не бред нёс. Эдакий деятель нашёлся, исправитель кривых рук своими же кривыми. А кривые от того, что опыта работы с графикой фиг да нифига - отсюда все эти идиотские ляпы, "ой извините, ошибся" и прочий хлам. Ещё раз говорю - попрограммируй немного, поймёшь что к чему.


 
homm ©   (2007-04-29 20:13) [28]

> А кривые от того, что опыта работы с графикой фиг да нифига - отсюда

Ну-ну :)

http://homm86.narod.ru/grushcontrols.rar


> Эдакий деятель нашёлся, исправитель кривых рук

Делаю то, что считаю нужным. Постараюсь со всеми аргументами объяснить человеку, если он ошибатся. А у тебя какие аргументы, кроме «Жевал бы лучше» ?


 
Rial ©   (2007-04-29 21:20) [29]

> [28] homm ©   (29.04.07 20:13)
> Делаю то, что считаю нужным. Постараюсь со всеми аргументами
> объяснить человеку, если он ошибатся. А у тебя какие аргументы,
> кроме «Жевал бы лучше» ?

Ок. :)

1. Дабл буфер уменьшает мерцания. По своей сути на скорость
отрисовки он вообще мало влияет. В лучшем случае, она не уменьшится.
Все плюсы идут уже он прямых рук.

2. Вообще глупость какая то. Одно дело светнуто в трей,
другое дело - отрисовка по таймеру, например, в игре.
Создавать растр 25 раз в секунду... лол.
Вообще, что тебе этот трей дался то ?

3. Ты не хочешь предусматривать 10 ситуаций, при которых
может возникнуть необходимоти освобождения ресурсов ?..
Между прочим, оптимизация никогда не идет в уменьшение
количества логических блоков, а, следовательно, количества кода.

4. Не причислял других подвигов я тебе. Просто преувеличил немного
твои аргументы. И ты сам понял, что они смешные. :)

5. По сути, аргументов не видел как таковых. Главная проблема в том,
что все это - твои проблемы, тормозить- то будут твои программы. %)


 
homm ©   (2007-04-29 21:38) [30]

1. Кто же спорит :) Я обоими руками за. И в DablBuffered сам буфер создаеться и уничтожаеться при каждой проприсавке.

2. Создавать растры 25 раз в секунду никто не предлагает! Речь о буфере для вывода!

3. «Ты не хочешь…» Нет, не хочу, я и говорю, что освобождать нужно как только стал не нужен, без дополнительных условий. Идею с освобождением по сворачиванию высказал не я!

4. «тормозить- то будут твои программы» Откопай гденить 500-й селерон с ТНТ видяшкой и 98-м виндовсом, сходи по ссылке, которую  я давал выше, посмотри с какой скоростью рисуются градиенты нехилых размеров со сглажеными краями бордеров и блендингом при наведении :) Попробуй сделать хотя-бы чистый градиент, без сглаженой рамки, всеми доступными способами (да хоть и в 2К) без глюков и правильным отображением в 16 цветах под обе линейки осей, сравни скорость с моей, вот тогда поговорим о тормозах в моих программах :)

ЗЫ «500-й селерон с ТНТ видяшкой и 98-м виндовсом» — это железо, на которых писались эти компоненты :)


 
homm ©   (2007-04-29 21:40) [31]

ЗЗЫ Да, насчет «всеми доступными способами» — как ты понимаешь DirectX не в счет ;)


 
homm ©   (2007-04-29 21:52) [32]

Ну и насчет моих аргументов, если я правда не понятно до этого изъяснялся:
Если это не полноэкранное приложение класса «игра», которуму действительно нужен постоянный буфер, то есть достаточно большая вероятность, что приложение будет достаточно долго не перерисовываться (не важно в следствии чего, свернули его в трей или закрыли другим окном), и тогда память этого приложения потихоньку будет утекать в своп. а когда пользователь снова возжелает лицезреть это приложение, ОС придеться доставать помимо непосредственных рессурсов приложения еще и его экранный буфер, хотя его содержимое не нужно никому. А если приложение и так часто перерисовываеться, то выделить память такого-же размера, как несколько сотен милисекунд назад освобожденная, — системе не доставит труда.


 
Rial ©   (2007-04-29 22:13) [33]

Присоединяюсь к:

> [24] antonn (work)   (29.04.07 16:25)
> homm, просто хочется поспорить?

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


 
Vovan #2   (2007-04-29 22:36) [34]

Ой... воришка! Наворовал загрузку PNG и своё имя написал.


 
homm ©   (2007-04-29 23:12) [35]

> Ой... воришка! Наворовал загрузку PNG и своё имя написал.

За слова то отвечать не привык что-ли? Если сам ничего не способен сделать, молчи уже.


 
Unknowing ©   (2007-05-02 17:36) [36]

Всем, конечно, спасибо большое за обсуждение! Но я так и непонял: правильно освобождать 10 раз в секунду или нет?? Давайте голосовать!


 
Rial ©   (2007-05-02 18:42) [37]

Создавать и уничтожать растр 10 раз в секунду - однозначно глупость.
Исключая какие- то частные, маловероятные в твоем случае ситуации.
И если бы они были, ты бы их наверняка упомянул :)
Вообще, надо выбрать критический параметр и решать задачу
исходя из него. Если слабый процессор - то отыгрываемся на памяти,
если 8 МБ памяти :o) - кушаем процессорное время.


 
Fenik ©   (2007-05-02 19:24) [38]

Блин. Не пойму, в чем проблема, вроде все объяснено
Оптимальный вариант для данной задачи:

1. При запуске приложения (OnCreate формы) создаем два растра одного размера. На первом рисуем циферблат с рисками. Можно даже с градиентом!

2. В событии OnPaint для PaintBox"a (или панели):
1) Копируем с первого растра на второй все содержимое (BitBlt)
2) Рисуем стрелку на втором растре.
3) Копируем второй растр на панель или на PaintBox (или панель) (BitBlt)

3. В OnTimer для таймера вызываем PaintBox.Paint;


 
Unknowing ©   (2007-05-02 20:39) [39]


> Fenik ©   (02.05.07 19:24) [38]

С первым растром понятно, да и давно уже всё работает!.. А со вторым, динамически обновляемым, что делать?? Если не освобождать каждый раз - жрёт память!


 
antonn ©   (2007-05-02 21:54) [40]


> Если не освобождать каждый раз - жрёт память!

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



Страницы: 1 2 вся ветка

Текущий архив: 2008.03.30;
Скачать: CL | DM;

Наверх




Память: 0.59 MB
Время: 0.033 c
2-1204533353
Wood
2008-03-03 11:35
2008.03.30
Преобразовать строку в TDateTime.


2-1204460411
KJ13
2008-03-02 15:20
2008.03.30
Открытие файла


15-1202910633
Пробегал...
2008-02-13 16:50
2008.03.30
Функция, возвращающая строку ошибки


15-1203476951
Slider007
2008-02-20 06:09
2008.03.30
С днем рождения ! 20 февраля 2008 среда


2-1204522838
mrfreeman2007
2008-03-03 08:40
2008.03.30
Открытие неисправной флешки