Newsgroup: it.comp.programmare.win32
Titolo: disegnare BMP

Salve a tutti. Volevo solo avere alcune delucidazioni sull'algoritmo per
disegnare BMP all'interno di una finestra, nell'implementazione del quale
trovo ancora qualche difficoltà. Premetto che io lavoro in M$ Visual C++.
Provate a scrivere:
void paintBMP(HINSTANCE hI, HDC dc, UINT BMP_ID, int x, int y, int width,
int height) {
    HBITMAP hBmp;
    HDC mdc;
    hBmp = LoadBitmap(hI, MAKEINTRESOURCE(BMP_ID));
    mdc = CreateCompatibleDC(dc);
    SelectObject(mdc, hBmp);
    BitBlt(mdc, x, y, width, height, dc, 0, 0, SRC_COPY);
    DeleteObject(hBmp);
    DeleteDC(mdc);
}
Finqui non mi sembra di aver scoperto nulla di nuovo, é una generica
funzione per visualizzare una bitmap di dimensione [width x height] alle
coordinate x;y. Però se viene invocata più volte (il che non è così
insolito; esempio:
al verificarsi dell'evento WM_MOUSEMOVE viene invalidata tutta l'area
client:
case WM_MOUSEMOVE:
    InvalidateRect(hWnd, NULL, TRUE);
    break;
) il programma smette di funzionare dopo poche iterazioni (un centinaio o
qualcosa di più).
Mi sembra di essere stato esplicito: ma allora la domanda che nasce é:
PEEERCHEEEEEEEE, MA SOPRATTUTTO PEEERCHEEEEEEEE?
Ciao e grazie per l'attenzione.

,

Perche' non distruggi il bitmap dopo che lo hai caricato dalle risorse del
programma.
Per fare una cosa del genere e' conveniente caricare il bitmap
durante l'inizializzazione (WM_CREATE o WM_INITDIALOG o altrove),
salvare l'HBITMAP in una variabile globale, variabile statica
di WndProc, membro della classe, e poi disegnare il bitmap e basta.
Il bitmat va poi distrutoo alla terminazione del programma o quando no serve
piu'.
MSDN recita:
The application must call the DeleteObject function to delete each bitmap
handle returned by the LoadBitmap function.
e quindi il MUST deve essere seguito.
Altrimenti esaurisci gli HBITMAT disponibili per l'applicazione
e non liberi le risorse allocate.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/
       Search, Read, Discuss, or Start Your Own    

handle returned by the LoadBitmap function.
Ma DeleteObject e' stata chiamata. Il problema, piuttosto,  e' che
il bitmap non sara' mai distrutto perche' e' ancora selezionato
dal device context. Bisogna invertire le due chiamate:
//prima distruggo il device context
DeleteDC(mdc);
//quindi, il bitmap
DeleteObject(hBmp)
Oreste Notelli.

,

Hai ragione. Sospettando che qualcosa non venisse liberato
ho letto in fretta il codice.
Ho preso lucciole per lanterne.
--== Sent via Deja.com 
http://www.deja.com/
 ==--
---Share what you know. Learn what you don't.---


Ti ringrazio; adesso funziona bene. Perņ, se faccio muovere la BMP, si vede
un fastidioso sfarfallio. Come faccio a ridurlo? Ho provato a creare un
apposito PixelFormatDescriptor che supporti il DoubleBuffering e a usare
SwapBuffers, ma non cambia un granchč?
Ringrazio ancora. Ciao.


Ad occhio la tua funzione mi pare piuttostio lenta:
Prima leggi in memoria un bitmap, poi crei un device
context in memoria, quindi richiami la SelectObject
che deve adattare il device al bitmap.
Disegni sul device context di destinazione.
Alla fine deallochi tutto device e bitmap.
Potresti cavartela definendo una classe del genere:
class CBitmapPainter
{
public:
 CBitmapPainter::CBitmapPainter(HDC hDc, HINSTANCE hI, UINT BMP_ID )
 {
     m_hBitmap = LoadBitmap(hI, MAKEINTRESOURCE(BMP_ID));
     m_hDc = CreateCompatibleDC(hDc);
     SelectObject(m_hDc, m_hBitmap);
 }
 CBitmapPainter::~CBitmapPainter()
 {
  DeleteDC(mdc);
  DeleteObject(hBmp);
 }
 void Paint(int x, int y, int width, int height)
 {
  BitBlt(m_hDc, x, y, width, height, m_hDc, 0, 0, SRC_COPY);
 }
private:
 HBITMAP m_hBitmap;
 HDC hDc;
};
Quindi mantieni un'oggetto di tipo CBitmapPainter per tutto il tempo
che ti serve disegnare sulla finestra e chiami la funzione
CBitmapPainter::Paint tutte le volte che devi spostare il bitmap.
Esempio:
... OnCreate ...
...
m_pBitmapPainter = new CBitmapPainter(hDC, hInst, BMP_ID);
...
... OnPaint ...
...
 m_pBitmapPainter->Paint(x, y, height);
...
... OnDestroy ...
 delete m_pBitmapPainter;
Avrai ridotto in parte lo sfarfallio: è diminuito il tempo di
disegno del bitmap.
Per migliorare ancora le prestazioni potresti prendere particolari
accortezze:
gestione attenta di eventuali chiamate ad InvalidateRect
implementazione ottimizzata dei messaggi WM_ERASEBKGND,
WM_PAINT, ecc.
Oreste Notelli