Si vous regardez le code source pour TVCLReport
, sa méthode Execute()
affiche une interface utilisateur à base VCL lorsque 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
est dérivé de TScrollBox
. ShowPreview()
est une fonction d'assistance qui place l'objet TRpPreviewControl
sur un objet TForm
personnalisé (TFRpPreview
) qui est affiché avec ShowModal()
. Les interfaces utilisateur basées sur la VCL ne sont pas sécurisées pour les threads et ne peuvent pas être utilisées en dehors du contexte du thread principal de l'interface utilisateur. Comme vous pouvez le voir, TVCLReport.Execute()
ne vous offre aucune possibilité de synchronisation avec le thread d'interface utilisateur principal, donc Preview=True
n'est PAS sûr à utiliser dans un thread de travail. Si vous souhaitez appeler TVCLReport.Execute()
dans un thread de travail, mais afficher son aperçu d'une manière thread-safe, une solution possible serait d'altérer le code source pour TVCLReport
pour exposer la fonctionnalité de prévisualisation d'une manière qui vous permet pour appeler à l'aide TThread.Synchronize()
, par exemple:
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;
Bien que, si votre rapport ne prend vraiment beaucoup de temps pour générer, alors les chances sont que l'aperçu prendra également un long moment pour générer. Si oui, cette solution ne vous apportera rien d'utile. Il peut être plus simple de laisser simplement le TVCLReport
dans le thread d'interface utilisateur principal et d'afficher un message à l'utilisateur pendant qu'il est en train de générer le rapport.
Vous aurez juste à l'essayer et voir ce qui se passe.
Merci beaucoup pour vos efforts et vos idées. Je vous en suis reconnaissant. Je vais essayer et vous faire savoir si cela fonctionne. – ErenRavenHeart
Je n'arrive pas à comprendre ... "dm.rmvFarm.DisplayPreview", "dm.rmvFarm.OnPreview" sont non déclarés .. – ErenRavenHeart
@ErenRavenHeart Vous avez peut-être une autre version de Reportmanager que Remy. Ou vous n'avez pas inclus les fichiers source appropriés dans votre clause Uses. Utilisez la documentation. –