Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Мерцание при перерисовке(GDI+) [D7, WinXP]


Страницы:   1 2 3

unknowing ©   (2007-04-24 20:11:00) 

Рисую окружность с рисками через каждые 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;


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

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


homm   (2007-04-29 09:39:00) [22]

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

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


antonn   (2007-04-29 09:12:00) [23]


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


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


homm   (2007-04-29 06:08:00) [24]

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

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


antonn   (2007-04-28 23:36:00) [25]

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

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


Unknowing   (2007-04-28 21:51:00) [26]


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

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


antonn   (2007-04-28 14:38:00) [27]

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


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


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

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


clickmaker   (2007-04-28 12:01:00) [29]


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

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


Unknowing   (2007-04-27 18:46:00) [30]


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

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


antonn   (2007-04-26 23:50:00) [31]

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


unknowing   (2007-04-26 19:50:00) [32]

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

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-25 00:24:00) [33]

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


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

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

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


antonn   (2007-04-24 23:49:00) [35]


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

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


Rial   (2007-04-24 23:46:00) [36]

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

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


antonn   (2007-04-24 23:36:00) [37]


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

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


homm   (2007-04-24 21:45:00) [38]

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

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


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

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

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

и установки:

graphics.SetSmoothingMode(SmoothingModeAntiAlias);

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

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

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


Fenik   (2007-04-24 21:10:00) [40]

Ну есть у тебя созданный при старте битмап:
 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 для уничтожения объектов.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо