国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

VCL中網(wǎng)格控件原理分析

2019-11-18 18:16:35
字體:
供稿:網(wǎng)友
VCL中網(wǎng)格控件原理分析
lxpbuaa(桂枝香在故國晚秋)
2004-9-15
 
去年還在成都的時(shí)候,因?yàn)橥鹿ぷ餍枰?,我研究了一下TDBGrid,最后有點(diǎn)收獲,在TDBGrid中加入了固定列及相關(guān)一些(如固定列可得到焦點(diǎn)、可拖放、數(shù)據(jù)可修改等)功能。
前幾天,有人在我的Blog(http://blog.csdn.net/lxpbuaa)上開罵:“TMD,我還準(zhǔn)備來看點(diǎn)技術(shù)文章,Delphi區(qū)大版主的Blog上除了幾篇破譯文就這些爛東西”(因?yàn)檠栽~不雅,刪除了。大意如此)。想想也是,所以今天抽空整理了一下原來的東西,發(fā)篇小文,對VCL中網(wǎng)格控件的實(shí)現(xiàn)原理作個(gè)簡單介紹(但不會(huì)涉及給TDBGrid添加固定列等具體內(nèi)容,那是三言兩語說不清楚的事^@^)。歡迎指正、補(bǔ)充。
 
網(wǎng)格(Grid)控件,可直觀描述二維信息。因此它具有橫向和縱向二軸,就是一個(gè)二維表格。
一、類繼承結(jié)構(gòu)圖
                                TCustomGrid
                               /                    /
TCustomDrawGrid                 TCustomDBGrid
TDrawGrid                             TDBGrid
TStringGrid
1、TCustomGrid為所有網(wǎng)格控件的父類,定義了網(wǎng)格控件的主要特征和網(wǎng)格控件的主要功能。在這里,我們著重要了解的是它的兩個(gè)保護(hù)級(PRotected)方法:
(1)procedure Paint;
所有TWinControl的子類都可通過Paint來繪制自身外形。在TCustomGrid.Paint中,主要實(shí)現(xiàn)兩個(gè)功能:繪制網(wǎng)格線和填充網(wǎng)格數(shù)據(jù)。其中,網(wǎng)格數(shù)據(jù)的填充具體實(shí)現(xiàn)由下述的DrawCell完成。在后面的內(nèi)容,我會(huì)結(jié)合源代碼詳細(xì)解釋Paint。
   (2)procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState:  TGridDrawState); virtual; abstract;
這是一個(gè)純虛方法,被Paint調(diào)用,用以實(shí)現(xiàn)網(wǎng)格數(shù)據(jù)的填充。因此,所有TCustomGrid的子類都可以覆蓋(override)這個(gè)方法,根據(jù)實(shí)際需要實(shí)現(xiàn)填充方式。
2、TCustomDrawGrid并沒有實(shí)際用處。它主要完成兩件事情:
(1)覆蓋TCustomGrid的抽象方法加以實(shí)現(xiàn)。TCustomDrawGrid不再是一個(gè)抽象類。
(2)添加了一些事件。
比如它覆蓋了TCustomGrid.DrawCell,并在其中觸發(fā)了OnDrawCell事件。因此,我們在OnDrawCell中添加代碼,就可以改變特定行列網(wǎng)格中的數(shù)據(jù)及其填充方式。但要注意的是TCustomDrawGrid覆蓋DrawCell后,并沒有真正實(shí)現(xiàn)數(shù)據(jù)填充(因?yàn)樗€不知道數(shù)據(jù)是什么)。簡化后的DrawCell源代碼如下:
    procedure TCustomDrawGrid.DrawCell(ACol, ARow: Longint; ARect: TRect;
AState: TGridDrawState);
    begin
      if Assigned(FOnDrawCell) then
        FOnDrawCell(Self, ACol, ARow, ARect, AState);
    end;
3、TDrawGrid、TStringGrid都是用戶可以在設(shè)計(jì)時(shí)使用的類,或者簡單的說都是控件。但TDrawGrid是TCustomDrawGrid的一個(gè)簡單包裝,因此DrawCell仍然只簡單地觸發(fā)事件OnDrawCell,而沒有真正實(shí)現(xiàn)數(shù)據(jù)填充。也正因?yàn)槿绱耍琓DrawGrid的使用就相當(dāng)靈活,我們可以利用它繪制文本、圖形圖像等多種信息。
TStringGrid派生于TDrawGrid,專門用于描述文本信息。從以下源代碼可以看到,它真正實(shí)現(xiàn)了數(shù)據(jù)填充:
    procedure TStringGrid.DrawCell(ACol, ARow: Longint; ARect: TRect;
AState: TGridDrawState);
    begin
      if DefaultDrawing then
        Canvas.TextRect(ARect, ARect.Left+2, ARect.Top+2, Cells[ACol, ARow]);{即這句}
      inherited DrawCell(ACol, ARow, ARect, AState);
    end;
4、TDBGrid是數(shù)據(jù)敏感類的網(wǎng)格控件。它是對TCustomDBGrid的簡單包裝,而TCustomDBGrid的實(shí)現(xiàn)原理和普通網(wǎng)格控件是類似的,主要的區(qū)別在于數(shù)據(jù)源不同。比如TStringGrid的數(shù)據(jù)來自于TStringGrid.Cells,而TCustomDBGrid的數(shù)據(jù)來自于TCustomDBGrid.DataSource.DataSet。
 
二、TCustomGrid的主要功能
前面已經(jīng)說了,TCustomGrid定義了網(wǎng)格控件的主要功能,具有網(wǎng)格控件的主要特征,因此要理解網(wǎng)格控件的基本原理,重點(diǎn)在于TCustomGrid的兩個(gè)方法:Paint和DrawCell。
DrawCell是一個(gè)純虛方法,在Paint中被調(diào)用(具體過程參見下文),因此理解的重點(diǎn)是在兩個(gè)地方:
(1)Paint有什么用,Paint是如何運(yùn)作的。
(2)Paint中做了什么工作。
1、Paint的運(yùn)作機(jī)制。
前面說過了,Paint用來繪制控件自身外形。Paint內(nèi)部定義了具體的繪制方法,因此,只要在適當(dāng)?shù)臅r(shí)間和地點(diǎn)調(diào)用Paint,就可以改變控件外觀。
在VCL中,可將Paint方法簡單理解為TControl對Windows標(biāo)準(zhǔn)消息WM_PAINT的反應(yīng)。調(diào)用Win32 API中的UpdateWindow、RedrawWindow和InvalidateRect以及VCL中TControl的Repaint、Refresh和Update方法等都會(huì)直接或者間接引發(fā)相應(yīng)的WM_PAINT消息。
因此,網(wǎng)格控件的基本運(yùn)作原理就是:數(shù)據(jù)或者數(shù)據(jù)源本身發(fā)生變化后,通過適當(dāng)方式調(diào)用Paint方法,從而更新數(shù)據(jù)填充。拿TStringGrid為例,其Cells的數(shù)據(jù)改變后:
    procedure TStringGrid.SetCells(ACol, ARow: Integer; const Value: string);
    begin
      TStringGridStrings(EnsureDataRow(ARow))[ACol] := Value;
      EnsureColRow(ACol, True);
      EnsureColRow(ARow, False);
      Update(ACol, ARow); {這句內(nèi)部調(diào)用Win32 APIInvalidateRect標(biāo)記[ACol, ARow]所指區(qū)域需要重畫;系統(tǒng)接著就會(huì)發(fā)送一個(gè)WM_PAINT消息。最終引起Paint的執(zhí)行。}
end;
2、Paint所做工作。先看看我簡化后的源代碼,更容易說清楚。以“★”為各功能部分劃分標(biāo)記:
    procedure TCustomGrid.Paint;
 
      procedure DrawLines(DoHorz, DoVert: Boolean; Col, Row: Longint;
        const CellBounds: array of Integer; OnColor, OffColor: TColor);
      begin
        {……}
      end;
 
      procedure DrawCells(ACol, ARow: Longint; StartX, StartY, StopX, StopY: Integer; Color: TColor; IncludeDrawState: TGridDrawState);
      begin
        {……}
        {其中調(diào)用了TCustomGrid的純虛方法DrawCell
       因此TCustomGrid的子類可以覆蓋這個(gè)方法,自定義數(shù)據(jù)的填充方式}
        DrawCell(CurCol, CurRow, Where, DrawState);
        {……}
      end;
 
    begin
      {0:計(jì)算網(wǎng)絡(luò)繪制參數(shù)}
      CalcDrawInfo(DrawInfo);
 
      with DrawInfo do
      begin
        {1:繪制網(wǎng)格線(如果線寬>0}
        if (Horz.EffectiveLineWidth > 0) or (Vert.EffectiveLineWidth > 0) then
        begin
          {左上角固定列}
          DrawLines(goFixedHorzLine in Options, goFixedVertLine in Options, 0, 0, [0, 0, Horz.FixedBoundary, Vert.FixedBoundary], clBlack, FixedColor);
          {橫向固定列}
          DrawLines(goFixedHorzLine in Options, goFixedVertLine in Options, LeftCol, 0, [Horz.FixedBoundary, 0, Horz.GridBoundary, Vert.FixedBoundary], clBlack, FixedColor);
          {縱向固定列}
          DrawLines(goFixedHorzLine in Options, goFixedVertLine in Options, 0, TopRow, [0, Vert.FixedBoundary, Horz.FixedBoundary, Vert.GridBoundary], clBlack, FixedColor);
          {非固定列}
          DrawLines(goHorzLine in Options, goVertLine in Options, LeftCol, TopRow, [Horz.FixedBoundary, Vert.FixedBoundary, ??? Horz.GridBoundary, Vert.GridBoundary], LineColor, Color);
        end;
 
        {2填充數(shù)據(jù)}
        {左上角固定列}
        DrawCells(0, 0, 0, 0, Horz.FixedBoundary, Vert.FixedBoundary, ??? FixedColor, [gdFixed]);
        {橫向固定列}
        DrawCells(LeftCol, 0, Horz.FixedBoundary - FColOffset, 0, ??? Horz.GridBoundary, Vert.FixedBoundary, FixedColor, [gdFixed]);
        {縱向固定列}
        DrawCells(0, TopRow, 0, Vert.FixedBoundary, Horz.FixedBoundary, ?Vert.GridBoundary, FixedColor, [gdFixed]);
        {非固定列}
        DrawCells(LeftCol, TopRow, Horz.FixedBoundary - FColOffset, Vert.FixedBoundary, Horz.GridBoundary, Vert.GridBoundary, Color, []);
 
        {3:給被選中網(wǎng)格繪制外框}
        Canvas.DrawFocusRect(FocRect);
 
        {4:填充客戶區(qū)中未被網(wǎng)格占用的區(qū)域}
        {橫向部分}
        if Horz.GridBoundary < Horz.GridExtent then
        begin
          Canvas.Brush.Color := Color;
          Canvas.FillRect(Rect(Horz.GridBoundary, 0, Horz.GridExtent, ??? Vert.GridBoundary));
        end;
        {縱向部分}
        if Vert.GridBoundary < Vert.GridExtent then
        begin
          Canvas.Brush.Color := Color;
          Canvas.FillRect(Rect(0, Vert.GridBoundary, Horz.GridExtent, Vert.GridExtent));
        end;
      end;
    end;
 
從以上代碼可見,TCustomGrid.Paint主要可以分為五個(gè)部分。其中★0用于計(jì)算當(dāng)前繪制參數(shù),結(jié)果用于后面4個(gè)部分。接下來4個(gè)部分中,★1和★2是主體。因此我們關(guān)注的重點(diǎn)是★0、★1和★2?!?和★2已有詳細(xì)注解,所以不逐行解釋了,有興趣但看不懂的可慢慢琢磨。最后對★0的DrawInfo作個(gè)解釋。
DrawInfo為TGridDrawInfo類型,定義如下:
    TGridDrawInfo = record {網(wǎng)絡(luò)繪制參數(shù)}
      Horz, Vert: TGridAxisDrawInfo; {分為橫向和縱向兩個(gè)部分}
    end;
 
下面以橫向?yàn)槔?,解釋TGridAxisDrawInfo的含義:
    TGridAxisDrawInfo = record
      EffectiveLineWidth: Integer;    {網(wǎng)格線寬}
      FixedBoundary: Integer;        {網(wǎng)格固定列總寬度(含網(wǎng)格線)}
      GridBoundary: Integer;        {網(wǎng)格各列總寬度(含網(wǎng)格線、固定列)}
      GridExtent: Integer;        {網(wǎng)格客戶區(qū)總寬度}
      LastFullVisibleCell: Longint;    {當(dāng)前最后一個(gè)未超出客戶區(qū)(即能全部看見)的列}
      FullVisBoundary: Integer;    {當(dāng)前可全部看見列的總寬度(含網(wǎng)格線)}
      FixedCellCount: Integer;    {固定列個(gè)數(shù)}
      FirstGridCell: Integer;    {第一個(gè)非固定列,即LeftCol橫向)或者TopRow(縱向)}
      GridCellCount: Integer;    {ColCount,總列數(shù)}
      GetExtent: TGetExtentsFunc;    {一個(gè)函數(shù),用于取得列寬,相當(dāng)于ColWidths[Index]}
end;

上一篇:利用Indy的TIdFtp控件實(shí)現(xiàn)FTP協(xié)議

下一篇:使用TImage瀏覽與保存網(wǎng)絡(luò)圖像

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
學(xué)習(xí)交流
熱門圖片

新聞熱點(diǎn)

疑難解答

圖片精選

網(wǎng)友關(guān)注

主站蜘蛛池模板: 淮阳县| 萨迦县| 监利县| 麻栗坡县| 临江市| 陈巴尔虎旗| 嘉禾县| 土默特右旗| 博湖县| 龙川县| 理塘县| 湛江市| 衡阳市| 安平县| 门头沟区| 温泉县| 开阳县| 瑞安市| 梅河口市| 柏乡县| 永丰县| 都兰县| 衡南县| 云安县| 灵山县| 黎川县| 璧山县| 金川县| 亚东县| 永兴县| 祁门县| 扎赉特旗| 廊坊市| 新兴县| 靖州| 新野县| 巧家县| 山西省| 阿克苏市| 河西区| 雅江县|