自画TListView带进度条的Item

 
自画 TlistView 带进度条的 Item
TListView的Item条一般是由系统自画的,但电驴就实现了自画,使之看起来很漂亮,我们用DELPHI也可以实现!
 
首先要引用 CommCtrl 单元,这是TListView底层控制单元:
uses
  CommCtrl;
 
// 画状态条
procedure DrawSubItem(LV: TListView; Item: TListItem; SubItem: Integer;
 Prosition: Single; Max, Style: Integer; IsShowProgress: Boolean;
 DrawColor: TColor = $00005B00 ;
 FrameColor: TColor = $00002F00 );
// 获取 SubItem 的区域
  function GetItemRect(LV_Handle, iItem, iSubItem: Integer): TRect;
  var
    Rect: TRect;
  begin
    ListView_GetSubItemRect(LV_Handle, iItem, iSubItem, LVIR_LABEL, @Rect);
    Result := Rect;
  end ;
var
  PaintRect, r: TRect;
 i, iWidth, x, y: integer;
 S: string ;
begin
 try
 
    with lv do
    begin
      //LockPaint := True;
      PaintRect := GetItemRect(LV.Handle, Item.Index, SubItem);
     r := PaintRect;
//      if SubItem = DrawSubItem then
      Begin
        // 这一段是算出百分比
        if Prosition >= Max then
          Prosition := 100
        else
          if Prosition <= 0 then
            Prosition := 0
          else
            Prosition := Round((Prosition / Max) * 100 );
 
        if (Prosition = 0 ) and ( not IsShowProgress) then
        begin
        // 如果是百分比是 0 ,就直接显示空白
          Canvas.FillRect(r);
 
        end
        else
        begin
        // 先直充背景色
          Canvas.FillRect(r);
          Canvas.Brush.Color := Color;
//          Canvas.FillRect(r);
 
        // 画一个外框
          InflateRect(r, - 2 , - 2 );
          Canvas.Brush.Color := FrameColor; //$00002F00;
          Canvas.FrameRect(R);
 
          Canvas.Brush.Color := Color;
          InflateRect(r, - 1 , - 1 );
//          Canvas.FillRect(r);
 
          InflateRect(r, - 1 , - 1 );
        // 根据百分比算出要画的进度条内容宽度
          iWidth := R.Right - Round((R.Right - r.Left) * (( 100 - Prosition) /
            100 ));
          case Style of
            0 : // 进度条类型,实心填充
              begin
                Canvas.Brush.Color := DrawColor;
                r.Right := iWidth;
                Canvas.FillRect(r);
              end ;
            1 : // 进度条类型,竖线填充
              begin
                i := r.Left;
                while i < iWidth do
                begin
                  Canvas.Pen.Color := Color;
                  Canvas.MoveTo(i, r.Top);
                  Canvas.Pen.Color := DrawColor;
                  canvas.LineTo(i, r.Bottom);
                  Inc(i, 3 );
                end ;
              end ;
          end ;
// 画好了进度条后,现在要做的就是显示进度数字了
          Canvas.Brush.Style := bsClear;
          if Prosition = Round(Prosition) then
            S := Format( '%d%%' , [Round(Prosition)])
          else
            S := FormatFloat( '#0.0' , Prosition);
 
          with PaintRect do
          begin
            x := Left + (Right - Left + 1 - Canvas.TextWidth(S)) div 2 ;
            y := Top + (Bottom - Top + 1 - Canvas.TextHeight(S)) div 2 ;
          end ;
          SetBkMode(Canvas.handle, TRANSPARENT);
          Canvas.TextRect(PaintRect, x, y, S);
 
        end ;
// 进度条全部画完,把颜色设置成默认色了
        Canvas.Brush.Color := Color;
 
      end
    end ;
  except
  end ;
end ;
 
 
上面是画进度条的,现在要给 TlistView 处理 Item 重绘的消息,事件是 On CustomDrawItem 需要说明的是,如果想要随心所欲的自画 Item ,那么就要全部自己来完成,不再需要系统来处理:
procedure TForm1.ListView1CustomDrawItem(
 Sender: TCustomListView; Item: TListItem; State: TCustomDrawState;
  var DefaultDraw: Boolean);
var
  BoundRect, Rect: TRect;
 i: integer;
 TextFormat: Word;
 LV: TListView;
 
// 这个子过程是用来画 CheckBox ImageList
  procedure Draw_CheckBox_ImageList(r: TRect; aCanvas: TCanvas; Checked: Boolean);
  var
    R1: TRect;
    i: integer;
  begin
    if Sender.Checkboxes then
    begin
      aCanvas.Pen.Color := clBlack;
      aCanvas.Pen.Width := 2 ;
      // CheckBox 外框
      aCanvas.Rectangle(r.Left + 2 , r.Top + 2 , r.Left + 14 , r.Bottom - 2 );
      if Checked then
      begin // CheckBox 的勾
        aCanvas.MoveTo(r.Left + 4 , r.Top + 6 );
        aCanvas.LineTo(r.Left + 6 , r.Top + 11 );
        aCanvas.LineTo(r.Left + 11 , r.Top + 5 );
      end ;
      aCanvas.Pen.Width := 1 ;
    end ;
    // 开始画图标
    i := PDownLoadListItem(Item.Data)^.StatsImageIndex;
    if i > - 1 then
    begin
    // 获取图标的 RECT
      if Boolean(ListView_GetSubItemRect(sender.Handle, item.Index, 0 , LVIR_ICON, @R1)) then
      begin
        ImageList_Stats.Draw(LV.Canvas, R1.Left, R1.Top, i);
        if item.ImageIndex > - 1 then
          LV.SmallImages.Draw(LV.Canvas, R1.Right + 2 , R1.Top, item.ImageIndex);
      end ;
 
    end ;
  end ;
begin
  LV := ListView1;
 BoundRect := Item.DisplayRect(drBounds);
 InflateRect(BoundRect, - 1 , 0 );
 
// 这个地方你可以根据自己的要求设置成想要的颜色,实现突出显示
  LV.Canvas.Font.Color := clBtnText;
 
// 查看是否是被选中
  if Item.Selected then
 begin
    if cdsFocused in State then
    begin
      LV.Canvas.Brush.Color := $00ECCCB9 ; // //clHighlight;
    end
    else
    begin
      LV.Canvas.Brush.Color := $00F8ECE5 ; //clSilver;
    end ;
  end
 else
 begin
    if (Item.Index mod 2 ) = 0 then
      LV.Canvas.Brush.Color := clWhite
    else
      LV.Canvas.Brush.Color := $00F2F2F2 ;
  end ;
 
 LV.Canvas.FillRect(BoundRect); // 初始化背景
 
  for i := 0 to LV.Columns.Count - 1 do
 begin
  // 获取 SubItem Rect
    ListView_GetSubItemRect(LV.Handle, Item.Index, i, LVIR_LABEL, @Rect);
    case LV.Columns[i].Alignment of
      taLeftJustify:
        TextFormat := 0 ;
      taRightJustify:
        TextFormat := DT_RIGHT;
      taCenter:
        TextFormat := DT_CENTER;
    end ;
    case i of
      0 : // Caption 0 就是表示 Caption ,这不是 Subitems[0]
        begin
// 先画选择框与图标
          Draw_CheckBox_ImageList(BoundRect, LV.Canvas, Item.Checked);
// 再画 Caption 的文字
          InflateRect(Rect, -( 5 + ImageList_Stats.Width), 0 ); // 向后移 3 个像素 , 避免被后面画线框时覆盖
          DrawText(
            LV.Canvas.Handle,
            PCHAR(Item.Caption),
            Length(Item.Caption),
            Rect,
            DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS or TextFormat);
        end ;
      1 ..MaxInt: // Subitems[i]
        begin
          if i - 1 = 2 then // 显示状态条
          begin
// 开始处理进度条了,这个示例是第 3 栏显示进度条,可以自己随便定义
            DrawSubItem(TListView(Sender),
              item,
              i,
              StrToFloatDef(Item.SubItems[i - 1 ], 0 ),
              100 ,
              0 ,
              True,
 // 这里用了一个 Lable 来选颜色,你自己可以使用一个变量来代替
             LableProgressColor.Color, // 进度条外框颜色
              LableProgressColor.Color  // 进度条颜色
);
 
          end
          else
// SubItem 的文字
            if i - 1 <= Item.SubItems.Count - 1 then
              DrawText(
                LV.Canvas.Handle,
                PCHAR(Item.SubItems[i - 1 ]),
                Length(Item.SubItems[i - 1 ]),
                Rect,
                DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS or TextFormat);
 
 
 
        end ;
    end ;
 
  end ;
 
 
 LV.Canvas.Brush.Color := clWhite;
 
  if Item.Selected then // 画选中条外框
  begin
    if cdsFocused in State then // 控件是否处于激活状态
      LV.Canvas.Brush.Color := $00DAA07A // $00E2B598; //clHighlight;
    else
      LV.Canvas.Brush.Color := $00E2B598 ; //$00DAA07A // clHighlight;
    LV.Canvas.FrameRect(BoundRect); //
  end ;
 
 DefaultDraw := False; // 不让系统画了
 
  with Sender.Canvas do
    if Assigned(Font.OnChange) then Font.OnChange(Font);
 
 
 
end ;
function ReDrawItem(HwndLV: HWND; ItemIndex: integer): boolean;
begin
  Result := ListView_RedrawItems(HwndLV, ItemIndex, ItemIndex);
end;
//使用:
item:=ListView1.Selected;
item.subitems[1]:='30';//设置为30%
//然后刷新这个item
ReDrawItem(ListView1.handle,Item.index);
 
不用进度条时的效果图:
 
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 在Delphi或C++ Builder编程中,BeginThread是一个函数,用于创建一个新的线程并开始执行指定的函数。TListView是一个控件,用于显示和管理列表数据。 使用BeginThread tlistview时,可以在程序中创建一个新的线程,并在该线程中实现TListView的相关操作。新线程的主要作用是在后台执行耗时的任务,以保持主线程的响应性。 例如,我们可以使用BeginThread tlistview来实现在后台加载和更新TListView中的数据,从而提高程序的用户体验。具体的步骤如下: 1. 创建新的线程:使用BeginThread函数创建一个新的线程。该函数接受一个线程函数作为参数,该函数将在新线程中执行。 2. 在线程函数中对TListView进行操作:在新线程的线程函数中,可以通过TListView控件的相关方法和属性来加载、更新、删除和显示列表数据。这些操作可以根据具体需求进行编写,例如从数据库中加载数据,更新列表项的内容等。 3. 保证线程的安全性:由于多线程同时操作TListView可能会导致冲突和错误,需要使用线程同步机制来保证线程的安全性。可以使用一些工具类如TCriticalSection、TMonitor或者使用Windows API的同步对象来实现线程同步。 4. 启动线程和等待线程结束:在主线程中,调用BeginThread函数启动新线程的执行。然后使用WaitForSingleObject等方法来等待新线程的执行完成,以确保线程的顺序和程序的正确性。 总之,通过使用BeginThread tlistview,我们可以在新的线程中对TListView进行相关操作,以提高程序的性能和用户体验。但需要注意线程的安全性和正确的线程同步机制,以避免出现冲突和错误。 ### 回答2: BeginThread是Delphi编程语言中的一个函数,用于创建一个新的线程来执行指定的代码。 TListViewDelphi中的一个控件,用于显示数据列表。 BeginThread TListView的意思是在TListView控件中使用BeginThread函数来创建一个新的线程。 使用BeginThread TListView可以实现在一个单独的线程中加载和更新TListView控件的数据,从而提高程序的运行效率和用户体验。 具体的步骤如下: 1. 创建一个新的线程,并将要执行的代码传递给BeginThread函数。 2. 在新线程中,使用相应的代码来加载和更新TListView控件的数据。可以通过访问数据库或其他数据源来获取数据,并将其填充到TListView控件中。 3. 在代码执行完毕后,结束线程。 使用BeginThread TListView需要注意以下几点: 1. 在访问TListView控件时,需要进行线程同步。因为TListView控件是在主线程中创建的,所以在新线程中访问TListView控件时,需要使用Synchronize或Queue方法来保证线程安全。 2. 在处理大量数据时,要考虑数据的处理效率和内存占用情况,避免因为数据量过大导致程序崩溃或响应变慢。 总之,使用BeginThread TListView可以实现在一个单独的线程中加载和更新TListView控件的数据,从而提高程序的运行效率和用户体验。 ### 回答3: beginthread是一个用于创建线程的函数,可以在C/C++中使用。tlistview是一个表示线程执行过程中生成的数据的对象,通常用于在多线程程序中共享数据。 在使用beginthread函数创建线程时,需要指定一个线程函数作为参数。该函数将在新创建的线程中执行。线程函数可以通过参数传递额外的数据,在不同的线程中共享或操作该数据。 tlistview对象可以用于存储线程执行期间产生的数据。例如,如果我们有一个需要在主线程和子线程之间共享数据的GUI应用程序,可以使用tlistview对象来存储子线程生成的数据,并在主线程中显示这些数据。这样可以避免多线程访问同一数据时的竞态条件问题。 在使用beginthread函数创建线程后,我们可以通过线程函数处理程序对tlistview对象进行读写操作。这样,子线程就可以将数据写入tlistview对象,并由主线程读取和显示这些数据。这使得多线程编程更加容易和安全。 总的来说,beginthread函数用于创建线程,而tlistview对象用于在多线程程序中共享数据。通过使用这两者,我们可以更轻松地实现多线程程序,并确保数据的正确读写和同步。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值