Страницы

Поиск по вопросам

пятница, 12 июля 2019 г.

Динамическая форма и sql запрос в потоке

Из основной формы создаю динамически дочернюю форму:
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 создается автоматически при старте проекта).

Комментариев нет:

Отправить комментарий