How can I display a SplashSreen?

This forum is meant for anything you would like to share with other visitors
Post Reply
Frank Müßner
Posts: 276
Joined: Sat Dec 12, 2015 2:22 pm
Location: Germany

How can I display a SplashSreen?

Post by Frank Müßner »

Hello,

I try to display a splash screen at startup. The SplashScreen is a DevExpress component.
So that the SplashSreen is updated, I think it has to be started in a separate task.
Unfortunately I get this error:

Code: Select all

System.ArgumentNullException: Der Wert darf nicht NULL sein.
Parametername: start
   bei System.Threading.Thread..ctor(ThreadStart start)
   bei XApp.Start(__Usual[] Xs$Args) in F:VSVisual Studio 2017XSWinQuickDev20VOMDIApp1Start.prg:Zeile 21.
   bei VOMDIApp.Exe.Functions.Start() in F:VSVisual Studio 2017XSWinQuickDev20VOMDIApp1Start.prg:Zeile 8.
But the SplashSreen is Show.

My code is:

Code: Select all

USING System
USING System.Threading.Tasks
[STAThread];
FUNCTION Start() AS INT
	LOCAL oXApp AS XApp
	TRY
		oXApp:=XApp{}
		oXApp:Start()
        
	CATCH oException AS Exception
		ErrorDialog(oException)
	END TRY
RETURN 0

CLASS XApp INHERIT App

	METHOD Start() 
	LOCAL oMainWindow AS StandardShellWindow
        local i AS DWORD
        local thread1 as System.Threading.Thread

        thread1:=System.Threading.Thread{XApp:ShowSreen()}
        thread1:Start()
        
        //Do Some Start routine
        For I:=1 to 100
            sleep(50)
        NEXT
        
        //how to close the SplashSreen Form? Kill the Task?
        thread1:Abort() 
        
	oMainWindow:Show(SHOWCENTERED)
        
        local Nw1 as Window1
        Nw1:=Window1{oMainWindow}
        Nw1:Show()
        
	SELF:Exec()
        
    RETURN NIL
    
    Static method ShowSreen() as System.Threading.ThreadStart
    Local sp as AuftragSQLKasseCSWinForms.SplashScreen1        
    sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}    
    sp:Show()
       
    return 
    
END CLASS

What am i thinking wrong?

VS2019 / X#2.4a

Regards, Frank
User avatar
SHirsch
Posts: 281
Joined: Tue Jan 30, 2018 8:23 am

How can I display a SplashSreen?

Post by SHirsch »

Hallo Frank,

try this:

Code: Select all

thread1:=System.Threading.Thread{ThreadStart{ShowSreen}}
...

method ShowSreen() as void
    Local sp as AuftragSQLKasseCSWinForms.SplashScreen1        
    sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}    
    sp:Show()
return 


Stefan
Frank Müßner
Posts: 276
Joined: Sat Dec 12, 2015 2:22 pm
Location: Germany

How can I display a SplashSreen?

Post by Frank Müßner »

Hi Stefan,

Thanks for your two examples.

I have change:

Code: Select all

thread1:=System.Threading.Thread{ShowSreen}
...
Static method ShowSreen() as void
Local sp as AuftragSQLKasseCSWinForms.SplashScreen1        
sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}    
sp:Show()
Error:

Code: Select all

XS1503	Argument 1: cannot convert from 'method' to 'System.Threading.ThreadStart'	

Code: Select all

thread1:=System.Threading.Thread{ThreadStart{ShowSreen}}
...
method ShowSreen() as void
Local sp as AuftragSQLKasseCSWinForms.SplashScreen1        
sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}    
sp:Show()
Error:

Code: Select all

XS0123	No overload for 'ShowSreen' matches delegate 'System.Threading.ThreadStart'	
User avatar
Chris
Posts: 4562
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

How can I display a SplashSreen?

Post by Chris »

Hi Frank,

Most likely you have the /vo5 compiler option enabled, and this options makes methods without parameters to be emitted as CLIPPER methods, which are indeed incompatible with the ThreadStart delegate and this is why you get that error message.

Please add the STRICT clause to the method declaration and it should work fine:

Static method ShowSreen() as void STRICT
Chris Pyrgas

XSharp Development Team test
chris(at)xsharp.eu
Frank Müßner
Posts: 276
Joined: Sat Dec 12, 2015 2:22 pm
Location: Germany

How can I display a SplashSreen?

Post by Frank Müßner »

Hi Chris,

you are right, the option /VO5 is activated.
I no longer get an error message, and the method ShowSreen() is called , but the SplashSreen is not displayed either. Another tip on what I'm doing wrong?
My final Code:

Code: Select all

CLASS XApp INHERIT App

	METHOD Start() 
		LOCAL oMainWindow AS StandardShellWindow
        local i AS DWORD
        
        oMainWindow := StandardShellWindow{}
        local thread1 as System.Threading.Thread
        thread1:=System.Threading.Thread{ThreadStart{ShowSreen}}
        thread1:Start()
        
        //Do Some Start routine
        For I:=1 to 100
            sleep(50)
           
        NEXT
        
        thread1:Abort() 
        
		oMainWindow:Show(SHOWCENTERED)
        
        local Nw1 as Window1
        Nw1:=Window1{oMainWindow}
        Nw1:Show()
        
	    SELF:Exec()
        
    RETURN NIL
    
Static method ShowSreen() as void STRICT
    Local sp as AuftragSQLKasseCSWinForms.SplashScreen1        
    sp:=AuftragSQLKasseCSWinForms.SplashScreen1{}    
    sp:Show()
return 
       
    return 
    
END CLASS
FRank
User avatar
Chris
Posts: 4562
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

How can I display a SplashSreen?

Post by Chris »

Hi Frank,

Maybe you need to use ShowDialog() instead of Show()? At least for regular forms, you'd need to use ShowDialog(), not sure how this particular component works.

If that still doesn't work, try using a simple regular (empty) Form instead, does it work with that? If yes, then we need to find what is special about this component.

But a general comment, I do not think you need a thread anyway. You'd need a thread in order to do things in parallel, but when you just want to show a splash screen for a while, you can simply do it in the Start() function. Or maybe I did not understand correctly how you plan to use this?
Chris Pyrgas

XSharp Development Team test
chris(at)xsharp.eu
Frank Müßner
Posts: 276
Joined: Sat Dec 12, 2015 2:22 pm
Location: Germany

How can I display a SplashSreen?

Post by Frank Müßner »

Hi Chris,

normal Winforms work with Show() That i have tested.

I can not use ShowDialog() this is modal. So the Program Stop at ShowDialog().

I think the Problem is the DexExpress Control.

i am looking for another solution, need more time

Thanks, Frank
User avatar
Chris
Posts: 4562
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

How can I display a SplashSreen?

Post by Chris »

Hi Frank,

You do not have a message loop running when you are showing the window, so I believe a simple Show() will just show the window for a brief moment and it will close right after. Did you have success using the exact same code with a regular windows forms Form?

Btw, another thing that you need to pay attention when using threads and GUI, is that you need to make sure you have included a STAThread attribute on your Start() funcntion:

[STAThread];
FUNCTION Start() AS VOID
Chris Pyrgas

XSharp Development Team test
chris(at)xsharp.eu
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

How can I display a SplashSreen?

Post by Karl-Heinz »

Hi Frank,

When you build with VO a StandardMDI app there´s also a splash window included. The splash window is created at the beginning of the VO App Start() and it´s destroyed via a timer. That´s the content of the SplashScreen Show() method.

Code: Select all

METHOD Show(kShowState) CLASS SplashScreen
	SUPER:show(kShowState)
	// Make window topmost
	SetWindowPos(SELF:handle(), HWND_TOPMOST, 0, 0, 0, 0, DWORD(_OR(SWP_NOSIZE, SWP_NOMOVE)))
	// Register Timer
	SELF:RegisterTimer(3, TRUE)
	// Remove the following two lines if you don't want to show the Splashscreen separatly
	GetAppObject():Exec(EXECWHILEEVENT)
	Sleep(1000)
	RETURN NIL

METHOD Timer() CLASS SplashScreen
	SELF:Destroy()
RETURN SELF
But you don´t really need a timer. Just paint a centered and *modeless* DialogWindow. Now your X# Start() method might look like:

Code: Select all

METHOD Start() 
	LOCAL oMainWindow AS StandardShellWindow
 

	// ------------------

	LOCAL oSplashScreen := DlgSplash{SELF}
	oSplashScreen:Show()

	// Make window topmost
//	SetWindowPos(SELF:handle(), HWND_TOPMOST, 0, 0, 0, 0, DWORD(_OR(SWP_NOSIZE, SWP_NOMOVE)))

	DoEvents()  // ensures that the content of the splash window is drawn !
	Sleep(1000)
 
	// -----------
       
        oMainWindow := StandardShellWindow{}
 	oMainWindow:Show(SHOWCENTERED)
        
        local Nw1 as Window1
        Nw1:=Window1{oMainWindow}
        Nw1:Show()

	oSplashScreen:Destroy()  // <---------  
        
	SELF:Exec()
        
    RETURN NIL
Regards
Karl-Heinz
Frank Müßner
Posts: 276
Joined: Sat Dec 12, 2015 2:22 pm
Location: Germany

How can I display a SplashSreen?

Post by Frank Müßner »

@ Chris,

Regular windows forms Form is show normal. The DevExpress SplashScreen need DoEvents() to show correctly.

I have [STAThread];
but not work.

@Karl-Heinz,

the normal *modeless* DialogWindow. is not nice as the DevExpress Control :-) Fadein Fadeout .


I have now this working code:

Code: Select all

CLASS XApp INHERIT App

	METHOD Start() 
		LOCAL oMainWindow AS StandardShellWindow
        LOCAL I as DWORD
        
        local SplashScreenHelper AS AuftragSQLKasseCSWinForms.XSTools
        SplashScreenHelper:=AuftragSQLKasseCSWinForms.XSTools{}
        SplashScreenHelper:TestAsyncWaitForm()
       
        For I:=1 to 100
            sleep(50)
        NEXT
        
        SplashScreenHelper:nStatus=1 //Close 
        
        For I:=1 to 20
            sleep(50)
            DoEvents()
            if SplashScreenHelper:nStatus=0  //is Closed
                Exit
            endif
        next
        
        SplashScreenHelper:=NULL_OBJECT 
        
		oMainWindow := StandardShellWindow{SELF}
		oMainWindow:Show(SHOWCENTERED)
	    SELF:Exec()
   RETURN NIL
END CLASS

Code: Select all

public class XSTools
    {

        public Int16 nStatus;
        public async void TestAsyncWaitForm()
        {
            SplashScreenManager.ShowForm(typeof(SplashScreen1), true, false);
            await Task.Run(() =>
            {
                for (int i = 0; i < 200; i++)
                {
                    System.Threading.Thread.Sleep(100);
                    if (nStatus == 1)
                    {
                        i = 300;
                    }
                }
            });
            SplashScreenManager.CloseForm();
            nStatus = 0;
        }
}

This work and I hope there are no side effects.

Frank
Post Reply