2008-12-23 20 views
12

Me gustaría mostrar la pantalla de bienvenida mientras se carga la aplicación. Sin embargo, algunos componentes de terceros bloquean el hilo principal durante la inicialización durante varios segundos, lo que hace que no se actualicen todas las formas. ¿Es posible tener una pantalla de bienvenida con hilo propio para que también se actualice cuando el hilo principal está ocupado?Mostrar pantalla de bienvenida en Delphi cuando el hilo principal está ocupado

La aplicación es win32 y la versión de Delphi 2007.

Editar: Estoy tratando de evitar la "pantalla de bienvenida no dispuesto" efecto, lo que sucede si algunas otras ventanas (de otras aplicaciones) están en la parte superior de la pantalla de bienvenida , por ejemplo, alt-tabbing a otra aplicación y viceversa.

Respuesta

9

Puede ejecutar la pantalla de bienvenida en otro hilo, pero luego deberá usar llamadas de API de Windows sin procesar o una biblioteca de terceros (como Key Objects Library) que implemente clases similares a VCL. Sin embargo, no acceda a las cosas de VCL desde el hilo de bienvenida.

Si va por esa ruta (lo que no creo que deba hacer, ya que es una gran cantidad de trabajo con pocas ganancias), asegúrese de observar las reglas sobre el acceso a la API de Windows desde varios subprocesos. Google, por ejemplo, para "hilos de la interfaz de usuario" para más información.

Editar:

yo no era consciente de ello antes, pero en realidad hay un componente de la implementación de un Threaded Splashscreen for Delphi en CodeCentral. Al usar este componente, es posible que (no lo haya probado) sea realmente fácil tener la pantalla de bienvenida en un hilo diferente, pero la advertencia contra el acceso a VCL desde hilos secundarios permanece.

+0

Gracias, KOL parece prometedor. – Harriv

0

Creo el toque en el código de inicio, siempre con el conjunto superior, y luego uso el archivo frmSplash.Update en los lugares apropiados para asegurar que esté visible y actualizado. La forma principal de crear es uno de esos lugares para llamarlo.

El problema es que Delphi 2007 asume que la primera forma es ahora la principal, y no hay forma de reemplazar la forma principal en el código central, por lo que las salpicaduras ya no son tan buenas. Tal vez la vieja solución visual básica de tener una pequeña aplicación splash rápida que luego ejecuta la aplicación principal en realidad podría ser mejor.

+0

Las formas de saltos funcionan igual en Delphi 2007 que en versiones anteriores, cuando las crea con una línea SplashForm: = TSplashForm.Create (nil); y déjalos que se liberen. La primera Application.CreateForm() establece Application.MainForm, pero eso siempre ha funcionado de esa manera, AFAIK. – mghie

+1

El problema es que frmSplash.Update no ayuda mucho si el hilo principal está bloqueado durante un largo período de tiempo. Necesito la pantalla de bienvenida en la pantalla para comunicar que "sí, este programa se está ejecutando, espere" – Harriv

0

El problema de un hilo principal de bloqueo no se resuelve al ejecutar la pantalla de inicio en un hilo separado, ya que necesitará el hilo principal para las actualizaciones de la pantalla.

Si la pantalla de bienvenida no cambia, esto no es un problema.

Quizás deba ponerse en contacto con su proveedor de componentes de terceros, porque un bloque largo como ese es un problema real.

+1

Usar un hilo secundario para el splash resolvería el problema. Desafortunadamente, usar el VCL está fuera de cuestión en ese caso.Pero los hilos de la interfaz de usuario secundario con su propia bomba de mensajes son posibles usando llamadas de API de Windows sin procesar. – mghie

+0

Necesito la pantalla de presentación "en vivo" para indicar que la aplicación realmente se está ejecutando. – Harriv

3

Cree su pantalla de inicio en el DPR primero, pero no use el método Application.CreateForm para ello. Aquí hay un código simple:

begin 
    Application.Initialize; 
    SplashForm := TSplashForm.Create(nil); 
    try 
    SplashForm.FormStyle := fsStayOnTop; 
    SplashForm.Show; 
    Application.ProcessMessages; 
    Application.CreateForm(TForm14, Form14); 
    // Other Form Creation here . . . . 
    Application.Run; 
    finally 
    if assigned(SplashForm) then 
     SplashForm.Release; 
    end; 
end. 

A continuación, coloque el código siguiente en el Salón del controlador de eventos (o posterior - cuando se realiza su inicialización) para su MainFrom (en este caso Form14):

SplashForm.Close; 
SplashForm.Release; 
SplashForm := nil; 

(Usted llama a Release en un formulario en lugar de Free, y lo asigna a cero para que el DRP no llame de nuevo. El lanzamiento en el DRP es solo en caso de que su mainform no pueda crear.)

Dado que su El formulario de bienvenida es FormStyle: = fsStayOnTop no debería ser un problema que no reciba mensajes de pintura cuando bloquee su hilo principal. Luego, cuando se desbloquea el hilo principal, se envía un mensaje de actualización (para cambiar la barra de progreso, etc.). Aunque estoy de acuerdo con Gamecat, es posible que desee ponerse en contacto con los proveedores de componentes de terceros y lograr que dejen de bloquear el hilo principal.

Alternativamente, usted puede crear su componentes 3 ª parte en un hilo separado (siempre que no sean visuales, ya que sería un poco más difícil.)

Esto funciona con Application.MainFormOnTaskBar conjunto a la verdadera también.

+0

> Dado que su forma de presentación es FormStyle: = fsStayOnTop, no debería ser un problema que no reciba mensajes de pintura cuando se bloquea el hilo principal.
No estoy de acuerdo, alt-tabbing a otra aplicación y volver hará que la pantalla de bienvenida se invalide. – mghie

+0

Realmente necesito la pantalla "en vivo", por lo que obtener esos mensajes de pintura es importante. – Harriv

+0

@mghie Técnicamente cierto, supongo. –

0

Jim McKeeth tiene una gran idea allí, pero no aborda una cosa que puede o no ser un problema. Habla de componentes que tardan mucho tiempo en inicializarse. Con eso, ¿te refieres a la sección de inicialización , o algo que sucede más adelante, como cuando se están creando tus formularios? Debido a que todas las secciones de inicialización se ejecutan antes de ejecutar cualquier código en el DPR. Si esa parte lleva mucho tiempo, tendrás que hacer algunas cosas complicadas para que aparezca la pantalla de bienvenida frente a todo:

Coloca la unidad del formulario tan cerca de la parte superior del archivo .DPR como usted puede. (Pero no antes de cosas que necesitan ir primero, como FastMM). Coloque el código para mostrar la pantalla de bienvenida en la sección de inicialización de esa unidad. Y asegúrese de que no haya unidades con periodos de inicialización largos que use su pantalla de inicio (o que las que lo usan usen ... o en cualquier lugar del árbol de dependencias). Y entonces, espero que eso funcione.

Si los problemas de ralentización no comienzan hasta después de que la pila inicial de inicialización haya finalizado, entonces, vaya con lo que dijo Jim.

+0

La sección de inicialización no es un problema, la larga espera ocurre cuando configuro el componente activo en FormCreate (o posterior). – Harriv

4

En realidad, la forma de WinApi es bastante simple, siempre y cuando utilice recursos de diálogo. Comprobar esto (trabajando incluso en D7 y XP):

type 
    TDlgThread = class(TThread) 
    private 
    FDlgWnd: HWND; 
    FCaption: string; 
    protected 
    procedure Execute; override; 
    procedure ShowSplash; 
    public 
    constructor Create(const Caption: string); 
    end; 

{ TDlgThread } 

// Create thread for splash dialog with custom Caption and show the dialog 
constructor TDlgThread.Create(const Caption: string); 
begin 
    FCaption := Caption; 
    inherited Create(False); 
    FreeOnTerminate := True; 
end; 

procedure TDlgThread.Execute; 
var Msg: TMsg; 
begin 
    ShowSplash; 
    // Process window messages until the thread is finished 
    while not Terminated and GetMessage(Msg, 0, 0, 0) do 
    begin 
    TranslateMessage(Msg); 
    DispatchMessage(Msg); 
    end; 
    EndDialog(FDlgWnd, 0); 
end; 

procedure TDlgThread.ShowSplash; 
const 
    PBM_SETMARQUEE = WM_USER + 10; 
    {$I 'Dlg.inc'} 
begin 
    FDlgWnd := CreateDialogParam(HInstance, MakeIntResource(IDD_WAITDLG), 0, nil, 0); 
    if FDlgWnd = 0 then Exit; 
    SetDlgItemText(FDlgWnd, IDC_LABEL, PChar(FCaption));   // set caption 
    SendDlgItemMessage(FDlgWnd, IDC_PGB, PBM_SETMARQUEE, 1, 100); // start marquee 
end; 

procedure TForm1.Button3Click(Sender: TObject); 
var th: TDlgThread; 
begin 
    th := TDlgThread.Create('Connecting to DB...'); 
    Sleep(3000); // blocking wait 
    th.Terminate; 
end; 

Por supuesto debe preparar recurso de diálogo (Dlg.rc) y agregarlo a su proyecto:

#define IDD_WAITDLG 1000 
#define IDC_PGB 1002 
#define IDC_LABEL 1003 

#define PBS_SMOOTH 0x00000001 
#define PBS_MARQUEE 0x00000008 

IDD_WAITDLG DIALOGEX 10,10,162,33 
STYLE WS_POPUP|WS_VISIBLE|WS_DLGFRAME|DS_CENTER 
EXSTYLE WS_EX_TOPMOST 
BEGIN 
    CONTROL "",IDC_PGB,"msctls_progress32",WS_CHILDWINDOW|WS_VISIBLE|PBS_SMOOTH|PBS_MARQUEE,9,15,144,15 
    CONTROL "",IDC_LABEL,"Static",WS_CHILDWINDOW|WS_VISIBLE,9,3,144,9 
END 

Nota estos PBS_* define. Tuve que agregarlos porque Delphi 7 no sabe nada de estas constantes. y definición de constantes (Dlg.inc)

const IDD_WAITDLG = 1000; 
const IDC_PGB = 1002; 
const IDC_LABEL = 1003; 

(utilizo editor de recursos que genera RadASM incluir archivo de forma automática).

Lo que obtenemos en XP

Lo que es mejor de esta manera en comparación con trucos VCL (orden de la creación formas y así n) es que se puede utilizar varias veces cuando su aplicación necesita un poco de tiempo para pensar .

Cuestiones relacionadas