動態建立 TClientDataSet 與 TDataSetProvider .. |
尚未結案
|
seaturn99
版主 發表:69 回覆:427 積分:214 註冊:2003-08-25 發送簡訊給我 |
請教一下各位先進,我寫了一段 Code 如下,不過都無法順利成功..
function ADODataSetToData(var ADataSet: TDataSet): OleVariant; var cds: TClientDataSet; dsp: TDataSetProvider; begin if not ADataSet.Active then ADataSet.Open; try dsp := TDataSetProvider.Create(nil); dsp.Name := 'tDataSetProvider'; dsp.DataSet := ADataSet; try cds := TClientDataSet.Create(nil); cds.ProviderName := dsp.Name; cds.Active := true; Result := cds.Data; finally cds.Close; FreeAndNil(cds); end; finally ADataSet.Active := false; FreeAndNil(dsp); end; end;這個 function 的目的是傳入一個 ADODataSet (Ex :TADOQuery) Open 之後傳回的結果,透過 TDataSetProvider 與 TClientDataSet 轉換成 OleVariant.. 不過,在 Design Time 中,於 TDataModule 拉相關元件可以達到效果,所以我想應該 Run-Time 也可以達到,只是 Design Time 隱含了不少的動作,請問在 Run Time 要設計以上 function 要如何修改 code ? ---- 我只會兩件事,這也不會,那也不會 眼見不一定為真 ---- |
conundrum
尊榮會員 發表:893 回覆:1272 積分:643 註冊:2004-01-06 發送簡訊給我 |
http://www.delphibbs.com/keylife/iblog_show.asp?xid=4562
KeyLife富翁筆記
作者 hongxing_dl
標題 ClientDataSet的隱含功能
關鍵字: Midas
分類 開發經驗
密級: 公開 ClientDataSet的隱含功能------轉載《Delphi 從入門到精通》 可能與前面的筆記有重複的地方 ClientDataSet元件支援很多特性,其中一些與三級結構有關,而且還可以用在其他環境中。該元件說明瞭一個資料庫完全映象在記憶體中,這使得可以進行動態的操作,如建立一個索引,其他資料集合通常不支援該特性。例如,為了對查詢分類,我們通常是重新執行它。為了索引一個局部表格,需要定義索引。只有ADO資料集合有一些與ClientDataSet一樣的動態索引功能。
索引並不是ClientDataSet提供的全部功能。當我們擁有了索引之後,可以基於它定義組,可能是多級別的分組。對於確定一個記錄在組中的位置(頭、尾或中間位置),甚至有專門的支援。在組或整個資料表格中,我們可以定義總計;也就是說,可以動態計算整個表格或當前組中一列的總和或平均值。資料不需要發送給物理伺服器,因為這些總計操作發生在記憶體中。我們甚至可以定義新的總計欄位,可以直接與資料敏感控制項相連。
注意,所有這些特性不但可以用與MIDAS應用程式,還可以用與客戶機/伺服器,甚至是局部瘦應用程式。事實上,ClientDataSet元件可以從遠端MIDAS連接、局部資料集合(建立起資料的快照)、或局部檔(就象在公事包模式中一樣,但使用的只是在客戶機資料集合中定義的整個表格)中獲得起資料。
這是另一個需要研究的領域,所以將向讀者演示兩個範例來突出關鍵特性。這些範例沒有基於MIDAS,而是基於局部表格。 1、定義抽象的資料的資料類型 VCL資料庫支援的一個有趣的特性是,當我們基於局部檔使用ClientDataSet時,可以定義抽象的資料類型。只需在表單上放置一個ClientDataSet元件,為FieldDefs屬性啟動編輯器,添加兩個欄位,並為他們的DataType屬性選擇ftADT值。現在,移到ChildDefs屬性,並定義子欄位,下麵是AdtDemo範例的欄位定義:
FieldDefs = <
item
Name = 'ID'
DataType = ftInteger
end
item
name = 'Name'
ChildDefs = <
item
name = 'LastName'
DataType = ftString
size = 20
end
item
name = 'FirstName'
datatype = ftString
size = 20
end>
datatype = ftADT
size = 2
end> 在此,只需為ClientDataSet的FileName屬性輸入一個名稱,用滑鼠右鍵單擊元件,並選擇Create Table命令即可;我們準備編譯並運行應用程式(在向它連接資料敏感元件之後)。資料會自動從提供的檔中讀取,關閉程式時會將變化保存在檔中。
如果使用DBGrid查看結果資料集合,它允許我們展開或壓縮ADT欄位的子欄位。我們可以通過定義欄位的OnGetText事件提供它的壓縮值(在Delphi4 中有一個缺省值,但Delphi5中沒有):
procedure TForm1.ClientDataSet1NameGetText(Sender:TField;
var Text:String;DisplayText:Boolean);
begin
Text:=ClientDataSet1NameFirstName.AsString ' '
ClientDataSet1NameLastName.AsString;
end; 2、動態索引 一旦ClientDataSet上有了資料,資料就已全部處於記憶體中了。當我們將元件基於局部檔中時(如在AdtDemo範例中),在程式啟動時整個檔就被裝載到了記憶體總。這與從Paradox資料表格中裝載資料(BDE只裝載正訪問的欄位)不同。
將整個表格裝在記憶體中的優點是,我們可以快速地對它進行分類。使用ClientDataSet元件,我們可以通過賦給IndexFieldNames屬性相應的欄位名來實現分類。在AdtDemo(以及很多程式)中,該索引變動會在單擊DBGrid控制項的標題(觸發OnTitleClick事件)時執行: procedure TForm1.DBGrid1TitleClick(Column:TColumn);
begin
if Column.Field.FullName = 'Name' then
ClientDataSet1.IndexFieldNames := 'Name.LastName'
else
ClientDataSet1.IndexFieldNames := Column.Field.FullName;
end; 由於ADT定義,程式使用了欄位的FullName屬性(而不是FieldName屬性)。事實上,對於子欄位元來說,索引應該基於Name.LastName,而不是LastName。而且ADT欄位元不能自己被索引,所以如果選擇它,程式會使用LastName子欄位元作為索引。這些索引不是持久性的;它們沒有保存在檔中,而只是在記憶體中應用於資料。 技巧:ClientDataSet可以擁有基於計算欄位元的索引,特別是內部計算欄位,這種欄位類型只能用於該資料集合。 3、分組 一旦為ClientDataSet定義了一個索引,就可以通過該索引對資料進行分組了。實際上,一組被定義為連續記錄的一個列表(根據索引),記錄中被索引的欄位元的值不會改變。例如,如果有一個基於國家的索引,帶有該國家的所有位址都將歸為一組。
cdsCalcs範例有一個ClientDataSet元件,它同樣從DBDEMOS資料庫的Country表格中讀取其資料。該操作可以在設計時,使用ClientDataSet元件快顯功能表的Assign Local Data命令來執行。為了在運行時讀取資料,獲得一個更新的快照,可以向表單添加一個DataSetProvider元件,如下連接三個元件:
Object Table :TTable
active = true
databasename = 'dbdemos'
tablename = 'country.db'
end
object datasetprovider1: TDataSetProvider
dataset = table1
end
object clientdataset1: tclientdataset
providername = 'datasetprovider1'
end
現在我們來看看組的定義。該定義可以通過為索引指定一個分組級別,與索引定義一起獲得:
object clientdataset1: tclientdataset
indexdefs = <
item
name = 'clientdataset1index1'
fields = 'continent'
groupinglevel = 1
end>
indexname = 'clientdtaset1index1'
當擁有了一組之後,我們可以在DBGrid中向用戶顯示分組結構。只需為分組欄位(在範例中是Continent欄位)處理OnGetText事件,只有當記錄是組的第一個記錄是才顯示文本:
procedure TForm1.ClientDataSet1ContinentGetText(Sender:TField;
var Text:String;DisplayText:Boolean);
begin
if gbFirst in ClientDataSet1.GetGroupState(1) then
Text:= sender.asstring
else
text:='';
end; 4、定義合計 ClientDataSet組件另一個功能強大的特性是對合計的支援。合計是一個基於多個記錄的計算值,如整個資料表格或一組記錄(使用我們剛才討論過的分組邏輯來定義)中某個欄位的和值或平均值。合計是可持續的;也就是說,如果有一個記錄發生改變,會立刻重新計算合計值。例如,當擁護在發貨清單條目中輸入時,發貨單的總和會自動被重新計算出來。
注意:::合計是遞增維持的,而不是每當有一個值改動時就重新計算所有的值。合計的更新利用了ClientDataSet追蹤的Delta。例如,當欄位發生改變時,為了更新Sum,ClientDataSet會從合計中讀取舊值,並加上新值。只需要兩次計算,即使在該合計組中有上千行。因此,合計更新是暫態的。
有兩種方法定義合計。我們可以使用ClientDataSet(是一個集合)的Aggregates屬性,或可以使用Fields編輯器定義合計欄位。在這兩種情況下,我們定義的合計運算式,賦給它一個名稱,並將它與一個索引和一個分組級別(除非想將它應用於整個資料表格)連接。下麵是CdsCalcs範例的Aggregates集合:
Object ClientDataSet1: TClientDataSet
Aggregates = <
item
Active = True
AggregateName = 'Count'
Expression = 'Count(Name)'
GroupingLevel = 1
IndexName = 'ClientDataSet1Index1'
Visible = False
end
item
Active = True
AggregateName = 'TotalPopulation'
Expression = 'SUM(POPULATION)'
Visible = False
end>
AggregatesActive = True
注意,在上面的最後一行代碼中,除了啟動每個想使用的特定合計之外,我們還必須為合計啟動支持。解除合計是重要的,因為合計太多會減慢程式執行的速度。我們曾提到的另一種方法是使用Fields編輯器,在其快顯功能表中選擇New Field命令,並選擇Aggregate選項(只有在一個ClientDataSet中可以與InternalCalc選項一起使用)。下麵是一個合計欄位的定義:
Object ClientDataSet1: TClientDataSet
object ClientDataSet1TotalArea: TAggregateField
FieldName = 'TotalArea'
ReadOnly = True
Visible = True
Active = True
DisplayFormat = '###,###,###'
Expression = 'SUM(AREA)'
GroupingLevel = 1
IndexName = 'ClientDataSet1Index1'
end
合計欄位在Fields編輯器中被顯示為獨立的一組。與普通合計相比,使用合計欄位的優點是,我們可以定義顯示格式,並將欄位直接與資料敏感控制項相連,如CdsCalcs範例中的DBEdit。因為合計與一個組相連,所以要選擇了另一組的記錄,輸出就會被自動更新。而且,如果改變資料,合計值也會立刻顯示新值。
為了使用普通合計,必須編寫一些代碼,如下例子中所示(注意合計的Value是一個變體):
procedure TForm1.Button1Click(Sender: TObject);
begin
Label1.Caption:= 'Area : ' ClientDataSet1TotalArea.DisplayText
#13'Population : ' FormatFloat('###,###,###',ClientDataSet1.Aggregates[1].Value)
#13'Number : ' IntToStr(ClientDataSet1.Aggregates[0].Value);
end;
|
conundrum
尊榮會員 發表:893 回覆:1272 積分:643 註冊:2004-01-06 發送簡訊給我 |
用Delphi開發基於Web的多層應用
http://www.ithome-cn.net/technology/delphi/de069.htm
多層體系結構最大的優勢可以概括為兩點,一是集中化的商業邏輯,另一個是客戶程式可以做得很“瘦”。 一、多層體系結構概述 多層結構其實是對傳統Client/Server 結構的擴展。三層模式是最典型的多層結構。一般來講,三層結構可作如下定義:表達邏輯層(即用戶端的介面部分),業務邏輯層(即業務處理部分),資料邏輯層(即資料庫部分)。相對于傳統的Client/Server 結構來講,表達邏輯層+業務邏輯層= 傳統的用戶端。
1. 資料邏輯層由對資料進行物理創建、更新、刪除和檢索的元件構成。這些元件負責與存儲介質的交互,使得物理資料對其他元件透明。 2. 業務邏輯層由實現業務規則的元件構成。業務規則只存在於這一層上。這些規則作為服務提供給其他元件。這一中間層伺服器是多線程的,可以提供多用戶訪問,並能由多個獨立的應用平等共用。三層結構大部分處理(邏輯和計算)由中間層伺服器控制,中間層代碼可供多個用戶端訪問和使用。 3. 客戶結點由負責系統介面的元件構成。這些元件可運行於不同的設備上,從ASCII 終端到Windows 介面,Internet 流覽器和網路電腦(NC)。當表達邏輯層的客戶需要計算或進行資料存取的時候,便產生一個調用傳給中間層伺服器。
二、MIDAS 技術 1. MIDAS 構件類型
MIDAS(Multi -tier Distributed Application Services)即多層分散式應用程式伺服器。它提供了一整套中間層應用服務,擴展了作業系統標準,這些服務用於解決各種具體的分散式計算問題,從用於網路定位的目錄服務到資料庫集成和業務規則處理。它主要基於Borland 的分散式資料集技術,至少包括兩方面的內容: * 內置在Delphi 組件中;
* OLEnterprise 產品對分散式計算和負載平衡提供的超強支援。 MIDAS 技術是多層體系結構的關鍵。無論是應用伺服器端還是用戶端,MIDAS 技術需要有DBCLIENT.DLL 的支援,這個動態連結程式庫用於管理資料包。基於MIDAS 的多層應用程式需要用到一些特殊的構件,這些構件分為四大種類:
(1) 物件庫中的遠端資料模組(Remote Data Module)。遠端資料模組與普通的資料模組有些相似,不同的是,遠端資料模組可以作為COM 伺服器或CORBA 伺服器讓客戶程式訪問它的介面。 (2)TDataSetProvider 和TProvider 構件。這兩個構件用在應用伺服器端,主要作用是提供IProvider 介面,客戶程式通過IProvider 介面獲得資料和更新資料集。 (3)TClientDataSet 構件。客戶資料集構件,這是一個從TDataset 繼承下來的但不需要BDE 的構件。 (4)MIDAS 連接構件。Delphi3 中提供TMIDASConnection 和TRemoteServer,Delphi4 在此基礎上又增加了TDCOMConnection、TSocketConnection、TCorbaConnection TOLEnterpriseConnection,MIDAS 連接構件的作用是為客戶程式定位伺服器和IProvider 介面。每個MIDAS 連接構件都以一種特定的通信協議工作
2. MIDAS 結構的程式實現 在多層的資料庫應用程式中,客戶程式、應用伺服器和遠端伺服器分佈在不同的機器上。其中,客戶程式主要提供用戶介面,它能夠向應用伺服器請求資料和申請更新資料。再由應用伺服器( 又叫Remote Data Broker) 向遠端資料庫伺服器請求資料和申請更新資料。在Delphi 中的實現如圖2
應用伺服器端的Remote Data Module 從概念上與一般的Data Module 相對應,但在實現時,一旦創建了Remote Data Module,Delphi 即把此應用程式看作是應用伺服器,實現為OLE 自動化伺服器。Provider 構件從概念上類似於兩層結構中的資料源構件,每一個Provider 都有一個TTable,Tquery 這樣的資料集構件相連,通過它們與資料庫交互。 用戶端的MIDAS 連接構件的主要作用是定位遠端的應用伺服器,並從應用伺服器取得Iprovider 介面提供給ClientDataSet,本身不參與資料庫操作。而ClientDataSet 構件在概念上與TTable、TQuery 等資料集構件相似,可對用戶介面中的可視資料構件提供資料,每一個ClientDataSet 必須與應用伺服器端的一個Provider 相連,因此ClientDataSet 中的資料實際上是Provider 對應的資料集構件中資料。 3. MIDAS 應用程式的工作流程 一個簡單的查詢——更新操作的流程如下: (1) 首先要啟動客戶程式,客戶程式將試圖連接應用伺服器,如果應用伺服器還沒有運行,客戶程式將啟動應用伺服器,並從中獲得IProvider 介面。 (2) 客戶程式向應用伺服器請求資料。如果TClientDataSet 的FetchOnDemand 屬性設為True,客戶程式會根據需要自動檢索附加的資料包如BLOB 欄位的值或嵌套表的內容。否則,客戶程式需要顯式地調用GetNextPacket 才能獲得這些附加的資料包。 (3 )應用伺服器收到客戶程式的請求後,就從遠端資料庫伺服器檢索資料,並打包返回給客戶程式。 (4) 客戶程式收到資料包後把包打開,然後顯示或進行處理。 (5) 用戶對資料進行編輯修改,然後向應用伺服器申請更新資料,實際上也要打包。 (6) 應用伺服器收到客戶程式的申請後,就向遠端資料庫伺服器申請更新資料。如果出錯,應用伺服器就把出錯的記錄返回給客戶程式去核對。 (7) 客戶程式核對並修改了資料後,既可以放棄此次更新,也可以繼續此次更新。 在多層模式下,幾個客戶有可能同時與一個應用伺服器通訊,應用伺服器實際上充當了一個閘道的作用。對於最終用戶來說,多層體系結構中的客戶程式與兩層體系結構中的應用程式沒有什麼區別。 三、基於Web 的多層體系結構 為了將分散式的資料庫結構引申到Internet/Intranet 上,可以將用戶端製作為一個ActiveX 控制項嵌入到標準HTML 頁面中,隨同HTML 頁面下載到當地執行。在Delphi 中,這種用戶端是以ActiveForm 的形式出現的。ActiveForm 是開發具有Web 功能的Client/Server 應用程式另外一個重要的部分。ActiveForm 是一個ActiveX 控制項,在設計階段和普通Form 並沒有什麼不同,但編譯後生成的*.OCX 檔可以在流覽器內運行。客戶機通過流覽器下載一個ActiveForm,ActiveForm 通過TRemoteServer 與遠端伺服器建立連接,再由遠端伺服器訪問資料庫。
一個基於Web 的多層應用程式的運行流程如圖3
(1) 客戶通過WWW 流覽器向WWW 伺服器發出請求,通過HTTP 協議下載嵌入了ActiveForm 的HTML 頁面,安裝ActiveForm,並在本機運行。 (2) ActiveForm 通過MIDAS 連接構件連接應用伺服器,將客戶的請求資料發送給應用伺服器。Internet/Intranet 上的應用伺服器必須支援DCOM 或TCP/IP 連接方式,同樣,設計成ActiveForm 的客戶程式也必須支援DCOM 或TCP/IP 連接方式,因為下載ActiveForm 的電腦上可能沒有安裝OLEnterprise 或CORBA 運行期軟體。 (3) 應用伺服器收到請求後連接遠端資料庫伺服器,申請檢索或更新資料。 (4) 遠端資料庫伺服器完成操作後,將資料發送給應用伺服器。 (5) 應用伺服器再將處理後的資料發送給用戶端的ActiveForm,ActiveForm 從ClientDataSet 中提取資料,按照一定的規則與格式在可視資料控制項中顯示出來。 四、基於Web的多層應用程式的開發步驟 1. 創建應用伺服器
要創建一個多層Client/Server 應用程式,首先要創建應用伺服器,然後註冊或安裝應用伺服器,只有應用伺服器已註冊並且正在運行的情況下,才能創建客戶程式。對於客戶程式來說,既可以在設計期連接應用伺服器,也可以在運行期連接應用伺服器。如果客戶程式與應用伺服器不在同一個系統中,必須在客戶電腦上註冊或安裝應用伺服器,這樣,在設計期就可以連接應用伺服器。 (1) 使用“File" ->"New Application" 開始一個新專案。如果在Delphi3 中, 則選取功能表“File" ->"New...",從彈出視窗中選取“New RemoteDataModule"。在Delphi4 中,如果要創建一個COM 自動化伺服器,允許客戶通過DCOM、TCP/IP、OLEnterprise 等方式訪問此伺服器,選擇“Remote Data Module",如果要創建一個允許客戶通過MTS 訪問的Active Library,選擇“MTSData Module",如果要創建一個CORBA 伺服器,選擇CORBA Data Module。 (2) 把一個資料集構件如TTable、TQuery 或TStoredProc 放到遠端資料模組上,並進行有關設置,使得它們能訪問遠端的SQL 資料庫。可將業務規則放入這些構件的Constraint 屬性或回應事件中。將來一旦業務規則發生改變只需調整應用伺服器端的程式,維護工作量大大減輕。 (3) 把TDataSetProvider 或TProvider 構件放到遠端資料模組上,有一個資料集構件,就要有一個TDataSetProvider 或TProvider 構件與之對應。然後,用滑鼠右鍵單擊TDataSetProvider 或TProvider 構件,在彈出的功能表中選擇“ExportFrom in Data Module",這是為了引出Provider 介面,在類型庫中註冊。設置TDataSetProvider 或TProvider 構件的DataSet 屬性指定要訪問的資料庫 (4) 編寫代碼,實現商業規則。 (5) 保存、編譯、註冊或安裝應用伺服器。 (6) 如果應用伺服器沒有使用DCOM,您必須安裝有關的運行期軟體,因為其他連接方式需要這些運行期軟體的支援。例如,對於TCP/IP 來說,需要安裝ScktSrver.exe 或ScktSrvc.exe,後者只能運行在Windows NT 環境下。對於OLEnterprise 來說,需要安裝OLEnterprise 運行期版本。對於CORBA 來說,需要安裝VisiBroker ORB。 2. 創建ActiveForm 用戶端 Internet/Intranet 上的應用伺服器必須支援DCOM 或TCP/IP 連接方式,同樣,設計成ActiveForm 的客戶程式也必須支援DCOM 或TCP/IP 連接方式,因為下載ActiveForm 的電腦上可能沒有安裝OLEnterprise 或CORBA 運行期軟體。最好採用TCP/IP 連接方式,因為您無法肯定下載ActiveForm 的電腦是否支援DCOM,而支援TCP/IP 的環境是很普遍的。 (1) 使用“File"功能表上的“New"命令打開“New Items"對話方塊,選取“ActiveX"頁,雙擊“ActiveForm"圖示,打開ActiveForm 嚮導,單擊“OK"按鈕,Delphi 4 就創建一個ActiveX 項目。然後使用“File"功能表上的“New"命令,再雙擊“Data Module"圖示加入一個資料模組。 (2) 把一個或幾個MIDAS 連接構件如TDCOMConnection、TSocketConnection、TOLEnterpriseConnection、TCorbaConnection、TRemoteServer 或TMIDASConnection 加到資料模組上。至於究竟選擇哪一種MIDAS 連接構件,這取決於通信協定。設置有關屬性指定和連接應用伺服器,這與具體的MIDAS 連接構件有關。 (3) 把一個或幾個TClientDataSet 構件放到資料模組上,設置RemoteServer 屬性指定一個MIDAS 連接構件,設置ProviderName 屬性指定應用伺服器上的TDataSetResolver 或TProvider 構件,這樣,客戶程式就可以通過IProvider 介面與應用伺服器通訊。 (4) 把一個TDataSource 構件放到資料模組上,設置它的DataSet 屬性指定TClientDataSet 構件。再把一個資料控制項如TDBGrid 放到表單上,設置它的DataSource 屬性指定TDataSource 構件。 (5) 使用“Project"功能表上的“Web DeploymentOptions"命令打開“Web Deployment Options"對話方塊,然後設置有關Web 發佈的選項,主要是指定ActiveForm 在Web 伺服器上的URL。最後,使用“Project"功能表上的“WebDeploy"命令把ActiveForm 發佈到Web 伺服器上。 為了測試這個Active 表單,可以用一個Web 流覽器如IE 下載嵌入了ActiveForm 的網頁。如果客戶程式通過DCOM 與應用伺服器連接,Windows 95 中需要安裝支援DCOM 的程式——DCOM95,而Windows NT 4.0 則不需要
|
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
我想,您的原因出在
dsp := TDataSetProvider.Create(nil);這一行,您不能讓TDataSetProvider的Owner為一個nil,這樣會導致TDataSetProvider 無法正常work,在source code 裡找到TCustomProvider.Create的程式碼(TDataSetProvider的祖先物件),有下列的片段: if AOwner is TRemoteDataModule then TRemoteDataModule(AOwner).RegisterProvider(Self) else if AOwner is TCRemoteDataModule then TCRemoteDataModule(AOwner).RegisterProvider(Self) else if Assigned(AOwner) then if AOwner.GetInterface(IProviderContainer, ProvContainer) then ProvContainer.RegisterProvider(Self);您試試看 |
william
版主 發表:66 回覆:2535 積分:3048 註冊:2002-07-11 發送簡訊給我 |
|
seaturn99
版主 發表:69 回覆:427 積分:214 註冊:2003-08-25 發送簡訊給我 |
引言: Don't know if this help, but you may try cds.SetProvider(dsp); instead of cds.ProviderName := dsp.Name; And remember to move the cursor of ADataSet back to the first record first.conundrum 兄 : 感謝您分享的文章,受益良多,您真是藏了不少好東西 ... change.jian Sir : 感謝您 trace 的成果,若將兩個元件的 Owner 皆設成 TDataModule 就可以正常 work .. william Sir: 完美的解法,上述的問題解決了,受 william Sir 諸多指導,獲益良多,不勝感激.. ---- 我只會兩件事,這也不會,那也不會 眼見不一定為真 ---- |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |