2011-12-07 10 views
5

La mia applicazione è un'applicazione di finestre che esegue determinati algoritmi matematici complessi. Poiché ho iniziato con l'applicazione molto tempo fa, la maggior parte è ancora single-threaded. Per essere più precisi, il thread principale esegue tutta la complessa logica di calcolo. È importante ricordare che durante i calcoli, mostro alcuni progressi sullo schermo.Come ingannare Windows pensando che l'applicazione sia ancora occupata, sebbene non risponda

Nella maggior parte dei casi, gli algoritmi matematici richiedono solo alcuni secondi, quindi dopo che l'utente ha avviato l'azione, viene visualizzata una clessidra (o il cerchio in esecuzione in Windows 7) e pochi secondi dopo vengono visualizzati i risultati.

In alcuni casi, l'algoritmo può richiedere diversi minuti. Durante questo periodo, mostro la clessidra, e mentre l'algoritmo è occupato, mostro i progressi nella mia finestra. Ma, se l'utente fa clic sull'applicazione dopo che è stata occupata per un po ', la finestra diventa "più bianca" (come se un pezzo di plastica non completamente trasparente fosse posto sopra la finestra), la finestra non viene più aggiornata e Windows riporta "l'applicazione non risponde".

Io uso Qt e io uso la funzione Qt QWidget :: repaint per forzare un repaint mentre il mio algoritmo è occupato. Il ridisegno funziona per qualche tempo, ma come detto sopra, Windows sembra bloccarlo dopo un po '.

Qual è il modo corretto per indicare a Windows che l'applicazione è ancora occupata in modo che la finestra continui ad aggiornarsi? Se inserisco un ciclo di messaggi esplicito, l'utente potrebbe attivare altre azioni nell'applicazione che non desidero.

  • È sufficiente chiamare PeekMessage?
  • È sufficiente chiamare GetMessage?
  • Oppure dovrei chiamare DispatchMessage? E come impedire all'utente di avviare un'altra azione (in realtà, impedire l'input dell'utente)
  • Devo chiamare uno di questi messaggi ogni volta che aggiorno la finestra o posso limitarmi a chiamarla ogni pochi secondi (10 secondi ?, 30 secondi? ...)

Si noti che lo spostamento della logica di calcolo su un thread separato al momento non è un'opzione.

Utilizzo Visual Studio 2010 su Windows 7, in combinazione con Qt 4.7.

+0

Re "l'utente potrebbe attivare altre azioni nell'applicazione che non desidero." Quindi disabilita quei controlli. – ikegami

risposta

0

La funzione DisableProcessWindowGhosting (vedere http://msdn.microsoft.com/en-us/library/ms648415(v=vs.85).aspx) indica a Windows che non deve mostrare la "finestra fantasma" se un'applicazione non risponde.

Il mio collega ha fatto alcuni esperimenti con essa e ho notato il seguente:

  • l'animazione che mostra lo stato di avanzamento continua piacevolmente (questo è in realtà ciò che volevo raggiungere)
  • l'utente può comunque ridurre al minimo, spostare, ... la finestra (grande)
  • sul rovescio della medaglia: se l'applicazione è davvero appeso, l'utente deve utilizzare Task manager per ucciderlo

Quindi, questo risolve il mio problema.

1

Si potrebbe semplicemente chiamare QApplication::processEvents() di volta in volta, diciamo ogni 2 o 3 secondi circa. Questo dovrebbe innescare un evento ridisegnato e aggiornare la barra di avanzamento e altri elementi.

1

domanda simile e un sacco di informazioni qui: I need a message pump that doesn't mess up my open window

Tuttavia, come probabilmente già sapete, questo è un bel trucco e sarebbe meglio cercare di spostare il codice a un altro thread. Perché questa "non è un'opzione"?

+0

Grazie per il link. Spostarlo su un thread separato non è al momento un'opzione in quanto c'è ancora un sacco di vecchio codice nell'algoritmo di calcolo che chiama via-tramite il codice UI (potrebbe anche mostrare una finestra di dialogo :-)). – Patrick

5

È necessario separare la GUI dalla logica dell'applicazione. Tutte le altre soluzioni sono hack. Spostare la logica di calcolo su un thread separato può essere facilmente ottenuto con Qt utilizzando uno sforzo minore.

Suppongo che esista una funzione (chiamiamola execute()) che quando chiamata esegue tutte queste operazioni matematiche che richiedono molto tempo. Un'opzione consiste nell'utilizzare Qt Concurrent API per chiamare questa funzione in un thread separato, senza utilizzare la gestione thread di basso livello.

Quello che vi serve è la funzione QtConcurrent::run:

La funzione QtConcurrent :: run() esegue una funzione in un thread separato. Il valore restituito della funzione è reso disponibile tramite l'API QFuture .

Invece di limitarsi a chiamare execute() che bloccherà l'interfaccia utente è possibile effettuare le seguenti operazioni (diciamo A essere la classe in cui execute() è definito):

QFuture<void> future = QtConcurrent::run(this, &A::execute); 

È possibile utilizzare QFutrureWatcher al fine di ottenere informato su quando la funzione è finita.

+0

Interessante. Darei un'occhiata a questo. – Patrick

Problemi correlati