Из основной формы создаю динамически дочернюю форму:
var
SomeForm: TForm;
FormClass: TFormClass;
begin
try
FormClass := TFormClass(FindClass('Tnof12Form'));
SomeForm := FormClass.Create(Application);
except
on E: Exception do
begin
MessageDlg('Не удалось открыть "nof12Form".' + #13#10 +
'Error: Could not find class.', mtError, [mbOK], 0)
end;
end;
Форма создается и показывается. Далее мне необходимо из созданной дочерней формы запустить поток в котором будет выполнен запрос к бд и результат возвращен в ту же форму в компонент DBGrid.
unit no12;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Data.Win.ADODB, Vcl.StdCtrls, Vcl.Grids, Vcl.DBGrids;
type
Tnof12Form = class(TForm)
DataSource1: TDataSource;
DBGrid1: TDBGrid;
Button1: TButton;
Query: TADOQuery;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
end;
TPotok = class(TThread)
private
procedure DataSource;
protected
procedure Execute; override;
end;
var
nof12Form: Tnof12Form;
implementation
{$R *.dfm}
procedure TPotok.DataSource;
begin
nof12Form.DataSource1.DataSet := nof12Form.Query;
end;
procedure TPotok.Execute;
begin
nof12Form.Query.Open;
Synchronize(DataSource);
end;
procedure Tnof12Form.Button1Click(Sender: TObject);
begin
Query.ConnectionString :='********';
Query.sql.text := '***********';
with TPotok.Create(True) do
begin
FreeOnTerminate := True;
Resume;
end;
end;
procedure Tnof12Form.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
Initialization
RegisterClasses([Tnof12Form]);
end.
Вроде бы все хорошо, но на самом деле ничего хорошего.
При обычном запуске никаких ошибок, просто DBGrid ничего не отображает.
А вот при детальном рассмотрении выдает ошибку на nof12Form.Query.Open;:
Project Forms.exe raised exception class $C0000005 with message 'access violation at 0x008473ec: read of address 0x000003cc'.
Но, если я создаю дочернюю форму вот таким способом:
nof12Form := Tnof12Form.Create(Application);
или
Application.CreateForm(Tnof12Form, nof12Form);
То все отлично работает и DBGrid отображает результат запроса.
Никак не могу понять что делать.
Ответ
У вас есть глобальная переменная:
var
nof12Form: Tnof12Form;
Когда вы создаете форму таким образом:
nof12Form := Tnof12Form.Create(Application);
то вы присваиваете этой переменной ссылку на экземпляр формы.
Когда вы создаете вот так:
Application.CreateForm(Tnof12Form, nof12Form);
То метод CreateForm создает экземпляр Tnof12Form и присваивает его в переменную nof12Form (так как второй параметр является выходным).
И всё работает. Но если вы создаете вот так:
var
SomeForm: TForm;
FormClass: TFormClass;
begin
try
FormClass := TFormClass(FindClass('Tnof12Form'));
SomeForm := FormClass.Create(Application);
...
То созданный экземпляр формы попадает только в локальную переменную SomeForm, а глобальная переменная nof12Form остается неинициализированной. Поэтому впоследствии при обращении к ней:
nof12Form.Query.Open;
возникает ошибка доступа.
При создании потока вам нужно в него передать ссылку на экземпляр вашей формы, типа того:
with TPotok.Create(Self) do
begin
FreeOnTerminate := True;
Resume;
end;
Переписав при этом конструктор потока, конечно:
TPotok = class(TThread)
private
procedure DataSource;
protected
FForm: Tnof12Form; // <-- НОВАЯ ПЕРЕМЕННАЯ ДЛЯ ХРАНЕНИЯ ФОРМЫ
procedure Execute; override;
public
constructor Create(AForm: Tnof12Form); reintroduce; // <-- НОВЫЙ КОНСТРУКТОР
end;
...
implementation
...
procedure TPotok.Create(AForm: Tnof12Form);
begin
FForm := AForm;
inherited Create(True);
end;
и в потоке обращаться к нему, а не к глобальной переменной:
procedure TPotok.DataSource;
begin
FForm.DataSource1.DataSet := nof12Form.Query;
end;
procedure TPotok.Execute;
begin
FForm.Query.Open;
Synchronize(DataSource);
end;
При таком подходе переменная:
var
nof12Form: Tnof12Form;
вам вообще не нужна (хотя она может быть нужна, если nof12Form создается автоматически при старте проекта).
Комментариев нет:
Отправить комментарий