整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          使用Delphi開發echarts圖表

          使用Delphi開發echarts圖表

          用DeWeb可以實現用Delphi開發echarts圖表

          DeWeb : Delphi開發者的Web解決方案!

          DeWeb是一個可以直接將Delphi程序快速轉換為網頁應用的工具! 使用DeWeb, 開發者不需要學習HTML、JavaScript、Java、PHP、ASP、C#等新知識,用Delphi搞定一切。 DeWeb開發的網頁支持所有客戶端,包括手機、平板等。

          網址:https://gitee.com/xamh/dewebsdk

          采用DeWeb可以非常方便開發echarts圖表應用。

          還不會DeWeb開發的朋友請參考相關文檔

          1 打開一個基本DeWeb應用

          比如自帶的hello例程

          2 創建echarts控件

          拖放一個TMemo控件,設置其HelpKeyword為echarts

          3 配置echarts控件

          (1)在echarts官網打開擬開發的圖表例程,如

          https://echarts.apache.org/examples/zh/editor.html?c=pie-nest

          效果圖如下:


          echarts圖表效果

          (2)復制該網頁左側的JS代碼,注意:只復制option后{....}及其中的內容

          (3)打開Notepad++, 新建一個文件,粘貼進去, 再全選,然后復制;

          這一步驟主要是保持原代碼的換行符。直接復制到TMemo控件中會丟失,導致錯誤。

          (4)打開Delphi中TMemo控件的Lines, 粘貼進去

          即內容為

          {
            tooltip: {
              trigger: 'item',
              formatter: '{a} <br/>{b}: {c} (j9np179%)'
            },
            legend: {
              data: [
                'Direct',
                'Marketing',
                'Search Engine',
                'Email',
                'Union Ads',
                'Video Ads',
                'Baidu',
                'Google',
                'Bing',
                'Others'
              ]
            },
            series: [
              {
                name: 'Access From',
                type: 'pie',
                selectedMode: 'single',
                radius: [0, '30%'],
                label: {
                  position: 'inner',
                  fontSize: 14
                },
                labelLine: {
                  show: false
                },
                data: [
                  { value: 1548, name: 'Search Engine' },
                  { value: 775, name: 'Direct' },
                  { value: 679, name: 'Marketing', selected: true }
                ]
              },
              {
                name: 'Access From',
                type: 'pie',
                radius: ['45%', '60%'],
                labelLine: {
                  length: 30
                },
                label: {
                  formatter: '{a|{a}}{abg|}\n{hr|}\n  {b|{b}:}{c}  {per|vhjd919%}  ',
                  backgroundColor: '#F6F8FC',
                  borderColor: '#8C8D8E',
                  borderWidth: 1,
                  borderRadius: 4,
                  rich: {
                    a: {
                      color: '#6E7079',
                      lineHeight: 22,
                      align: 'center'
                    },
                    hr: {
                      borderColor: '#8C8D8E',
                      width: '100%',
                      borderWidth: 1,
                      height: 0
                    },
                    b: {
                      color: '#4C5058',
                      fontSize: 14,
                      fontWeight: 'bold',
                      lineHeight: 33
                    },
                    per: {
                      color: '#fff',
                      backgroundColor: '#4C5058',
                      padding: [3, 4],
                      borderRadius: 4
                    }
                  }
                },
                data: [
                  { value: 1048, name: 'Baidu' },
                  { value: 335, name: 'Direct' },
                  { value: 310, name: 'Email' },
                  { value: 251, name: 'Google' },
                  { value: 234, name: 'Union Ads' },
                  { value: 147, name: 'Bing' },
                  { value: 135, name: 'Video Ads' },
                  { value: 102, name: 'Others' }
                ]
              }
            ]
          }

          在窗體的OnMouseDown事件中寫入

          dwEcharts(Memo1);

          編譯運行,即可得到


          (5)更新數據。

          執行到上一步,效果出來了,但會發現無法更新數據。

          原因是代碼中把數據(data部分)寫成固定的了

          先需要把TMemo的內容改成以下。注意"data:XXX"的變化

          {
            tooltip: {
              trigger: 'item',
              formatter: '{a} <br/>{b}: {c} (fjbv7pn%)'
            },
            legend: {
              data: [
                'Direct',
                'Marketing',
                'Search Engine',
                'Email',
                'Union Ads',
                'Video Ads',
                'Baidu',
                'Google',
                'Bing',
                'Others'
              ]
            },
            series: [
              {
                name: 'Access From',
                type: 'pie',
                selectedMode: 'single',
                radius: [0, '30%'],
                label: {
                  position: 'inner',
                  fontSize: 14
                },
                labelLine: {
                  show: false
                },
                data: this.value0
              },
              {
                name: 'Access From',
                type: 'pie',
                radius: ['45%', '60%'],
                labelLine: {
                  length: 30
                },
                label: {
                  formatter: '{a|{a}}{abg|}\n{hr|}\n  {b|{b}:}{c}  {per|v7799v9%}  ',
                  backgroundColor: '#F6F8FC',
                  borderColor: '#8C8D8E',
                  borderWidth: 1,
                  borderRadius: 4,
                  rich: {
                    a: {
                      color: '#6E7079',
                      lineHeight: 22,
                      align: 'center'
                    },
                    hr: {
                      borderColor: '#8C8D8E',
                      width: '100%',
                      borderWidth: 1,
                      height: 0
                    },
                    b: {
                      color: '#4C5058',
                      fontSize: 14,
                      fontWeight: 'bold',
                      lineHeight: 33
                    },
                    per: {
                      color: '#fff',
                      backgroundColor: '#4C5058',
                      padding: [3, 4],
                      borderRadius: 4
                    }
                  }
                },
                data: this.value1
              }
            ]
          }

          對應

          this.value0應為
          [
              { value: 1548, name: 'Search Engine' },
              { value: 775, name: 'Direct' },
              { value: 679, name: 'Marketing', selected: true }
          ]
          
          this.value1應為
          [
              { value: 1048, name: 'Baidu' },
              { value: 335, name: 'Direct' },
              { value: 310, name: 'Email' },
              { value: 251, name: 'Google' },
              { value: 234, name: 'Union Ads' },
              { value: 147, name: 'Bing' },
              { value: 135, name: 'Video Ads' },
              { value: 102, name: 'Others' }
          ]
          

          在Delphi中的事件中組類似的字符串就可以了

          具體做法是增加一個Timer, 時間設置為3000,代碼如下:

          procedure TForm1.Timer1Timer(Sender: TObject);
          var
              sV0,sV1     : String;
              sJS         : String;
          begin
              //value0
              //[
              //    { value: 1548, name: 'Search Engine' },
              //    { value: 775, name: 'Direct' },
              //    { value: 679, name: 'Marketing', selected: true }
              //]
          
              //value1
              //[
              //    { value: 1048, name: 'Baidu' },
              //    { value: 335, name: 'Direct' },
              //    { value: 310, name: 'Email' },
              //    { value: 251, name: 'Google' },
              //    { value: 234, name: 'Union Ads' },
              //    { value: 147, name: 'Bing' },
              //    { value: 135, name: 'Video Ads' },
              //    { value: 102, name: 'Others' }
              //]
              //
          
              //
              Randomize;
          
              //Get value0 string
              sV0 :='this.value0=['
                  +'{ value: %d, name: ''Search Engine'' },'
                  +'{ value: %d, name: ''Direct'' },'
                  +'{ value: %d, name: ''Marketing'', selected: true }'
              +'];';
              sV0 :=Format(sV0,[Random(1500),Random(1000),Random(1000)]);
          
              //Get value1 string
              sV1 :='this.value1=['
                  +'{ value: %d, name: ''Baidu'' },'
                  +'{ value: %d, name: ''Direct'' },'
                  +'{ value: %d, name: ''Email'' },'
                  +'{ value: %d, name: ''Google'' },'
                  +'{ value: %d, name: ''Union Ads'' },'
                  +'{ value: %d, name: ''Bing'' },'
                  +'{ value: %d, name: ''Video Ads'' },'
                  +'{ value: %d, name: ''Others'' }'
              +'];';
              sV1 :=Format(sV1,[Random(1500),Random(1000),Random(1000),Random(1000),Random(1000),Random(1000),Random(1000),Random(1000)]);
          
              //
              dwRunJS(sV0+sV1,self);
          
              dwEcharts(Memo1);
          
          end;

          這樣echarts圖表就可以動態更新了。

          關注我, 學習更多Delphi知識!

          載大文件時,斷點續傳是很有必要的,特別是網速度慢且不穩定的情況下,很難保證不出意外,一旦意外中斷,又要從頭下載,會很讓人抓狂。斷點續傳就能很好解決意外中斷情況,再次下載時不需要從頭下載,從上次中斷處繼續下載即可,這樣下載幾G或十幾G大小的一個文件都沒問題。本文介紹利用miniframe開源Web框架分別在lazarus、delphi下實現文件HTTP下載斷點續傳的功能。

          本文Demo還實現了批量下載文件,同步服務器上的文件到客戶端的功能。文件斷點續傳原理:分塊下載,下載后客戶端逐一合并,同時保存已下載的位置,當意外中斷再次下載時從保存的位置開始下載即可。這其中還要保證,中斷后再次下載時服務器上相應的文件如果更新了,還得重新下載,不然下載到的文件是錯了。說明:以下代碼lazarus或delphi環境下都能使用。全部源碼及Demo請到miniframe開源web框架下載: https://www.wyeditor.com/miniframe/或https://github.com/dajingshan/miniframe。

          服務器端代碼

          文件下載斷點續傳服務器端很簡單,只要提供客戶端要求下載的開始位置和指定大小的塊即可。

          以下是服務器獲取文件信息和下載一個文件一塊的代碼:

          <%@//Script頭、過程和函數定義
          program codes;
          %>
           
          <%!//聲明變量
          var
            i,lp: integer;
            FileName, RelativePath, FromPath, ErrStr: string;
            json: TminiJson;
            FS: TFileStream;
            
          function GetOneDirFileInfo(Json: TminiJson; Path: string): string;
          var
            Status: Integer;
            SearchRec: TSearchRec;
            json_sub: TminiJson;
          begin
            Path :=PathWithSlash(Path);
            SearchRec :=TSearchRec.Create;
            Status :=FindFirst(Path + '*.*', faAnyFile, SearchRec);
            try
              while Status=0 do
              begin 
                if SearchRec.Attr and faDirectory=faDirectory then
                begin
                  if (SearchRec.name <> '.') and (SearchRec.name <> '..') then
                    GetOneDirFileInfo(Json, Path + SearchRec.Name + '\');
                end else
                begin
                  FileName :=Path + SearchRec.Name;
                  try
                    if FileExists(FileName) then
                    begin 
                      json_sub :=Pub.GetJson;  
                      json_sub.SO; //初始化 或 json.Init;    
                      json_sub.S['filename'] :=SearchRec.name;
                      json_sub.S['RelativePath'] :=GetDeliBack(FileName, FromPath);
                      json_sub.S['FileTime'] :=FileGetFileTimeA(FileName);
                      json_sub.I['size'] :=SearchRec.Size;
                      json.A['list'] :=json_sub;
                    end;
                  except
                    //print(ExceptionParam)
                  end;//}
                end; 
                Status :=FindNext(SearchRec);
              end;
            finally
              FindClose(SearchRec);
              SearchRec.Free;
            end;//*) 
          end;
          %>
          <%
          begin
            FromPath :='D:\code\delphi\sign\發行文件'; //下載源目錄
            
            json :=Pub.GetJson; //這樣創建json對象不需要自己釋放,系統自動管理
            json.SO; //初始化 或 json.Init;
            
            // 驗證是否登錄代碼
            {if not Request.IsLogin('Logined') then
            begin 
              json.S['retcode'] :='300';
              json.S['retmsg'] :='你還沒有登錄(no logined)!'; 
              print(json.AsJson(true));
              exit; 
            end;//} 
            
            json.S['retcode'] :='200';
            json.S['retmsg'] :='成功!';
            if Request.V('opr')='1' then
            begin //獲取服務上指定目錄的文件信息
              GetOneDirFileInfo(Json, FromPath);
            end else
            if Request.V('opr')='2' then
            begin //下載指定文件給定大小的塊 
              FromPath :=PathWithSlash(FromPath);   
              RelativePath :=Request.V('fn');
              FileName :=FromPath + RelativePath;
              Fs :=Pub.GetFS(FileName, fmShareDenyWrite, ErrStr);
              if trim(ErrStr) <> '' then 
              begin
                json.S['retcode'] :='300';
                json.S['retmsg'] :=ErrStr;
                print(json.AsJson(true));  
                exit;
              end;
              Fs.Position :=StrToInt(Request.V('pos'));
              Response.ContentStream :=TMemoryStream.Create; //注意不能用 Pub.GetMs,這是因為Pub.GetMs創建的對象在動態腳本運行完就釋放了
              Response.ContentStream.CopyFrom(Fs, StrToInt(Request.V('size')));
              //返回流數據
              Response.ContentType :='application/octet-stream';   
            end;
            print(json.AsJson(true));
          end;
          %>

          客戶端代碼

          客戶端收到塊后,進行合并。全部塊下載完成后,還要把新下載的文件的文件修改為與服務器上的文件相同。以下是客戶端實現的主代碼:

          procedure TMainForm.UpgradeBlock_Run(var ThreadRetInfo: TThreadRetInfo);
          const
            BlockSize=1024*1024; //1M
          var
            HTML, ToPath, RelativePath, FN, Tmp, TmpFileName, FailFiles, SuccFiles, Newfn, TmpToPath: string;
            Json, TmpJson: TminiJson;
            lp, I, Number, HadUpSize, AllSize, AllBlockCount, MySize, MyNumber: Int64;
            Flag: boolean;
            SL, SLDate, SLSize, SLTmp: TStringlist;
            MS: TMemoryStream;
            Fs: TFileStream;
            procedure HintMsg(Msg: string);
            begin
              FMyMsg :=Msg; // '正在獲取文件列表。。。';
              ThreadRetInfo.Self.Synchronize(ThreadRetInfo.Self, MyUpdateface); //為什么不直接用匿名,因為laz不支持
            end;
          begin
            ToPath :='D:\superhtml'; //如果是當前程序更新  ExtractFilePath(ParamStr(0))
           
            ThreadRetInfo.Ok :=false;
           
            HintMsg('正在獲取文件列表。。。');
            if not HttpPost('/接口/同步文件到客戶端.html?opr=1',
                '', ThreadRetInfo.ErrStr, ThreadRetInfo.HTML) then exit;
            if Pos('{', ThreadRetInfo.HTML) <> 1 then
            begin
              ThreadRetInfo.ErrStr :='請先檢查腳本源碼是否配置正確!';
              exit;
            end;
            ToPath :=Pub.PathWithSlash(ToPath);
           
            Json :=TminiJson.Create;
            SL :=TStringlist.Create;
            SLDate :=TStringlist.Create;
            SLSize :=TStringlist.Create;
            SLTmp :=TStringlist.Create;
            try
              Json.LoadFromString(ThreadRetInfo.HTML);
              if json.S['retcode']='200' then
              begin
                TmpJson :=json.A['list'];
                for lp :=0 to TmpJson.length - 1 do
                begin
                  HintMsg(lp.ToString + '/' + TmpJson.length.ToString + '正在檢查文件:' + RelativePath);
                  RelativePath :=TmpJson[lp].S['RelativePath'];
                  if trim(RelativePath)='' then Continue;
                  Flag :=FileExists(ToPath + RelativePath);
                  if Flag then
                  begin
                    if (PubFile.FileGetFileTimeA(ToPath + RelativePath)=TmpJson[lp].S['FileTime']) and
                       (PubFile.FileGetFileSize(ToPath + RelativePath)=TmpJson[lp].I['Size']) then
                    else
                      Flag :=false;
                  end;
                  if not Flag then //此文件需要更新
                  begin
                    SL.Add(RelativePath);
                    SLDate.Add(TmpJson[lp].S['FileTime']);
                    SLSize.Add(TmpJson[lp].S['Size']);
                  end;
                end;
           
                //開始下載
                FailFiles :='';
                SuccFiles :='';
                HintMsg('需要更新的文件共有' + IntToStr(SL.Count) + '個。。。');
                for lp :=0 to SL.Count - 1 do
                begin
                  RelativePath :=SL[lp];
                  if RelativePath[1]='\' then RelativePath :=Copy(RelativePath, 2, MaxInt);
                  FN :=ToPath + RelativePath;
           
                  //先計算要分幾個包,以處理進度
                  Number :=0;
                  HadUpSize :=0;
                  AllSize :=StrToInt64(SLSize[lp]);
                  AllBlockCount :=0;
                  while true do
                  begin
                    AllBlockCount :=AllBlockCount + 1;
                    if AllSize - HadUpSize >=BlockSize then
                       MySize :=BlockSize
                    else
                       MySize :=AllSize - HadUpSize;
                    HadUpSize :=HadUpSize + MySize;
                    if HadUpSize >=AllSize then
                      break;
                  end;
           
                  //開始分塊下載
                  Number :=0;
                  HadUpSize :=0;
                  //AllSize :=Fs.Size;
                  //TmpToPath :=PubFile.FileGetTemporaryPath;
                  Newfn :='@_' + PubPWD.GetMd5(SLDate[lp] + SLSize[lp]) + ExtractFileName(FN);  //Pub.GetClientUniqueCode;
           
                  if FileExists(ToPath + Newfn) and (FileExists(FN)) then
                  begin
                    SLTmp.LoadFromFile(ToPath + Newfn);
                    MyNumber :=StrToInt64(trim(SLTmp.Text));
                    Fs :=TFileStream.Create(FN, fmOpenWrite);
                  end else
                  begin
                    MyNumber :=0;
                    Fs :=TFileStream.Create(FN, fmCreate);
                  end;
                  try
                    while true do
                    begin
                      HintMsg('正在下載文件[' + Pub.GetDeliBack(RelativePath, '@@') + ']第[' + IntToStr(Number + 1) + '/' + IntToStr(AllBlockCount) + ']個包。。。');
           
                      if AllSize - HadUpSize >=BlockSize then
                         MySize :=BlockSize
                      else
                         MySize :=AllSize - HadUpSize;
                      Number :=Number + 1;
                      if (MyNumber=0) or (Number >=MyNumber) or (HadUpSize + MySize >=AllSize) then
                      begin
                        for I :=1 to 2 do //意外出錯重試一次
                        begin
                          if not HttpPost('/接口/同步文件到客戶端.html?opr=2fn=' + UrlEncode(RelativePath) +
                            'pos=' + UrlEncode(IntToStr(HadUpSize)) + 'size=' + UrlEncode(IntToStr(MySize)),
                            '', ThreadRetInfo.ErrStr, ThreadRetInfo.HTML, MS) then
                          begin
                            if I=2 then
                            begin
                              ThreadRetInfo.ErrStr :=Json.S['retmsg'];
                              exit;
                            end else
                              Continue;
                          end;
                          if Pos('{', ThreadRetInfo.HTML) < 1 then
                          begin
                            if I=2 then
                            begin
                              ThreadRetInfo.ErrStr :=Json.S['retmsg'];
                              exit;
                            end else
                              Continue;
                          end;
           
                          Json.LoadFromString(ThreadRetInfo.HTML);
                          if json.S['retcode'] <> '200' then
                          begin
                            if I=2 then
                            begin
                              ThreadRetInfo.ErrStr :=Json.S['retmsg'];
                              exit;
                            end else
                              Continue;
                          end;
                          break;
                        end;
           
                        if MS=nil then
                        begin
                          ThreadRetInfo.ErrStr :='沒能下載到文件[' + RelativePath + ']!' + json.S['retmsg'];
                          exit;
                        end else
                        begin
                          Fs.Position :=HadUpSize;
                          MS.Position :=0;
                          Fs.CopyFrom(MS, MS.Size);
                          MS.Free;
                          MS :=nil;
                          SLTmp.Text :=Number.ToString;
                          try
                            SLTmp.SaveToFile(ToPath + Newfn);
                          except
                          end;
                        end;
                      end;
                      HadUpSize :=HadUpSize + MySize;
           
                      if HadUpSize >=AllSize then
                      begin //全部下載完成
                        Fs.Free;
                        Fs :=nil;
                        Sleep(10);
                        PubFile.FileChangeFileDate(Fn, SLDate[lp]);
                        DeleteFile(ToPath + Newfn);
                        SuccFiles :=SuccFiles + #13#10 + RelativePath;
                        break;
                      end;
                    end;
                  finally
                    if Fs <> nil then
                      Fs.Free;
                  end;
                end;
                ThreadRetInfo.HTML :='';
                if trim(SuccFiles) <> '' then
                  ThreadRetInfo.HTML :='本次更新了以下文件:'#13#10 + SuccFiles;
                //if trim(FailFiles) <> '' then
                  //ThreadRetInfo.HTML :=trim(ThreadRetInfo.HTML + #13#10'以下文件更新失敗:'#13#10 + FailFiles);
              end;
            finally
              SLTmp.Free;
              SLSize.Free;
              SL.Free;
              Json.Free;
              SLDate.Free;
            end;
            ThreadRetInfo.Ok :=true;
          end;

          以下是Demo運行界面:

          方描述

          Unit that implements generic container classes to group data items in arrays, dictionaries, lists, stacks, queues, and more.

          譯文:實現泛型容器類的單元,以在數組中對數據項進行分組,詞典,列表,堆棧,隊列等。

          起初在接觸到Delphi的時候我以為沒有這一部分內容,所有的都要自己實現,此處請原諒我的無知。。。。

          關于從那個版本開始支持泛型的,我在官方文檔上沒有找到對應的說明,也可能是我英語太菜,在官網迷路了。

          根據百度得來的結果2007的版本沒有(真百度的)支持2009的版本(萬一老師的博客上引用的也是這個版本)開始出現,也就是最早支持泛型容器的版本應該是Delphi2009

          聊泛型容器避不開的就是泛型的概念,之前看嗶哩嗶哩的網友留言從泛型一節就是開始懵逼了。其實大可不必,泛型可以理解為一個變量,它的值是一個具體的類型

          嗯,其實也可以把它當作孫大圣,它可以變成任何東西

          Collections單元

          在這個單元內一共定義了13個容器類,我們在其中甚至可以看到線程隊列。那么問題來了,我們需要精通或者學習所有的類嗎?答案是否定的

          容器類就我個人的理解其實一共有兩大表現形式,一種是列表形式的像數組,而另一種形式則以 Key,Value 成對的形式。也就是說我們從中選擇兩個比較有代表性的類進行學習即可。下面是我選擇的兩個類

          • System.Generics.Collections.TList:很明顯這個是列表
          • System.Generics.Collections.TDictionary:Dictionary這個單詞翻譯成中文是字典的意思,不知道為啥這么起名,它是K,V形式的代表

          注意:在單元內我們還可以看到相似的類例如 System.Generics.Collections.TObjectList<T> 和 System.Generics.Collections.TList<T>區別在于帶有Object的類會在刪除元素時釋放對象,而沒有帶Object的不會釋放

          API代碼

          針對容器類學習的總原則是圍繞增、刪、改、查這幾個核心的API功能即可,其他的就只能現用現查了,不知道別人寫代碼是什么習慣,我寫代碼的時候幫助文檔基本上都是開著的。。。

          下面是針對兩個容器類的代碼實現

          TList

          實體類(TStudent)代碼

          type
          
              TStudent=class
              private
                  FName: string;
              public
                  property Name: string read FName write FName;
                  // 構造方法
                  constructor Create; overload;
                  // 有參構造方法
                  constructor Create(FName: string); overload;
              end;
          
          constructor TStudent.Create;
          begin
          
          end;
          
          constructor TStudent.Create(FName: string);
          begin
              Self.FName :=FName;
          end;
          
          

          操作類(即增、刪、改、查),我沒有使用內聯,幾次想用都刪了

          uses
              System.Generics.Collections, System.SysUtils;
          
          var
              // 文檔上的定義是TList<T>,而我們的定義尖括號中的是TStudent,這就是泛型的用法
              StudentList: TList<TStudent>;
              // 循環中使用獲取TList成員
              Stu: TStudent;
          
          begin
              // 初始化學生列表
              StudentList :=TList<TStudent>.Create;
              StudentList.add(TStudent.Create('小強'));
              StudentList.add(TStudent.Create('蕭薔'));
              StudentList.add(TStudent.Create('小黑'));
              StudentList.add(TStudent.Create('小白'));
              StudentList.add(TStudent.Create('小黃'));
          
              // 開始之前輸出一次
              for Stu in StudentList do begin
          
                  Writeln('學生信息是:' + Stu.Name);
              end;
          
              // 泛型容器自帶的刪除函數,偷個懶
              StudentList.Delete(0);
          
              // 修改,查詢到指定的學生,修改其值即可
              StudentList.Items[0].Name :='小白';
          
          
              // 查詢,其實和數組的操作沒有太大區別
              for Stu in StudentList do begin
          
                  Writeln('學生信息是:' + Stu.Name);
              end;
          
          end.
          

          TDictionary

          此類容器的特點是 key 唯一,并且幾乎所有的操作都是根據 key 來的

          改造下實體類(TStudent)增加一個屬性,代碼如下

          type
          
              TStudent=class
              private
                  FName: string;
                  FId: string;
              public
                  property Name: string read FName write FName;
                  property Id: string read FId write FId;
          
                  // 構造方法
                  constructor Create; overload;
                  // 有參構造方法
                  constructor Create(FName: string; FId: string); overload;
              end;
          
          constructor TStudent.Create;
          begin
          
          end;
          
          constructor TStudent.Create(FName: string; FId: string);
          begin
              Self.FName :=FName;
          end;
          

          操作類(即增、刪、改、查)

          
          {注意單元的引用}
          uses
              System.Generics.Collections, System.SysUtils;
          
          var
              // 文檔上的定義是TList<T>,而我們的定義尖括號中的是TStudent,這就是泛型的用法
              StudentMap: TDictionary<string, TStudent>;
              // 循環中使用獲取TList成員
              Key: string;
              Student,Stu: TStudent;
          
          begin
              // 初始化學生列表
              StudentMap :=TDictionary<string, TStudent>.Create;
              // 此處的添加其實并不是太好,根據文檔描述,當我們添加的元素的key已經存在會拋出異常
              // 建議使用AddOrSetValue
              StudentMap.add('1001', TStudent.Create('1002', '小強'));
              StudentMap.add('1002', TStudent.Create('1001', '蕭薔'));
              StudentMap.add('1003', TStudent.Create('1003', '小黑'));
              StudentMap.add('1004', TStudent.Create('1004', '小白'));
              StudentMap.add('1005', TStudent.Create('1004', '小黃'));
          
              // 注意此處獲取是key,也就是1001 1002這些東西
              for Key in StudentMap.Keys do begin
          
                  // 獲取到key之后,再根據key獲取對應value也就是學生對象
                  // 這里的獲取方式有點兒任性居然要的是一個指針,而不是直接返回
                  StudentMap.TryGetValue(Key, Student);
                  // 最好判斷一下,否則容易出現空指針
                  if (Student <> nil) then
                      Writeln('學生信息是:' + Student.Name)
              end;
          
              // 刪除元素,無論什么操作都是通過key去操作,因為key是不可以重復的
              StudentMap.Remove('1005');
          
              // 修改,沒有就添加,有就更新
              StudentMap.AddOrSetValue('1004', TStudent.Create('1004', '小黃'));
          
              // 直接獲取value
              for Stu in StudentMap.values do begin
                  // 最好判斷一下,否則容易出現空指針
                  if (Stu <> nil) then
                      Writeln('學生信息是:' + Student.Name)
          
              end;
          end.
          

          參考資料

          萬一的博客:https://www.cnblogs.com/del/category/113556.html

          官方文檔:http://docwiki.embarcadero.com/Libraries/Sydney/en/System.Generics.Collections


          主站蜘蛛池模板: 国产乱码精品一区二区三区 | 中文精品一区二区三区四区| 国产福利电影一区二区三区,亚洲国模精品一区 | 精品无码av一区二区三区| 日本不卡免费新一区二区三区| 亚洲国产老鸭窝一区二区三区| 亚洲综合无码一区二区三区| 日本一区二区三区在线观看视频| 一区国严二区亚洲三区| 国产一区二区三区久久精品| 3d动漫精品啪啪一区二区中| 国产丝袜一区二区三区在线观看| 精品国产日韩亚洲一区| 久久99精品免费一区二区| 一区 二区 三区 中文字幕| 国产探花在线精品一区二区| 无码人妻一区二区三区av| 精品无码人妻一区二区三区不卡| 色妞AV永久一区二区国产AV| 波多野结衣一区二区| 日本一区午夜爱爱| 一本大道在线无码一区| 亚洲一区免费观看| 男插女高潮一区二区| 国产精品被窝福利一区 | 国产在线观看一区二区三区四区| 视频一区二区中文字幕| 大香伊人久久精品一区二区 | 国产在线一区二区在线视频| 老鸭窝毛片一区二区三区| 中文乱码人妻系列一区二区| 无码人妻精品一区二区三区99性| 色老板在线视频一区二区 | 一区二区免费视频| 亚洲韩国精品无码一区二区三区| 日本高清天码一区在线播放| 久久精品免费一区二区| 亚洲av乱码一区二区三区| 国产日韩精品一区二区在线观看| 国产精品伦子一区二区三区| 亚洲国产AV无码一区二区三区|