Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2023-03

animated splash screen for lengthy operation, works with windows, doesn't with linux

22 messages · 6 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Luca Olivetti

Hello,

I'd like to show a splash screen with an animation during a lengthy operation.
I cannot rely on a timer to show the animation since the message loop isn't running, so I'm using a thread to directly paint over the form, i.e.:

WaitForm.Show;
Application.ProcessMessages;

...

procedure TWaitForm.FormShow(Sender: TObject);
begin
   FUpdateThread:=TUpdateThread.Create(self);
end;

...

procedure TUpdateThread.Execute;
begin
   while not Terminated do
   begin
     FWaitForm.ShowProgress;
     Sleep(30);
   end;
end;

...

procedure TWaitForm.ShowProgress;
begin
   PaintBox1.Canvas.Clear;
   //WaitAnimation is an image list
   WaitAnimation.Draw(PaintBox1.Canvas,0,0,FImageIndex);
   FImageIndex:=FImageIndex+1;
   if FImageIndex>=WaitAnimation.Count then
     FImageIndex:=0;
end;

This works wonderfully under windows (which is my intended target, so no problem here), but under Linux it doesn't work (tested with gtk2, gtk3 and qt5). In fact, even the "Show; Application.ProcessMessages" is erratic, sometimes it shows the form, sometimes it doesn't.

Lazarus 2.2.6/fpc 3.2.2

Any idea?

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Jean SUZINEAU
to Luca Olivetti

Le 27/03/2023 ? 09:46, Luca Olivetti via lazarus a ?crit?:

Show quoted text 8 lines
procedure TUpdateThread.Execute; begin ? while not Terminated do ? begin ??? FWaitForm.ShowProgress; ??? Sleep(30); ? end; end;

Usually I use TThread.Synchronize to ensure that the graphic code is run by the main thread.

But it won't work if your main thread is blocking.

May be you should do the inverse move the lengthy operation to a separate thread and keep the main thread for the splash screen ?

As far as I know the graphic code must be run by the main thread.

Reply by email

Luca Olivetti
to Jean SUZINEAU

El 27/3/23 a les 10:13, Jean SUZINEAU via lazarus ha escrit:

Show quoted text 15 lines
Le 27/03/2023 ? 09:46, Luca Olivetti via lazarus a ?crit?: > procedure TUpdateThread.Execute; > begin > ? while not Terminated do > ? begin > ??? FWaitForm.ShowProgress; > ??? Sleep(30); > ? end; > end; Usually I use TThread.Synchronize to ensure that the graphic code is run by the main thread. But it won't work if your main thread is blocking.

Exactly

May be you should do the inverse move the lengthy operation to a separate thread and keep the main thread for the splash screen ?

Yes, I usually do that, but in this case it's not possible (the lengthy operation is just a TSQLQuery.open that I cannot delegate to a different thread).

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Luca Olivetti

El 27/3/23 a les 10:34, Luca Olivetti via lazarus ha escrit:

Show quoted text 26 lines
El 27/3/23 a les 10:13, Jean SUZINEAU via lazarus ha escrit: > > Le 27/03/2023 ? 09:46, Luca Olivetti via lazarus a ?crit?: >> procedure TUpdateThread.Execute; >> begin >> ? while not Terminated do >> ? begin >> ??? FWaitForm.ShowProgress; >> ??? Sleep(30); >> ? end; >> end; > > Usually I use TThread.Synchronize to ensure that the graphic code is > run by the main thread. > > But it won't work if your main thread is blocking. Exactly > > May be you should do the inverse move the lengthy operation to a > separate thread and keep the main thread for the splash screen ? Yes, I usually do that, but in this case it's not possible (the lengthy operation is just a? TSQLQuery.open that I cannot delegate to a different thread).

Sorry, in this project I'm using zeos, so it's TZQuery.open.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Sven Barth
to Luca Olivetti: El 27/3/23 a les 10:13, Jean SUZINEAU via lazarus ha escrit: Exactly Yes, I usually do…

Luca Olivetti via lazarus schrieb am Mo.,
27. M?rz 2023, 10:34:

Show quoted text 27 lines
El 27/3/23 a les 10:13, Jean SUZINEAU via lazarus ha escrit: > > Le 27/03/2023 ? 09:46, Luca Olivetti via lazarus a ?crit : >> procedure TUpdateThread.Execute; >> begin >> while not Terminated do >> begin >> FWaitForm.ShowProgress; >> Sleep(30); >> end; >> end; > > Usually I use TThread.Synchronize to ensure that the graphic code is run > by the main thread. > > But it won't work if your main thread is blocking. Exactly > > May be you should do the inverse move the lengthy operation to a > separate thread and keep the main thread for the splash screen ? Yes, I usually do that, but in this case it's not possible (the lengthy operation is just a TSQLQuery.open that I cannot delegate to a different thread).

You need to find a way then, because the GUI handling *must* be done in the main thread.

Regards,
Sven

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20230327/04ad7a1f/attachment-0001.htm>

Reply by email

Luca Olivetti
to Sven Barth

El 27/3/23 a les 11:06, Sven Barth via lazarus ha escrit:

Show quoted text 35 lines
Luca Olivetti via lazarus < <mailto:>> schrieb am Mo., 27. M?rz 2023, 10:34: El 27/3/23 a les 10:13, Jean SUZINEAU via lazarus ha escrit: > > Le 27/03/2023 ? 09:46, Luca Olivetti via lazarus a ?crit?: >> procedure TUpdateThread.Execute; >> begin >> ? while not Terminated do >> ? begin >> ??? FWaitForm.ShowProgress; >> ??? Sleep(30); >> ? end; >> end; > > Usually I use TThread.Synchronize to ensure that the graphic code is run > by the main thread. > > But it won't work if your main thread is blocking. Exactly > > May be you should do the inverse move the lengthy operation to a > separate thread and keep the main thread for the splash screen ? Yes, I usually do that, but in this case it's not possible (the lengthy operation is just a? TSQLQuery.open that I cannot delegate to a different thread). You need to find a way then, because the GUI handling *must* be done in the main thread.

Opening the query in a thread[*] seems to have no ill effects, so that's what I'm doing now.

[*] instead of opening the query I spawn a thread that opens it, wait for it to finish while executing Application.ProcessMessages and eventually reraise the exception that was generated inside the thread.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Giuliano Colla
to Luca Olivetti: I'd like to show a splash screen with an animation during a lengthy operation. I cannot…

Il 27/03/23 09:46, Luca Olivetti via lazarus ha scritto:

Show quoted text 53 lines
Hello, I'd like to show a splash screen with an animation during a lengthy operation. I cannot rely on a timer to show the animation since the message loop isn't running, so I'm using a thread to directly paint over the form, i.e.: WaitForm.Show; Application.ProcessMessages; ... procedure TWaitForm.FormShow(Sender: TObject); begin ? FUpdateThread:=TUpdateThread.Create(self); end; ... procedure TUpdateThread.Execute; begin ? while not Terminated do ? begin ??? FWaitForm.ShowProgress; ??? Sleep(30); ? end; end; ... procedure TWaitForm.ShowProgress; begin ? PaintBox1.Canvas.Clear; ? //WaitAnimation is an image list ? WaitAnimation.Draw(PaintBox1.Canvas,0,0,FImageIndex); ? FImageIndex:=FImageIndex+1; ? if FImageIndex>=WaitAnimation.Count then ??? FImageIndex:=0; end; This works wonderfully under windows (which is my intended target, so no problem here), but under Linux it doesn't work (tested with gtk2, gtk3 and qt5). In fact, even the "Show; Application.ProcessMessages" is erratic, sometimes it shows the form, sometimes it doesn't. Lazarus 2.2.6/fpc 3.2.2 Any idea? Bye

Yes, it's a known issue.

The difference between Windows and Unix is that Windows generates frequently useless mouse events to all windows, which wake up the main thread of Delphi/Lazarus, while Unix/X11/Wayland is well behaved and sends a mouse event only to the appropriate window, and only if there's been a physical mouse event to send.

You may verify if such is the case by moving the mouse over your splash screen window. You move the mouse and the image is updated, you stop moving and the image freezes.

In a similar scenario my solution has been that of an horrible hack. It's a hack, but it works. I've put in a corner of my window a label of just one character, and, with a frequent timer (200 ms in my case) I update the caption. I'm using a sequence of "-" "\" " |" "/" "-" to display a rotating bar. Usually users do not even notice, but if they do it's harmless. This way I trigger an event which will force a paint operation, and all pending graphic updates are performed.

Maybe this works also for you. You should just tune the timer to the speed of your animation.

Hope that it helps,

Giuliano

Do not do to others as you would have them do to you.They might have different tastes.

Reply by email

Luca Olivetti
to Giuliano Colla

El 27/3/23 a les 12:07, Giuliano Colla ha escrit:

Show quoted text 10 lines
In a similar scenario my solution has been that of an horrible hack. It's a hack, but it works. I've put in a corner of my window a label of just one character, and, with a frequent timer (200 ms in my case) I update the caption. I'm using a sequence of "-" "\" " |" "/" "-" to display a rotating bar. Usually users do not even notice, but if they do it's harmless. This way I trigger an event which will force a paint operation, and all pending graphic updates are performed. Maybe this works also for you. You should just tune the timer to the speed of your animation.

Thank you, but I don't think it would work (at least under windows I'm sure it doesn't), since in order to process the timer events the main loop must be processing events, and it's not doing that if the program is stuck in a lengthy operation.
As per Sven's indication, I'm now doing all the painting in the main thread and delegated the lengthy operation to a thread.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Luca Olivetti: El 27/3/23 a les 11:06, Sven Barth via lazarus ha escrit: Opening the query in a…

El 27/3/23 a les 11:59, Luca Olivetti via lazarus ha escrit:

[*] instead of opening the query I spawn a thread that opens it, wait for it to finish while executing Application.ProcessMessages and eventually reraise the exception that was generated inside the thread.

Speaking of which, I encapsulated it in a procedure (TWaitForm is the spash screen, Aproc is a procedure of object, TExecInThread simply calls AProc in its execute method):

procedure ExecWithSplash(AProc:TThreadProc);
var wf:TWaitForm;
     ut:TExecInThread;
begin
   Wf:=TWaitForm.Create(Application);
   WF.Show;
   ut:=TExecInThread.create(AProc);
   while not ut.Finished
     Application.ProcessMessages
   wf.free;
   if ut.FatalExceptionnil then
     raise(ut.FatalException);
   ut.free;
end;

The problem here is, if AProc raises an exception, I cannot free the thread causing a leak.
Since I don't want to expose the thread to the caller, so that it can free it in its exception handler, how can I copy FatalException so I can free the thread and only then raise the exception? I cannot simply assign it to a local variable since the TThread destructor also frees FatalException.

Encapsulating it in a try..finally block also doesn't work

try
   if ut.FatalExceptionnil then
     raise(ut.FatalException);
finally
   ut.free;
end

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Mattias Gaertner
to Luca Olivetti
Show quoted text 30 lines
El 27/3/23 a les 11:59, Luca Olivetti via lazarus ha escrit: > [*] instead of opening the query I spawn a thread that opens it, > wait for it to finish while executing Application.ProcessMessages > and eventually reraise the exception that was generated inside the > thread. Speaking of which, I encapsulated it in a procedure (TWaitForm is the spash screen, Aproc is a procedure of object, TExecInThread simply calls AProc in its execute method): procedure ExecWithSplash(AProc:TThreadProc); var wf:TWaitForm; ut:TExecInThread; begin Wf:=TWaitForm.Create(Application); WF.Show; ut:=TExecInThread.create(AProc); while not ut.Finished Application.ProcessMessages wf.free; if ut.FatalExceptionnil then raise(ut.FatalException); ut.free; end; The problem here is, if AProc raises an exception, I cannot free the thread causing a leak.

What does TExecInThread.Execute do?

Show quoted text 6 lines
try if ut.FatalExceptionnil then raise(ut.FatalException); finally ut.free; end

Mattias

Reply by email

Luca Olivetti
to Mattias Gaertner: On Mon, 27 Mar 2023 14:40:26 +0200 What does TExecInThread.Execute do? Mattias

El 27/3/23 a les 15:40, Mattias Gaertner via lazarus ha escrit:

Show quoted text 21 lines
> > procedure ExecWithSplash(AProc:TThreadProc); > var wf:TWaitForm; > ut:TExecInThread; > begin > Wf:=TWaitForm.Create(Application); > WF.Show; > ut:=TExecInThread.create(AProc); > while not ut.Finished > Application.ProcessMessages > wf.free; > if ut.FatalExceptionnil then > raise(ut.FatalException); > ut.free; > end; > > > The problem here is, if AProc raises an exception, I cannot free the > thread causing a leak. What does TExecInThread.Execute do?

As I said, it just calls AProc (which the constructor stored in FProc)

procedure TExecInThread.Execute;
begin
   FProc()
end;
constructor TExecInThread.create(AProc:TThreadProc);
begin
   FProc:=AProc;
   inherited create(false);
end;

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Jean SUZINEAU: Le 27/03/2023 ? 14:40, Luca Olivetti via lazarus a ?crit?: May be you can create a new…

El 27/3/23 a les 15:55, Jean SUZINEAU via lazarus ha escrit:

Show quoted text 8 lines
Le 27/03/2023 ? 14:40, Luca Olivetti via lazarus a ?crit?: > The problem here is, if AProc raises an exception, I cannot free the > thread causing a leak. May be you can create a new exception class specifically for ExecWithSplash, instantiate it and put all the information of ut.FatalException in the new exception instance before raising it?

Creating a specific exception class wouldn't solve the problem on how to make a deep copy of the original exception.
I can just store the message an raise it again, losing the rest of the details, i.e.:

   ExceptionMessage:='';
   if ut.FatalExceptionnil then
     ExceptionMessage:=Exception(ut.FatalException).Message;
   ut.free;
   if ExceptionMessage'' then
     raise Exception.create(ExceptionMessage);

The goal is to easily substitute the original code:

   try
     dosomething;
     dosomethingelse;
     ....
   except
     ....
   end;

with

   try
     ExecWithSplash(@doit);
   except
     ...
   end;
procedure TMyDatamodule.doit;
begin
   dosomething;
   dosomethingelse;
end;

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Michael Van Canneyt
to Luca Olivetti: El 27/3/23 a les 11:59, Luca Olivetti via lazarus ha escrit: Speaking of which, I…
Luca Olivetti wrote 24 lines
El 27/3/23 a les 11:59, Luca Olivetti via lazarus ha escrit: > [*] instead of opening the query I spawn a thread that opens it, wait for > it to finish while executing Application.ProcessMessages and eventually > reraise the exception that was generated inside the thread. Speaking of which, I encapsulated it in a procedure (TWaitForm is the spash screen, Aproc is a procedure of object, TExecInThread simply calls AProc in its execute method): procedure ExecWithSplash(AProc:TThreadProc); var wf:TWaitForm; ut:TExecInThread; begin Wf:=TWaitForm.Create(Application); WF.Show; ut:=TExecInThread.create(AProc); while not ut.Finished Application.ProcessMessages wf.free; if ut.FatalExceptionnil then raise(ut.FatalException); ut.free;

Ehm. In case of an exception, ut will never be freed ?

Michael.

Reply by email

Luca Olivetti
to Michael Van Canneyt

El 27/3/23 a les 16:13, Michael Van Canneyt via lazarus ha escrit:

Show quoted text 30 lines
On Mon, 27 Mar 2023, Luca Olivetti via lazarus wrote: > El 27/3/23 a les 11:59, Luca Olivetti via lazarus ha escrit: > >> [*] instead of opening the query I spawn a thread that opens it, wait >> for it to finish while executing Application.ProcessMessages and >> eventually reraise the exception that was generated inside the thread. > > > Speaking of which, I encapsulated it in a procedure (TWaitForm is the > spash screen, Aproc is a procedure of object, TExecInThread simply > calls AProc in its execute method): > > procedure ExecWithSplash(AProc:TThreadProc); > var wf:TWaitForm; > ?? ut:TExecInThread; > begin > ?Wf:=TWaitForm.Create(Application); > ?WF.Show; > ?ut:=TExecInThread.create(AProc); > ?while not ut.Finished > ?? Application.ProcessMessages > ?wf.free; > ?if ut.FatalExceptionnil then > ?? raise(ut.FatalException); > ?ut.free; Ehm. In case of an exception, ut will never be freed ?

That's what I said.
I was looking for a way to free it *and* raise the exception in the context of the main thread.
If I move the ut.free before the raise, the exception has already been freed and it's invalid, causing a sigsev, if I enclose it in a try..finally the exception handler will be called after the finally has freed the thread (and the exception, so it's the same problem).

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Michael Van Canneyt
to Luca Olivetti
Luca Olivetti wrote 39 lines
El 27/3/23 a les 16:13, Michael Van Canneyt via lazarus ha escrit: > > > On Mon, 27 Mar 2023, Luca Olivetti via lazarus wrote: > >> El 27/3/23 a les 11:59, Luca Olivetti via lazarus ha escrit: >> >>> [*] instead of opening the query I spawn a thread that opens it, wait >>> for it to finish while executing Application.ProcessMessages and >>> eventually reraise the exception that was generated inside the thread. >> >> >> Speaking of which, I encapsulated it in a procedure (TWaitForm is the >> spash screen, Aproc is a procedure of object, TExecInThread simply >> calls AProc in its execute method): >> >> procedure ExecWithSplash(AProc:TThreadProc); >> var wf:TWaitForm; >> ?? ut:TExecInThread; >> begin >> ?Wf:=TWaitForm.Create(Application); >> ?WF.Show; >> ?ut:=TExecInThread.create(AProc); >> ?while not ut.Finished >> ?? Application.ProcessMessages >> ?wf.free; >> ?if ut.FatalExceptionnil then >> ?? raise(ut.FatalException); >> ?ut.free; > > Ehm. In case of an exception, ut will never be freed ? That's what I said. I was looking for a way to free it *and* raise the exception in the context of the main thread. If I move the ut.free before the raise, the exception has already been freed and it's invalid, causing a sigsev, if I enclose it in a try..finally the exception handler will be called after the finally has freed the thread (and the exception, so it's the same problem).

Normally, I'd do

Raise Exception(ut.fatalexception.classtype).Create(ut.fatalexception.message);

Michael.

Reply by email

Luca Olivetti
to Michael Van Canneyt

El 27/3/23 a les 16:50, Michael Van Canneyt ha escrit:

Show quoted text 15 lines
>> >> Ehm. In case of an exception, ut will never be freed ? > > That's what I said. > I was looking for a way to free it *and* raise the exception in the > context of the main thread. > If I move the ut.free before the raise, the exception has already been > freed and it's invalid, causing a sigsev, if I enclose it in a > try..finally the exception handler will be called after the finally > has freed the thread (and the exception, so it's the same problem). Normally, I'd do Raise Exception(ut.fatalexception.classtype).Create(ut.fatalexception.message);

Actually I'd have to first create the exception, then free ut, then raise the exception (keep in mind that FatalException is a TObject and it isn't necessarily of class Exception), otherwise a direct raise as you wrote would not free ut.

   MyException:=nil;
   if ut.FatalExceptionnil then
   begin
      if ut.FatalException is Exception then
MyException:=Exception(ut.FatalException).Create(Exception(ut.FatalException).message)
      else
        MyException:=Exception.create(ut.FatalException.ClassName);
   end;
   ut.free;
   if MyExceptionnil then
     raise MyException;

But it still doesn't work, since this way MyException is a copy of FatalException (i.e. it's no different than
MyException:=Exception(ut.FatalExcaption), so freeing ut, which in turn frees ut.FatalException, makes it invalid and causes a sigsev.

The best I could do is store the exception message and raise a new one.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Luca Olivetti

El 27/3/23 a les 17:26, Luca Olivetti via lazarus ha escrit:

Show quoted text 29 lines
El 27/3/23 a les 16:50, Michael Van Canneyt ha escrit: >>> >>> Ehm. In case of an exception, ut will never be freed ? >> >> That's what I said. >> I was looking for a way to free it *and* raise the exception in the >> context of the main thread. >> If I move the ut.free before the raise, the exception has already >> been freed and it's invalid, causing a sigsev, if I enclose it in a >> try..finally the exception handler will be called after the finally >> has freed the thread (and the exception, so it's the same problem). > > Normally, I'd do > > Raise > Exception(ut.fatalexception.classtype).Create(ut.fatalexception.message); Actually I'd have to first create the exception, then free ut, then raise the exception (keep in mind that FatalException is a TObject and it isn't necessarily of class Exception), otherwise a direct raise as you wrote would not free ut. ? MyException:=nil; ? if ut.FatalExceptionnil then ? begin ???? if ut.FatalException is Exception then MyException:=Exception(ut.FatalException).Create(Exception(ut.FatalException).message)

Ouch, I left out the ClassType, but if I change it to

MyException:=Exception(Exception(ut.FatalException).ClassType).Create(Exception(ut.FatalException).message)

it's an instant segfault.

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Michael Van Canneyt
to Luca Olivetti
Luca Olivetti wrote 23 lines
El 27/3/23 a les 17:26, Luca Olivetti via lazarus ha escrit: > El 27/3/23 a les 16:50, Michael Van Canneyt ha escrit: > >>>> >>>> Ehm. In case of an exception, ut will never be freed ? >>> >>> That's what I said. >>> I was looking for a way to free it *and* raise the exception in the >>> context of the main thread. >>> If I move the ut.free before the raise, the exception has already >>> been freed and it's invalid, causing a sigsev, if I enclose it in a >>> try..finally the exception handler will be called after the finally >>> has freed the thread (and the exception, so it's the same problem). >> >> Normally, I'd do >> >> Raise >> Exception(ut.fatalexception.classtype).Create(ut.fatalexception.message); > > Actually I'd have to first create the exception, then free ut, then > raise the exception (keep in mind that FatalException is a TObject and > it isn't necessarily of class Exception), otherwise a direct raise as > you wrote would not free ut.

I only gave the line to show that you can raise a second exception object with the same class and message as the original.

Show quoted text 15 lines
> > ? MyException:=nil; > ? if ut.FatalExceptionnil then > ? begin > ???? if ut.FatalException is Exception then > > MyException:=Exception(ut.FatalException).Create(Exception(ut.FatalException).message) Ouch, I left out the ClassType, but if I change it to MyException:=Exception(Exception(ut.FatalException).ClassType).Create(Exception(ut.FatalException).message) it's an instant segfault.

My bad, I made a typo, it should have been

MyException:=ExceptionClass(ut.FatalException).ClassType).Create(Exception(ut.FatalException).message)
with
ExceptionClass= class of exception;

Actually, I never write it like this in one statement, I save the class pointer and message in local variables, do cleanup first and then use the class pointer and message later to raise an exception. But the effect is the same: you create a copy with the same class and message as the original.

Michael.

Reply by email

Luca Olivetti
to Michael Van Canneyt

El 28/3/23 a les 0:01, Michael Van Canneyt ha escrit:

My bad, I made a typo, it should have been MyException:=ExceptionClass(ut.FatalException).ClassType).Create(Exception(ut.FatalException).message)

Thank you.

Actually it is

MyException:=TExceptionClass(Exception(ut.FatalException).ClassType).Create(Exception(ut.FatalException).message);
with ExceptionClass= class of exception; Actually, I never write it like this in one statement,

Yep, it's quite a mouthful, I had to break it up to spot the error :-)

Show quoted text 5 lines
I save the class pointer and message in local variables, do cleanup first and then use the class pointer and message later to raise an exception. But the effect is the same: you create a copy with the same class and message as the original.

But not with the same detail (i.e. any extra fields are missing). Not that I'm really interested in them (usually I just use the message), but still...

Bye

Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Luca Olivetti
to Luca Olivetti

El 28/3/23 a les 0:45, Luca Olivetti via lazarus ha escrit:

Show quoted text 12 lines
El 28/3/23 a les 0:01, Michael Van Canneyt ha escrit: > > My bad, I made a typo, it should have been > > MyException:=ExceptionClass(ut.FatalException).ClassType).Create(Exception(ut.FatalException).message) Thank you. Actually it is MyException:=TExceptionClass(Exception(ut.FatalException).ClassType).Create(Exception(ut.FatalException).message);

or

MyException:=TExceptionClass(ut.FatalException.ClassType).Create(Exception(ut.FatalException).message)

(TObject already has a ClassType, no need to cast it to Exception).

Show quoted text 20 lines
> with ExceptionClass= class of exception; > > Actually, I never write it like this in one statement, Yep, it's quite a mouthful, I had to break it up to spot the error :-) > I save the class pointer and message > in local variables, do cleanup first and then use the class pointer and > message later to raise an exception. But the effect is the same: you > create > a copy with the same class and message as the original. But not with the same detail (i.e. any extra fields are missing). Not that I'm really interested in them (usually I just use the message), but still... Bye
Luca Olivetti Wetron Automation Technology http://www.wetron.es/ Tel. +34 93 5883004 (Ext.3010) Fax +34 93 5883007

Reply by email

Michael Van Canneyt
to Luca Olivetti: El 28/3/23 a les 0:01, Michael Van Canneyt ha escrit: Thank you. Actually it is…
Luca Olivetti wrote 28 lines
El 28/3/23 a les 0:01, Michael Van Canneyt ha escrit: > > My bad, I made a typo, it should have been > > MyException:=ExceptionClass(ut.FatalException).ClassType).Create(Exception(ut.FatalException).message) Thank you. Actually it is MyException:=TExceptionClass(Exception(ut.FatalException).ClassType).Create(Exception(ut.FatalException).message); > with ExceptionClass= class of exception; > > Actually, I never write it like this in one statement, Yep, it's quite a mouthful, I had to break it up to spot the error :-) > I save the class pointer and message > in local variables, do cleanup first and then use the class pointer and > message later to raise an exception. But the effect is the same: you create > a copy with the same class and message as the original. But not with the same detail (i.e. any extra fields are missing). Not that I'm really interested in them (usually I just use the message), but still...

I am aware of that. But the extra fields are usually only interesting in the debugger. You will see them if you inspect ut.FatalException. For the user normally only the message is interesting.

Michael.

Reply by email