Конференция "KOL" » Очень Древний Баг с прозрачностью (DoubleBuffered)
 
  • Galkov (10.06.09 22:14) [0]
    Есть такой баг-демо:
    Program test;
    uses  windows,kol;

    var MainForm,ChildForm,Label1,Label2:PControl;

    begin
     Applet    := NewApplet('Bug-Demo');
    //главная форма
     MainForm  := NewForm (Applet, 'Main Form').SetPosition(120,120).SetSize(400,200);
     Label1    := NewLabel(MainForm, 'TEST-1').SetPosition( 20, 20);
     Label1.Transparent := true;
    //дочерняя форма
     ChildForm := NewForm (MainForm, 'Child Form').SetPosition(220,220).SetSize(400,200);
     Label2    := NewLabel(ChildForm,'TEST-2').SetPosition( 20, 20);
     Label2.Transparent := true;
    //поехали...
     Run(Applet);
    end.



    По неким причинам, связанным с совместимостью, у меня в работе "правленная" 1.69
    И там это исправлено. Т.е., мне известна причина баги, и способы ее устранения (чего уже не скажу про версию 2.88)
    Просто я бесконечно удивлен "долгожительством" этой баги.
    Может пора поправить, а ???
  • D[u]fa (11.06.09 10:35) [1]
    дык выложил бы исправление хотя бы для старой версии
  • Galkov (11.06.09 11:23) [2]
    Дык они отличаются как небо и земля. И не всегда в лучшую сторону :)

    А смысл очень простой: получивши ivalidate в нижнем контролле, мы всегда "передаем" его на верх. Тому, кто и будет рисовать на самом деле.
    Так вот: не надо передавать енто паренту тупо, на ФОРМЕ следует таки остановиться.
    Вот и вся премудрость...

    В старых версиях этим делом занимался TControl.DblBufTopParent, и в нем фикс элементарен:

    function TControl.DblBufTopParent: PControl;
    var Ctl: PControl;
    begin
     Result := nil;
     Ctl := @ Self;
     while Ctl <> nil do
     begin
       if Ctl.fDoubleBuffered then
         Result := Ctl;
       if Ctl.isForm then exit; // <-- да вот он
       Ctl := Ctl.fParent;
     end;
    end;



    Это пригодно только для демонстрации смысла сказанного, естественно
  • D[u]fa (11.06.09 15:07) [3]
    Ага смысл понял, но отличий действительно очень много.. хотя попробовать поковырять новую версию все же стоит..
  • Hallif © (12.06.09 19:20) [4]
    Galkov, попробуйте с директивой OLD_TRANSPARENT
    Начиная с версии 2.24 введена функция WndProcTransparent, которая на данный момент представлена в двух вариантах: базовая и модифицированная фаст-версия (автор Александр Карпинский). В фаст-версии  часть условий была вынесена из цикла обработки сообщений.
    В частности, эпизод WM_PAINT:  

    ValidateRect(Sender.fHandle, nil);
       if (Sender.fTransparent) and (not Sender.fParentRequirePaint) then begin
                        InvalidateRect(Sender.fParent.Handle, nil, FALSE);
                        Result := TRUE;


    теперь находится в несколько измененном виде под условием

    if (Sender.fTransparent or Sender.fDoubleBuffered)
     and (Sender.FParent <> nil)
     and Sender.FParent.fDoubleBuffered
     and (not Sender.fParentRequirePaint)  then…


    Предположительно для дочернего контролла существует альтернативный вызов при
    fTransparent =0, fDoubleBuffered=1
    Решением в данном случае, будет скорее всего замена части условия на
    if (Sender.fTransparent or (not Sender.fDoubleBuffered)…
    или вообще на   if Sender.fTransparent …
  • Galkov (12.06.09 22:59) [5]
    Hallif вот Вы пальцем показали на ValidateRect, и соответствующий InvalidateRect для Sender.fParent
    Это категорически неправильно для случая, когда этот парент является owner-ом
    Неправильно, и все тут.
    Тут даже не очень важно, успел ли кто придумать визуализацию этого "неправильно".
    Не, ну можно сказать: "нет контр-примера - нет ошибки".
    Сказать-то можно, а ошибка - будет, еще через год... Ну нельзя же всю жизнь делать один и тот же код.

    В принципе, если приведенный Вами код из NEW_TRANSPARENT заменить на такой (кстати, первое условие там - это уже "давно проверенное" условие):

     if (not Sender.isForm)
     and Sender.FParent.fDoubleBuffered
     and (not Sender.fParentRequirePaint) then



    - то стартовой баги не видно. Зато становятся видны другие :)

    В общем, надо ставить "трассировщики", и со всем аккуратно разбираться.
    Правда мне казалось, что сделать это авторам сих TRANSPARENT-ов было бы на порядок проще :(
  • D[u]fa (14.06.09 11:00) [6]
    При OLD_TRANSPARENT глюка невидно почему не правильно то? оО
    И при NEW_TRANSPARENT после добавления (not Sender.isForm) тоже бага нет...


    > - то стартовой баги не видно. Зато становятся видны другие
    > :)


    какие другие?
  • Galkov (14.06.09 20:43) [7]

    > При OLD_TRANSPARENT глюка невидно почему не правильно то?

    Это значит его будет видно кому-то через год.
    Оставлять неразорвавшиеся мины в чистом поле, даже если нашел обходной путь - это не правильно. Правильно - обезвреживать мины.
    "Мина", это когда по WM_PAINT в ClildForm он делается валидным, зато инвалидся MainForm.
    А делается именно так: коллега Hallif в это место пальцем ведь показал.
    Ну не нарисует MainForm ничего в ChildForm. Просто, чтобы это увидеть - нужны, наверное, более тонкие примеры... Которые рано или поздно появятся.
    И вот мне кажется, что правильней не искать эти примеры ради самих примеров, а мину напрочь обезвредить, а потом уже ждать примеров.


    > какие другие?

    а) минимизируем ChildForm, и видим артефакты на MainForm
    б) более того, усмотреть артефакты на MainForm можно и без фикса. Убираем прозрачность с Label1 (просто комментируем строку в стартовом примере) - типа все правильно работает и без фиксов. Дулю с маком, на самом деле.
    Передвигаем ChildForm, чтобы он перекрывал Label1, и опять минимизация.
    Вот вам и артефакты на Label1
  • Galkov (14.06.09 20:58) [8]
    Вот же ж блин :shock:
    Если вышеприведенный мной "якобы фикс" делать в таком виде (разница - жирная):

     if (Sender.fParent<>nil) and (not Sender.isForm)
     and Sender.FParent.fDoubleBuffered
     and (not Sender.fParentRequirePaint) then
     begin
       TR := Sender.BoundsRect;
       InvalidateRect(Sender.fParent.fHandle, @TR, true);
       ValidateRect(Sender.fHandle, nil);  //???--brandys???+
       exit;
     end;



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

    Неужели получается, что теперь, для полного удовольствия -- осталось только придумать получение TR не тупо через BoundsRect, а через GetUpdateRect....
  • D[u]fa (14.06.09 22:05) [9]
    А у меня они остались =\
    хотя с OLD_TRANSPARENT артефактов нет... КОЛ все же библиотека для создания компактного кода, поэтому кому надо то будет использовать OLD_TRANSPARENT.... и вот когда через Х лет найдет новый баг, тогда его и будут исправлять))
  • Galkov (15.06.09 08:56) [10]
    Ваша правда, коллега - остались. Это я глухо тупанул, Sorry :(

    Да фигня все это. Чудес не бывает
    Исправлю, да и все... Один раз справился (с 1.69), и второй раз - тоже справлюсь.
    Кстати говоря, пытался "ее" насиловать аналогичными методами - ничего не вышло, все чистенько до противности. Похоже, что объем тестирования у нас был не хуже, чем здесь. Мягко говоря...
    Вот выберу свободное время только.
    Если уж Авторы отмалчиваются :(
  • D[u]fa (15.06.09 10:05) [11]
    Ну мнение авторов примерно отражено в 9 посте)
    Поэтому могу только пожелать свободного времени и удачи, либо забить до новых багов =)
  • Galkov (15.06.09 17:20) [12]
    Если в я чего решил, то выпью обязательно :D

    Да, надо бы еще как-то придумать, как выделить из своих фиксов в 1.69-й те, которыми в 2.88 и не пахнет...
    Кроме SetCurIndex еще парочка-то -- точно найдется... Больше, наверное...
  • D[u]fa (16.06.09 09:59) [13]
    Я предлагаю выложить все фиксы =) возможно коллективно удастся "впихнуть" в новую версию
 
Конференция "KOL" » Очень Древний Баг с прозрачностью (DoubleBuffered)
Есть новые Нет новых   [134431   +11][b:0][p:0.002]