• <i id="549yd"></i>
  • 
    
  • 現在位置:范文先生網>理工論文>計算機論文>酒杯上的碟

    酒杯上的碟

    時間:2023-02-20 22:49:05 計算機論文 我要投稿
    • 相關推薦

    酒杯上的碟

    交叉平臺控件(Cross-platform Controls)
    從windows到Linux,或者相反


    Borland處在一個令人興奮的時期.并不是自從delphi--這個Borland的令人興奮的產品的第一聲.我正在談論的當然是關于Kylix,這個把C++Builder和Delphi帶到Linux操作系統的項目.Delphi版本將首先面世,所以在本文余下部分,Kylix指的是Delphi for Linux.

    我們正在為Delphi開發嶄新的能夠在Windows和Linux下工作的VCL.這意味著你可以在windows下寫一個應用程序,然后把源代碼轉移到Linux下面重新編譯--反之亦然.這個新的VCL叫CLX,意即"交叉平臺控件庫(Component Library Cross-Platform)",CLX包含整個隨Kylix發布的交叉平臺庫.在我寫本文時它被分為下面四個子類:


    BaseCLX就是RTL,包含并且升級了Classes.pas
    VisualCLX包含了用戶界面類,比如常用的控件
    DataCLX包含交叉平臺的數據庫控件
    NetCLX包含Internet部分,比如Apache等等..

    在我寫這篇文章的時候(2000年5月之前),Kylix的第一部分測試已經正在進行了.當你讀到這篇文章的時候,我正在使用的Kylix和你將要看到的正式版本將會有很大不同.這為我的工作帶來很多不便.是簡單地談一談便罷?還是涉及一下底層的結構?我更傾向于詳細的討論,這樣無論如何你能得到一點關于CLX控件構造的頭緒.但是要牢記一點: 當你閱讀此文的時候,很可能這篇文章中很多細節的討論已經改變了.

    沒有更接近的了(No One Else Comes Close)

    這篇文章是關于寫定制VisualCLX控件的初級讀本.從本質上說,VisualCLX就是你所知道并熱愛的VCL.當你這樣認為的時候,"可視構件庫"(Visual Component Library)有一點用詞不當:還有比"可視構件"更多的東西.但是在這篇文章里面,我只談論"可視"控件.類似Button, Edit, ListBox, PageControl, StatusBar, ProgressBar等等的控件,都已經在交叉平臺下重新實現.但是目前的VCL如此依賴Windows,我們是怎么做到這些的呢?簡單地說,我們剝離了所有的Windows元素,然后把它們用別的工具包(toolkit)代替.

    在Linux下,有大量的工具包包含標準windows控件(如Buttons).它們被稱做"widgets".其中GTK和Qt(被發音成"cute")就是兩個非常流行的.Qt是一個工作在windows和Linux下的widgets,因為它非常接近我們的目標,所以Qt被選擇作為CLX的基礎.換句話說,Qt和CLX就好像Windows API/通用控件和VCL的關系.對于Linux下的Delphi的定制構件開發者來說,Qt有一些明顯的好處:


    它是一個廣泛使用的Linux下的widgets集,被流行的KDE桌面采用.
    它的開發和Windows API風格非常相似
    它的圖形模塊和VCL的圖形模塊相似
    它的類看上去非常像VCL控件
    它引入大量標準widgets,并且具有消息循環

    這將引發兩個疑問:是否這意味著Kylix只支持KDE,而不支持其他的桌面(desktop)?比如Gnome?并且,以Qt為基礎的CLX會給我帶來多大影響? 第一個問題的回答是:kylix應用程序將運行在所有Linux桌面下,特別是Gnome和KDE. 本文的余下部分將回答第二個問題.

    不讓你返回(????)(Don't Want You Back)

    我們的目標是讓開發者容易地將應用程序轉移到linux下,并且困難要最小化.大部分(新舊控件)的名字都是一樣的,大部分的屬性也是一樣的.盡管有一些控件的少數屬性去掉了,增加了一些新的屬性,但對于絕大部分來說,應該可以平穩的轉移你的應用程序.

    對控件作者來說有一些不同. 對于一個新手,現在沒有Windows.pas了,也沒有Windows API了.你可以對message標識和所有CN,CM通知(notifications)說再見了.這些都轉換成了動態的(dynamics)(???).在第一版中也不再有dock,BiDi相關的方法/屬性,輸入法(IME),遠東語言支持了.當然,更不會有ActiveX,COM或者OLE支持,Windows 3.1控件也去掉了.


    Methods
    CreateParams
    CreateSubClass
    CreateWindowHandle
    CreateWnd
    DestroyWindowHandle
    DestroyWnd
    DoAddDockClient
    DockOver
    DoDockOver
    DoRemoveDockClient
    DoUnDock
    GetDeviceContext
    MainWndProc
    ResetIme
    ResetImeComposition
    SetIme
    SetImeCompositionWindow
    WndProc
    Properties
    Ctl3D
    DefWndProc
    DockManager
    DockSite
    ImeMode
    ImeName
    ParentCtl3D
    UseDockManager
    WheelAccumulator

    附圖1: 從TWidgetControl(和TWinControl相類似)里面去掉的Methods和properties.


    此刻我打賭你正在想:"還不壞.轉移我的應用程序聽上去不是很難",但是請等等----還有更多的.在寫此文的時候,CLX類的名字都被加上了一個"Q"的前綴,比如StdCtrls變成了QStdCtrls,有些類被稍微攪亂了一點,在類繼承上面只有一些細微差別.(見附圖 2)


    附圖 2: 在類繼承上面的細微區別.


    CLX的這個"Q"前綴不一定是最終版本的前綴.TWinControl現在變成了TWidgetControl,不過為了安撫痛苦,我們為TWidgetControl添加了一個TWinControl的別名.TWidgetControl和它的后代都有一個Handle屬性,隱式地指向Qt對象,有一個Hooks屬性指向一個hook對象,用來實現事件機制.(Hooks是一個復雜的話題,已經超出本文的討論范圍)

    OwnerDraw將被一種叫做Styles

    酒杯上的碟

    的方法替代. 基本上Styles是widget或應用程序顯示新面孔的一種機制,類似于windows下面的貼圖(skins). 這部分正在開發當中,所以本文中我無法更進一步的介紹,我只能說:它非?!

    (新舊控件中)有沒有什么是一樣的?當然有,TCanvas(包括Pens,Brushes等)和你記得的一樣.就像我說過的,類的繼承基本上一樣,還有事件,比如OnMouseDown, OnMouseMove, OnClick...等等都還在.

    讓我看看內涵(Show Me the Meaning)(???)

    讓我們進入到CLX的軀體,看看它是如何工作的.Qt是一個C++的工具集,所以所有的widgets都是C++對象.另一方面,CLX是用Object Pascal寫的,并且Object Pascal不能直接和C++對象對話.越想簡單就越難,Qt在幾個地方使用了多繼承,所以我們建立了一個接口層(interface layer)來獲得所有Qt的類,并且把它們還原成一系列普通的C函數,然后把它們包裝成Windows下的DLL或是Linux下的共享對象(shared object).

    每個TWidgetControl都有CreateWidget, InitWidget, 和HookEvents虛方法,并且幾乎總是被重載. CreateWidget創建Qt的widget,然后指派Handle到FHandle這個私有域變量.當widget被構造(constructed)后,InitWidget被調用,然后Handle有效.你的一些屬性賦值將從Create這個構造函數轉移到InitWidget.這將能夠做到延遲構造(delayed construction)一個對象,直到真的需要它的時候.舉個例子,你有一個屬性叫Color,在SetColor里面,你可以通過HandleAllocated來檢測是否你有一個Qt的Handle,如果handle已經分配(allocated),你就可以正確地調用Qt來設置顏色.如果沒有分配,你可以把值保存在一個私有域變量中,然后在InitWidget中設置屬性.


    有兩種類型的事件(events): Widget事件和系統事件.HookEvents是一個虛方法(virtual method),它鉤住(hooks)CLX控件的事件方法到一個特殊的Hook對象,通過這個對象和Qt對象通訊.(至少這是我希望看到的)
    這個hook對象其實是方法指針的集合.系統事件現在通過EventHandler,基本上是WndProc的替代品.

    比生命還大(Larger Than Life)(????)

    所有這些都只是后臺信息(background information),因為你真的不必為了寫交叉平臺的定制控件而知道這些.在CLX的幫助下,寫交叉平臺控件只是小菜一碟(a snap).就像你不必理解Windows API的復雜性而去寫VCL控件一樣.CLX和Qt也是如此. 本文最后展示了一個用CLX寫的定制控件代碼

    下面是一個工程文件CalcTest.dpr. 計算器控件運行在windows下(見附圖4) 和Linux下(見附圖5) 看上去多么像標準的Microsoft Windows 計算器!

    program CalcTest;
    uses
    SysUtils, Classes, QControls, QForms, QStdCtrls, Qt,
    QComCtrls, QCalc, Types;
    type
    TTestForm = class(TForm)
    Calc: TCalculator;
    public
    constructor Create(AOwner: TComponent); override;
    end;

    var
    TestForm: TTestForm;
    { TTestForm }
    constructor TTestForm.Create(AOwner: TComponent);
    begin
    inherited CreateNew(AOwner);
    SetBounds(10,100,640,480);
    Calc := TCalculator.Create(Self);
    // Don't forget: we have to set the parent.
    Calc.Parent := Self;
    Calc.Top := 100;
    Calc.Left := 200;
    // Uncomment these to try other Border effects:
    // Calc.BorderStyle := bsEtched;
    end;

    begin
    Application := TApplication.Create(nil);
    Application.CreateForm(TTestForm, TestForm);
    TestForm.Show;
    Application.Run;
    end.

    附圖 3: CLX計算器控件的工程文件


    附圖 4: 運行在Windows下的計算器控件.



    附圖 5: 運行在Red Hat Linux下的計算器控件.

    就像你所看到的,TCalculator是TFrameControl的子類.TFrameControl繼承自TWidgetControl的一個子類.它為你的控件提供了一個框架(frame),我們最感興趣的屬性是BorderStyle:

    TBorderStyle = (bsNone, bsSingle, bsDouble, bsRaisedPanel,bsSunkenPanel,
    bsRaised3d, bsSUnken3d, bs Etched, bsEmbossed);

    在這個控件(TCalculator)中有兩個重要的方法.BuildCalc創建所有的按鈕,并且把它們擺放到正確的位置.正如你所看到的,我使用了一個叫TButtonType的枚舉類型來控制按鈕的"功能(function)",還有少量的信息做為整型保存在Tag屬性里面.我在后面的Calc方法里面會講到它.所有的計算器按鈕保存在一個叫做Btns的受保護的(protected)記錄數組里面,類型是TButtonRecord.

    TButtonRecord = record
    Top: Integer;
    Left: Integer;
    Width: Integer;
    Height: Integer;
    Caption: string;
    Color: TColor;
    end;

    這樣做能夠

    容易的在一個循環里面設置所有的按鈕,而不用寫一大串的TButton.Create調用.注意所有按鈕的OnClick句柄都指派給了TCalculator的Calc方法.直接指派到一個自定義事件是不錯的,因為所有按鈕都在計算器的內部,并且這些事件都不用被published(見附圖6)

    for i := Low(TButtonType) to High(TButtonType) do
    with TButton.Create(Self) do
    begin
    Parent := Self;
    SetBounds(Btns[i].Left, Btns[i].Top, Btns[i].Width,
    Btns[i].Height);
    Caption := Btns[i].Caption;
    Color := Btns[i].Color;
    OnClick := Calc;
    Tag := Ord(i);
    end;
    附圖 6: 在這種情況下,直接指派一個自定義事件是明智的

    我有一個叫FStatus的TLabel控件. TLabel也是TFrameControl的后代,我想在計算器里面使用它,所以我讓它具有"sunken box"的外觀來顯示計算器的存儲記憶,就像Windows里面的計算器一樣.Qt標簽的widget非常像VCL里面的TPanel控件.對于CLX里面的TLabel,我們沒有發布(publish)它的框架(frame)屬性,但是這并不妨礙你繼承使用它.

    在BuildCalc里面我做的最后一件事是創建一個edit控件來顯示計算結果,正像你所看到的,計算器控件的Text屬性和Edit控件的Text屬性直接掛鉤.

    另一個重要的方法是Calc,它實質上是一個龐大的case語句,用來計算哪一個按鈕被按下,并且決定該如何去做.我使用了私有域變量FCurrentValue, FLastValue 和 FRepeatValue來保存計算的值,所以我不必使用堆棧來實現.這個例子只是為了展示如何創建交叉平臺控件,而不是如何寫一個計算器.

    很好,還記得嗎,我在BuildCalc中使用了Tag屬性來控制它的功能.在這個方法里面,我們將參數Sender強制轉化成TButton,再將它的Tag強制轉化成TButtonType類型,最后賦值給ButtonType. ButonType就是那個case語句里面的選擇器表達式.

    ButtonType := TButtonType(TButton(Sender).Tag);

    對于我們如何把這些轉換成交叉平臺控件,你感到驚奇嗎? 不? 非常好! 這說明你已經集中注意力了.這些代碼可以同時在Windows和Linux下面編譯,而不用改動任何地方.沒有任何額外的步驟.正是仰仗于CLX的優點,控件已經全部完工了.

    所有不得不交待的(All I Have to Give)(????)

    你已經看到,寫一個交叉平臺控件和寫一個VCL控件并不是完全不同.如果你是一個控件開發的新手,學習起來不會很難.如果你是一個經驗豐富的VCL控件作者,你的大部分知識都將平滑地轉移到Kylix上去.

    我前面說過,(交叉平臺控件)會有一些不同,但是這只會影響那些依賴于Windows API寫控件的開發者.如果你寫的控件是從VCL繼承的,是聚合(aggregate)了一些控件的(就像我在TCalculator里面做的),是一個非可視的不依賴于Windows API的,或者是一個TGraphic控件,那么轉移到Linux下不會遇到什么麻煩.

    這篇文章介紹的軟件產品的功能正在開發中,并且會在沒有通知的情況下有些變化.相應功能的描述是應時而變的,并且沒有任何確定的服務承諾.

    做為Delphi最初測試版的用戶,Robert Kozak從1999年下半年加入Borland的Kylix R&D小組.從他加入Borland開始,他就和C++Builder 5和Kylix的開發密切相關.Robert還和TaDDA(多倫多區Delphi開發者協會)有關,這個協會后來和TDUG(多倫多區Delphi用戶組)合并.Robert在這些用戶社團一直很活躍,同時也經常出現在Borland的新聞組里面.

    [列表1]
    QCalc.pas

    { ***************************************************** }
    { }
    { Borland Delphi Visual Component Library }
    { Borland Delphi Component Library (X)Crossplatform }
    { }
    { Copyright (c) 2000 Inprise/Borland }
    { }
    { ***************************************************** }

    unit QCalc;

    // This is the very first Custom control written for CLX.

    interface

    uses
    Sysutils, Classes, QT, QControls, QStdCtrls, QComCtrls,
    QGraphics;

    type
    TButtonType = (bt0, bt1, bt2, bt3, bt4, bt5, bt6, bt7,
    bt8, bt9, btDecimal, btPlusMinus, btMultiply, btDivide,
    btAdd, btSubtract, btSqrt, btPercent, btInverse,
    btEquals, btBackspace, btClear, btClearAll,
    btMemoryRecall, btMemoryStore, btMemoryClear,
    btMemoryAdd);

    TCalcState = (csNone, csAdd, csSubtract, csMultiply, csDivide);

    TButtonRecord = record
    Top: Integer;
    Left: Integer;
    Width: Integer;
    Height: Integer;
    Caption: string;
    Color: TColor;
    end;

    TCalculator = class(TFrameControl)
    private
    FResultEdit: TEdit;

    FStatus: TLabel;
    FMemoryValue: Single;
    FCurrentValue: Single;
    FLastValue: Single;
    FRepeatValue: Single;
    FState: TCalcState;
    FBackSpaceValid: Boolean;
    protected
    Btns: array [TButtonType] of TButtonRecord;
    procedure BuildCalc;
    procedure Calc(Sender: TObject);
    function GetText : string; override;
    procedure SetText(const Value : string); override;
    public
    constructor Create(AOwner: TComponent); override;
    property Value : Single read FCurrentValue;
    published
    property Text : string read GetText write SetText;
    property BorderStyle;
    property LineWidth;
    property Margin;
    property MidLineWidth;
    property FrameRect;
    end;

    implementation

    function ButtonRecord(aTop, aLeft, aWidth, aHeight: Integer; aCaption: string;
    aColor: TColor = clBtnFace): TButtonRecord;
    begin
    Result.Top := aTop;
    Result.Left := aLeft;
    Result.Width := aWidth;
    Result.Height := aHeight;
    Result.Caption := aCaption;
    Result.Color := aColor;
    end;

    { TCalculator }

    constructor TCalculator.Create(AOwner: TComponent);
    begin
    inherited Create(AOwner);
    SetBounds(0,0,250,200);
    FMemoryValue := 0;
    FCurrentValue := 0;
    FLastValue := 0;
    FRepeatValue := 0;
    BorderStyle := bsRaisedPanel;
    BuildCalc;
    end;

    procedure TCalculator.BuildCalc;
    var
    i: TButtonType;
    begin
    Btns[bt7] := ButtonRecord(70, 48, 36, 29, '7');
    Btns[bt4] := ButtonRecord(102, 48, 36, 29, '4');
    Btns[bt1] := ButtonRecord(134, 48, 36, 29, '1');
    Btns[bt0] := ButtonRecord(166, 48, 36, 29, '0');
    Btns[bt8] := ButtonRecord(70, 88, 36, 29, '8');
    Btns[bt5] := ButtonRecord(102, 88, 36, 29, '5');
    Btns[bt2] := ButtonRecord(134, 88, 36, 29, '2');
    Btns[btPlusMinus] :=
    ButtonRecord(166, 88, 36, 29, '+/-');
    Btns[bt9] := ButtonRecord(70, 128, 36, 29, '9');
    Btns[bt6] := ButtonRecord(102, 128, 36, 29, '6');
    Btns[bt3] := ButtonRecord(134, 128, 36, 29, '3');
    Btns[btDecimal] := ButtonRecord(166, 128, 36, 29, '.');
    Btns[btDivide] := ButtonRecord(70, 168, 36, 29, '/');
    Btns[btMultiply] := ButtonRecord(102, 168, 36, 29, '*');
    Btns[btSubtract] := ButtonRecord(134, 168, 36, 29, '-');
    Btns[btAdd] := ButtonRecord(166, 168, 36, 29, '+');
    Btns[btBackspace] :=
    ButtonRecord(37, 49, 63, 25, 'Backspace');
    Btns[btClear] := ButtonRecord(37, 115, 63, 25, 'CE');
    Btns[btClearAll] := ButtonRecord(37, 181, 63, 25, 'C');
    Btns[btsqrt] := ButtonRecord(70, 208, 36, 29, 'sqrt');
    Btns[btPercent] := ButtonRecord(102, 208, 36, 29, '%');
    Btns[btInverse] := ButtonRecord(134, 208, 36, 29, '1/x');
    Btns[btEquals] := ButtonRecord(166, 208, 36, 29, '=');
    Btns[btMemoryAdd] := ButtonRecord(166, 5, 36, 29, 'M+');
    Btns[btMemoryStore] :=
    ButtonRecord(134, 5, 36, 29, 'MS');
    Btns[btMemoryRecall] :=
    ButtonRecord(102, 5, 36, 29, 'MR');
    Btns[btMemoryClear] := ButtonRecord(70, 5, 36, 29, 'MC

    ');

    for i := Low(TButtonType) to High(TButtonType) do
    with TButton.Create(Self) do
    begin
    Parent := Self;
    SetBounds(Btns[i].Left, Btns[i].Top, Btns[i].Width,
    Btns[i].Height);
    Caption := Btns[i].Caption;
    Color := Btns[i].Color;
    OnClick := Calc;
    Tag := Ord(i);
    end;

    FStatus := TLabel.Create(Self);
    with FStatus do
    begin
    Parent := Self;
    SetBounds(10, 38, 25, 25);
    BorderStyle := bsRaisedPanel;
    end;

    FResultEdit := TEdit.Create(Self);
    FResultEdit.Parent := Self;
    FResultEdit.SetBounds(5, 5, 240, 25);
    FResultEdit.Alignment := taRightJustify;
    FResultEdit.Font.Height := -13;
    FResultEdit.Font.Name := 'Arial';
    FResultEdit.Text := '0';
    end;

    procedure TCalculator.Calc(Sender: TObject);
    const
    MemoryStoreMap: array [Boolean] of string = (' M','');
    var
    ButtonType: TButtonType;
    Temp: string;
    TempValue: Single;
    begin
    ButtonType := TButtonType(TButton(Sender).Tag);

    try
    case ButtonType of
    bt0..bt9:
    begin
    FBackSpaceValid := True;
    if (FResultEdit.Text = '0') or (FCurrentValue = 0) then FResultEdit.Text := '';
    FResultEdit.Text :=
    FResultEdit.Text + Btns[ButtonType].Caption;
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FRepeatValue := 0;
    end;

    btDecimal:
    if Pos('.', FResultEdit.Text) < 1 then
    begin
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FLastValue := 0;
    FResultEdit.Text :=
    FResultEdit.Text + Btns[ButtonType].Caption;
    end;

    btPlusMinus:
    begin
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FCurrentValue := FCurrentValue * -1;
    FResultEdit.Text := FloatToStr(FCurrentValue);
    end;

    btClearAll:
    begin
    FCurrentValue := 0;
    FLastValue := 0;
    FResultEdit.Text := '0';
    FState := csNone;
    end;

    btClear:
    begin
    FCurrentValue := 0;
    FResultEdit.Text := '0';
    end;

    btAdd:
    begin
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FState := csAdd;
    FLastValue := FCurrentValue;
    FCurrentValue := 0;
    end;

    btSubtract:
    begin
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FState := csSubtract;
    FLastValue := FCurrentValue;
    FCurrentValue := 0;
    end;

    btDivide:
    begin
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FState := csDivide;
    FLastValue := FCurrentValue;
    FCurrentValue := 0;
    end;

    btMultiply:
    begin
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FState := csMultiply;
    FLastValue := FCurrentValue;
    FCurrentValue := 0;
    end;

    btBackSpace:
    if FBackSpaceValid then
    begin
    Temp := FResultEdit.Text;
    Delete(Temp, Length(Temp),1);
    if Temp = '' then Temp := '0';
    FCurrentValue := StrToFloat(Temp);
    FResultEdit.Text := FloatToStr(FCurrentValue);
    end;

    btInverse:
    begin
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FCurrentValue := 1 / FCurrentValue;

    FResultEdit.Text := FloatToStr(FCurrentValue);
    end;

    btPercent:
    begin
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FCurrentValue := FCurrentValue / 100;
    FResultEdit.Text := FloatToStr(FCurrentValue);
    end;

    btSqrt:
    begin
    FCurrentValue := StrToFloat(FResultEdit.Text);
    FCurrentValue := Sqrt(FCurrentValue);
    FResultEdit.Text := FloatToStr(FCurrentValue);
    end;

    btMemoryStore:
    begin
    FMemoryValue := StrToFloat(FResultEdit.Text);
    FMemoryValue := FMemoryValue * 1;
    FCurrentValue := 0;
    end;

    btMemoryAdd:
    begin
    TempValue := FMemoryValue;
    FMemoryValue := StrToFloat(FResultEdit.Text);
    FMemoryValue := (FMemoryValue * 1) + TempValue;
    end;

    btMemoryRecall:
    begin
    FResultEdit.Text := FloatToStr(FMemoryValue);
    FCurrentValue := 0;
    end;

    btMemoryClear:
    begin
    FMemoryValue := 0;
    end;

    btEquals:
    if FState <> csNone then
    begin
    FBackSpaceValid := False;
    FCurrentValue := StrToFloat(FResultEdit.Text);
    if FRepeatValue = 0 then
    begin
    FRepeatValue := FCurrentValue;
    FCurrentValue := FLastValue;
    end;
    FLastValue := FRepeatValue;
    case FState of
    csAdd:
    FCurrentValue := FCurrentValue + FLastValue;
    csMultiply:
    FCurrentValue := FCurrentValue * FLastValue;
    csSubtract:
    FCurrentValue := FCurrentValue - FLastValue;
    csDivide:
    FCurrentValue := FCurrentValue / FLastValue;
    end;
    FLastValue := FCurrentValue;
    FResultEdit.Text := FloatToStr(FCurrentValue);
    FCurrentValue := 0;
    end;
    end; // case ButtonType of...

    except
    on E: Exception do
    begin
    FResultEdit.Text := E.Message;
    FLastValue := 0;
    FCurrentValue := 0;
    FRepeatValue := 0;
    FState := csNone;
    end;
    end;
    FStatus.Caption := MemoryStoreMap[FMemoryValue = 0];
    end;

    function TCalculator.GetText: string;
    begin
    Result := FResultEdit.Text;
    end;

    procedure TCalculator.SetText(const Value: string);
    begin
    FResultEdit.Text := Value;
    end;

    end.


    【酒杯上的碟】相關文章:

    酒杯優秀作文09-05

    草原上08-17

    上、下08-16

    下水(上)08-17

    《草原上》說課稿07-12

    淮上的語錄01-26

    指尖上的中國02-27

    在金茂大廈上02-28

    上與下作文02-22

    av片在线观看无码免费_日日高潮夜夜爽高清视频_久久精品中文字幕乱码视频_在线亚州av播放