配列をこのフォームのメンバーにするには?


Array  2005-05-26 23:54:50  No: 15083

今配列について考えているのですが、ある配列をこのフォームのメンバー
として使いたいと思っています。教えてくれませんか?


りおりお  2005-05-28 08:24:05  No: 15084

たんに private か protected か public に宣言するだけです。


array2  2005-06-08 03:15:50  No: 15085

ある配列をこのフォームのメンバーとして使いたいと思っています、ではなく
どこかのオブジェクトのメンバーにして他から参照したいと思っております。
どこのオブジェクトがいいの


あれ  2005-06-08 03:22:39  No: 15086

別の質問者さんですか?

オブジェクトはクラスのインスタンスです。
まず、クラスの public フィールドに配列を宣言しなければなりません。

> どこのオブジェクトがいいの

それは誰にも答えられません。あなたの用途が書いてないからです。


array2  2005-06-08 21:14:05  No: 15087

すいません、表記不足でした。少し長くなりますが
------------------------------
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    ListBox1: TListBox;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
・・・
var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  ListBox1.Items.Add(Edit1.Text);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  editString: String;
begin
  editString := Edit1.Text;
  Form2.Setedit1(editString);
  Form2 := TForm2.Create(nil);
  Form2.ShowModal;
end;
end.

--------------------------------
unit Unit2;

interface

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

type
   AAARecord = record
    Edit2: String;
end;

  TForm2 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private

  public
    procedure Setedit1(edit1: String);
  end;

var
  Form2: TForm2;

implementation

uses Unit1;

var
  str: String;
   aaaArr: array of AAARecord;
{$R *.DFM}

procedure TForm2.Setedit1(edit1: String);
begin
  Str := Edit1;
end;

procedure TForm2.FormShow(Sender: TObject);
var i: Integer;
begin
  Edit1.Text := str;
  for i := Low(aaaArr) to High(aaaArr) do
  begin
    if Edit1.Text = Form1.ListBox1.Items[Form1.ListBox1.ItemIndex] then
    begin
      Edit2.Text := aaaArr[i].Edit2;
    end;
  end;
end;

procedure TForm2.Button1Click(Sender: TObject);
var i : Integer;

begin
  SetLength(aaaArr, Form1.ListBox1.Items.Count);
  for i := Low(aaaArr) to High(aaaArr) do
  begin
    if Edit1.Text = Form1.ListBox1.Items[Form1.ListBox1.ItemIndex] then
    begin
      aaaArr[i].Edit2 := Edit2.Text;
    end;
  end;
  Self.Close;
end;

end.

というような感じです。
フォーム2で定義されているレコード型配列(ユニット変数に定義されている動的配列)をどこかのオブジェクトのメンバーにして使用したい場合、どこに記述すれば
よいでしょうか?


Basser  2005-06-08 23:49:37  No: 15088

配列が必要な処理にみえませんが...

ソースコードを載せただけでどのような処理を行いたいのか説明が無いのもどうかと思います。
ソースコードからは該当オブジェクト無しとしか答えることができません。


array2  2005-06-09 00:09:50  No: 15089

配列が必要なんですよ。
簡単に要点だけを記述しただけです。


ななし  2005-06-09 00:23:24  No: 15090

> どこかのオブジェクトのメンバーにして使用したい場合、どこに記述
どこかのオブジェクトにプロパティを作って
プロパティのアクセス関数で、Form2の配列を参照すれば良いのでは。


ふが  2005-06-10 03:42:36  No: 15091

継承は?


ん?  2005-06-10 04:43:36  No: 15092

回答ではありませんが。。。

> type
>      AAARecord = record
>       Edit2: String;
> end;

レコード型のメンバにString型があるとき、そのString型のメモリの開放がうまくいかないんじゃなかったかなと。

SetLengthで、要素数が減る場合、減る分の要素に対して Edit2 := '' とかして、文字列への参照を無くしておかないといかんかった気がする。
この辺は、過去ログあたりにもあるのかもしれないが、良ければ識者の方、教えてください。

[その他つっこみ]
> procedure TForm1.Button2Click(Sender: TObject);
> var
>   editString: String;
> begin
>   editString := Edit1.Text;
>   Form2.Setedit1(editString);
>   Form2 := TForm2.Create(nil);
>   Form2.ShowModal;
> end;
Form2のインスタンスがクリエイトされる前に、Form2のメソッドSetedit1を使っている。
普通はエラーになるが、Form2の自動生成がOnになっており、かつ、
> var
>   Form2: TForm2;

> implementation
このように、自動で作成されるグローバルな変数 Form2が存在するため、エラーにならない。

しかも、Form2のクリエイトのパラメータがnilのため、自動破棄されない。
いわゆるメモリーリークになる。
Form1のButton2をたたけばたたくほど、見えないForm2のインスタンスが次々作成されていく。
タスクマネージャーを起動し、Form1のButton2を連打しまくれば、使用メモリが次々増えていく様子を確認することができるでしょう。

ただし、Form2.OnCloseでAction = caFree としているなら、メモリーリークは発生しない。
発生しないが、
>   Form2.Setedit1(editString);
ここで、破棄されたForm2のインスタンスにアクセスすることになり、結局エラーになるわけだ。

一般には、以下のように書くのが望ましいでしょう。
必要に応じて例外処理を記述すること。

procedure TForm1.Button2Click(Sender: TObject);
var
  editString: String;
  xxForm2: TForm2;
begin
  editString := Edit1.Text;
  xxForm2:= TForm2.Create(Self{nil});
  xxForm2.Setedit1(editString);
  xxForm2.ShowModal;
  xxForm2.Free;
  //または
  //xxForm2.Releace;
end;


> procedure TForm2.Setedit1(edit1: String);
> begin
>   Str := Edit1;
> end;
コンポーネントにも Edit1 があり、まぎらわしい。
今回は、引数の型がStringであるため大事に至らないが、バグの元である。

さらに次
> procedure TForm2.FormShow(Sender: TObject);
> var i: Integer;
> begin
>   Edit1.Text := str;
>   for i := Low(aaaArr) to High(aaaArr) do
>     begin
>         if Edit1.Text = Form1.ListBox1.Items[Form1.ListBox1.ItemIndex] then
>         begin
>             Edit2.Text := aaaArr[i].Edit2;
>     end;
>   end;
> end;
配列aaaArrのサイズとForm1.ListBox1のアイテム数が一致している保証がない。
最初のうちは、配列aaaArrのサイズが0のため、「Indexが範囲を超えています」というメッセージに遭遇していないだけです。

結論
やりたいことがわからない。
Unit2のユニット変数にしないで、TFormの変数にしてしまったほうが楽。
また、前述の通り、Record型のメンバにString型がある場合、メモリの行方が気になる。
今回、String型一つだけなので、むしろTStringListを使った方が吉。

勉強中だから、どうしても使いたいというのであれば、以下のようにするとイイかもな。
-----------------------------------------------
type
  TArrayAAARecord = array of AAARecord;

funstion GetUnit2ArrayAAARecord: TArrayAAARecord;

implementation

> var
>   str: String;
>   //aaaArr: array of AAARecord;
    aaaArr: TArrayAAARecord;

funstion GetUnit2ArrayAAARecord: TArrayAAARecord;
begin
  Result := aaaArr;
end;  
-----------------------------------------------

これで、GetUnit2ArrayAAARecordを使って配列を拾っておけば、メンバとして使えるでしょう。
ただし、array of HogeHoge のような動的配列は、暗黙ポインタ型。
例えば、以下のようにした場合、AとBは同じ内容(ポインタ)をさす。
したがって、実行結果は A[0] = 2 = B[0]
var
  A, B: array of Integer;
begin
  SetLength(A, 1);
  A[0] := 1;
  B := A;
  B[0] := 2;
end;

じゃ、こっちはどうなる?

var
  A, B: array of Integer;
begin
  SetLength(A, 1);
  B := A;
  SetLength(A, 2);
  //これって B = A なの?
end;

やったことがないので知りません。
実行結果が常に B = A なるのであれば、上記のTArrayAAARecord型宣言の方式で十分要求を満たすでしょう。

あとは、自分でやるべし。


あれ・・  2005-06-10 08:34:28  No: 15093

> レコード型のメンバにString型があるとき、そのString型のメモリの開放がうまくいかないんじゃなかったかなと。

心配ありません。このレコード型の動的配列でも大丈夫。New Dispose でもOK。


あれ  2005-06-13 20:44:29  No: 15094

レコード型の動的配列のメモリリークを防ぐ方法は?


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加