Форум: "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