2010-10-11 17 views
5

Okay, quindi nella mia richiesta, ci sono un sacco di WinAPI e pochi controlli personalizzati. Yay ...doppio buffering WINAPI

Ora, normalmente, si ridisegneranno silenziosamente per animazioni, cambi di stato, ecc .... e tutto funziona perfettamente.

ma ho un metodo della classe finestra chiamata fix(). Questo viene chiamato ogni volta che è necessario aggiornare l'intera finestra. Ridimensiona i controlli e invalida la finestra.

Quando questo accade, lo sfondo è disegnata, quindi il controllo scheda, poi tutti gli altri sulla parte superiore. Ciò provoca un lampeggiamento molto irritante, soprattutto quando si ridimensiona la finestra (a causa delle continue chiamate a fix()).

Quello che ho cercato:

  • WS_EX_COMPOSITED. Questo solo doppio buffer i singoli controlli. È un miglioramento, ma lo sfarfallio rimane inevitabilmente.
  • Disattivazione del disegno di sfondo. Difficilmente risolve il problema, e in realtà peggiora le cose.

Quindi: Ho bisogno di una tecnica/metodo/a che mi permette di raddoppiare-buffer della finestra nella sua interezza. Ho pensato che gestire il messaggio WM_PAINT da solo potesse essere una soluzione, ma non saprei da dove cominciare. Ho la sensazione orribile questo non è nemmeno possibile ...

Si prega di aiuto, questo è un problema critico. Sarò molto sollevato quando verrà risolto questo stupido piccolo problema.

+0

Forse controllare questa pagina? http://www.gamedev.net/community/forums/topic.asp?topic_id=411559 –

risposta

4

È in questo momento che si è realizzato il profondo disinteresse di Microsofts per gli sviluppatori nativi. Si potrebbe in effetti iniziare a nutrire paranoie deliranti che Microsoft ha intenzionalmente interrotto la pittura nativa per costringere gli sviluppatori nativi a passare a WPF.

Innanzitutto, considerare WS_EX_COMPOSITED. WS_EX_COMPOSITED sembra essere la senape: - dice che applica un ordine di pittura in cima per i controlli figlio e fondamentalmente che i messaggi WM_PAINT vengono gestiti in un batch. Dice che è stato aggiunto in Windows 2000 (5.0) e, poche righe in basso, che non funziona con la composizione desktop abilitata. Ad esempio, smette di funzionare come in Windows Vista (6.0), a meno che il vetro aerodinamico non sia disattivato e chi lo farà?

Poi, ci sono due possibili "hack" per cercare di ottenere lo sfarfallio pittura libera di lavorare:

  • In primo luogo, è necessario mimimize la quantità di ridipintura. WS_EX_CLIPCHILDREN | WS_EX_CLIPSIBLINGS sono necessari per garantire che una particolare area della finestra venga dipinta una sola volta. BeginDeferWindowPos è inoltre necessario eseguire il raggruppamento delle operazioni di ridimensionamento per garantire che gli stati transitori, in cui una finestra si sovrappone a un'altra, non si verifichi (ad esempio, quando la finestra A è stata ridimensionata ma la finestra B non lo è).

Naturalmente, quando si sta cercando di disegnare una finestra di dialogo dalla pelle, o utilizzare caselle di gruppo, o controlli struttura a schede, o un qualsiasi numero di altre restrizioni, WS_EX_CLIPSIBLINGS non è solo appropriata.

  • WM_SETREDRAW è un messaggio magico. Non esiste alcuna API per accedere a questa funzionalità: viene gestito direttamente da DefWindowProc per contrassegnare essenzialmente la finestra come nascosta per la durata. Dopo l'invio di WM_SETREDRAW, FALSE, le chiamate a GetDC/GetDCEx/GetWindowDC ecc. Utilizzando l'handle della finestra principale (e tutti i relativi elementi secondari) restituiranno una DC che non verrà disegnata sullo schermo. Questo ti dà la possibilità di fare ogni genere di cose sulle finestre figlio, quando hai finito invia un WM_SETREDRAW,TRUE (e poi ridipinga manualmente la finestra). Ovviamente tutte le finestre figlio dipingeranno nel loro tempo e dopo che la finestra madre avrà fatto il suo background di cancellazione, quindi WM_SETREDRAW non è un tipo di panacea.

Dopo la rottura WS_EX_COMPOSITED, in WinForms di .NET e WPF ri-scritto i comandi da terra fino a non utilizzare i controlli nativi, in modo da poter cuocere nella pittura tamponata lì. E anche il supporto alfa.

0

Senza codice Non riesco a immaginare quale sia la situazione attuale ... Ma puoi provare a gestire WM_ERASEBKGND, restituire VERO ogni volta che li hai ricevuti per saltare la cancellazione.

+0

Ho provato questo. Ha fatto solo un gran casino. Sai cosa succede quando non cancelli lo sfondo? Lo sfondo –

+0

non viene "cancellato", ovviamente:>. Bene, se il tuo dipinto copre l'intera area, non importa se è cancellato o meno. – YeenFei

1

Hm. Prima che le persone si affrettano a chiudere questo argomento come un duplicato, è meglio dire che il problema non è il doppio buffering di per sé, ma lo sfarfallio durante il riposizionamento dei controlli, per il quale il doppio buffering "manuale" è solo una delle varie soluzioni.

Potrebbe essere che ad esempio Gli amici BeginDeferWindowPos & possono correggere lo sfarfallio.

Disclaimer: una volta conoscevo quasi tutti i dettagli dell'API di Win16, ma sono passati alcuni anni da quando eseguivo la programmazione a livello di API.

Acclamazioni & hth,

-. Alf

+0

questo è win32 ... –

+0

@Alexander, win32 è solo il gemello meno fortunato di win16s. –

0

Maniglia WM_ERASEBKGND per la vostra finestra e nell'attuazione escludono i rettangoli di ciascuno dei vostri controlli figlio, poi riempire lo sfondo restante in modo appropriato e dire il quadro che si hanno dipinto lo sfondo di se stessi restituendo true. Fai la stessa cosa per tutti gli altri controlli figlio che a loro volta tengono altri controlli come il controllo a schede nel tuo caso.

Vedere here per un esempio che utilizza MFC.

+0

Questa è una soluzione indesiderata. Forse come ultima risorsa ... –

1

In .net c'è ControlStyle.AllPaintingInWmPaint Che dovrebbe essere impostato su ogni finestra del contenitore (quindi la finestra principale e le schede). Non sono riuscito a trovare un equivalente Winapi. Ma ciò che fa è spostare il disegno dello sfondo da WM_ERASEBKGND a WM_PAINT. sottrae anche l'area del controllo figlio dal genitore per evitare lo sfarfallio. Potrebbe essere necessario farlo manualmente.

Sono sorpreso WS_EX_COMPOSITED non aiuta. Questo dovrebbe funzionare, se lo si imposta nella finestra di livello superiore e non si chiama RedrawWindow nei controlli secondari.

Assicuratevi anche di testare con e senza DWM/Aero. Puoi ottenere risultati diversi.

+0

P.S. Inserisco un pezzo di codice C# di esempio in una mia precedente risposta. Potresti essere in grado di modificarlo per dimostrare l'effetto che stai vedendo. http: // StackOverflow.it/questions/3735121/direct2d-gdi-and-slow-windows-forms-drawing-what-can-be-done/3735328 # 3735328 –

+0

È possibile cancellare manualmente lo sfondo in WM_PAINT. –

+0

@Alexander: questo è quello che devi fare. Devi anche restituire true su WM_ERASEBKGND. Anche escludere i riquadri della finestra figlio dalla vernice potrebbe essere necessario (forse l'aggiunta di WS_CLIPCHILDREN farà il trucco). –