我如何更新线程内的listview项索引

时间:2015-08-29 17:54:50

标签: delphi listview delphi-xe7

我创建的项目允许多个用户登录并在EOF内添加详细信息,但我遇到了问题,但首先是我的线程代码和注释实现

listview

每件事情都很好,只有当我尝试type TUPDATEAFTERDOWNLOAD = class(TThread) private FListView: TListView; FListViewIdx: Integer; FMs: TMemoryStream; FURL: String; procedure UpdateVisual; // update after download function DownloadToStream: Boolean; // download function function CheckURL(const URL: Widestring): Boolean; // Check if its http url using urlmon protected procedure Execute; override; public property URL: String read FURL write FURL; property ListView: TListView read FListView write FListView; property ListViewIdx: Integer read FListViewIdx write FListViewIdx; end; function TUPDATEAFTERDOWNLOAD.CheckURL(const URL: Widestring): Boolean; begin if IsValidURL(nil, PWideChar(URL), 0) = S_OK then Result := True else Result := False; end; function TUPDATEAFTERDOWNLOAD.DownloadToStream: Boolean; var aIdHttp: TIdHttp; begin Result := False; if CheckURL(URL) = False then exit; aIdHttp := TIdHttp.Create(nil); try aIdHttp.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0'; aIdHttp.Get(FURL, FMs); Result := FMs.Size > 0; finally aIdHttp.Free; end; end; // procedure to start adding items then download image then update image to current item index Procedure TForm1.Add_Item(strCaption: String; ListView: TListView; strFile: String; strUniqueID: String); begin With ListView.Items.Add do begin Caption := ''; SubItems.Add(strCaption); // subitem 0 SubItems.AddObject('IMA', TObject(aGif)); // subitem 1 SubItems.Add(strUniqueID); // subitem 2 // Client id SubItems.Add('-'); // subitem 3 // Next User Idx (beside) With TUPDATEAFTERDOWNLOAD.Create(False) do begin FreeOnTerminate := True; URL := strFile; ListView := ListView1; ListViewIdx := ListView1.Items.Count - 1; // this for define index of item that just added Application.ProcessMessages; end; end; end; procedure TForm1.Button1Click(Sender: TObject); var Strname, image, strUniqueID: String; begin Strname := 'Matrin'; Add_Item(Strname, ListView1, image, strUniqueID); end; // Execute thread procedure TUPDATEAFTERDOWNLOAD.Execute; begin FMs := TMemoryStream.Create; if DownloadToStream then // if download done then start update the visual inside list view synchronize(UpdateVisual); end; procedure TUPDATEAFTERDOWNLOAD.UpdateVisual; var ResStream: TResourceStream; i: Integer; begin FMs.Position := 0; begin aGif := TGifImage.Create; aGif.LoadFromStream(FMs); aGif.Transparent := True; FListView.Items[FListViewIdx].SubItems.Objects[1] := TObject(aGif); if Streamin = True then begin for i := 0 to ListView.Items.Count - 1 do if ListView.Items[i].SubItems[3] = IntToStr(IDCLIENT) then begin ExchangeItems(ListView, FListViewIdx, 0); end; end; end; FMs.Free; end; 文字交换时我才遇到问题但是如果有5个或10个客户端,那么总是图像保持错误的索引,我认为我这样做的方式错过了

忘记添加Exchange项目功能

ExchangeItems(ListView, FListViewIdx, 0);

更新信息

我试图将GIF图像移动到TListItem.Data属性,但图像显示为空

procedure ExchangeItems(lv: TListView; i, j: Integer);
var
  tempLI: TListItem;
begin
  lv.Items.BeginUpdate;
  try
    tempLI := TListItem.Create(lv.Items);
    tempLI.Assign(lv.Items.Item[i]);
    lv.Items.Item[i].Assign(lv.Items.Item[j]);
    lv.Items.Item[j].Assign(tempLI);
    tempLI.Free;
  finally
    lv.Items.EndUpdate
  end;
end;

我在procedure TFORM1.UpdateVisual(Sender: TObject; AUserData: Pointer; var AImage: TGifImage); var Item: TListItem; i : integer; begin Item := TListItem(AUserData); if ListView1.Items.IndexOf(Item) = -1 then Exit; Item.Data:= AImage;// iam not sure if this right or wrong AImage := nil; if recorder.Active = True then begin for i := 0 to ListView1.Items.Count-1 do if ListView1.Items[i].SubItems[3] = IntToStr(UniqueID) then begin ExchangeItems(ListView1, Item.Index, 0); ListView1.Invalidate; SendCommandWithParams(TCPClient, 'Streamin', IntToStr(UniqueID) + Sep); end; end; end; gif事件中如何使用listview

OnDrawitem

对于procedure TFORM1.ListView1DrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); Var xOff, yOff : Integer; R: TRect; i : Integer; NewRect : TRect; begin // Client image NewRect := Rect; NewRect.Right := Sender.Column[0].Width - 4; // for Right Justify NewRect.Left := NewRect.Right - ImageList1.Width; NewRect.Top := NewRect.Top + 2; NewRect.Bottom := NewRect.Bottom; Sender.Canvas.StretchDraw( NewRect, TGIFImage( Item.data) ); end; 动画,我正在使用计时器重新绘制gif

listview

这是当我向其他客户端发送流应该发生什么时

procedure TFrom1.Timer1Timer(Sender: TObject);
{$j+}
  Const iCount : Cardinal = 0;
{$j-}
begin
  inc(iCount);
  if (iCount * TTimer(Sender).Interval) > 500 then
  begin
    iCount := 0;
  end;
  ListView1.Invalidate; // This is for animation over ListView Canvas
end;

我发布了我的项目中的所有内容我跟随雷米的建议并回答这个问题看起来非常复杂我不能在编码中发现任何错误希望有人知道什么事情

更新

通过使用procedure TFORM1.Streamin; var i : integer; begin for i := 0 to ListView1.Items.Count-1 do if ListView1.Items[i].SubItems[3] = Trim(CLIENTID) then begin R:= listview1.Items[i].Index; ExchangeItems( ListView1, R, 0); end; Panel2.Top := xSelItemTop; panel2.Visible := true; panelmeter.Visible := True; end; 问题减少但是当执行请求太快时问题是从计时器发生的吗?

更新

创建独立应用程序后,唯一的问题是在交换项目中它通过以下代码更改交换项目有一些错误的索引

wininet

它运行良好,但有时它插入空项目和应用程序中止,直到重新交换发生

更新了mcve

procedure ExchangeItems(lv: TListView; ItemFrom, ItemTo: Word);
var
 Source, Target: TListItem;
begin
  lv.Items.BeginUpdate;
  try
 Source := lv.Items[ItemFrom];
 Target := lv.Items.Insert(ItemTo);
 Target.Assign(Source);
 Source.Free;
  finally
    lv.Items.EndUpdate
  end;
end;

1 个答案:

答案 0 :(得分:3)

尝试更像这样的事情:

type
  TDownloadImageReadyEvent = procedure(Sender: TObject; AUserData: Pointer; var AImage: TGifImage) of object;

  TDownloadImage = class(TThread)
  private
    FURL: String;
    FGif: TGifImage;
    FOnImageReady: TDownloadImageReadyEvent;
    FUserData: Pointer;
    procedure DoImageReady;
  protected
    procedure Execute; override;
  public
    constructor Create(const AUrl: String; AOnImageReady: TDownloadImageReadyEvent; AUserData: Pointer); reintroduce;
  end;

constructor TDownloadImage.Create(const AUrl: String; AOnImageReady: TDownloadImageReadyEvent; AUserData: Pointer);
begin
  inherited Create(False);
  FreeOnTerminate := True;
  FUrl := AUrl;
  FOnImageReady := AOnImageReady;
  FUserData := AUserData;
end;

procedure TDownloadImage.Execute;
var
  aMs: TMemoryStream;
  aIdHttp: TIdHttp;
begin
  FGif := TGifImage.Create;
  try
    aMs := TMemoryStream.Create;
    try
      aIdHttp := TIdHttp.Create(nil);
      try
        aIdHttp.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
        aIdHttp.Get(FURL, aMs);
      finally
        aIdHttp.Free;
      end;
      aMs.Position := 0;
      FGif.LoadFromStream(aMs);
      FGif.Transparent := True;
    finally
      aMs.Free;
    end;
    if Assigned(FOnImageReady) then
      Synchronize(DoImageReady);
    end;
  finally
    FGif.Free;
  end;
end;

procedure TDownloadImage.DoImageReady;
begin
  if Assigned(FOnImageReady) then
    FOnImageReady(Self, FUserData, FGif);
end;

procedure TForm1.Add_Item(const strCaption, strFile, strUniqueID: String);
var
  Item: TListItem;
begin
  Item := ListView1.Items.Add;
  Item.Caption := '';
  Item.SubItems.Add(strCaption); // subitem 0
  Item.SubItems.Add('IMA'); // subitem 1
  Item.SubItems.Add(strUniqueID); // subitem 2 // Client id
  Item.SubItems.Add('-'); // subitem 3 // Next User Idx (beside)
  Item.Data := nil;
  TDownloadImage.Create(strFile, ImageReady, Item);
end;

procedure TForm1.ListView1Deletion(Sender: TObject; Item: TListItem);
begin
  TGifImage(Item.Data).Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Strname, image, strUniqueID: String;
begin
  Strname := 'Matrin';
  image := ...;
  strUniqueID := ...;
  Add_Item(Strname, image, strUniqueID);
end;

procedure TForm1.ImageReady(Sender: TObject; AUserData: Pointer; var AImage: TGifImage);
var
  Item: TListItem;
  i: Integer;
  sClientID: string;
begin
  Item := TListItem(AUserData);

  if ListView1.Items.IndexOf(Item) = -1 then
    Exit;

  Item.Data := AImage;
  AImage := nil;

  if Streamin then
  begin
    sClientID := IntToStr(IDCLIENT);
    for i := 0 to ListView1.Items.Count - 1 do
    begin
      if ListView.Items[i].SubItems[3] = sClientID then
      begin
        ExchangeItems(ListView1, Item.Index, 0);
        Exit;
      end;
    end;
  end;
end;