いつもお世話になります。
XE7.1のwin32でテストしていて、
「モジュール'xxx.exe'のアドレス xxxxxxでアドレスyyyyyに対する
読み込み違反がおきました」
となります。
Formが3コあり、メインはForm1で自動生成がForm1とForm3です。
Form1からForm2を呼び出して、Form3のコンポーネントを参照しています。
Form2の1度目の呼び出しからのForm3のコンポーネント参照ではエラーが出ません。
2度目からの呼び出しでの参照では上記エラーとなります。
元々Form2も自動作成でした。Form2が呼ばれたときと閉じたときの変更内容を
取得したくてForm2の自動生成をやめました。
以下がForm1での記述です。
procedure TForm1.FormCreate(Sender: TObject);
begin
Form2 := nil;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(Form2) then
Form2 := TForm2.Create(Application);
Form2.Show;
end;
以下がForm2での記述です。
procedure TForm2.ButtonListDispClick(Sender: TObject);
var
i : integer;
item : TListboxItem;
begin
with Form3 do begin
//リストをクリア
SelectList.Clear; //ここでエラーになる
SelectList.BeginUpdate;
〜したい処理 省略〜
end; //with
end;
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := TCloseAction.caFree;
Form2 := nil;
end;
ご教授いただけませんでしょうか。
宜しくお願いいたします。
SelectList は、呼び出す前には、どのような状態ですか?
(Freeされたり、してませんか?)
早速の返答ありがとうございます。
SelectListはFreeとかしていないです。
テストで、Form3にボタンを貼り付けてそのボタンのTextを
参照するだけでもこのエラーは発生します。
XE8でもXE7.1VCLでも同様の結果となります。
挙げられたコードのうち、
>procedure TForm2.ButtonListDispClick(Sender: TObject);
の処理を
>Form3にボタンを貼り付けてそのボタンのTextを参照するだけ
に置き換えたものを、試したところ、こちらでは、エラーは出ませんでした。(Delphi XE8)
igyさん 試していただいてありがとうございます。
こちらではエラーになります。
長文となりますが、UPします。問題解決のために行数を少なくしたもので
業務としては意味のないものです。
まずはプロジェクト*************************************************
program z1156;
uses
System.StartUpCopy,
FMX.Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2},
Unit3 in 'Unit3.pas' {Form3};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm3, Form3);
Application.Run;
end.
次にUNIT1のType以降************************************************
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ private 宣言 }
public
{ public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
uses Unit2;
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(Form2) then
Form2 := TForm2.Create(Application);
Form2.Show;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Form2 := nil;
end;
end.
次にUNIT2のType以降************************************************
type
TForm2 = class(TForm)
Button1: TButton;
ButtonListDisp: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ButtonListDispClick(Sender: TObject);
private
{ private 宣言 }
procedure ButtonSettingOkClick(Sender: TObject);
public
{ public 宣言 }
end;
var
Form2: TForm2;
implementation
{$R *.fmx}
uses Unit1, Unit3;
procedure TForm2.Button1Click(Sender: TObject);
begin
close;
end;
procedure TForm2.ButtonListDispClick(Sender: TObject);
begin
Label1.Text := Form3.SelectOkButton.Text; //ここでエラー
Form3.Panel1.Parent := Form2;
Form3.Panel1.Visible := true;
Form3.SelectOkButton.OnClick := ButtonSettingOkClick;
end;
procedure TForm2.ButtonSettingOkClick(Sender: TObject);
begin
Form3.Panel1.Visible := false;
self.Label1.text := Form3.SelectOkButton.Text; //これは参照のテスト用
end;
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := TCloseAction.caFree;
Form2 := nil;
end;
end.
最後にUNIT2のType以降************************************************
FormにPanelを配置しその上にListBoxとLabelとButtonを置いています。
type
TForm3 = class(TForm)
SelectList: TListBox;
Panel1: TPanel;
SelectOkButton: TButton;
SelectTitle: TLabel;
private
{ private 宣言 }
public
{ public 宣言 }
end;
var
Form3: TForm3;
implementation
{$R *.fmx}
end.
こちらでしている操作は、
(1)プログラムを立ち上げて、
(2)Button1をクリックしてForm2を表示
(3)Form2のButtonListDispをクリックして、Form3にあるパネルを表示
(4)SelectOkButtonを押下
(5)Form2の右上の閉じるボタン[X]を押下
(6)Form1に戻るので(2)の操作
(7)(3)の操作をするとエラーが発生
となります。
Form2を自動生成にして、Form2のFormCloseをコメント化すると
エラーは発生しません。
// Action := TCloseAction.caFree;
// Form2 := nil;
不思議です。
>に置き換えたものを、試したところ、こちらでは、エラーは出ませんでした。(Delphi XE8)
ちなみに、これは、Delphi XE8 VCL 32bit版 でした。
FMX 32bit版 でも試したところ、こちらもエラーがでませんでした。
OS:Windows 7 64bit
エラーが出る行にブレークポイントを設定して、その行にあるもの、つまり
Form3、Form3.SelectOkButton、Form3.SelectOkButton.Text、Label1
といったものに何が入っているかを確認してみてはいかがでしょう?
TForm2.ButtonListDispClick の中にある
> Form3.Panel1.Parent := Form2;
これを外しても結果は同じですか?
このままForm2が解放されると、Form3.Panel1がParent不在のまま取り残されることになってまずそうですが……
ちなみに、Form内で別のまとまったコンポーネントを再利用したいとかの用途だったら、Frameを使った方がいい気がします。
と言うか、Parentを変更したから、Form2が解放される時にForm3も一緒に解放されていますねこれは。
やっぱり、こういう用途だったらFrameにするべきでしょう……。
igyさん
何か環境が違うのでしょうか。XE7.1,XE8ともにWindows8の環境でWin32,Win64
でエラーが発生します。Android5.0.1でも同様です。
通りすがりさん
エラーの箇所にブレークポイントを設定してみると、Form3.SelectOkがnilでした。
torさん
>これを外しても結果は同じですか?
パネルが表示されなくなります。
それで原因と思われることがわかりました。Parentの扱いに考慮が足りていなかったのではないかと。
ご指摘のとおりForm2が解放されたときその子(?)となってしまっているPanelも
なくなるのではないかと。Form2が再生成されたときはPanelは生成されないと。
そこでButtonSettingOkClickに
Panel1.Parent := Form3;
として、Parentを戻してみたところエラーは発生せず期待した動きになりました。
コンポーネントを増やしたくないためにこういうことをしているのですが、
避けたほうがいいのでしょうか。Frameを使ったことがないのですが勉強
して試してみます。
igyさん
>>に置き換えたものを、試したところ、こちらでは、エラーは出ませんでした。>(Delphi XE8)
>ちなみに、これは、Delphi XE8 VCL 32bit版 でした。
>FMX 32bit版 でも試したところ、こちらもエラーがでませんでした。
>OS:Windows 7 64bit
最初の私の情報提供不足からこの結果になったと思います。
申し訳ありませんでした。
ありがとうございました。
解決です。
ツイート | ![]() |