Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Media";
Текущий архив: 2008.03.30;
Скачать: [xml.tar.bz2];

Вниз

Мерцание при перерисовке(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 вся ветка

Форум: "Media";
Текущий архив: 2008.03.30;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.037 c
2-1204027484
Эрни
2008-02-26 15:04
2008.03.30
найти каталог


15-1203006018
Cyrax
2008-02-14 19:20
2008.03.30
Общепринятый формат записи федеральных номеров сотовых телефонов~


2-1204373153
GHT
2008-03-01 15:05
2008.03.30
высота строк и перенос слов в DBGrid


2-1204610265
wasko
2008-03-04 08:57
2008.03.30
TFileStream


2-1204467333
Kiril
2008-03-02 17:15
2008.03.30
Как в SpinEdit вводить десятичные числа?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский