delphi – 如何在线程内更新listview项索引

前端之家收集整理的这篇文章主要介绍了delphi – 如何在线程内更新listview项索引前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在创建允许多用户登录并在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,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;

当我尝试使用ExchangeItems(ListView,0)时,每一件工作都很好我只会遇到问题;文本交换但总是图像保持在错误的索引,如果有5或10个客户端,我认为我这样做的方式是错过了

忘记添加Exchange项目功能

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;

更新的信息

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

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;

这就是我在listview OnDrawitem事件中使用gif的方式

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问题减少但当执行请求太快时问题是从计时器发生的?

更新

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

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;

它工作得很好,但有时它插入空项目和应用程序中止,直到重新交换发生

更新了mcve

unit Unit1;

interface

uses
  Winapi.Windows,Winapi.Messages,System.SysUtils,System.Variants,System.Classes,Vcl.Graphics,Vcl.Controls,Vcl.Forms,Vcl.Dialogs,Vcl.StdCtrls,Vcl.ComCtrls,Vcl.ExtCtrls,JPEG,Vcl.Imaging.pngimage,GIFImg,GraphUtil,Vcl.ImgList;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    Additem: TButton;
    Exchange: TButton;
    Timer1: TTimer;
    ImageList1: TImageList;
    Panel2: TPanel;
    Shape1: TShape;
    Edit1: TEdit;
    AddToSTringlistFirst: TButton;
    procedure FormCreate(Sender: TObject);
    procedure AdditemClick(Sender: TObject);
    procedure ListView1DrawItem(Sender: TCustomListView; Item: TListItem;
      Rect: TRect; State: TOwnerDrawState);
    procedure Timer1Timer(Sender: TObject);
    procedure ExchangeClick(Sender: TObject);
    procedure AddToSTringlistFirstClick(Sender: TObject);
  private
     namelist: TList;
    { Private declarations }
  public
    { Public declarations }
    procedure Add_Item(strCaption: String; ListView: TListView; strFile: String;
    boolBlink: Boolean; strUniqueID,Currentstatus: string);
    procedure UpdateVisual(Sender: TObject; AUserData: Pointer;
      var AImage: TGifImage);
  end;

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

  type
  TURLDownload = class(TThread)
  private
    FGif         : TGifImage;
    FOnUpdateVisual: TDownloadUpdateVisualEvent;
    FUserData: Pointer;
    FURL         : String;
    procedure DoUpdateVisual;
  protected
    procedure Execute; override;
  public
  constructor Create(const AUrl: String; AOnUpdateVisual: TDownloadUpdateVisualEvent; AUserData: Pointer); reintroduce;
  end;


  Tcollectlist = class(TObject)
  Name: String;
  icon:string;
  UniqueID : Dword;
  end;

var
  Form1: TForm1;
  xProcessingTime : Boolean = False;
  aGIF : TGifImage;
  jpg : TJPEGImage;
  png : TPngImage;
  Status : string = '-';
  xSelItemLeft   : Integer = 0;
  xSelItemTop    : Integer = 0;
  recorder : Boolean;
  UniqueID : Dword;
  xboolBlink : Boolean = False;
  listMS: TMemoryStream;


implementation

uses wininet;

{$R *.dfm}

{$j+}
  Const boolblink : boolean = false;
  Const Sep = '#$%^&';
{$j-}



constructor TURLDownload.Create(const AUrl: String; AOnUpdateVisual: TDownloadUpdateVisualEvent; AUserData: Pointer);
begin
  inherited Create(False);
  FreeOnTerminate := True;
  FUrl := AUrl;
  FOnUpdateVisual:= AOnUpdateVisual;
  FUserData := AUserData;
end;


procedure ExchangeItems(lv: TListView; ItemFrom,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;


procedure TForm1.FormCreate(Sender: TObject);
begin
namelist := TList.Create;
  // This is for repaint the ListView and so for the animation
    Timer1.Interval       := 10;
    Timer1.Enabled        := true;

  // This is for enlarge the ListView height
  //   ImageList1.Width      := 50;
  //   ImageList1.Height     := 30;
  With ListView1 do
  begin
    SmallImages    := ImageList1;
    ViewStyle      := vsReport;
    RowSelect      := True;
    ReadOnly       := True;
    OwnerDraw      := True;
    DoubleBuffered := True;
    With Columns.Add do Width := (ImageList1.Width+4)*2; // Caption
    With Columns.Add do Width := ListView1.Width - ListView1.Columns[0].Width;  // 0 Name
  end;
end;

procedure TForm1.ListView1DrawItem(Sender: TCustomListView; Item: TListItem;
  Rect: TRect; State: TOwnerDrawState);
Var
  xOff,yOff : Integer;
  i : Integer;
    R: TRect;
  NewRect : TRect;
begin
  With TListView(Sender).Canvas do
  begin
    if Item.Selected then
    begin
          SetRect(R,Rect.Left,Rect.Top,Rect.Right,Rect.Bottom-( (Rect.Bottom-Rect.Top) div 2 ) );
      SetRect(R,Rect.Bottom-( (Rect.Bottom-Rect.Top) div 2 ),Rect.Bottom );
      Sender.Canvas.Brush.Style := bsClear;
      Sender.Canvas.Pen.Width   := 0;

      //Sender.Canvas.Font.Color  := clBlue;
      //Sender.Canvas.Brush.Color := clYellow;
      //Sender.Canvas.FillRect(Rect);
      Rectangle( Rect.Left,Rect.Top + ImageList1.Height);
    end;
    xSelItemTop    := sender.Top + ImageList1.Height;
    Sender.Canvas.Brush.Style := bsClear;
    // User State Image
     if (Item.SubItems[5] <> '-') then
     begin
      if Panel2.Visible AND (Item.Index = 0) then
     else
     ImageList1.Draw( Sender.Canvas,StrToInt(Item.SubItems[5]) );
      end;
    // User 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) );

    // Image - Beside User
      if Item.SubItems[4] <> '-' then
      begin
        NewRect := Rect;
        NewRect.Left   := NewRect.Left  + ImageList1.Width; // after StateImage offset
        NewRect.Right  := NewRect.Left  + ImageList1.Width;
        NewRect.Top    := NewRect.Top    + 4;
        NewRect.Bottom := NewRect.Bottom - 4;
        Sender.Canvas.StretchDraw( NewRect,TGIFImage( TListView(Sender).Items[StrToInt(Item.SubItems[4])].SubItems.Objects[1]) );
      end;

    // --- Caption and Text --- //
    xOff := Rect.Left;
    for i := 1 to TListView(sender).Columns.Count-1 do // 1,2,3,4,5,6
    begin
      xOff := xOff + TListView(Sender).Columns[i-1].Width;
      yOff := Rect.Top + ((ImageList1.Height-Canvas.TextHeight('H')) div 2);
      if xboolBlink or ( Item.SubItems[2] = '' )
        then sender.canvas.font.color := clgray
        else sender.canvas.font.color := clred;
      TextOut( xOff,yOff,Item.SubItems[i-1] );
    end;
  end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
{$j+}
  Const iCount : Cardinal = 0;
{$j-}
begin
  inc(iCount);
  if (iCount * TTimer(Sender).Interval) > 500 then
  begin  // this is for blink text which subitem[2] contains 'blink'
    xboolBlink := NOT xboolBlink;
    iCount := 0;
  end;
  ListView1.Invalidate; // This is for animation over ListView Canvas
end;


procedure parselist(Line: string; var strName,strUniqueID,icon: string);
var
  P,I: Integer;
begin
  I := 0;
  repeat
    P := Pos(Sep,Line);
    if P <> 0 then
    begin
      Inc(I);
      case I of
        1: strName     := Copy(Line,1,P - 1);
        2: strUniqueID := Copy(Line,P - 1);
        3: icon  := Copy(Line,P - 1);
      end;
      Delete(Line,P + Length(Sep) - 1);
    end;
  until (I = 3) or (P = 0) or (Line = '')
end;


procedure TForm1.AdditemClick(Sender: TObject);
var
I : integer;
Line: string;
strName,icon : String;
strSelectedUID : String;
Sl : Tstringlist;
begin
  if ListView1.Selected <> nil
      then strSelectedUID := Listview1.Selected.SubItems[3]
      else strSelectedUID := '';
    listview1.Items.BeginUpdate;
    try
    ListView1.Items.Clear;
finally
    listview1.Items.EndUpdate;
  end;
    if Assigned(listms) then
    SL := TStringList.Create;
    begin
      try
        listms.Position := 0;
        Sl.LoadFromStream(listms);
        for I := 0 to SL.Count -1  do
        begin
            Line := SL.Strings[I];
            parselist(Line,strName,icon);
            boolblink := True;
           Add_Item( strName,icon,boolblink,Status);
        end;
      finally
       Sl.Free
      end;
      listms.Free;

    if strSelectedUID <> '' then
      begin
        for i := 0 to ListView1.Items.Count-1
          do if ListView1.Items[i].SubItems[3] = strSelectedUID
            then Listview1.Items[i].Selected := True;
      end;
    end;
end;


procedure TForm1.AddToSTringlistFirstClick(Sender: TObject);
var
  I: Integer;
  image : string;
  collectlist : Tcollectlist;
  MS: TMemoryStream;
  Sl : Tstringlist;
begin
collectlist := Tcollectlist.Create;
SL := TStringList.Create;
image := edit1.Text;
collectlist.Name := 'Martinloanel';
collectlist.UniqueID :=  StrToint('5555' + intTostr(1));
collectlist.icon := image;
namelist.Add(collectlist);

 try
    // Collect List
    for I := 0 to namelist.Count - 1 do
    begin
      collectlist := Tcollectlist(namelist.Items[I]);
      SL.Add(collectlist.Name + Sep + IntToStr(collectlist.UniqueID) + Sep +  collectlist.icon + Sep);
    end;
// Send List
    for I := 0 to namelist.Count - 1 do
    begin
      collectlist := Tcollectlist(namelist.Items[I]);
      if (SL.Count > 0) then
      begin
        MS := TMemoryStream.Create;
        listms :=  TMemoryStream.Create;
        try
          SL.SaveToStream(MS);
          MS.Position := 0;
          listms.LoadFromStream(MS);

        finally
         MS.Free;
        end;
      end;
    end;
  finally
    Sl.Free
  end;
end;

Procedure TForm1.Add_Item( strCaption: String; ListView : TListView; strFile: String; boolBlink : Boolean; strUniqueID:String; Currentstatus: string);
var
  Item: TListItem;
begin
Currentstatus := Status;
  begin
    Item := ListView1.Items.Add;
    Item.Caption   := '';
    Item.SubItems.Add( strCaption ); // subitem 0
    Item.SubItems.AddObject( 'IMA',nil); // subitem 1
    if boolBlink
      then  Item.SubItems.Add( 'blink' ) // subitem 2
      else  Item.SubItems.Add( '' );     // subitem 2
      Item.SubItems.Add( strUniqueID );                  // subitem 3 // UniqueID
      UniqueID := strToint(strUniqueID);
    Item.SubItems.Add('-');                            // subitem 4 // Next User Idx (beside)
    Item.SubItems.Add(Currentstatus);                              // subitem 5 // StateIdx
    TURLDownload.Create(strFile,UpdateVisual,Item);
    end;
  end;



  procedure TForm1.ExchangeClick(Sender: TObject);
begin
recorder := True;
end;

procedure TURLDownload.DoUpdateVisual;
begin
  if Assigned(FOnUpdateVisual) then
    FOnUpdateVisual(Self,FUserData,FGif);
end;

procedure TURLDownload.Execute;
var
  aMs: TMemoryStream;
  hSession     : HINTERNET;
  hService     : HINTERNET;
  lpBuffer     : array[0..1023] of Byte;
  dwBytesRead  : DWORD;
  dwBytesAvail : DWORD;
  dwTimeOut    : DWORD;
begin
  FGif := TGifImage.Create;
  try
  aMs := TMemoryStream.Create;
  hSession := InternetOpen('anyname',INTERNET_OPEN_TYPE_PRECONFIG,nil,0);
  if not Assigned(hSession) then Exit;
    try
      hService := InternetOpenUrl(hSession,PChar(FUrl),0);
    if hService = nil then
      Exit;
      try
      dwTimeOut := 60000;
      InternetSetOption(hService,INTERNET_OPTION_RECEIVE_TIMEOUT,@dwTimeOut,SizeOf(dwTimeOut));
      if InternetQueryDataAvailable(hService,dwBytesAvail,0) then
      repeat
      if not InternetReadFile(hService,@lpBuffer[0],SizeOf(lpBuffer),dwBytesRead) then
      Break;
      if dwBytesRead <> 0 then
      aMs.WriteBuffer(lpBuffer[0],dwBytesRead);
      until dwBytesRead = 0;
      finally
       InternetCloseHandle(hService);
      end;
      aMs.Position := 0;
      FGif.LoadFromStream(aMs);
      FGif.Transparent := True;
    finally
      aMs.Free;
      InternetCloseHandle(hSession);
    end;
    if Assigned(FOnUpdateVisual) then
    begin
      Synchronize(DoUpdateVisual);
    end;
  finally
    FGif.Free;
  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;
  AImage := nil;

if recorder = True then
      begin
       for i := 0 to ListView1.Items.Count-1
     do if ListView1.Items[i].SubItems[3] = IntToStr(UniqueID)
     then
     begin
     ExchangeItems(ListView1,0);
     ListView1.Invalidate;
     end;
   end;
end;


end.

解决方法

尝试更像这样的东西:
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,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,strUniqueID: String;
begin
  Strname := 'Matrin';
  image := ...;
  strUniqueID := ...;
  Add_Item(Strname,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,0);
        Exit;
      end;
    end;
  end;
end;
原文链接:https://www.f2er.com/delphi/102936.html

猜你在找的Delphi相关文章