Domanda

mi piacerebbe per visualizzare la schermata iniziale mentre l'applicazione sta caricando. Tuttavia alcuni componenti 3a parte bloccano thread principale durante initilization per alcuni secondi, che causa tutte le forme non aggiornare. E 'possibile avere splash screen con un thread in modo da sarebbe aggiornare anche quando thread principale è occupato?

L'applicazione è Win32 e Delphi 2007.

Modifica:. Sto cercando di evitare di "splash screen non utilizzata" effetto, che succede se alcune altre finestre (da altre applicazioni) sono sulla parte superiore della schermata di avvio, ad esempio alt-tab a un'altra applicazione e viceversa

È stato utile?

Soluzione

È possibile eseguire la schermata iniziale in un altro thread, ma allora si avrà bisogno di utilizzare le chiamate API di Windows prime o una libreria di terze parti (come oggetti chiave Biblioteca ) che implementa le classi VCL-like. Non, tuttavia, non accedere VCL roba da filo schizzi.

Se seguire questa strada (che non credo che si dovrebbe, in quanto è un sacco di lavoro per poco guadagno), assicurarsi di rispettare le regole per l'accesso alle API di Windows da più thread. Google per esempio per "le discussioni interfaccia utente" per ulteriori informazioni.

Modifica

Non ero a conoscenza di prima, ma v'è in realtà un componente l'attuazione di un filettato Splashscreen per Delphi su CodeCentral. Questo componente può (non ho provato) effettivamente essere facile avere la schermata iniziale in un thread diverso, ma l'avvertimento contro l'accesso da VCL thread secondari rimane.

Altri suggerimenti

In realtà modo Winapi è abbastanza semplice fino a quando si utilizza le risorse di dialogo. Controllare questo (che lavora anche su D7 e 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;

Naturalmente è necessario preparare risorsa finestra di dialogo (Dlg.rc) e aggiungerlo al progetto:

#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

Si noti questi definisce PBS_*. Ho dovuto aggiungere perché Delphi 7 non sa nulla di queste costanti. E la definizione di costanti (Dlg.inc)

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

(io uso RadASM editor di risorse che genera file include automaticamente).

Quello che si ottiene sotto XP

Cosa c'è di meglio in questo modo il confronto a trucchi VCL (ordine della creazione e così le forme n) è che si può utilizzare più volte quando la vostra applicazione ha bisogno di tempo per pensare.

Create voi Splash Screen nel DPR prima, ma non si utilizza il Metodo Application.CreateForm per esso. Ecco qualche semplice codice:

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.

Quindi inserire il seguente codice nel gestore di evento Mostra (o versione successiva - quando la vostra inizializzazione è fatto) per il vostro MainFrom (in questo caso Form14):

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

(Si chiama uscita su una forma al posto di libero, e si assegna a zero in modo che il DRP non chiama rilascio di nuovo. Il rilascio del DRP è solo nel caso in cui il vostro MainForm non riesce a creare.)

Dal momento che il modulo iniziale è FormStyle: = fsStayOnTop non dovrebbe essere un problema che non sta ottenendo i messaggi di vernice quando i tuoi principali blocchi di filettatura. Poi, quando il thread principale sblocca lo si invia un messaggio di aggiornamento (per cambiare la barra di avanzamento, ecc) Anche se sono d'accordo con Gamecat che si potrebbe desiderare di contattare i fornitori di componenti 3rd party e farli smettere di bloccare il thread principale su di voi.

In alternativa, è possibile creare i componenti 3rd party in un thread separato (purché non visivo, come che sarebbe un po 'più difficile.)

Questo funziona con Application.MainFormOnTaskBar è impostata su true pure.

creo il tonfo nel codice di avvio, con sempre sul set top, e quindi utilizzare il frmSplash.Update in luoghi adeguati per assicurarsi che sia visibile e aggiornata. La forma principale di creare è uno di questi luoghi di chiamarlo.

Il problema è che Delphi 2007 presuppone che il primo modulo è ora la forma principale, e non v'è alcun modo per sostituire il modulo principale nel codice di base, quindi schizzi non sono così buono più. Forse la vecchia soluzione di Visual Basic di avere una piccola applicazione rapida spruzzata che poi viene eseguito l'applicazione principale potrebbe in realtà essere migliore!

Il problema di un filo principale blocco non viene risolto eseguendo la schermata iniziale in un thread separato perché sarà necessario il filo principale per aggiornamenti dello schermo.

E 'la schermata iniziale non cambia, questo non è un problema.

Forse si dovrebbe contattare il fornitore terzo componente partito, perché un lungo blocco del genere è un problema reale.

Jim McKeeth ha avuto una grande idea là, ma lui non affrontare una cosa che può o non può essere un problema. Lei parla di componenti di prendere un lungo periodo di tempo per l'inizializzazione. Con questo, vuoi dire la di inizializzazione , o qualcosa che accade in seguito, come mentre sono stati creati i moduli? Perché tutte le sezioni di inizializzazione eseguono prima di qualsiasi codice del DPR viene eseguito. E 'quella parte di prendere un lungo periodo di tempo, si dovrà fare alcune cose difficili da ottenere la vostra schermata iniziale di presentarsi di fronte a tutto questo:

Mettere l'unità del modulo più vicino alla parte superiore della .DPR come si può. (Ma non prima di cose che devono andare in primo luogo, come FastMM). Inserire il codice per visualizzare la schermata iniziale nella sezione di inizializzazione di tale unità. E assicurarsi che non ci sono unità con lunghi periodi di inizializzazione che utilizza il vostro splash screen (o che quelli che lo utilizzano uso ... o in qualsiasi parte l'albero delle dipendenze.) E poi sperare che le opere.

Se i problemi di rallentamento non cominciano fino a dopo la pila di inizializzazione iniziale è finita, però, poi con quello che ha detto Jim.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top