[fpr 959] 直線的処理

岡本安晴

岡本@金沢大学です。

  ウィンドウズ・プログラミングでもDOSや汎用機のときの
感覚でプログラミングできます。

>実は,数年前に,ビジュアルベイシックにトライして見事に失敗しました.
>BASICは知っていたはずなのに,結局身につかずに終わりました.DOS言語
>のように直線的に処理が進まず,いろいろなところから割り込みが入るの
>で,とても書きにくかったことを記憶しております.([fpr 957]より)

  Delphiで直線的な処理を行う方法としてDelphiユーザーの
間で知られているものは、コンソールアプリケーションとして
作成する方法でしょう。
  コンソールアプリケーションとはDOS窓を開いて実行される
ものです。
  作成方法は、例えば次のようにします。

  まず、次のファイルを適当なテキストエディタで作成します。

======================
{$AppType Console}
program sample;
uses    Windows;
begin
      writeln('Hello');
      readln;
end.
=======================

  「=============」で挟まれた部分を作成したら、
ファイル名「sample.dpr」で保存します。
  ファイル名はプログラム名の後に拡張子.dprを付けます。
  プログラム名は「program プログラム名;」の形で与えられる
ものです。
  拡張子.dprによってメインプログラムであることが示されます。
  {$AppType Console]は、このプログラムがコンソールタイプとして
コンパイルされるものであることを示すものです。
  usesで始まる行は、サブルーチンを別に集めたユニットと呼ばれる
ものを指定するものです。必要なものを指定します。
  上のプログラムでは特に必要なユニットは無いのですが、Delphiでは
使用するユニットが無い場合でもuses節が必要なので、例えば、
Windowsユニットの使用が宣言されています。使用しなくても形の上で
必要なため「uses ユニット名;」を入れておくのです。
  プログラムの実行部はbegin〜endです。
  まず、
            writeln('Hello');
が実行されて、DOS窓に「Hello」が表示されます。
  その後、
            readln;
が実行され、リターンキーが押されるのを待ちます。
  リターンキーが押されるとreadlnの実行終了となります。
  プログラムの実行が終了するとDOS窓は閉じられます。

  上のプログラムを実行するときは、Delphiを起動してから
保存したsample.dprを開きます。開いてからF9キーを押すと
コンパイルが行われて実行されます。
  メニュ「実行|実行」でも実行されます。

  平均値を求めるプログラムなら次のようになります。

===========================
{$AppType Console}
program ConMean;
uses    Windows;
Label   Q;
var     c, x, sum : Extended;
        n : Longint;
begin
      write('基準値 = ');
      readln(c);
      n:=0;
      sum:=0.0;
      while true do
        begin
          n:=n+1;
          readln(x);
          if x < c then goto Q;
          sum:=sum+x;
        end;
  Q : n:=n-1;
      writeln;
      writeln('平均値 = ', sum/n);
      readln;
end.
===========================

  今度は上の「========」で挟まれた部分をファイル名
ConMean.dprで保存します。
  保存したテキストファイルをDelphiを起動して開きます。
  実行するとDOS窓が開いて
            基準値 =
と聞いてくるので、平均を求めたいデータ値より小さい値を
入力します。1から10までの和を求めるときには例えば0を
入力してリターンキーを押します。
  後は、順番にデータ値を1つ入力してはリターンキーを押して
いきます。
  最後に基準値として入力した値より小さい値を入力すると
             goto Q;
が実行されてデータの読み込み終了となり、平均値が表示されます。
  実数型を表わすExtendedは十進で19〜20桁の精度をもつものです。
  整数型を表わすLongintは符号付き32ビットの整数です。

  コンソールアプリケーションとしてではなく、普通のWindows
プログラム(コンソールアプリケーションに対してGUIアプリ
ケーションといいます)としての場合でも直線的なプログラミング
ができます。

  GUIアプリケーションの場合は次のような構成になります。

 メインプログラム:
           これはプロジェクトソースと呼ばれるもので
           pascalのメインプログラムです。拡張子は.dprです。
 ユニット:
           メインプログラムが利用するサブルーチンなどが記述
           されるものです。拡張子は.pasが使われます。
 フォーム:
           ユニットと組み合わせて用意されるもので、この上で
           描画が行われたり、ボタンなどが用意されます。
           拡張子は.dfmで、ユニットと同じ名前の後に付きます。
           ユニットがUnit1.pasのときはフォームのファイル名は
           Unit1.dfmとなります。このフォームのファイル前は
           ユニットの名前を決めるとDelphiによって自動的に
           与えられます。

  メニュ「ファイル|アプリケーションの新規作成」でGUIアプリ
ケーションを新しく用意すると上の3つのファイルは自動的に
Delphiによって用意されます。
  このときのメインファイルは次のようになっています。

=======================
program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
==========================

  ユニットファイルは次のようになっています。

=========================
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs;

type
  TForm1 = class(TForm)
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

end.
============================

  フォームはフォームとして表示されています。これはエディタ画面の
前面に重なっています。

  GUIアプリケーションの場合もコンソールアプリケーションの場合と
同じようにF9キーの押下などで実行されます。
  実行されると、実行部の

      Application.Initialize;
      Application.CreateForm(TForm1, Form1);

が実行されて実行時のフォームが表示されます。

  その後、

       Application.Run;

の実行に入り、Runの実行中においてWindowsのイベントが
あると、そのイベントに対応した手続き(イベントハンドラ)が
実行されます。
  イベントハンドラはユニットに記述されます。

  イベントとイベントハンドラの用意に必要な作業はDelphiが
自動的に行ってくれます。
  例えば、「ファイル|アプリケーションの新規作成」でGUI
アプリケーションを新しく用意したとき、表示されている
フォーム上をダブルクリックするとユニットは以下のように
自動的に変わります。

=============================
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin

end;

end.
===============================

  手続きTForm1.FormCreate(Sender: TObject)が追加されています。
  この手続きはプログラムの実行開始時に生起するOnCreateイベント
によって呼び出されるイベントハンドラです。このイベントと
イベントハンドラとの結合に必要な作業はDelphiが自動的に行います。
  要するに、この手続きはプログラムの実行開始時に自動的に実行
される手続きになっているということです。

  この手続きの実行部に適当な文を書くと、その文はプログラムの
実行開始時に実行されます。
  例えば、
       procedure TForm1.FormCreate(Sender: TObject);
       begin
              ShowMessage('Hello');
       end;
とすると
             ShowMessage('Hello');
が実行されてメッセージボックスによって「Hello」が表示されます。
  メッセージボックスのOKボタンをクリックすると、メッセージ
ボックスは消えてフォームが表示されます。
  フォームの右上のX印ボタンをクリックするとプログラムの実行
終了となります。

  拙著「Delphiプログラミング入門」(CQ出版社、1997)では、
上のやり方で実行するサンプルプログラムを用意してObject Pascalの
基本的な説明を行っております。

  私が多変量解析や多次元尺度法などのプログラミングで使っている
方法は拙著「Delphiで学ぶデータ分析法」で用いているものです。
  この方法の基本的な考え方は、汎用機でのプログラミングと
同じもので、Windows以外でのプログラミングではお馴染みの
方法です。
  データ入力用のテキストファイルと計算結果の出力用のテキスト
ファイルを用意して、後はプログラムを直線的に実行するという
ものです。出力用テキストファイルには必要に応じて計算の
途中経過の値も出力できます。

  上の方法でのGUIアプリケーションを作成するために、まず、
次のようにフォームの準備をします(拙著「Delphiで学ぶデータ
分析法」、図1.2.1参照)。但し、このフォームは図1.2.1を簡単に
したもの、Labelコンポーネントを少し省いたものです。


ーーーーーーーーーーーーーーーーーーーーーーーーーーーー
|                                                    |
|         メッセージ表示用ラベル                     |
|              MsgLabel                              |
|                                                    |
|                                                    |
|  入力用ファイル名設定用Editコンポーネント          |
|         InFileNmEdit                               |
|                                                    |
|                                                    |
|  出力用ファイル名設定用Editコンポーネント          |
|         OutFileNmEdit                              |
|                                                    |
|                                                    |
|                                                    |
|       OKボタン           Exitボタン              |
|        OKButton            ExitButton              |
|                                                    |
ーーーーーーーーーーーーーーーーーーーーーーーーーーーー

  このときのユニットファイルは次のようになっています。

==============================
unit UAppSmpl;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    InFileNmEdit: TEdit;
    OutFileNmEdit: TEdit;
    OKButton: TButton;
    ExitButton: TButton;
    MsgLabel : TLabel;
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

end.
===============================

  ユニット名がUAppSmplになっているのは、アプリケーションの新規
作成で新しいプロジェクトが表示されたとき、すぐ、「ファイル|
プロジェクトに名前を付けて保存」をクリックして適当なフォルダ
に保存の操作をしているからです。アプリケーションの作成のときは
、まず、この保存の操作を行っておくのがよいと思います。
  保存の操作を行うとユニット名の指定も要求されますが、このとき
UAppSmplを設定すると、拡張子.pasが付いて保存され、ユニット名も
UAppSmplに変更されます。

  ファイル名設定用のEditコンポーネントを用意したら、次は直線的に
プログラムを実行するためのイベントハンドラ(手続き)の準備をします。
  これはOKボタンをクリックすると計算が始まるようにするために
OKButtonのOnClickイベントに対するものとして用意します。
  OKButtonコンポーネントを選んでオブジェクト・インスペクタの
イベントページを表示します。OnClick蘭のダブルクリックで下の
ような手続き宣言の雛形が用意されます。

procedure TForm1.OKButtonClick(Sender: TObject);
begin

end;

  この手続きOKButtonClickがOKButtonコンポーネントのOnClick
イベントに対するイベントハンドラとして呼び出されるものです。

  この手続き宣言に以下のように追加を行います。


procedure TForm1.OKButtonClick(Sender: TObject);
var in_f, Out_f : TextFile;
begin
    MsgLabel.Caption:='Calculation started';
    UpDate;
    AssignFile(in_f, InFileNmEdit.Text);
    Reset(in_f);
    AssignFile(out_f, OutFileNmEdit.Text);
    Rewrite(out_f);

    (*   入出力ファイルの準備終了   *)


    CloseFile(in_f);    (*  入力ファイルを閉じる  *)
    CloseFile(out_f);   (*  出力ファイルを閉じる  *)
    MsgLabel.Caption:='Calculation Ended';
end;

  この段階のプロジェクト(Windowsではプログラムのことを
プロジェクトというようです)をプログラミングの出発点として
保存しておくと、後でこれを出発点としてプログラミングが行える
ので便利だと思います。

  これを基にして、次のように平均値を計算するプログラムが
できます。

===========================
unit UAppSmpl;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    InFileNmEdit: TEdit;
    OutFileNmEdit: TEdit;
    OKButton: TButton;
    ExitButton: TButton;
    MsgLabel: TLabel;
    procedure OKButtonClick(Sender: TObject);
    procedure ExitButtonClick(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

var x : array[1..1000] of Extended;

procedure TForm1.OKButtonClick(Sender: TObject);
var in_f, Out_f : TextFile;
    i, n : Longint;
    c, v, mean : Extended;
begin
    MsgLabel.Caption:='Calculation started';
    UpDate;
    AssignFile(in_f, InFileNmEdit.Text);
    Reset(in_f);
    AssignFile(out_f, OutFileNmEdit.Text);
    Rewrite(out_f);

    (*   入出力ファイルの準備終了   *)

    readln(in_f,c);
    n:=0;
    repeat
        n:=n+1;
        readln(in_f,x[n]);
    until x[n] < c;
    n:=n-1;

    v:=0.0;
    for i:=1 to n do v:=v+x[i];
    mean:=v/n;

    writeln(out_f, 'Data...');
    for i:=1 to n do
      writeln(out_f,x[i]);
    writeln(out_f);
    writeln(out_f, 'Mean = ', mean);

    CloseFile(in_f);    (*  入力ファイルを閉じる  *)
    CloseFile(out_f);   (*  出力ファイルを閉じる  *)
    MsgLabel.Caption:='Calculation Ended';
end;

procedure TForm1.ExitButtonClick(Sender: TObject);
begin
             Close;
end;

end.
==========================

  上のプログラムではExitButtonのOnClickイベントに
対する手続きExitButtonClickも追加されています。これは
フォーム上のExitButtonコンポーネントをクリックしてから
オブジェクトインスペクタのイベントページに表示されている
ExitButtonのOnClickイベント蘭をダブルクリックすることに
よって加えられます。
  イベントハンドラは直接エディタ画面に書き加えるのではなく、
オブジェクトインスペクタのイベント蘭のダブルクリックに
よってDelphiが自動的に用意するようにします。このことによって
イベントハンドラの設定に必要な作業がDelphiによって自動的に
行われます。
  上のExitButtonClickでは、Closeが実行されていますが、
このCloseの実行によってフォームは閉じられ、メインファイルの

    Application.run;

が終了して、プログラムの実行終了となります。
  このClose実行と同じ効果は、フォームの右上のX印のボタンの
クリックでも得られます。

  上のユニットでは、配列xが手続きの外で宣言してあります。
これは、他の変数と同じように手続き内で宣言してもよいもの
ですが、手続き内で宣言された変数はその手続きの呼び出し時に
スタックという領域に取られます。スタックの大きさはデフォルト
では1MBytesです。したがって、大きな配列とかを宣言すると
実行時にスタックオーバーのエラーになることがあります。
  手続きの外で宣言しておくとスタック外にとられるので、
Windowsのメモリー容量内であればOKです。理論的にはギガバイト
単位のものですが、実用上は実装されているメモリと仮想記憶
、および同時に実行されている他のアプリケーションの大きさで
決まります。
  スタックのデフォルト値はコンパイラ指令
       {$MAXSTACKSIZE 整数値}
によって変えることができます。

  上のプログラムを実行する前に、入力用データファイルを
次のように用意しておきます。

=================
-1
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
-9
==================

  これを入力ファイルとして実行すると、出力ファイルは
次のようになります。

====================
Data...
 1.00000000000000E+0000
 2.00000000000000E+0000
 3.00000000000000E+0000
 4.00000000000000E+0000
 5.00000000000000E+0000
 6.00000000000000E+0000
 7.00000000000000E+0000
 8.00000000000000E+0000
 9.00000000000000E+0000
 1.00000000000000E+0001

Mean =  5.50000000000000E+0000
======================

  出力ファイルは実行終了後、適当なエディタで
開いて見ることができます。もちろん、Delphiの
エディタで見ることもできます。

  上の方法のメリットは、Delphiの統合環境の機能を
生かしたプログラムの開発ができることです。
  例えば、デバッグ機能の便利さによってプログラムの
開発効率が高まります。


*****  大変長いメール、失礼しました。 *****


                             岡本 安晴
                             C00279 (at) simail.ne.jp


スレッド表示 著者別表示 日付順表示 トップページ

ここは心理学研究の基礎メーリングリストに投稿された過去の記事を掲載しているページです。