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

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Помогите победить TListView  (Прочитано 20408 раз)
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
Гость
« Ответ #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
Гость
« Ответ #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
Гость
« Ответ #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
Гость
« Ответ #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
Гость
« Ответ #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 » new

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

С прорисовкой 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