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

Вниз

Как устранить флики   Найти похожие ветки 

 
Danger ©   (2007-06-22 21:00) [0]

Вопрос по ходу портирования одного компонента: как ликвидировать мигания при перерисовках контрола? (контрол представляет собой нечто вроде прогресс-бара, поэтому должен обновляться часто и без фликов).

Вот куски кода, ответственные за перерисовку:

// ----------------------------------------------------------
function QProgBar_WndProc( Control: PControl; var Msg: TMsg; var Rslt: Integer): Boolean;
var
PaintStruct: TPaintStruct;
begin
Result := False;
case Msg.message of
 WM_PAINT:
  begin
   BeginPaint( Control.Handle, PaintStruct );
   PQProgressBar( Control ).Paint;
   EndPaint( Control.Handle, PaintStruct );
   Result:= True;
   Rslt:= 0;
  end;
 WM_SIZE:
   PQProgressBar( Control ).Resize;
end; // case
end;


Функция QProgBar_WndProc аттачена к обработке событий при создании компонента:
// ----------------------------------------------------------
function NewQProgressBar( AParent: PControl ): PQProgressBar;
.........
begin
.........

Result.AttachProc( QProgBar_WndProc );
end;


Сама процедура отрисовки, полностью:

// ----------------------------------------------------------
procedure TQProgressBar.Paint;
// Main loop. Called each time a setting changes, notably, each time
// a new position is sent.
// Surround is drawn first, then the bar itself. Caption is added lastly (if needed).

var i,k,sp: Integer;
   OldBkMode : Integer;
   D: PQDataObj;
begin
 D:= PQDataObj( CustomObj );

 // -1- Bevel
 if ( D.fHasShape ) then
 with Canvas^ do
 begin
   Pen.PenWidth := 1;
   Brush.BrushStyle := bsSolid;
   Brush.Color := D.fBkgClr;
   Pen.Color   := D.fShapeClr;
   RoundRect (0, 0, Width, Height, D.fCorner, D.fCorner);
 end;

 // -2- The bar itself
 case D.fOrientation of
   boHorizontal :
     begin
       for i := ( D.fBorderSize - 1 ) to D.fPosition  do
       begin
         if ( D.fByBlock ) then
         begin
           if ( D.fPosDescr[i].isInBlock = true) then
           begin
             if  ( (D.fFullBlock) and (D.fPosition >= D.fPosDescr[i].blkLimit) )
             or not( D.fFullBlock ) then
             for k := (D.fBorderSize - 1) to (Height - (D.fBorderSize))
                      do Canvas.Pixels [i,k] := D.fPixDescr[i,k]
             else if (D.fShowInactPos) then
                     for k := (D.fBorderSize - 1) to (Height -(D.fBorderSize))
                         do Canvas.Pixels [i,k] := D.fInactDescr[k];
           end;
         end else
         begin
           for k := (D.fBorderSize - 1) to (Height -(D.fBorderSize)) do
               Canvas.Pixels [i,k] := D.fPixDescr[i,k];
         end;
       end;
       // Now dealing with inactive positions, if they"re to be drawn.
       if ( D.fShowInactPos ) then
       begin
         if (D.fPosition < 3) then sp := 3
         else sp := D.fPosition + 1;
         for i := sp to D.fUSefullDrawSpace do
         begin
           if (D.fByBlock) then
           begin
             if (D.fPosDescr[i].isInBlock = True) then
             begin
                for k := (D.fBorderSize -1) to (Height -(D.fBorderSize)) do
                      Canvas.Pixels [i,k] := D.fInactDescr[k];
             end;
           end else  //If not(byBlock), all pixels must be drawn
           begin
             for k := (D.fBorderSize - 1) to (Height -(D.fBorderSize)) do
                 Canvas.Pixels [i,k] := D.fInactDescr[k];
           end;
         end; {for}
       end; {inactive}
     end; {boHorizontal}
   boVertical :
     begin
       for i := (D.fUSefullDrawSpace-1) downto Height - D.fPosition  do
       begin
         if (D.fByBlock) then
         begin
           if (D.fPosDescr[i].isInBlock = true) then
           begin
             if  ( (D.fFullBlock) and ((Height - D.fPosition) <= D.fPosDescr[i].blkLimit) )
             or not( D.fFullBlock ) then
              for k := (D.fBorderSize - 1 ) to (Width - (D.fBorderSize))
                      do Canvas.Pixels [k,i] := D.fPixDescr[i,k]
             else if ( D.fShowInactPos ) then
                      for k := (D.fBorderSize - 1) to (Width -(D.fBorderSize))
                          do Canvas.Pixels [k,i] := D.fInactDescr[k];
           end;
         end
         else
          for k := (D.fBorderSize - 1) to (Width -(D.fBorderSize))
                      do Canvas.Pixels [k,i] := D.fPixDescr[i,k];
       end;
       // inactive positions :
       if (D.fShowInactPos) then
       begin
         if ( D.fPosition < 3 ) then sp := D.fUSefullDrawSpace
         else sp := Height - D.fPosition - 1;
         for i := sp downto D.fBorderSize do
         begin
           if ( D.fByBlock ) then
           begin
             if ( D.fPosDescr[i].isInBlock = true ) then
             begin
                for k := (D.fBorderSize - 1) to (Width -(D.fBorderSize)) do
                    Canvas.Pixels [k,i] := D.fInactDescr[k];
             end;
           end else
             for k := (D.fBorderSize - 1) to (Width -(D.fBorderSize))
                 do Canvas.Pixels [k,i] := D.fInactDescr[k];
         end; {for... downto}
       end; {inactive}
     end; {boVertical}
   end; // Case

   // caption management. The font is the canvas" one. Can be overrided
   // using the Font property :
   if ( D.fCaptionOvr ) then
      if ( D.fShowPosAsPct ) then _SetCaption( Double2Str( D.fUSerPosPct ) + "%")
      else SetCaption( Int2Str(D.fUSerPos) );
   if ( D.fHasCaption ) then
   begin
     OldBkMode := SetBkMode(Canvas.Handle, Windows.TRANSPARENT);
     with Canvas^ do
     begin
       TextOut(D.fCapPos.X, D.fCapPos.Y, Caption);
     end;
     SetBkMode(Canvas.Handle, OldBkMode);
   end;

end;


В чем может быть проблема, что при перерисовке контрол сильно мигает? Подскажитте, как можно исправить?


 
Vladimir Kladov   (2007-06-22 21:56) [1]

Мелькание происходит из-за того, что в процессе обновления сначала затирается прежнее изображение (цветом фона), а затем поверх него рисуется заново новое состояние. Если есть возможность обесчпечить рисование нового состояния без затирания предыдущего, то надо так и поступить. И не забыть в этом случае отработать WM_ERASEBKGND, ответив системе, что все уже сделано, и ничего делать не надо, иначе сама система по умолчанию займется созданием флика. Если такой возможности нет (изображение слишком сложное), то единственный выход - рисовать на битмапе в памяти, и перебрасывать все содержимое битмапа на DC в OnPaint. Как вариант этой возможности - DoubleBuffered := true - всего лишь создает такой битмап в памяти сам, и отрабатывает WM_PAINT и WM_ERASEBKGND на канву этого битмапа, после чего сам перебрасывает содержимое на экран. Следует только учесть, что все дочерние контролы такого контрола с двойной буферизацией так же рисуются на этом же битмапе в памяти.


 
homm ©   (2007-06-22 22:30) [2]

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

Неправда ваша. Только те у которых самих DoubleBuffered = true


 
Danger ©   (2007-06-23 09:42) [3]


> Vladimir Kladov   (22.06.07 21:56) [1]
> Как вариант этой возможности - DoubleBuffered := true -
> всего лишь создает такой битмап в памяти сам, и отрабатывает
> WM_PAINT и WM_ERASEBKGND на канву этого битмапа, после чего сам
> перебрасывает содержимое на экран.

DoubleBuffered решает проблему мигания, но появляется небольшая проблемка: рамка контрола изначально не прямоугольная (рисуется через RoundRect в процедуре Paint):

// -1- Bevel
if ( D.fHasShape ) then
with Canvas^ do
begin
  Pen.PenWidth := 1;
  Brush.BrushStyle := bsSolid;
  Brush.Color := D.fBkgClr;
  Pen.Color   := D.fShapeClr;
  RoundRect (0, 0, Width, Height, D.fCorner, D.fCorner);
end;

И при использовании DoubleBuffered у контрола появляются черные уголки, "спрямляющие" его в прямоугольник. В отрисовке без DoubleBuffered рамка отрисовывается нормально. Как заставить DoubleBuffered отрисовывать правильно?

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

Контрол не будет иметь потомков, поэтому несущественно.


 
Vladimir Kladov   (2007-06-23 11:18) [4]

Залить сначала тем цветом, которым надо чтобы были уголки.


 
Danger ©   (2007-06-23 15:08) [5]


> Vladimir Kladov   (23.06.07 11:18) [4]
> Залить сначала тем цветом, которым надо чтобы были уголки.

Спасибо, Владимир, сработало.


 
Jimmy Lee   (2007-08-27 19:59) [6]

Тестировал компонент. - все равно флики сильно заметные, если caBottom и таскать верхнюю границу. На мой взгляд сам метод align в KOL реализован не совсем оптимально. При ресайзе за верхнюю границу - нижняя прыгает как сумасшедшая. Что скажете? Тема далека от закрытия!


 
exero ©   (2007-08-28 08:47) [7]

В продолжение темы пример:
1. Кидаем на форму панель с Align = caClient
2. Кидаем на нее три панельки у первой Align = caTop у второй caBottom у третей caClient.
3. У нижней ставим все Anchor в True.
Запускаем - сворачиваем-разворачиваем - получаем совсем не ту картинку которую хотели (.

PS. Если OLD_ALIGN то все нормально.


 
Vladimir Kladov   (2007-08-28 21:15) [8]

2JimmyLee: разве в VCL меньше фликов или в любой другой программе в Windows, в том же проводнике? (Вы еще в Linux"е посмотрите, какие там флики в X-окнах, наши флики вам совсем незаметными покажутся). В принципе, с фликами бороться можно. Но - в каждом конкретном случае - отдельно. Кому-нибудь этот геморрой из разработчиков нужен?


 
danger ©   (2007-08-29 07:43) [9]


> Jimmy Lee   (27.08.07 19:59) [6]
> Тестировал компонент. - все равно флики сильно заметные,
>  если caBottom и таскать верхнюю границу.

В большинстве случаев флики в компонентах KOL такие же, как и в VCL аналогах. Не больше.

Касательно align для компонента - нужно обращаться к гуру KOL. Все это должно средствами библиотеки реализовываться. Не должно компоненту быть умнее библиотеки, отслеживание разных версий ALIGN"a и всевозможные фиксы для разных версий align"a не является задачей.


 
Vladimir Kladov   (2007-08-29 15:30) [10]

Если не бросать  панельку, а сразу на форму, то флики меньше. Сначала выравнивается то, что есть на формеЮ когда меняются ее размеры. Потом идёт каскадная обработка сообщения изменения размеров для дочерних панелей. И так далее, а поскольку изменение размеров - явление непрерывное и продолжается сколько-то во времени выравнивание выполняется многократно. В процессе окна перерисовываются, происходит обработка OnResize, если есть, и не факт, что всё это не тормозит процесс ещё больше.

Вывод: хотите убрать флики в конкретном приложении? Уберите все Align, при изменении размеров 1. вычислите все прямоугольники всех контролов сами 2. Присвойте новые координаты через BoundsRect :=. При этом, если ещё в процессе срабатывают какие-то ваши обработчики, сделайте так чтобы обработка шла потом, т.е. никакая отрисовка и никакие действия не выполнялись внутри вашей процедуры выравнивания.

Еще можно обрабатывать WM_WINDOWPOSCHANGING (так, кажется), и "правильно" задавать при этом, какие пиксели сдвигать, т.е. корректно определять только небольшую изменившуюся прямоугольную область, а остальное не перерисовывать (не всегда она оказывается внизу справа, но даже это по умолчанию Windows не используется, и инвалидируется весь контрол).


 
Andrey_rus ©   (2007-08-29 18:00) [11]

То, что флики KOL аналогичны фликам VCL, не повод успокаиваться. Я специально использую слабый компьютер (Celeron Pentium II - 300 Mz) для того чтобы воочию наблюдать медленную отрисовку контролов и соответсвенно предпринемать какие то действия. Однако на моем компбтере даже перегруженные контролами диалоговые окна MS Office отрисовываются моментально. Использование стандарного DoubleBuffer приносит больше вреда чем пользы (глюки с темами, не работает с RichEdit). Вот бы подумать сообща и реализовать собственный DoubleBuffer"инг. Это явно выделяло бы программы написанные на KOL и привлекло бы дополнительное количество разработчиков с VCL лагеря.


 
Jimmy Lee   (2007-08-29 18:41) [12]

Жаль нельзя аттачить в форуме, но если кто желает - могу прислать два примера:
1 KOL (форма->панель(align=caClient)->прогрессбар(алигн=caBottom))
2 Форма (не KOL), на ней панель(align=caClient) и на ней еще разные градиентные контролы, которые рисуются между прочим без BitBlt, а прямо в DC

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


 
homm ©   (2007-08-29 22:01) [13]

> [11] Andrey_rus ©   (29.08.07 18:00)
> Вот бы подумать сообща и реализовать собственный DoubleBuffer"инг.
> Это явно выделяло бы программы написанные на KOL.

http://www.delphimaster.ru/cgi-bin/nuts.pl?showpage=2
Первый пост про тебя :)


 
homm ©   (2007-08-29 22:02) [14]

> которые рисуются между прочим без BitBlt, а прямо в DC

Сегодня день перлов что-ли? :)


 
Andrey_rus ©   (2007-08-29 22:40) [15]

Зря ты homm, я ведь по делу.

Причем здесь написание файлового менеджера?

Лучше бы хотя бы предположил – как Office так быстро отрисовывает диалоговое окно с большим количеством на нем контролов.


 
homm ©   (2007-08-29 23:20) [16]

> Зря ты homm, я ведь по делу.

Да нет, не зря.


> Лучше бы хотя бы предположил – как Office так быстро отрисовывает
> диалоговое окно с большим количеством на нем контролов.

Временный битмап? Кто мешает его сделать в своем приложении?


 
Andrey_rus ©   (2007-08-29 23:24) [17]

> Да нет, не зря.
homm... homm...

> Временный битмап? Кто мешает его сделать в своем приложении?
Как?


 
homm ©   (2007-08-29 23:48) [18]

NewDibBitmap


 
Andrey_rus ©   (2007-08-29 23:56) [19]

>NewDibBitmap

Хороший пример... :)
homm, Не в обиду, хорош флуд разводить.


 
homm ©   (2007-08-30 00:04) [20]

> [19] Andrey_rus ©   (29.08.07 23:56)
> homm, Не в обиду, хорош флуд разводить.

пока ты ту флуд разводишь. Пока в КОЛ даблбуфер и transparent моей реализации, готов поспорить что когда исходник откроешь, у тебя духу не хватит в нем разобратся. Это пока единственная реализация работающая от 95 до висты. Наишешь лучше — возьму свои слова обратно, но пока, ты кроме как на тот орех, что я процетировал не тянешь.


 
homm ©   (2007-08-30 00:08) [21]

> Это пока единственная реализация работающая от 95 до висты.

Имеется ввиду не только КОЛ.


 
Andrey_rus ©   (2007-08-30 00:19) [22]

> пока ты ту флуд разводишь.
Где то я уже это видел... и не раз...

> Пока в КОЛ даблбуфер и transparent моей реализации
Огромное спасибо! Серьезно. Вот только пользоваться ими проблематично, по причине описанной мной выше.

>> Это пока единственная реализация работающая от 95 до висты.
> Имеется ввиду не только КОЛ.
А что еще?

Есть ли какие нибудь предположения относительно скорости прорисовки контролов в Office?


 
homm ©   (2007-08-30 00:33) [23]

> Есть ли какие нибудь предположения относительно скорости
> прорисовки контролов в Office?

Сделай скриншот, покажи, мне этьот контрол :)

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


> А что еще?
Все.


> Есть ли какие нибудь предположения относительно скорости
> прорисовки контролов в Office?
NewDibBitmap?


 
homm ©   (2007-08-30 00:43) [24]

Офис тоже не может похвастаться безглючной работой с темами. Пример прилагаеться:
http://homm86.narod.ru/files/office.png


 
homm ©   (2007-08-30 00:44) [25]

При многократном наведении эффект усиливаеться и контрол становиться почти черным.


 
Andrey_rus ©   (2007-08-30 00:51) [26]

> Сделай скриншот, покажи, мне этьот контрол :)
Открой в Office любое окно где много контролов.

> Пока в КОЛ даблбуфер и transparent моей реализации
> Это пока единственная реализация работающая от 95 до висты.
> Имеется ввиду не только КОЛ.
А что еще?
> Все.
Вывод - код, во всех библиотеках осуществляющих отображение контролов, написан тобой?


 
homm ©   (2007-08-30 00:57) [27]

> > Все.
> Вывод - код, во всех библиотеках осуществляющих отображение
> контролов, написан тобой?

НЕ верный вывод. Попробуй еше раз.


> [11] Andrey_rus ©   (29.08.07 18:00)
> не работает с RichEdit

Блин, что я вечно делаю не так? :)
http://homm86.narod.ru/files/rtf.rar


 
Andrey_rus ©   (2007-08-30 01:17) [28]


> НЕ верный вывод. Попробуй еше раз.

А по моему, все логично, перечитай свои посты.


> Блин, что я вечно делаю не так? :)http://homm86.narod.ru/files/rtf.rar


Тем, что предлагаешь для ознакомления в архиве - "Delphi 6 Release Notes
" и выполняемый файл неизвестного происхождения. Хочешь запустить мой. :)


 
homm ©   (2007-08-30 01:41) [29]

> [28] Andrey_rus ©   (30.08.07 01:17)
> и выполняемый файл неизвестного происхождения

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


 
exero ©   (2007-08-30 07:29) [30]

Уважаемый homm, хорош флудить! А что я делаю не так: качаем вашу прогу:
Load - Transparent - щелкаем на тексте и нажимаем клавишу стрелка влево (вправо) - что получится думаю увидите сами. А после этого скажите что никаких проблем нет и что это у меня кривые руки.


 
exero ©   (2007-08-30 07:51) [31]


> homm ©   (30.08.07 00:08) [21]
> > Это пока единственная реализация работающая от 95 до висты.
>


К сожалению это не так, под 98 (не поленился, проверил) тот же пример при включении прозрачности ведет себя некорректно - не отображает содержимое файла - оно появляется при щелчке мышкой и выделении - но у меня при потере фокуса окна содержимое снова пропадало.


 
homm ©   (2007-08-30 08:01) [32]

> А что я делаю не так:

Лучше чем есть все равно для RichEdit не сделать (тут ксати уж я совсем не причем, все вопросы к Microsoft). Единственное применение прозрачного RE — запретить в него вообще вставлять курсор.


 
exero ©   (2007-08-30 08:14) [33]

Я и не пытался найти виноватого, просто есть проблема и все.


 
Jimmy Lee   (2007-08-30 08:17) [34]

2 homm:

>  >Сегодня день перлов что-ли? :)

а что непонятного? или надо было расписать подробно, что графика де рисуется НЕ на битмапе с последующим трансфером этого битмапа на экран, а сразу в контексте устойства получаемом в BeginPaint, что в свою очередь, подразумевает медленный вывод графики, и что несмотря на это фликов все равно меньше?


> Пока в КОЛ даблбуфер и transparent моей реализации, готов
> поспорить что когда исходник откроешь, у тебя духу не хватит
> в нем разобратся.

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

Флики - это причина по которой я ваяю приложение без KOL, и мне очень тягостно далось это решение. В KOL очень многое реализовано, и писать самому - конечно лень. Но, приложение должно выглядеть профессионально, и не мерцать, когда его ресайзят, заказчик привередливый.


 
Jimmy Lee   (2007-08-30 08:31) [35]

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


 
homm ©   (2007-08-30 08:36) [36]

> [34] Jimmy Lee   (30.08.07 08:17)
> а зачем разбираться в чужом, глючном, да еще и медленном коде...

Ба, сколько эппитетов! :) Только «наезжать на всех это не сложно, но к сожалению не конструктивно». Сам то в этом как приуспел?


> А теперь о конструктивном:
Морево конечно :) «А теперь я выскажусь конструктивно: Давайте делайте что-б было все хоршо». Очень констрктивно :)



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

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

Наверх




Память: 0.59 MB
Время: 0.017 c
6-1185475224
MikeLevin
2007-07-26 22:40
2008.04.27
Разбор заголовка и пакетов.


15-1205350043
Interfer0n
2008-03-12 22:27
2008.04.27
Ищем программистов Delphi, C++/Visual Studio


15-1205412702
Пробегал2...
2008-03-13 15:51
2008.04.27
Вывод в WEB-страницу видео


15-1205740771
Wold
2008-03-17 10:59
2008.04.27
SSL и TLS


15-1205804316
Anatoly Podgoretsky
2008-03-18 04:38
2008.04.27
Какой нормальный индекс производительности для Висты