Конференция "KOL" » OwnerDraw для ListView [Lazarus, KOL+MCK, Windows]
 
  • Maloric (27.08.08 16:00) [0]
    Можно примерчик, как изменить у некоторых ячеек цвет шрифта, не нашел по OwnerDraw на форуме ничего... =(
  • mdw © (27.08.08 16:02) [1]
    В качестве примера можно посмотреть компонент ECMListEdit
  • Maloric (27.08.08 20:41) [2]
    Да смотрел я его, что то не вкуриваю я в эту систему, буду пробовать раз трудно показать самый простой пример
  • Compiler © (28.08.08 00:28) [3]
    Примеры на форуме есть!!!

    Вот, разбирайся:

    OwnerDrawFixed:=True
    Колонок - 3
    Style=lvsDetail;

    function TForm1.ListView1DrawItem(Sender: PObj; DC: HDC; const Rect: TRect;
     ItemIdx: Integer; DrawAction: TDrawAction;
     ItemState: TDrawState): Boolean;
    var
     br:HBRUSH;
     iR:Trect; iCol:Integer;
     s:string;
    begin
    Result := TRUE;
    iR:=Rect;

    if (odsSelected in ItemState) then begin
      br := GetSysColorBrush(COLOR_HIGHLIGHT);
      SetTextColor(DC,GetSysColor(COLOR_HIGHLIGHTTEXT));
    end else begin  //Отрисовка фона
      br := GetSysColorBrush(COLOR_WINDOW);
    //  SetTextColor(DC,clBlack);
    end;
     FillRect(DC,iR,br);

     for iCol:=0 to Pcontrol(Sender).LVColCount-1 do
     begin
     if (iCol in [1,3]) and (ItemIdx in [2,4,5,7])  then
        SetTextColor(DC,clRed)
     else
        SetTextColor(DC,clBlack);
       
     iR:=Pcontrol(Sender).LVSubItemRect(ItemIdx,iCol);
     if iCol=0 then begin
       iR.Right:=Pcontrol(Sender).LVColWidth[iCol];
       iR.Left:=iR.Left;
      end;
     Inc(iR.Left, 5);
     S:=Pcontrol(Sender).LVItems[ItemIdx,iCol];
     DrawText(DC,@S[1], Length(s),iR,
          DT_SINGLELINE or DT_NOPREFIX or DT_VCENTER or DT_WORD_ELLIPSIS);
     end;
    end;

  • andreil (28.08.08 08:02) [4]
    Хм, раз тут пошло такое дело, не подскажет ли кто, как можно перехватить рисование заголовка ListView'а (Style = lvsDetail)? А то это единственная деталь в программе, которая рисуется не моим кодом :(
  • Maloric (28.08.08 08:50) [5]
    [b]Compiler[/b],

    > Вот, разбирайся

    Спасибо огромное, наконец-то получилось
  • mdw © (28.08.08 12:22) [6]

    > Хм, раз тут пошло такое дело, не подскажет ли кто, как можно
    > перехватить рисование заголовка ListView'а (Style = lvsDetail)?
    >  А то это единственная деталь в программе, которая рисуется
    > не моим кодом :(

    Смотри TKOLmdvHeaderControl. Там есть пользовательская отрисовка заголовка. А в ListView используется тот же SysHeader32.
  • Sapersky (28.08.08 13:18) [7]
    Можно примерчик, как изменить у некоторых ячеек цвет шрифта, не нашел по OwnerDraw на форуме ничего...

    Есть ещё вариант для Listview без ownerdraw. Удобен в тех случаях, когда не нужно всё рисовать по-своему, а только подправить цвет (я изменял цвет фона, но вроде бы можно и шрифта).

    FList.AttachProc( WndProcCustomDraw );

    function WndProcCustomDraw( Sender: PControl; var Msg: TMsg;
                               var Rslt: Integer ): Boolean;
    var NMCustDraw: PNMLVCustomDraw;
       NMHdr: PNMHdr;
       ItemIdx : Integer;
       ItemState: TDrawState;
    begin
    Result := FALSE;
    If Msg.message = WM_NOTIFY then begin
     NMHdr := Pointer( Msg.lParam );
     if (NMHdr.code = NM_CUSTOMDRAW) then begin
       NMCustDraw := Pointer( Msg.lParam );
       ItemIdx := -1;
       If LongBool( NMCustDraw.nmcd.dwDrawStage and CDDS_ITEM ) then begin
         ItemIdx := NMCustDraw.nmcd.dwItemSpec;
         If (ItemIdx > 0) and (нужно выделить данный Item) then
           NMCustDraw.clrTextBk := SelColor; // или NMCustDraw.clrText
         Rslt := 0;
       end else
         Rslt := CDRF_NOTIFYITEMDRAW;
       Result := TRUE;
     end;
    end;
    end;
  • RGaysin © (28.08.08 13:23) [8]
    Как цвет менять я понял, а как стиль изменить шрифта?
  • Compiler © (28.08.08 19:48) [9]
    > RGaysin ©   (28.08.08 13:23) [8]

    Listview1.Font.FontStyle:=[fsBold];
    Listview1.Font.FontName:='Arial Black';
    Listview1.Invalidate;

  • RGaysin © (28.08.08 20:50) [10]

    > Listview1.Font.FontStyle:=[fsBold];Listview1.Font.FontName:
    > ='Arial Black';Listview1.Invalidate;

    Дык я не про это, как DrawText-ом вывести жирный шрифт?
    В примере который Вы выкладавали выше с изменением цвета
  • Compiler © (29.08.08 00:09) [11]
    > RGaysin ©   (28.08.08 20:50) [10]

    А пример-то из [9] пробовали? Меняем у ListView FontStyle и будет жирный шрифт
  • L`Autour © (29.08.08 06:15) [12]
    А можно ли вручную рисовать в ListView элементы разной высоты? (нужно выводить многострочные тексты)
  • RGaysin © (29.08.08 12:17) [13]
    Да нет, он же меняет стиль всей таблицы, а я имел ввиду только в одной ячейке, извиняюсь, за неточность =)
  • L`Autour © (29.08.08 13:23) [14]

    > Да нет, он же меняет стиль всей таблицы, а я имел ввиду
    > только в одной ячейке, извиняюсь, за неточность =)

    Проверяешь строку и столбец текущей отрисовываемой ячейки, меняешь для нужной шрифт и после вывода меняешь его обратно.
  • RGaysin © (29.08.08 15:23) [15]
    Точно забывал убирать стиль.
    А почему тогда все мигает в таблице:
     for iCol:=0 to PControl(Sender).LVColCount-1 do
     begin
       iR:=Pcontrol(Sender).LVSubItemRect(ItemIdx,iCol);
       if iCol=0 then begin
         iR.Right:=PControl(Sender).LVColWidth[iCol];
         iR.Left:=iR.Left;
       end;
       //Отступ в ячейки
       Inc(iR.Left, 8);
       //Обработка текста
       S:=PControl(Sender).LVItems[ItemIdx,iCol];
       SetTextColor(DC,clBlack);
       if (Str2Int(S)>49) then SetTextColor(DC,clRed);
       if (Str2Int(S)>55) then SetTextColor(DC,clGreen);
       if (iCol in [1]) then SetTextColor(DC,clBlue);
       if (Str2Int(S)>49) then PControl(Sender).Font.FontStyle:=[fsBold]
                          else PControl(Sender).Font.FontStyle:=[];
       DrawText(DC,@S[1], Length(s),iR,
       DT_SINGLELINE or DT_NOPREFIX or DT_VCENTER or DT_WORD_ELLIPSIS);
     end;      

  • L`Autour © (01.09.08 08:05) [16]
    А зачем ручную отрисовывать все элементы через цикл? В обработчике нужно управлять прорисовкой только текущего элемента. Только DrawItem в отличии от CustomDraw, вызывается для всей строки, а не для каждого подъэлемента (при отрисовке вручную - не проблема).

    Еще можно в включить двойную буферизацию отрисовки.
  • RGaysin © (01.09.08 12:49) [17]
    Ну я делаю через DrawItem как [b]Compiler[/b] научил. Я пока чайник в этих перехватах отрисовки
  • L`Autour © (01.09.08 14:31) [18]
    Вот мой пример (примерно так сейчас отрисовываю в своей проге):

    function TForm1.ListView1DrawItem(Sender: PObj; DC: HDC;
     const Rect: TRect; ItemIdx: Integer; DrawAction: TDrawAction;
     ItemState: TDrawState): Boolean;
    var
     TempStr: string;
     SolidBrush: HBRUSH;
     DefaultColor: COLORREF;
     R: TRect;
     TextSize: TSize;

     //вывод подъэлементов с формированием многоточия для длинных строк
     procedure SubItemTextOut;
     var
       i, l: Integer;
       d, iprev: Integer;
     begin
       l := Length(TempStr);
       iprev := 0;
       for i := 0 to l do
       begin
         GetTextExtentPoint32W(DC, PWideChar(TempStr), i, TextSize);
         d := (R.Right - R.Left - 4) - TextSize.cx;
         if (d < 0) then
         begin
           if (iprev = 0) then
             iprev := i;
           if (l - iprev <= 3) then
             SetLength(TempStr, l + 3);
           TempStr[iprev] := '.';
           TempStr[iprev + 1] := '.';
           TempStr[iprev + 2] := '.';
           l := iprev + 2;
           Break;
         end //if
         else if (d < 9)and(iprev = 0) then//if
           iprev := i;
       end; //for

       ExtTextOut(DC, R.Left + 4, R.Top, ETO_CLIPPED, @R,
         PWideChar(TempStr), l, nil);
     end;

    begin
     Result := True;

     //смена цвета шрифта и фона для выделения текущего элемента
     DefaultColor := GetTextColor(DC);
     if (odsSelected in ItemState)and(odsFocused in ItemState) then
     begin
       SolidBrush := CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
       FillRect(DC, Rect, SolidBrush);
       DeleteObject(SolidBrush);
       SetTextColor(DC, $FFFFFF - DefaultColor);
     end;// else
       //FillRect(DC, Rect, CreateSolidBrush(GetSysColor(COLOR_WINDOW)));
     R := Rect;

     //вывод подъэлемента 1
     //--тут меняем шрифт--
     TempStr := ListView1.LVItems[ItemIdx, 0]
     R.Right := R.Left + PControl(Sender).LVColWidth[0] - 2;
     SubItemTextOut;

     //вывод подъэлемента 3
     //--тут меняем шрифт--
     TempStr := ListView1.LVItems[ItemIdx, 1]
     R.Left := R.Right + 2;
     R.Right := R.Left + PControl(Sender).LVColWidth[1] - 2;
     SubItemTextOut;

     //вывод подъэлемента 2
     //--тут меняем шрифт--
     TempStr := ListView1.LVItems[ItemIdx, 2]
     R.Left := R.Right + 2;
     R.Right := R.Left + PControl(Sender).LVColWidth[2] - 2;
     SubItemTextOut;

     //возврат цвета по муолчанию
     SetTextColor(DC, DefaultColor);
    end;
  • L`Autour © (01.09.08 14:38) [19]
    С LVustomDraw можно делать вывод только со сменой шрифта и фона, без ручного вывода текста. Но по тех.причинам он мне не подошел и примера дать не могу. Сам находил хорошо расписанные примеры с LVCustomDraw на http://www.delphikingdom.com
  • RGaysin © (01.09.08 15:58) [20]
    Вместо

    if (Str2Int(S)>49) then PControl(Sender).Font.FontStyle:=[fsBold]
    else PControl(Sender).Font.FontStyle:=[];


    вставил

    Font: Cardinal;
    LFont: LOGFONT;
    FillChar( LFont, SizeOf( LFont ), 0 );
    LFont.lfHeight := LV1.Font.FontHeight;
    LFont.lfFaceName:='Verdana';
    if (iCol in [1]) then LFont.lfWeight:=700
                      else LFont.lfWeight:=0;
    Font := CreateFontIndirect(LFont);
    SelectObject(DC,Font);

     
    Перестало маргать =)
  • L`Autour © (02.09.08 06:18) [21]
    Я шрифты через CreateFontIndirect создаю при инициализации формы и уничтожаю при закрытии программы. Создавать и удалять шрифт в процессе вывода - не оптимально.
  • RGaysin © (02.09.08 18:27) [22]
    Эх, точно, это я не подумал! Спасибо за подсказку)
 
Конференция "KOL" » OwnerDraw для ListView [Lazarus, KOL+MCK, Windows]
Есть новые Нет новых   [134432   +18][b:0][p:0.002]