Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Помогите победить TListView  (Прочитано 15681 раз)
0 Пользователей и 1 Гость смотрят эту тему.
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« : 29-12-2005 04:28 » 

Пытаюсь оформить TListView используя событие OnCustomDrawItem. Все рисуется но! при изменении размера колонки строка не обновляется полностью и появляется вот такой глюк:

насколько я понял TListView блокирует прорисовку всей строки.
вот код самого Event-а:
Код:
procedure TViewMsgForm.MailListViewCustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
var Rect:TRect; i:Integer;
begin
  with Sender.Canvas do
  begin
   //закрашиваю строку нужным цветом
   Rect:=Item.DisplayRect(drBounds);
   if Item.Selected then
   begin Brush.Color:=clHighlight; Font.Color:=clWhite; end
   else
   begin Brush.Color:=clWhite; Font.Color:=clBlack; end;
   FillRect(Rect);
 
  //вывод текста Caption (1-я колонка)
   rect:=Item.DisplayRect(drLabel);
   if Item.StateIndex=1 then Font.Style:=[fsBold]
   else Font.Style:=[];   
   TextRect(Rect,Rect.Left+2,rect.Top+2,Item.Caption);

   //вывод текста SubItems
   rect:=Item.DisplayRect(drBounds);
   for i := 0 to Item.SubItems.Count - 1 do
   begin
    Rect.Left:=rect.Left+TListView(Sender).Columns[i].Width;
    Rect.Right:=rect.Left+TListView(Sender).Columns[i+1].Width;
    TextRect(rect,rect.Left+2,rect.Top+2,Item.SubItems[i]);
   end;   
  end;
 DefaultDraw:=false;
end;
Как с этим жить иль боротся?
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #1 : 29-12-2005 04:58 » 

Попробуй после изменения размера колонки вставить MailListView.Invalidate
Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #2 : 29-12-2005 05:20 » 

Во-первых TListView почемуто не хочет вызывать OnColumnDragged.
Во-вторых глюк проявляется и во время изменения размера колонки  :nono:  Ха-ха-ха
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #3 : 30-12-2005 07:58 » 

Не знаю, у себя проверил твой код, все нормально работает, никаких глюков при изменении размеров колонки не обнаружил. Может ты где еще перерисовываешь свой ListView, к примеру в OnPaint. Покажи остальной код, может понятнее станет.
Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 31-12-2005 09:28 » 

может это зависит от версии Delphi.
У меня шестая, со всеми сервиспаками.
Остальной код приводить нет смысла, т.к. там только устанавливаются значения Item.StateIndex.
« Последнее редактирование: 31-12-2005 09:35 от RomCom » Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 01-01-2006 15:06 » 

Оказывается все дело в виндах Улыбаюсь
Я в основном работаю в WinXP, а тут решил проверить этот код под Win98 и о чудо, все работает.
Теперь вообще не знаю что делать, источник проблемы нашел, но легче от этого не стало.
У кого нить есть мысли идеи насчет особенностей вывода графики в WinXP?

P.S. С новым годом All!!!!
Пусть ваши проблемы решаются сами собой. Да не иссякнет ваш источник вдохновения искусства програмера.
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #6 : 01-01-2006 22:45 » 

У меня WinXP, Delphi6, никаких глюков не наблюдаю.
Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 02-01-2006 08:05 » 

Тогда не знаю что и думать.
Глюк явно проявляется на моей операционке (причем как на работе так и дома, везде стоит WinXP sp1), только не понятно что является причиной.
Так же я заметил разницу в "алгоритме" изменения размера колонок в Win98 и WinXP. В первом случае новый размер показывается полосой во время изменения и только в конце строки перерисовываются на новом месте, во втором случае содержимое строк перетаскивается в "реальном времени". Возможно дело как раз в этом. Честно говоря для меня не понятно почему появляются эти различия. Я просмотрел весь код компонента но не нашел какой либо привязки к ОС.
Как мне кажется это нельзя так оставлять, т.к. раз этот глюк появился у меня то может проявиться и у других пользователей и не факт что только при изменении размера колонок.
Кому не в тягость проверьте у себя на компе. Вот архив с тестовым exe-шником и проектом: http://www.romcom.ru/download/TestLB.zip
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
Oldy
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 02-01-2006 19:11 » 

Глюк подтверждаю WinXP Pro SP2
Записан

С уважением, Oldy.
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #9 : 02-01-2006 22:14 » 

Явно проблема в отрисовке, так как контрол который создает заголовок совершенно другой с другим хэндлом, в обработчике OnMouseUp не срабатывает. Вот решение проблемы, может не очень красивое, но искать глубоко в компоненте у меня нет времени:
Код:
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
 If msg.message=WM_LBUTTONUP then
 begin
  ListView1.Invalidate;
 end;
 Handled:=False;
end;
Боле оптимально будет еще проверять положение курсора мыши, если в области заголовка то тогда вызывать Invalidate.
Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #10 : 03-01-2006 08:07 » 

Частично проблемка решилась через обработку события WM_NOTIFY.
Код:
type
  TForm1 = class(TForm)
  private
    { Private declarations }
    OldWindowProc:TWndMethod;
    LV_Header:HWND;
    procedure NewWindowProc(var Message: TMessage);

....

procedure TForm1.FormCreate(Sender: TObject);
begin
 OldWindowProc:=ListView1.WindowProc;
 ListView1.WindowProc:=NewWindowProc;
 LV_Header:=SendMessage(ListView1.Handle,LVM_GETHEADER,0,0);
end;

procedure TForm1.NewWindowProc(var Message: TMessage);
begin
      case Message.Msg of
       WM_NOTIFY:
          with PHDNotify(Pointer(Message.LParam))^ do
          begin
           if LV_Header=Hdr.hwndFrom then
            case Hdr.code of
              HDN_ENDTRACKW:
               ListView1.Invalidate;
            end;
          end;
      end;
 OldWindowProc(Message);
end;
Покрайней мере теперь ТListView перерисовывется в конце изменеия колонки. Если покапатся еще по глубже можно и остальное устранить.
Разница в работе компонента в разных ОС связана (ИМХО) с версией ComCtl32.dll (у меня она 6-я).
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
x77
Модератор

ro
Offline Offline
Пол: Мужской
меняю стакан шмали на обратный билет с Марса.


« Ответ #11 : 05-01-2006 06:24 » 

мужики, а настройки рабочего стола не сверяли? в частности, опцию прорисовки окон при перетаскивании?
Записан

RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #12 : 05-01-2006 15:12 » 

Сегодня почти целый день убил разбираясь как сам компонент перерисовывает строки. Испробовал с десяток способов борьбы.
В итоге понял что без обработки сообщения NM_CUSTOMDRAW ничего путного не получится.
Вот что у меня получилось в итоге:
Код:
procedure TForm1.FormCreate(Sender: TObject);
begin
 OldWindowProc:=ListView1.WindowProc;
 ListView1.WindowProc:=NewWindowProc;
end;

function TForm1.CustomDrawLV(nmlvcd:TNMLVCustomDraw):Integer;
var SubItem:Boolean;
begin
 Result := CDRF_DODEFAULT;
 if (nmlvcd.nmcd.dwDrawStage and CDDS_ITEM) = 0 then
 begin
  if nmlvcd.nmcd.dwDrawStage=CDDS_PREPAINT then
       Result := CDRF_NOTIFYITEMDRAW or CDRF_NOTIFYPOSTPAINT or CDRF_NOTIFYPOSTERASE or CDRF_NOTIFYSUBITEMDRAW;
 end else
 begin
  SubItem := (nmlvcd.nmcd.dwDrawStage and CDDS_SUBITEM) <> 0;
  if SubItem and (nmlvcd.iSubItem = 0) then Exit;

  if nmlvcd.nmcd.dwDrawStage and CDDS_ITEMPREPAINT <> 0 then
  begin
   if not SubItem then
   begin
    //рисую 1-ю колонку (Caption)
    CustomDrawItem(ListView1,ListView1.Items[nmlvcd.nmcd.dwItemSpec]);
    //Result := Result or CDRF_SKIPDEFAULT; //Если здесь убрать слеши то не рисуются СубИтемы
    Result := Result or CDRF_NOTIFYSUBITEMDRAW or CDRF_NOTIFYPOSTPAINT or CDRF_NOTIFYPOSTERASE;
   end
   else
   begin
    //рисую SubItem (2-я и последующие колонки)
    CustomDrawSubItem(ListView1,ListView1.Items[nmlvcd.nmcd.dwItemSpec],nmlvcd.iSubItem);
    Result := Result or CDRF_SKIPDEFAULT or CDRF_NOTIFYPOSTPAINT or CDRF_NOTIFYPOSTERASE;
   end;
  end;
 end;
end;

procedure TForm1.NewWindowProc(var Message: TMessage);
begin
 case Message.Msg of
   CN_NOTIFY:
     with TWMNotify(Message) do
      if NMHdr^.code=NM_CUSTOMDRAW then
      begin result:=CustomDrawLV(PNMLVCustomDraw(NMHdr)^);
       Exit;
      end;
 end;
 OldWindowProc(Message);
end;
Все красиво и хорошо, но...
До совершенства не дотягивает. Получается мелькание первой колонки, т.к. ListView тоже ее перерисовывает из-за вот этой строки:
Код:
    Result := Result or CDRF_NOTIFYSUBITEMDRAW or CDRF_NOTIFYPOSTPAINT or CDRF_NOTIFYPOSTERASE;
если же ее заменить на:
Код:
    Result := Result or CDRF_SKIPDEFAULT;
то мелькание исчезает, но не рисуются остальные колонки.
кто-нибудь знает как объяснить ListView что я сам рисую содержимое первой колонки и при этом чтоб можно было рисовать и SubItem?
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
zubr
Модератор

by
Offline Offline
Пол: Мужской

« Ответ #13 : 05-01-2006 22:28 » 

RomCom да чего ты паришся. x77 правильно подсказал, у тебя в настройках системы опция прорисовки окон при перетаскивании включена. При работе своей программы отключай ее программно, а затем опять включай. Вот как можно это сделать программно: SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, 0, nil, 0) - отключить, SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, 1, nil, 0) - включить.
Записан
RomCom
Опытный

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #14 : 07-01-2006 06:09 » 

Изменение настройки системы решает проблему, но это так сказать "обходной маневр". Он снимает эту проблему но не факт что не появятся другие. Так что более верный подход разобраться один раз и быть спокойным за свою прогу.

С прорисовкой SubItem вопрос я решил вызовом CustomDrawSubItem в CustomDrawItem.
Так что тему считаю закрытой.
Записан

R.O.M.C.O.M.: Robotic Operational Mathematics and Ceaseless Observation Machine
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines