Sintomi
La barra di scorrimento scorre continuamente anche quando si rilascia il pulsante sinistro del mouse. Il tipo di barra di scorrimento non è pertinente a questo problema, ovvero lo stesso problema si verifica indipendentemente dal fatto che la barra di scorrimento faccia parte della finestra o sia un controllo barra di scorrimento.
Causa
Questo problema si verifica in genere quando viene eseguito un ciclo di recupero del messaggio come risultato delle azioni intraprese per lo scorrimento dopo la ricezione di uno dei messaggi di notifica della barra di scorrimento. Durante lo scorrimento, viene avviato un ciclo di recupero messaggi interno in Windows. L'attività di questo ciclo di messaggi consiste nel tenere traccia dello scorrimento e inviare i messaggi di notifica della barra di scorrimento appropriati WM_HSCROLL e WM_VSCROLL. Lo scorrimento viene terminato dopo la ricezione di WM_LBUTTONUP. Se durante lo scorrimento viene avviato un altro ciclo di messaggi, la WM_LBUTTONUP viene recuperata da tale ciclo di messaggi e poiché un'applicazione non ha accesso al ciclo di recupero dei messaggi interno della barra di scorrimento, WM_LBUTTONUP non può essere inviato correttamente. Di conseguenza, la WM_LBUTTONUP non viene mai ricevuta dalla funzione di recupero messaggi interna e lo scorrimento non viene mai terminato. L'applicazione che esegue lo scorrimento non deve recuperare i messaggi in modo esplicito per causare questo problema. La chiamata di una delle funzioni seguenti o l'elaborazione di qualsiasi messaggio che contiene un ciclo di recupero dei messaggi, mentre lo scorrimento, può causare la perdita del WM_LBUTTONUP. Le funzioni elencate di seguito rientrano in questa categoria:
DialogBox() DialogBoxIndirect() DialogBoxIndirectParam() DialogBoxParam() GetMessage() MessageBox() PeekMessage()
Risoluzione
Durante lo scorrimento, il messaggio di WM_LBUTTONUP non deve essere recuperato dalla coda da qualsiasi ciclo di recupero dei messaggi diverso da quello interno della barra di scorrimento. Un'applicazione può imbattersi in questo problema nel modo seguente:
-
Un'applicazione implementa un ciclo di recupero dei messaggi per implementare l'elaborazione in background, ad esempio l'elaborazione in background durante l'esecuzione di una pittura che richiede tempo.
-
Un'applicazione implementa un ciclo di recupero dei messaggi per implementare la comunicazione con un'altra applicazione o DLL. Ad esempio, per scorrere l'applicazione deve ricevere i dati da un'altra posizione.
Possibili soluzioni alternative
Di seguito sono elencate due possibili soluzioni alternative. La prima soluzione alternativa è usata da molte applicazioni in uscita e da Windows; Tuttavia, in rare circostanze, la prima soluzione alternativa potrebbe non essere possibile. In questo caso, è possibile usare la seconda soluzione alternativa. Tuttavia, se possibile, provare ad evitare di implementare completamente il recupero del messaggio durante lo scorrimento.
-
Usare l'elaborazione basata su messaggi temporizzati. Suddividere l'elaborazione complessa in attività più piccole e tenere traccia del punto in cui ogni attività viene avviata e terminata, quindi eseguire ogni attività in base a un messaggio timer. Dopo aver completato tutti i componenti dell'elaborazione, eliminare il timer. Vedere di seguito per un esempio di questa soluzione alternativa.
-
Implementare un ciclo di recupero dei messaggi, ma verificare che WM_LBUTTONUP non sia recuperato. Questa operazione può essere eseguita tramite filtri. Per alcuni esempi di questa soluzione alternativa, vedere di seguito.
Esempio di dimostrazione della soluzione alternativa 1
Un'applicazione ha una procedura di verniciatura complessa. La chiamata di ScrollWindow (), per scorrere, genera i messaggi di disegno. L'elaborazione in background avviene durante la pittura.
-
Quando si riceve il messaggio di WM_PAINT, eseguire le operazioni seguenti:
-
Chiama BeginPaint ().
-
Copiare l'oggetto Rect Invalidated in una variabile rect globale, ad esempio grcPaint, da usare nel passaggio 2. Il grcPaint rect globale può essere un'Unione dell'oggetto Rect (grcPaint) ottenuto in precedenza e il nuovo oggetto Rect invalidato (PS. rcPaint). Il codice per questo aspetto sarà simile al seguente:
RECT grcPaint; // Should be initialized before getting the // first paint message. : : UnionRect(&grcPaint, &ps.rcPaint,&grcPaint);
-
Chiama ValidateRect () con PS. rcPaint.
-
Chiama EndPaint ().
-
Impostare un timer.
In questo modo non vengono generati più messaggi di WM_PAINT, perché non sono presenti aree geografiche non valide e viene configurato un timer che genererà WM_TIMER messaggi.
-
-
Dopo aver ricevuto un messaggio di WM_TIMER, controllare la variabile rect globale; Se non è vuota, prendere una sezione e dipingerla. Quindi regola la variabile rect globale in modo che non includa più l'area dipinta.
-
Dopo aver svuotato la variabile rect globale, uccidi il timer.
Esempio di dimostrazione della soluzione alternativa 2
Un'applicazione deve ottenere alcuni dati tramite DDE o un altro meccanismo da un'altra applicazione, che viene quindi visualizzata nella finestra. Per scorrere l'applicazione deve richiedere e quindi ottenere i dati da un'applicazione server. Esistono tre filtri diversi che possono essere usati per configurare un PeekMessage () e ottenere le informazioni. I filtri possono essere configurati usando i parametri uFilterFirst e uFilterLast di PeekMessage (). uFilterFirst specifica il messaggio di pugno nell'intervallo da controllare e uFilterLast specifica l'ultimo messaggio nell'intervallo da controllare.
-
Selezionare e recuperare solo i messaggi correlati per ottenere i dati necessari.
-
Verificare la WM_LBUTTONUP senza rimuoverla dalla coda; Se è in coda, Interrompi. In caso contrario, recupera e invia tutti i messaggi.
-
Recuperare tutti i messaggi con meno di WM_LBUTTONUP e maggiori di WM_LBUTTONUP, ma non recuperare WM_LBUTTONUP.
Ulteriori informazioni
Procedura per riprodurre il problema
Di seguito è riportata la sequenza di eventi che causano la perdita del messaggio di WM_LBUTTONUP:
-
Fare clic sulla barra di scorrimento con il mouse.
-
Il passaggio 1 genera un messaggio di WM_NCLBUTTONDOWN.
-
Il passaggio 2 causa l'avvio di un ciclo di messaggi interno di Windows. Questo ciclo di messaggi cerca i messaggi correlati alla barra di scorrimento. Lo scopo di questo ciclo di messaggi consiste nel generare messaggi di WM_HSCROLL o WM_VSCROLL appropriati. Il ciclo di messaggi e lo scorrimento terminano dopo la ricezione di WM_LBUTTONUP.
-
Quando si riceve il messaggio WM_HSCROLL o WM_VSCROLL, l'applicazione entra direttamente in un ciclo di recupero dei messaggi o chiama le funzioni che causano il recupero di messaggi.
-
WM_LBUTTONUP viene rimosso dalla coda dal ciclo di messaggi menzionato nel passaggio 4. WM_LBUTTONUP viene quindi inviato.
-
Come risultato del passaggio 5 WM_LBUTTONUP messaggio viene inviato altrove e il ciclo di recupero dei messaggi interno, menzionato nel passaggio 3, non viene mai ricevuto. Il ciclo di messaggi nel passaggio 3 sta cercando la WM_LBUTTONUP per interrompere lo scorrimento. Poiché non viene ricevuta, la barra di scorrimento continua a scorrere.