在TListView的绘制一个复选框 [英] drawing a checkbox in a TListView

查看:270
本文介绍了在TListView的绘制一个复选框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要画一个复选框,在特定列在的TListView ,所以我检查这个问题,<一个href=\"http://stackoverflow.com/questions/5478972/how-can-i-setup-tlistview-with-checkboxes-in-only-certain-columns\"><$c$c>How我可以设置使用的TListView只有某些列的CheckBox? 和接受的答案建议使用此另一个问题<一描述的方法href=\"http://stackoverflow.com/questions/5306037/how-to-set-a-checkbox-tstringgrid-in-delphi\"><$c$c>How在德尔福设置复选框TStringGrid中 ,现在移植是code。与一个ListView我带着这个工作:

 程序TForm15.ListView1CustomDrawSubItem(发件人:TCustomListView;项目:TListItem;子项目:整数;状态:TCustomDrawState; VAR DefaultDraw:布尔);
常量
  PADDING = 4;
VAR
  H:HTHEME;
  小号:TSIZE;
  R:TRect;
  RECT:TRect;
  我:整数;
  DX:整数;
开始
  如果(分项= 1),然后
  开始
    DefaultDraw:= TRUE;
    矩形:= Item.DisplayRect(drBounds);
    DX:= 0;    对于i:= 0到子项目办
    公司(霉素,Sender.Column [I] .WIDTH);
    Rect.Left:= Rect.Left +霉素;    Rect.Right:= Rect.Left + Sender.Column [子项目+ 1] .WIDTH;    FillRect(Sender.Canvas.Handle,矩形,GetStockObject(WHITE_BRUSH));
    s.cx:= GetSystemMetrics的(SM_CXMENUCHECK);
    s.cy:= GetSystemMetrics的(SM_CYMENUCHECK);
    如果UseThemes然后
    开始
      H:= OpenThemeData(Sender.Handle,按钮);
      如果H&LT;&GT; 0,则
        尝试
          GetThemePartSize(H,Sender.Canvas.Handle,BP_CHECKBOX,CBS_CHECKEDNORMAL,零,TS_DRAW,S);
          r.Top:= Rect.Top +(Rect.Bottom - Rect.Top - s.cy)DIV 2;
          r.Bottom:= r.Top + s.cy;
          r.Left:= Rect.Left + PADDING;
          r.Right:= r.Left + s.cx;
          DrawThemeBackground(小时,Sender.Canvas.Handle,BP_CHECKBOX,ifthen以(CompareText(Item.SubItems [1],'真')= 0,CBS_CHECKEDNORMAL,CBS_UNCHECKEDNORMAL)中,r,无);
        最后
          CloseThemeData(H);
        结束;
    结束
    其他
    开始
      r.Top:= Rect.Top +(Rect.Bottom - Rect.Top - s.cy)DIV 2;
      r.Bottom:= r.Top + s.cy;
      r.Left:= Rect.Left + PADDING;
      r.Right:= r.Left + s.cx;
      DrawFrameControl(Sender.Canvas.Handle,R,DFC_BUTTON,ifthen以(CompareText(Item.SubItems [1],'真')= 0,DFCS_CHECKED,DFCS_BUTTONCHECK));
    结束;
   // R:= Classes.Rect(r.Right + PADDING,Rect.Top,Rect.Right,Rect.Bottom);
   // DrawText的(Sender.Canvas.Handle,StringGrid1.Cells [ACOL,AROW],长度(StringGrid1.Cells [ACOL,AROW]),R,DT_SINGLELINE或DT_VCENTER或DT_LEFT或DT_END_ELLIPSIS);
  结束
  其他
  DefaultDraw:= FALSE;
结束;

但我在试图绘制一个复选框:(惨遭失败,有人可以点我在正确的方向绘制在ListView中的复选框,(在code不画在ListView任何复选框)。

ListView控件是vsReport模式,并有3列,我希望把复选框中的第三列。请不要认为它们使用THRID党组成部分,我想用TListView的控制。

更新1 :感谢sertac recomendattion设置 DefaultDraw 值现在复选框显示,但另一列看起来awfull

更新2 ,继安德烈亚斯建议列表视图现在看起来更好,但仍显示黑盒;

 程序TForm15.ListView1CustomDrawSubItem(发件人:TCustomListView;项目:TListItem;子项目:整数;状态:TCustomDrawState; VAR DefaultDraw:布尔);
VAR
  H:HTHEME;
  小号:TSIZE;
  R:TRect;
  RECT:TRect;
  我:整数;
  DX:整数;
开始
  如果(分项= 2),然后
  开始
    DefaultDraw:= FALSE;
    矩形:= Item.DisplayRect(drBounds);    DX:= 0;
    对于i:= 0分项目-1做
      公司(霉素,Sender.Column [I] .WIDTH);    Rect.Left:= Rect.Left +霉素;
    Rect.Right:= Rect.Left + Sender.Column [子项目] .WIDTH;
    FillRect(Sender.Canvas.Handle,矩形,GetStockObject(WHITE_BRUSH));
    s.cx:= GetSystemMetrics的(SM_CXMENUCHECK);
    s.cy:= GetSystemMetrics的(SM_CYMENUCHECK);
    DX:=(Sender.Column [子项目] .WIDTH-GetSystemMetrics的(SM_CXMENUCHECK))DIV 2;
    如果UseThemes然后
    开始
      H:= OpenThemeData(Sender.Handle,按钮);
      如果H&LT;&GT; 0,则
        尝试
          GetThemePartSize(H,Sender.Canvas.Handle,BP_CHECKBOX,CBS_CHECKEDNORMAL,零,TS_DRAW,S);
          r.Top:= Rect.Top +(Rect.Bottom - Rect.Top - s.cy)DIV 2;
          r.Bottom:= r.Top + s.cy;
          r.Left:= Rect.Left +霉素;
          r.Right:= r.Left + s.cx;
          DrawThemeBackground(H,Sender.Canvas.Handle,BP_CHECKBOX,ifthen以(CompareText(Item.SubItems [分项-1],'真')= 0,CBS_CHECKEDNORMAL,CBS_UNCHECKEDNORMAL),R,无);
        最后
          CloseThemeData(H);
        结束;
    结束
    其他
    开始
      r.Top:= Rect.Top +(Rect.Bottom - Rect.Top - s.cy)DIV 2;
      r.Bottom:= r.Top + s.cy;
      r.Left:= Rect.Left +霉素;
      r.Right:= r.Left + s.cx;
      DrawFrameControl(Sender.Canvas.Handle,R,DFC_BUTTON,ifthen以(CompareText(Item.SubItems [子项目-1],'真')= 0,DFCS_CHECKED,DFCS_BUTTONCHECK));
    结束;
  结束;
结束;


解决方案

要摆脱这种错误的一个比较简单的办法是业主绘制整个项目。设置的OwnerDraw:= TRUE ,删除你的 OnCustomDrawSubItem 常规,并添加

 程序TForm15.ListView1DrawItem(发件人:TCustomListView;项目:TListItem;
  RECT:TRect;状态:TOwnerDrawState);  功能ShrinkRect(常量R:TRect; const的X0,X1,Y0,Y1:整数):TRect;一致;
  开始
    结果:= R;
    INC(result.Left,X0);
    增量(result.Top,Y0);
    DEC(result.Right,X1);
    分解(result.Bottom,Y1);
  结束;常量
  CHECK_COL = 2;
  PADDING = 4;
VAR
  R:TRect;
  我:整数;
  小号:字符串;
  大小:TSIZE;
  H:HTHEME;
开始  FillRect(Sender.Canvas.Handle,矩形,GetStockObject(WHITE_BRUSH));
  R:=矩形;
  INC(r.Left,填充);
  对于i:= 0的TListView(发件人).Columns.Count - 1做
  开始
    r.Right:= r.Left + Sender.Column [I] .WIDTH;
    如果我&LT;&GT; CHECK_COL然后
    开始
      若i = 0,则
      开始
        小号:= Item.Caption;
        如果不是IsWindowVisible(ListView_GetEditControl(Sender.Handle)),然后
        开始
          如果UseThemes和([odSelected,odHotLight] *州及LT;&GT; []),那么
          开始
            H:= OpenThemeData(Sender.Handle,'LISTVIEW');
            如果H&LT;&GT; 0,则
              尝试
                DrawThemeBackground(小时,Sender.Canvas.Handle,LVP_GROUPHEADER,ifthen以(在国家,LVGH_CLOSESELECTED,LVGH_OPENHOT)odSelected,ShrinkRect(R,-2,6,1,1),无);
              最后
                CloseThemeData(H);
              结束;
          结束;
          如果(在国家odSelected),而不是UseThemes然后
            DrawFocusRect(Sender.Canvas.Handle,ShrinkRect(R,-2,6,1,1));
        结束;
      结束
      其他
        小号:= Item.SubItems [我 - 1];
      Sender.Canvas.Brush.Style:= bsCle​​ar;
      DrawText的(Sender.Canvas.Handle,
        PChar类型(多个),
        长度(S),
        R,
        DT_SINGLELINE或DT_VCENTER或DT_LEFT或DT_END_ELLIPSIS);
    结束
    其他
    开始      size.cx:= GetSystemMetrics的(SM_CXMENUCHECK);
      size.cy:= GetSystemMetrics的(SM_CYMENUCHECK);
      如果UseThemes然后
      开始
        H:= OpenThemeData(Sender.Handle,按钮);
        如果H&LT;&GT; 0,则
          尝试
            GetThemePartSize(H,Sender.Canvas.Handle,BP_CHECKBOX,CBS_CHECKEDNORMAL,零,TS_DRAW,大小);
            r.Top:= Rect.Top +(Rect.Bottom - Rect.Top - size.cy)DIV 2;
            r.Bottom:= r.Top + size.cy;
            r.Left:= r.Left + PADDING;
            r.Right:= r.Left + size.cx;
            DrawThemeBackground(小时,Sender.Canvas.Handle,BP_CHECKBOX,ifthen以(CompareText(Item.SubItems [1],'真')= 0,CBS_CHECKEDNORMAL,CBS_UNCHECKEDNORMAL)中,r,无);
          最后
            CloseThemeData(H);
          结束;
      结束
      其他
      开始
        r.Top:= Rect.Top +(Rect.Bottom - Rect.Top - size.cy)DIV 2;
        r.Bottom:= r.Top + size.cy;
        r.Left:= r.Left + PADDING;
        r.Right:= r.Left + size.cx;
        DrawFrameControl(Sender.Canvas.Handle,R,DFC_BUTTON,ifthen以(CompareText(Item.SubItems [1],'真')= 0,DFCS_CHECKED,DFCS_BUTTONCHECK));
      结束;    结束;
    INC(r.Left,Sender.Column [I] .WIDTH);
  结束;结束;

上面的code需要进一步测试,但可能是在正确的方向。现在是很晚了,我得走了。

I need to draw a checkbox in a particular column in aTListView, so i check this question How can I setup TListView with CheckBoxes in only certain columns? and in the accepted answer suggest use the method described in this another question How to set a Checkbox TStringGrid in Delphi?, now porting that code to work with a ListView i come with this :

procedure TForm15.ListView1CustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean);
const
  PADDING = 4;
var
  h    : HTHEME;
  s    : TSize;
  r    : TRect;
  Rect : TRect;
  i    : Integer;
  Dx   : Integer;
begin
  if (SubItem=1) then
  begin
    DefaultDraw:=True;
    Rect  :=Item.DisplayRect(drBounds);
    Dx:=0;

    for i := 0 to SubItem do
    Inc(Dx,Sender.Column[i].Width);
    Rect.Left  :=Rect.Left+Dx;

    Rect.Right :=Rect.Left+Sender.Column[SubItem+1].Width;

    FillRect(Sender.Canvas.Handle, Rect, GetStockObject(WHITE_BRUSH));
    s.cx := GetSystemMetrics(SM_CXMENUCHECK);
    s.cy := GetSystemMetrics(SM_CYMENUCHECK);
    if UseThemes then
    begin
      h := OpenThemeData(Sender.Handle, 'BUTTON');
      if h <> 0 then
        try
          GetThemePartSize(h, Sender.Canvas.Handle, BP_CHECKBOX, CBS_CHECKEDNORMAL, nil, TS_DRAW, s);
          r.Top    := Rect.Top + (Rect.Bottom - Rect.Top - s.cy) div 2;
          r.Bottom := r.Top + s.cy;
          r.Left   := Rect.Left + PADDING;
          r.Right  := r.Left + s.cx;
          DrawThemeBackground(h, Sender.Canvas.Handle, BP_CHECKBOX, IfThen(CompareText(Item.SubItems[1],'True')=0, CBS_CHECKEDNORMAL, CBS_UNCHECKEDNORMAL), r, nil);
        finally
          CloseThemeData(h);
        end;
    end
    else
    begin
      r.Top    := Rect.Top + (Rect.Bottom - Rect.Top - s.cy) div 2;
      r.Bottom := r.Top + s.cy;
      r.Left   := Rect.Left + PADDING;
      r.Right  := r.Left + s.cx;
      DrawFrameControl(Sender.Canvas.Handle, r, DFC_BUTTON, IfThen(CompareText(Item.SubItems[1],'True')=0, DFCS_CHECKED, DFCS_BUTTONCHECK));
    end;
   //r := Classes.Rect(r.Right + PADDING, Rect.Top, Rect.Right, Rect.Bottom);
   // DrawText(Sender.Canvas.Handle,   StringGrid1.Cells[ACol, ARow], length(StringGrid1.Cells[ACol, ARow]),  r, DT_SINGLELINE or DT_VCENTER or DT_LEFT or DT_END_ELLIPSIS);
  end
  else
  DefaultDraw:=False;
end;

but i fail miserably in my attempt to draw a checkbox :(, can someone point me in the right direction to draw the checkbox in the listview, (the code does not draw any checkbox in the listview).

The listview is in vsReport mode and had 3 columns, i want put the checkbox in the third column. please don't suggest which use a thrid party component, i want use the TlistView control.

UPDATE 1 : thanks to the sertac recomendattion setting the DefaultDraw value now the checkboxes are shown, but the another columns looks awfull.

UPDATE 2 , following the Andreas suggestions the listview now look better, but still shown the black box;

procedure TForm15.ListView1CustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; var DefaultDraw: Boolean);
var
  h    : HTHEME;
  s    : TSize;
  r    : TRect;
  Rect : TRect;
  i    : Integer;
  Dx   : Integer;
begin
  if (SubItem=2) then
  begin
    DefaultDraw:=False;
    Rect  :=Item.DisplayRect(drBounds);

    Dx:=0;
    for i := 0 to SubItem-1 do
      Inc(Dx,Sender.Column[i].Width);

    Rect.Left  :=Rect.Left+Dx;
    Rect.Right :=Rect.Left+Sender.Column[SubItem].Width;
    FillRect(Sender.Canvas.Handle, Rect, GetStockObject(WHITE_BRUSH));
    s.cx := GetSystemMetrics(SM_CXMENUCHECK);
    s.cy := GetSystemMetrics(SM_CYMENUCHECK);
    Dx   := (Sender.Column[SubItem].Width-GetSystemMetrics(SM_CXMENUCHECK)) div 2;
    if UseThemes then
    begin
      h := OpenThemeData(Sender.Handle, 'BUTTON');
      if h <> 0 then
        try
          GetThemePartSize(h, Sender.Canvas.Handle, BP_CHECKBOX, CBS_CHECKEDNORMAL, nil, TS_DRAW, s);
          r.Top    := Rect.Top + (Rect.Bottom - Rect.Top - s.cy) div 2;
          r.Bottom := r.Top + s.cy;
          r.Left   := Rect.Left + Dx;
          r.Right  := r.Left + s.cx;
          DrawThemeBackground(h, Sender.Canvas.Handle, BP_CHECKBOX, IfThen(CompareText(Item.SubItems[SubItem-1],'True')=0, CBS_CHECKEDNORMAL, CBS_UNCHECKEDNORMAL), r, nil);
        finally
          CloseThemeData(h);
        end;
    end
    else
    begin
      r.Top    := Rect.Top + (Rect.Bottom - Rect.Top - s.cy) div 2;
      r.Bottom := r.Top + s.cy;
      r.Left   := Rect.Left + Dx;
      r.Right  := r.Left + s.cx;
      DrawFrameControl(Sender.Canvas.Handle, r, DFC_BUTTON, IfThen(CompareText(Item.SubItems[SubItem-1],'True')=0, DFCS_CHECKED, DFCS_BUTTONCHECK));
    end;
  end;
end;

解决方案

One relatively simple way to get rid of this bug is to owner-draw the entire item. Set OwnerDraw := true, remove your OnCustomDrawSubItem routine, and add

procedure TForm15.ListView1DrawItem(Sender: TCustomListView; Item: TListItem;
  Rect: TRect; State: TOwnerDrawState);

  function ShrinkRect(const r: TRect; const X0, X1, Y0, Y1: integer): TRect; inline;
  begin
    result := r;
    inc(result.Left, X0);
    inc(result.Top, Y0);
    dec(result.Right, X1);
    dec(result.Bottom, Y1);
  end;

const
  CHECK_COL = 2;
  PADDING = 4;
var
  r: TRect;
  i: Integer;
  s: string;
  size: TSize;
  h: HTHEME;
begin

  FillRect(Sender.Canvas.Handle, Rect, GetStockObject(WHITE_BRUSH));
  r := Rect;
  inc(r.Left, PADDING);
  for i := 0 to TListView(Sender).Columns.Count - 1 do
  begin
    r.Right := r.Left + Sender.Column[i].Width;
    if i <> CHECK_COL then
    begin
      if i = 0 then
      begin
        s := Item.Caption;
        if not IsWindowVisible(ListView_GetEditControl(Sender.Handle)) then
        begin
          if UseThemes and ([odSelected, odHotLight] * State <> []) then
          begin
            h := OpenThemeData(Sender.Handle, 'LISTVIEW');
            if h <> 0 then
              try
                DrawThemeBackground(h, Sender.Canvas.Handle, LVP_GROUPHEADER, IfThen(odSelected in State, LVGH_CLOSESELECTED, LVGH_OPENHOT), ShrinkRect(r, -2, 6, 1, 1), nil);
              finally
                CloseThemeData(h);
              end;
          end;
          if (odSelected in State) and not UseThemes then
            DrawFocusRect(Sender.Canvas.Handle, ShrinkRect(r, -2, 6, 1, 1));
        end;
      end
      else
        s := Item.SubItems[i - 1];
      Sender.Canvas.Brush.Style := bsClear;
      DrawText(Sender.Canvas.Handle,
        PChar(s),
        length(s),
        r,
        DT_SINGLELINE or DT_VCENTER or DT_LEFT or DT_END_ELLIPSIS);
    end
    else
    begin

      size.cx := GetSystemMetrics(SM_CXMENUCHECK);
      size.cy := GetSystemMetrics(SM_CYMENUCHECK);
      if UseThemes then
      begin
        h := OpenThemeData(Sender.Handle, 'BUTTON');
        if h <> 0 then
          try
            GetThemePartSize(h, Sender.Canvas.Handle, BP_CHECKBOX, CBS_CHECKEDNORMAL, nil, TS_DRAW, size);
            r.Top    := Rect.Top + (Rect.Bottom - Rect.Top - size.cy) div 2;
            r.Bottom := r.Top + size.cy;
            r.Left   := r.Left + PADDING;
            r.Right  := r.Left + size.cx;
            DrawThemeBackground(h, Sender.Canvas.Handle, BP_CHECKBOX, IfThen(CompareText(Item.SubItems[1],'True')=0, CBS_CHECKEDNORMAL, CBS_UNCHECKEDNORMAL), r, nil);
          finally
            CloseThemeData(h);
          end;
      end
      else
      begin
        r.Top    := Rect.Top + (Rect.Bottom - Rect.Top - size.cy) div 2;
        r.Bottom := r.Top + size.cy;
        r.Left   := r.Left + PADDING;
        r.Right  := r.Left + size.cx;
        DrawFrameControl(Sender.Canvas.Handle, r, DFC_BUTTON, IfThen(CompareText(Item.SubItems[1],'True')=0, DFCS_CHECKED, DFCS_BUTTONCHECK));
      end;

    end;
    inc(r.Left, Sender.Column[i].Width);
  end;

end;

The code above needs further testing, but is probably in the right direction. Now it's very late, and I have to go.

这篇关于在TListView的绘制一个复选框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆