Serversコンポーネント

 今回は Delphi 5 (Pro以上) に付属の Servers コンポーネントの Excelコンポーネントを使って Excel97 を操作してみたいと思います。サーバーコンポーネントを使わなくても OLE オートメーションを使えば操作できるのですが、せっかくコンポーネントがあるので使ってみたいと思います。
 まずは Demosフォルダの Activex\Oleauto\SrvComp の中のデモを見てテクニックを盗もうと思ったんですがここにあるのは Word と PowerPoint のデモだけです。なぜか Excel のデモはありません。しかも Serversコンポーネントにはヘルプもありません。と、言うわけで、ここで簡単な使い方を紹介したいと思います。当然ですが、開発環境に Excel97 がインストールされている必要があります。


簡単な例

 まずは Excelを起動して指定のセルに文字をセットする簡単なサンプルを作ります。が、よく見ると Serversパレットにはエクセル関係のコンポーネントがいくつもあります。どれを使うのでしょうか??今回使うコンポーネントはこのうちの
 ・ TExcelApplication
 
TExcelWorkbook
 
TExcelWorksheet
の3つです。 名前のとおり TExcelApplication は エクセルそのものを意味し、後のふたつはそれぞれ Workbook 、 Worksheet を意味します。ワークブックはファイルの事で、保存や読み込みの対象となります。ワークシートはブック内のそれぞれのページになります。では、この3つをフォームに配置してください。それから TEdit と TButton をひとつずつ配置します。Button をクリックされたらエクセルを起動し、セルに Edit の内容をセットするようにコーディングします。

TExcelApplicationで、エクセルを起動

 まずは、TExcelApplicationコンポーネントを使ってプログラムからエクセルを起動します。従来ならば CreateOleObject を使っていましたが TExcelApplication では Connect メソッドを使用します。このメソッドでエクセルを起動します。すでに起動している場合はそのインスタンスが使用されます。起動しただけではエクセルは画面上には現れません。さらに Visibleプロパティでエクセルを画面上に表示します。なお、引数はよく分からなかったので (えへへ) ゼロを入れています。

■ Connect メソッドの例
procedure TForm1.Button1Click(Sender: TObject);
begin
  //エクセル起動
  ExcelApplication1.Connect;
  //エクセル表示
  ExcelApplication1.Visible[0]  :=  True;
end;

 実行してみると見事エクセルが起動するのですが、よく見るとブックが作成されていません。 TExcelApplication には Workbooksプロパティがあります。ここまで見つけることが出来ればその Workbooksクラスの Addメソッドを見つけるのは容易です。これでワークブックを追加することができます。引数にはテンプレートファイルを指定できますが、必要ないなら Null を指定します。

■ ブック追加の例
procedure TForm1.Button1Click(Sender: TObject);
begin
  //エクセル起動
  ExcelApplication1.Connect;
  //エクセル表示
  ExcelApplication1.Visible[0]  :=  True;
  //ブック追加
  ExcelApplication1.Workbooks.Add(Null, 0);
end;

TExcelWorkbook でワークブックを操作

 これで実行するとエクセル起動後、ブックが追加されます。次はこの新たに追加されたブックを TExcelWorkbook に適用してブックを操作できるようにします。よく見るとこの TExcelApplication の Workbooks.Add メソッドは追加したブックオブジェクトを返します。と、言うことは・・・

  //ブック追加 ※これはエラー
  ExcelWorkbook1 := ExcelApplication1.Workbooks.Add(Null, 0);

こう記述したくなりますが、これだとコンパイルエラーが発生してしまいます。残念ながら Workbooks.Add が返すブックオブジェクトとは型が一致しないようです。では、どうやるのかと言いますと、、、分からないので Demos の Wordのデモを探ったところ、 ConnectTo メソッドを使うことが判明しました。

■ TExcelWorkbookの ConnectToの例
procedure TForm1.Button1Click(Sender: TObject);
begin
  //エクセル起動
  ExcelApplication1.Connect;
  //エクセル表示
  ExcelApplication1.Visible[0]  :=  True;
  //ブック追加
  ExcelWorkbook1.ConnectTo(
       ExcelApplication1.Workbooks.Add(Null, 0));
end;

 これで追加したブックが TExcelWorkbook で操作できるようになります。試しに TExcelWorkbook.Sheets.Add とすると新しいシートがブックに追加されます。

■ シート追加の例
  //ブック追加
  ExcelWorkbook1.ConnectTo(
       ExcelApplication1.Workbooks.Add(Null, 0));
  ExcelWorkbook1.Sheets.Add(Null, Null, Null, Null, 0)

TExcelWorksheet でワークブックを操作

 後はブック内のシートを ExcelWorksheet にセットすれば OK です。シートもブックと同じように Add する際などに ConnectTo を使えばいいような感じです。

■ TExcelWorksheet の ConnectToの例
  //ブック追加
  ExcelWorkbook1.ConnectTo(
       ExcelApplication1.Workbooks.Add(Null, 0));
  //シート1を ExcelWorksheetに接続 ※これはエラー
  ExcelWorksheet1.ConnectTo(
       ExcelWorkbook1.Worksheets['Sheet1']);

 と、これで良さそうなんですがエラーが発生します。なぜか TExcelWorkbookの Worksheetsプロパティは _Worksheet 型を返してくれません。同じように Addメソッドも _Worksheet 型を返しません。戻ってくるのは IDispatch型です。従来の OLEオートメーションでの操作で、 IUnknown型を他の型にキャストして使用したのを覚えていればこれをクリアすることはそう難しくありません。以下のように記述すればいいのです。

■ IDispatchを _Worksheet へキャストする例
  //シートを ExcelWorksheetに接続
  ExcelWorksheet1.ConnectTo(
       ExcelWorkbook1.Worksheets['Sheet1'] as _Worksheet);

簡単な例、完成!

 シートまで取得できれば後は簡単です、目的のセルに値をセットするだけです。セルを指定するには Rangeプロパティを使用します。以下は完全なコードです。

■ エクセルを起動して値をセルに入れる例
procedure TForm1.Button1Click(Sender: TObject);
begin
  //エクセル起動
  ExcelApplication1.Connect;
  //エクセル表示
  ExcelApplication1.Visible[0]  :=  True;
  //ブック追加
  ExcelWorkbook1.ConnectTo(
       ExcelApplication1.Workbooks.Add(Null, 0));
  //シートを ExcelWorksheetに接続
  ExcelWorksheet1.ConnectTo(
       ExcelWorkbook1.Worksheets['Sheet1'] as _Worksheet);
  //A1に文字をセット
  ExcelWorksheet1.Range['A1','A1'].Value  :=  Edit1.Text;
end;

 エクセルが起動し、セルの A1 に Editに入力した文字列が見事セットされました。 Rangeの引数を "A1" , "C5" とすれば A1から C5 まですべてを同じ文字で埋め尽くすことが出来ます。 Range は指定されたセルを選択しません。選択状態にするには Rangeの Select メソッドを使用します。


保存・印刷を行う

 次は、データベースから値を取り出し、エクセルに一覧形式で出力後、保存して印刷するコードを書いてみましょう。データベースには DBDEMOS を使用します。テーブルは Animals です。このテーブルの BMP 以外のすべてのフィールドをエクセルに出力します。

■ DBDEMOSの内容を出力する例
procedure TForm1.Button2Click(Sender: TObject);
var
  Col   : integer;
  Row   : integer;
  Cell  : string;
begin
  try
    //エクセル起動・初期処理
    ExcelApplication1.Connect;
    ExcelApplication1.Visible[0]  :=  True;
    ExcelWorkbook1.ConnectTo(
         ExcelApplication1.Workbooks.Add(Null, 0));
    ExcelWorksheet1.ConnectTo(
         ExcelWorkbook1.Worksheets['Sheet1'] as _Worksheet);
    //データベース準備
    //エリアス:DBDEMOS
    //テーブル:Animals.dbf
    //※項目エディタで BMP は削除しています。
    with  Table1  do  begin
      Open;
      Row       :=  0;
      while not Eof do  begin
        for Col :=  0   to  Fields.Count - 1  do  begin
          //セル指定用の文字列作成("A1"から)
          Cell  :=  Char(65 +  Col) + IntToStr(Row + 1);
          ExcelWorksheet1.Range[Cell,Cell].Value :=
                                           Fields[Col].Value;
        end;
        Next;
        inc(Row);
      end;
      Close;
    end;
    //印刷プレビュー表示
    ExcelWorkbook1.PrintPreview;
    //ファイルを保存
    ExcelWorkbook1.SaveAs('C:\Work\Test.xls'{FileName},
                          Null {FileFormat},
                          Null {Password},
                          Null {WriteResPasswrd},
                          Null {ReadOnlyRecommended},
                          Null {CreateBackup},
                          xlShared {AccessMode},
                          Null {ConflicResolution},
                          Null {AddToMru},
                          Null {TextCodepage},
                          Null {TextVisualLayout},
                          0);
  finally
    //Excel終了
    ExcelApplication1.Quit;
  end;
end;

 印刷プレビューは TExcelWorkbook の PrintPreviewメソッドを使います。プレビューはモーダル表示なので、印刷プレビュー画面を閉じるまで処理は返ってきません。保存には TExcelWorkbook の SaveAsメソッドを使います。引数が多いのですがほとんどは Null で構いません。途中 AccessMode だけが列挙型プロパティとなっています。Excel終了には TExcelApplication の Quit メソッドを使います。


Serversコンポーネントを使ってみて

 基本的にタイプライブラリを取り込んで非ビジュアルに開発するのとあまり変わらないような感じを受けました。タイプライブラリを取り込んだ場合と同じくほとんどの関数が OleVariant の省略不可能な引数を採用しているのでとても使いにくい印象を受けました。いざ業務で使うとなるといろいろと悩みそうです、、、。



Delphi Acid Floor -TechDocs- Copyright 1998-2000 Toyota