1. 程式人生 > >通過 DB2 表為 Delphi 產生動態的資料輸入窗體

通過 DB2 表為 Delphi 產生動態的資料輸入窗體

本文檢查了 IBM DB2 Universal Database 的元資料,以便動態構建檢視和窗體,其中包括如何動態生成新的 CLX 窗體,以及將窗體流化(stream)為 Delphi .pas 和 .xfm 檔案,並準備將它們新增到 Kylix 和 Delphi CLX 專案中。

簡介
在 上一篇文章中,我檢查了 IBM® DB2® Universal Database™(UDB)的元資料,以便動態構建檢視和窗體。我使用了 Linux 上的 Borland® Kylix™ 3 和 dbExpress 資料訪問驅動程式,來分析 IBM DB2 UDB 資料庫表、欄位(名稱和型別),允許使用者選擇特定的表,來回切換應該顯示的欄位,以及在資料網格(datagrid)和單個數據感知控制元件中動態檢視輸出。

這次,我們將擴充套件該方法,以允許使用者指定更加複雜的查詢(例如 JOIN)。作為附加步驟,我們將產生一個單獨的窗體,並以 .pas 和 .xfm 源格式儲存它,因此,可以將結果窗體新增至 Borland Delphi™ 或 Kylix 專案中。這類似於原來的基於 BDE(且僅用於 Windows)的資料庫-窗體嚮導,但這次產生的是一個跨平臺的 CLX 窗體。

從 Linux 進行遷移
上次,我完成了一個在 Linux 上執行的 Kylix 3 專案。這次,我首先需要將該專案遷移到 Windows 上,並在那裡進行擴充套件(用以說明該專案和由此生成的 CLX 窗體是跨平臺的,既可以用於 Linux 上的 Kylix,也可用於 Windows 上的 Delphi)。

將該專案從 Kylix 遷移到 Delphi 僅涉及一項更改:LibraryName 和 VendorLib 的 TSQLConnection 屬性在 Linux 上被設定為 libsqldb2.so 和 libdb2.so,但在 Windows 上,該屬性必須設為 dbexpdb2.dll 和 db2cli.dll。關於如何建立跨平臺專案的指導,請參閱 大轉變:利用 Kylix 3 從 Windows 遷移到 Linux。

新增 SQL 功能
一旦可以在 Delphi 7 中重新開啟該專案,您就可以對頁面控制的 Meta Data 選項卡進行一些增強。具體地說,您需要允許使用者輸入 SQL 語句,而不是隻能從可用表的列表中選擇表名。圖 1 展示了新的使用者介面(顯示了 EMP_PHOTO 表的欄位),您可以使用左下方的 memo 欄位輸入 SQL 語句。

圖 1. 用於 DB2 的新動態窗體
圖 1. 用於 DB2 的新動態窗體

就在 TMemo 控制元件的正上方,我放置了文字 SELECT * FROM,作為小小的一個提示:使用者只需指定表名,以及下面可選的 where子句。可以用程式碼來構造 SQL 語句,檢索元資料(metadata)來獲取欄位名,並將這些欄位名置於 TCheckListBox 中,該程式碼如下所示:  

procedure TDBWizForm.QCheckBoxClick(Sender: TObject);

var i: Integer;

begin

   if QCheckBox.Checked then begin ClientDataSet1.Active := False;   

      SQLDataSet1.CommandType := ctQuery;

      SQLDataSet1.CommandText := 'select * from ' + QMemo.Text;

      SQLDataSet1.FieldDefs.Update; // get meta information 

      CheckListBox1.Clear;

      for i:=0 to Pred(SQLDataSet1.FieldDefs.Count) do

        CheckListBox1.Items.Add(SQLDataSet1.FieldDefs[i].Name)

      end

end;

作為一個實際示例,我輸入了一條 SQL 語句,以連線 EMPLOYEE 和 EMP_PHOTO 表,該操作是基於 EMPNO 欄位的。因為已經給定了 SELECT * FROM,所以我只需要在查詢 memo 欄位中輸入 EMP_PHOTO, EMPLOYEE WHERE EMP_PHOTO.EMPNO = EMPLOYEE.EMPNO,然後啟用 Select fields from query複選框,這將執行以上程式碼,產生 TCheckListBox 中的欄位列表。

圖 2. 從查詢中選擇欄位
圖 2. 從查詢中選擇欄位

請注意,EMPNO 欄位出現了兩次:一次是在 EMP_PHOTO 表中(稱作 EMPNO),一次是在 EMPLOYEE 表中(然後自動稱作 EMPNO_1)。

在上面的例項中,通過左下方所指定的 where子句,我從查詢中選擇了 PICTURE、FIRSTNME、LASTNAME、PHONENO、HIREDATE 和 SEX 欄位。

為了給 DBGrid 和其他資料感知控制元件提供真正的資料,您需要新增一些程式碼,以獲取表名(從 TListBox 中)或 where子句(從 TMemo 控制元件中)。這項決策是基於複選框的啟用情況的,其編碼如下:

SQLDataSet1.CommandText := 'SELECT ';

comma := False;

for i:=0 to Pred(CheckListBox1.Items.Count) do

begin

   if CheckListBox1.Checked[i] then

   begin

     if not comma then comma := True

     else    

     SQLDataSet1.CommandText :=SQLDataSet1.CommandText + ', ';

     SQLDataSet1.CommandText := SQLDataSet1.CommandText + CheckListBox1.Items[i]

   end

end;

   if QCheckBox.Checked then

   SQLDataSet1.CommandText := SQLDataSet1.CommandText + ' FROM ' + QMemo.Text

   else if

     ListBox1.ItemIndex >= 0 then SQLDataSet1.CommandText := SQLDataSet1.CommandText

     + ' FROM ' + ListBox1.Items[ListBox1.ItemIndex];

這確保您可以使用帶有表名的 TListBox,或使用帶有 SQL where 子句的 TMemo ,來選擇欄位併為檢視產生資料。

新增更多的控制元件
您在圖 2 中選擇的欄位是 PICTURE 欄位。上次,我在由 TDBMemo 表示的 Memo 欄位之間進行了區分,雖然其他所有欄位都是由 TDBEdit 表示的。對於可以是 ftGraphic 或 ftBlob(本例項中)的 image 欄位,您可以使用 TDBImage 控制元件。請注意,ftBlob 的情況並不是百分之百確定的:大多數 BLOB 欄位只包含二進位制資料,而不是總包含影象。但是對於本例,ftBlob PICTURE 欄位包含影象(以不同的格式,如 bmp 或 gif)。

必須新增一些附加程式碼,以檢測欄位型別,並通過動態建立 TDBImage 對此作出響應,這些附加程式碼片斷如下所示:

if (ClientDataSet1.FieldDefs[i].DataType = ftGraphic) or (ClientDataSet1.FieldDefs[i].DataType = ftBlob) then

begin

  with TDBImage.Create(Self) do

   begin

    Parent := TabSheet3;

    Left := 126;

    Top := Y - 4;

    Y := Y + 204;

    Height := 200;

    Width := 200;

    DataSource := DataSource1;

    DataField := ClientDataSet1.FieldDefs[i].Name;

   end

end ;

在您選擇了 PICTURE、FIRSTNME、LASTNAME、PHONENO、HIREDATE 和 SEX 欄位的示例中,該程式碼的結果如圖 3 所示。

圖 3. 動態資料控制元件預覽
圖 3. 動態資料控制元件預覽

請注意,這裡還有一個附加的按鈕,在這裡,將用它在新的 CLX 窗體上從該 tabsheet 重新建立這些控制元件。該窗體將被流化為 Delphi .pas 原始檔和 .xfm 窗體檔案;並準備將它們新增至 Kylix 或 Delphi CLX 專案中。

設計新的窗體框架
雖然在 tabsheet 中檢視資料效果極佳(如圖 3 中),但是在新的窗體(不同於原先那個您指定了表名或查詢,並選擇了要使用的欄位名的窗體)中檢視控制元件將具有更強大的功能。您必須重新建立 TLabel、TDBEdit、TDBMemo 和 TDBImage 控制元件,這意味著您可以從一個幾乎為空的框架窗體開始,準備建立到 DB2 UDB 資料庫新的 dbExpress 連線,輸入 SQL 語句,並放置資料感知控制元件,以顯示資料。

通過 Delphi 7,我設計了一個新的 CLX 窗體,該窗體包含 TSQLConnection、TSQLDataSet、TDataSetProvider、TClientDataSet、TdataSource 和 TDBNavigator 控制元件;其佈局如圖 4 中所示。像您以前多次做過的那樣,將它們都關聯起來,但是此時還沒有任何資料感知控制元件。

圖 4. 設計時的新窗體模板
圖 4. 設計時的新窗體模板

現在,應該為圖 3 中首次出現的 Generate Code 按鈕實現 OnClick 事件處理程式了。

生成新的窗體內容
Generate Code 按鈕將建立新 CLX 框架窗體的一個例項,並動態新增 TLabel、TDBEdit、TDBMemo 和 TDBImage 控制元件(使用與原來窗體相同的屬性值)。用來建立新的 CLX 窗體並克隆將放置在新 CLX 窗體上的控制元件的程式碼如下所示:

procedure TDBWizForm.btnWizardClick(Sender: TObject);

var

ThisForm: TDBWizForm;

NewForm: TNewForm;

LabelNr,EditNr,MemoNr,ImageNr,i: Integer;

begin

  ThisForm := Self;

  NewForm := TNewForm.Create(Self);

try

   NewForm.Caption := 'Dr.Bob's Database Form Wizard';  

   NewForm.SQLConnection1.Params.Clear;

   NewForm.SQLConnection1.Params.Assign(ThisForm.SQLConnection1.Params);

   NewForm.SQLDataSet1.CommandText := ThisForm.SQLDataSet1.CommandText;

   LabelNr := 0;

   EditNr := 0;

   MemoNr := 0;

   ImageNr := 0;

  for i:=0 to Pred(ThisForm.ComponentCount) do

  begin

    if (ThisForm.Components[i] is TLabel) then

      begin

        with TLabel.Create(NewForm) do

         begin

           Inc(LabelNr);

           Name := Format('Label%d',[LabelNr]);

           Parent := NewForm;

           Left := (ThisForm.Components[i] as TLabel).Left;

           Top := (ThisForm.Components[i] as TLabel).Top;

           Width := (ThisForm.Components[i] as TLabel).Width;

           Alignment := taRightJustify;

           Caption := (ThisForm.Components[i] as TLabel).Caption

         end

      end

      else if (Components[i] is TDBEdit) then

      begin

        with TDBEdit.Create(NewForm) do

        begin Inc(EditNr);

         Name := Format('Edit%d',[EditNr]);

         Parent := NewForm;

         Left := (ThisForm.Components[i] as TDBEdit).Left;

         Top := (ThisForm.Components[i] as TDBEdit).Top;

         Width := 200;

         DataSource := NewForm.DataSource1;

         DataField := (ThisForm.Components[i] as TDBEdit).DataField

        end

      end

      else if (Components[i] is TDBMemo) then

      begin

       with TDBMemo.Create(NewForm) do

       begin 

         Inc(MemoNr);

         Name := Format('Memo%d',[MemoNr]);

         Parent := NewForm;

         Left := (ThisForm.Components[i] as TDBMemo).Left;

         Top := (ThisForm.Components[i] as TDBMemo).Top;

         Height := 200;

         Width := 200;

         DataSource := NewForm.DataSource1;

         DataField := (ThisForm.Components[i] as TDBMemo).DataField

        end

     end

    else if (Components[i] is TDBImage) then

    begin

     with TDBImage.Create(NewForm) do

     begin Inc(ImageNr);

      Name := Format('Image%d',[ImageNr]);

      Parent := NewForm;

      Left := (ThisForm.Components[i] as TDBImage).Left;

      Top := (ThisForm.Components[i] as TDBImage).Top;

      Height := 200;

      Width := 200;

      DataSource := NewForm.DataSource1;

      DataField := (ThisForm.Components[i] as TDBImage).DataField

     end

   end

end;

try

  NewForm.ClientDataSet1.Active := True;

except

end;

NewForm.ShowModal; // See Figure 5. NewForm.ClientDataSet1.Active := False; NewForm.SQLConnection1.Connected := False; WriteComponentResFile(UnitName+'.xfm', NewForm);

finally NewForm.Free

end

end;

在該事件處理程式的結尾,通過呼叫 ShowModal 顯示了 NewForm,其結果如圖 5 所示。因為就在顯示該窗體之前激活了 TClientDataSet(關閉該窗體之時再取消啟用狀態),所以該圖將顯示帶有資料的新窗體。

圖 5. 執行時的新窗體
圖 5. 執行時的新窗體

在顯示了該窗體之後,您可以建立一個 Delphi .xfm 檔案,其中包含窗體的流化(streaming)資訊、其上所有的元件及其屬性資訊。對 WriteComponentResFile 的呼叫將為該窗體建立一個二進位制的原始檔。該檔案可用於 Kylix 或 Delphi CLX 專案,但是還需要相應的 .pas 檔案,其中包含窗體上每個元件的原始碼宣告。

生成相關的原始碼
最後一步(也整合在“Generate Code”OnClick 事件處理程式中)是建立包含元件宣告的相應的 .pas 檔案。這是一個由三個階段組成的過程。首先,您要編寫該 .pas 檔案的第一部分,然後動態新增單個 TLabel、TDBEdit、TDBMemo 和 TDBImage 控制元件,最後,新增該 .pas 檔案的最後一部分。

procedure TDBWizForm.btnWizardClick(Sender: TObject); var f: System.Text; LabelNr,EditNr,MemoNr,ImageNr,i: Integer; begin System.Assign(f,UnitName+'.pas'); Rewrite(f); writeln(f,'unit ',UnitName,';'); writeln(f,'interface'); writeln(f,'uses'); writeln(f,' SysUtils, Types, Classes, Variants, QTypes, QGraphics, QControls, QForms,'); writeln(f,' QDialogs, QStdCtrls, DBXpress, QCheckLst, DB, SqlExpr, QComCtrls, FMTBcd,'); writeln(f,' DBClient, Provider, QGrids, QDBGrids, QDBCtrls, QExtCtrls, QMask;'); writeln(f); writeln(f,'type'); writeln(f,' TNewForm = class(TForm)'); writeln(f,' SQLConnection1: TSQLConnection;'); writeln(f,' SQLDataSet1: TSQLDataSet;'); writeln(f,' DataSetProvider1: TDataSetProvider;'); writeln(f,' ClientDataSet1: TClientDataSet;'); writeln(f,' DataSource1: TDataSource;'); writeln(f,' DBNavigator1: TDBNavigator;'); LabelNr := 0; EditNr := 0; MemoNr := 0; ImageNr := 0; for i:=0 to Pred(ThisForm.ComponentCount) do begin if (ThisForm.Components[i] is TLabel) then begin Inc(LabelNr); Name := Format('Label%d',[LabelNr]); writeln(f,' ',Name,': TLabel;'); end else if (Components[i] is TDBEdit) then begin Inc(EditNr); Name := Format('Edit%d',[EditNr]); writeln(f,' ',Name,': TDBEdit;'); end else if (Components[i] is TDBMemo) then begin Inc(MemoNr); Name := Format('Memo%d',[MemoNr]); writeln(f,' ',Name,': TDBMemo;'); end else if (Components[i] is TDBImage) then begin Inc(ImageNr); Name := Format('Image%d',[ImageNr]); writeln(f,' ',Name,': TDBImage;'); end end; writeln(f,' procedure FormCreate(Sender: TObject);'); writeln(f,' private'); writeln(f,' { Private declarations }'); writeln(f,' public'); writeln(f,' { Public declarations }'); writeln(f,' end;'); writeln(f); writeln(f,'var'); writeln(f,' NewForm1: TNewForm;'); writeln(f); writeln(f,'implementation'); writeln(f); writeln(f,'{$R *.xfm}'); writeln(f); writeln(f,'procedure TNewForm.FormCreate(Sender: TObject);'); writeln(f,'begin'); writeln(f,' try'); writeln(f,' ClientDataSet1.Active := True'); writeln(f,' except'); writeln(f,' end'); writeln(f,'end;'); writeln(f); writeln(f,'end.'); System.Close(f); end;

完整的原始碼整合位於事件處理程式之中,可通過下載獲得。

使用結果
其結果就是一個 .pas 以及相應的 .xfm 檔案,可以將它們用於 Linux 上的 Kylix 以及 Windows 上的 Delphi CLX 專案中。例如,目前給出了給定演示的結果窗體,如圖 6 中所示,該圖中顯示了 Delphi 7 在設計時顯示的結果窗體。該窗體與初始的框架窗體一樣,只是添加了 TLabel、TDBImage 和 TDBEdit 控制元件,事實上,Height 已經被修改,以顯示所有控制元件。

圖 6. 設計時生成的新窗體
圖 6. 設計時生成的新窗體

正如我上次提到的,所生成的窗體不包含呼叫 TClientDataSet 的 ApplyUpdates 方法(用以將更新送回資料庫)或 UndoLastChange,以及其他 Undo 方法的按鈕。這將作為練習留給讀者來完成。作為一點小小的一個提示,我建議在 NewForm 中將這些按鈕新增至框架窗體,因此,您所做的修改將用於所有新生成的窗體中。那樣的話,就可以將 NewForm 視作一個基類,用於所有動態建立的資料庫窗體。

結束語
在這篇以及上一篇文章中,都檢查了 IBM DB2 Universal Database 元資料,以便動態構建檢視和窗體。您已經使用了帶有 dbExpress 的 Linux 上的 Borland Kylix 3,以及 Windows 上的 Delphi 7,來分析 DB2 UDB 資料表、欄位(名稱和型別),允許使用者選擇特定的表或指定 SQL 語句的 join/where 子句,來回切換應該顯示的欄位,以及在資料網格(datagrid)和單個數據感知控制元件中動態檢視輸出。

最後一步包括動態生成新的 CLX 窗體,以及將該窗體流化為 Delphi .pas 和 .xfm 檔案,並準備將它們新增到 Kylix 和 Delphi CLX 專案中(為 DB2 UDB 資料庫表產生我們自己定製的資料庫窗體嚮導)。

相關推薦

通過 DB2 Delphi 產生動態資料輸入窗體

本文檢查了 IBM DB2 Universal Database 的元資料,以便動態構建檢視和窗體,其中包括如何動態生成新的 CLX 窗體,以及將窗體流化(stream)為 Delphi .pas 和 .xfm 檔案,並準備將它們新增到 Kylix 和 Delphi CLX

用cglib包來產生動態代理類對象

方法 source uil owa pac 類對象 進行 desc clas 一:在JDK裏也有動態代理的類和接口,是Proxy和InvocationHandler,但是Proxy只能為接口產生代理類,借助InvocationHandler的實現類來完成對類對象的代理;

前臺通過form單向Django後臺傳輸資料,Django處理後返回給前臺

摘要:Django前後臺數據傳遞   通過action將資料傳輸給apitest這個地址,使用get方法傳遞,此處需要傳遞name="request_method"的下拉列表值和name="api_url"的輸入框的值, 注意這裡用name屬性,向Django後臺傳遞時需要用name的值作為鍵

Qt將Sqlite中的資料匯出CSV格式表格資料

開發環境ubuntu16.04+Qt5.6.1   WIN7+Qt5.6.1兩個環境都測試過 1.問題 寫一個小軟體的時候,帶有匯出excel功能,但是要在linux下執行,最後瞭解到csv格式,實現起來方便多了,只是用excel開啟中文有亂碼的現象有一個簡單的解決辦法。 2.

SpringMVC——通過form單繫結資料

今天寫一個簡單的專案用到form表單繫結資料,這裡介紹一下方法。 首先需要配置好相應的檔案,這個步驟我這裡就不再贅述,直接進入主題。 我的controller程式碼如下: @RequestMapping(value ="views/html_jsp/revise_good",prod

Matlab產生動態變化的字串,便於將資料批量存入表格

記錄一下。 在使用Matlab跑程式的時候,需要將最後的結果存入表格,例如: xlswrite('xxx.xls',result, 'a1:i1'); 此處只儲存一行,所以 ‘result’ 是個一維向量。 上述程式碼只能適用於跑一次程式的情況。下次跑的時候,我們需要改為: xl

mysql 多管理 查詢的時候資料null

1.1原sql查詢的時候left join的 某張表的資料為null SELECT t.bill_no billNo, t.item_code itemCode, t.status pickTicketStatus, a.status pickTick

Multipart/form-data POST檔案上傳詳解 理論 簡單的HTTP POST 大家通過HTTP向伺服器傳送POST請求提交資料,都是通過form單提交的,程式碼如下:

Multipart/form-data POST檔案上傳詳解 理論 簡單的HTTP POST 大家通過HTTP向伺服器傳送POST請求提交資料,都是通過form表單提交的,程式碼如下: <form method="post"action="http://w.soh

將datagrid表格資料匯出Excel(動態列)

【需求】:當datagrid表格顯示的每列的欄位名稱並不固定,如要求每列欄位為日期,這樣的話,我們不能從新定義實體來接收這個欄位,因為不同的條件,後臺返回的資料的時間也不會固定,而這時用常用的匯出Excel的工具就會遇到些麻煩。 【解決】:(直接上程式碼) @Reque

通過hive整合查詢hbase資料

大家知道,直接從hbase的讀取資料是一個比較繁鎖的過程,需要java程式碼或是spark 查詢 通過Hive整合HBase,可以通過hive表查詢hbase資料,下面是測試過程 --建立hbase表 create "user","account","address","i

mysqldump備份資料庫或資料空解決辦法。

今天在shell中利用mysqldump備份資料庫或資料表時,發現結果檔案為空,定位很久得出結論:未找到mysqldump對應的路徑,現給出解決辦法: 1.找到mysqldump所在的路徑,linux命令:find / -name mysqldump 2.將msqldum

C#匯出資料Excel檔案

博文以匯出Access資料庫中的資料表為例,只要修改一下同樣可以用於SQL Server資料庫。 string filePath = "F:\\Book.xls"; string OleDbConne

RDLC報表動態繫結資料

C#程式碼   string conStr = "Data Source=.;Initial Catalog=Book;Integrated Security=True";   SqlConnection con = new SqlConnection(conS

通過Ajax技術,將陣列型別資料轉換JSON格式的物件

一、在伺服器端將list型別資料放入JSON物件中的方法  tjyjList=PxcscjbDAO.getTjyjList(pxcscjbQOMap);  //生成JSON物件,用來容納獲得的樣卷陣列  JSONObject jsonObject=new JSONObjec

python如何獲取javascript動態產生資料

然後一個個排查,圖片css均不考慮,那麼很容易就能找到http://comment5.news.sina.com.cn/page/info?format=js&channel=gn&newsid=1-1-27642839&group=0&compress=1&ie=gb

mysql語句 一個統計每天產生的不同型別資料 根據型別欄位 統計每天有多少

DROP TABLE IF EXISTS `risk_business02`; CREATE TABLE `risk_business02` (   `rb02id` bigint(20) NOT NULL COMMENT '主鍵',   `rb01id` bigint

Delphi 中,基於介面,封裝類 BPL 包動態載入的程式架構 之一

DELPHI 的普通程式編譯出來比較大,一個空程式也要超過1M。其原因是 DELPHI 的程式把所有需要的庫都編譯到EXE檔案裡面去了。這樣做有個好處:程式釋出簡單,只要釋出一個 EXE 就搞定。 不過,當程式寫得很大,又是多人開發,並且程式不斷升級,可能還有多個版本的時候

DB2新建空間及匯入匯出資料

DB2新建表空間: su到相應的資料庫使用者下 db2 connect to 資料庫名 db2(進入模式) create bufferpool bp32k  all nodes size -1 pagesize  32k(一個表空間對應一條) ...... force ap

資料結構與算法系列2 線性 使用java實現動態陣列+ArrayList原始碼詳解

## 資料結構與算法系列2 線性表 使用java實現動態陣列+ArrayList原始碼詳解 對陣列有不瞭解的可以先看看我的另一篇文章,那篇文章對陣列有很多詳細的解析,而本篇文章則著重講動態陣列,另一篇文章連結如下,可點選跳轉: 連結:[https://blog.csdn.net/pjh88/article/d

C#根據字體名通過註冊獲取該字體文件路徑(win10)

cat mic 約束 lec 運行 window mac war 控件 方法一: 直接先上源碼: private System.Collections.Generic.SortedDictionary<string, string> ReadF