Если вы посмотрите на исходный код для TVCLReport
, его метод Execute()
отображает VCL на основе пользовательского интерфейса, когда Preview=True
:
type
TVCLReport=class(TCBaseReport)
private
prcontrol:TRpPreviewControl;
...
end;
function TVCLReport.Execute:boolean;
var
...
begin
inherited Execute;
...
try
if Preview then
begin
prcontrol:=TRpPreviewControl.Create(nil);
try
prcontrol.Report:=Report;
Result:=ShowPreview(prcontrol,Title);
finally
prcontrol.free;
end;
end
else
begin
...
end;
TRpPreviewControl
является производным от TScrollBox
. ShowPreview()
- вспомогательная функция, которая помещает объект TRpPreviewControl
в пользовательский объект TForm
(TFRpPreview
), который отображается с ShowModal()
. Пользовательские интерфейсы на основе VCL не являются потокобезопасными и не могут использоваться вне контекста основного потока пользовательского интерфейса. Как вы можете видеть, TVCLReport.Execute()
не предоставляет вам возможности синхронизации с основным потоком пользовательского интерфейса, поэтому Preview=True
НЕ безопасно использовать в рабочем потоке.
Если вы хотите позвонить TVCLReport.Execute()
в рабочий поток, но отобразить его предварительный просмотр в потокобезопасном режиме, одним из возможных решений было бы изменить исходный код для TVCLReport
, чтобы показать функциональность предварительного просмотра таким образом, чтобы вы могли вызвать его с помощью TThread.Synchronize()
, например:
type
TVCLReportPreviewEvent = procedure(Sender: TObject; var VResult: Boolean) of object;
TVCLReport=class(TCBaseReport)
private
prcontrol:TRpPreviewControl;
...
public
OnPreview: TVCLReportPreviewEvent;
function DisplayPreview: Boolean;
end;
function TVCLReport.Execute:boolean;
var
...
begin
inherited Execute;
...
try
if Preview then
begin
if Assigned(OnPreview) then
OnPreview(Self, Result)
else
Result := DisplayPreview;
end
else
begin
...
end;
function TVCLReport.DisplayPreview: Boolean;
begin
prcontrol:=TRpPreviewControl.Create(nil);
try
prcontrol.Report:=Report;
Result := ShowPreview(prcontrol, Title);
finally
prcontrol.free;
end;
end;
procedure TReportThread1.Execute;
begin
if ReportBUFFER = 1 then begin
dm.rmvFarm.Filename := reportpath + 'aoc.rep';
dm.rmvFarm.Report.Params.Items[0].Value := Thread_StartOfTheDayR1;
dm.rmvFarm.Report.Params.Items[1].Value := Thread_EndOfTheDayR1;
dm.rmvFarm.Report.Params.Items[2].Value := currentusr;
dm.rmvFarm.Preview := true;
dm.rmvFarm.OnPreview := DisplayPreviewInMainThread;
dm.rmvFarm.Execute;
ReportThread1.free;
end;
end;
procedure TReportThread1.DisplayPreviewInMainThread(Sender: TObject; var VResult: Boolean);
begin
TThread.Synchronize(nil,
procedure
begin
VResult := dm.rmvFarm.DisplayPreview;
end
);
end;
Хотя, если отчет действительно занимает много времени для создания, то есть вероятность, что просмотр будет также принимать долгое время генерировать. Если это так, это решение не принесет вам ничего полезного. Возможно, было бы проще просто оставить TVCLReport
в главном потоке пользовательского интерфейса и отобразить сообщение пользователю, когда он занят созданием отчета.
Вам просто нужно попробовать и посмотреть, что произойдет.
Благодарим вас за ваши усилия и идеи. Я ценю это. Я дам ему попытку и дам вам знать, работает ли это. – ErenRavenHeart
Я не могу понять это ... «dm.rmvFarm.DisplayPreview», «dm.rmvFarm.OnPreview» не объявлены. – ErenRavenHeart
@ErenRavenHeart У вас может быть другая версия Reportmanager, кроме Remy. Или вы не включили правильные исходные файлы в предложение Uses. Используйте документацию. –