Board index » cppbuilder » Invalidate, Repaint(), HDC, flicker, double-buffering, TGraphicControl problem

Invalidate, Repaint(), HDC, flicker, double-buffering, TGraphicControl problem

Please tell me, why it doesn't works (just one (black I think) pixel
appears):

Canvas is the property of component I based on TGraphicControl.
FMyBitmap have assigned TBitmap *, and in other cases is available.

blah...

          HDC hdcMem, hdcMem2, hdcMem3;
          hdcMem3 = CreateCompatibleDC(Canvas->Handle);
          hdcMem2= CreateCompatibleDC(Canvas->Handle);
          hdcMem = CreateCompatibleDC(Canvas->Handle);

 SelectObject(hdcMem, FMyBitmap->Handle);
 BitBlt(hdcMem2, 0, 0, Width, Height, hdcMem, Width, 0, SRCAND);
 BitBlt(hdcMem2, 0, 0, Width, Height, hdcMem, 0, 0, SRCPAINT);

 SelectObject(hdcMem3, hdcMem2);
 BitBlt(Canvas->Handle, 0, 0, Width, Height, hdcMem3, 0, 0, SRCCOPY);

 DeleteDC(hdcMem);
 DeleteDC(hdcMem2);
 DeleteDC(hdcMem3);

blah...

My point is how to realize double-buffered graphics in descendant of
TGraphicControl?
I've implemented smth like this (*FBuffer is an instance o ITmage, with
assigned *TBitmap (otherwise TImage->Canvas is unavailable):

blah...(in Paint() method)

 FBufferCanvasHandle = FBuffer->Canvas->Handle;
 FMyBitmapCanvasHandle = FMyBitmap->Canvas->Handle;

 BitBlt(FBufferCanvasHandle, 0, 0, Width, Height, GetDC((TWinControl
*)Parent->Handle), Left, Top, SRCCOPY);

 /*---------------- How to get data (from (TWinControl
*)Parent->Handle----------------*/
 /*------------------------------without invalidating by
Repaint()? ---------------------------------*/

 BitBlt(FBufferCanvasHandle, 0, 0, Width, Height, FMyBitmapCanvasHandle,
Width, 0, SRCAND);
 BitBlt(FBufferCanvasHandle, 0, 0, Width, Height, FMyBitmapCanvasHandle, 0,
0, SRCPAINT);
 BitBlt(Canvas->Handle, 0, 0, Width, Height, FBufferCanvasHandle, 0, 0,
SRCCOPY);

blah...,

but flickering (when I am changing some bitmaps) occurs.

(1) need to copy a backround of my component (Canvas of TForm or smth else
desc. from TWinControl, etc. or GDI Handle) to component canvas
(2) next blit mask (SRCAND) (MASK IS NOT ALWAYS 1-BIT (2 colors))
(3) next blit image (SRCPAINT)
(4) finally blit result onto component canvas, all fast and without flicker.

Important is that I prefer to use Repaint() method to invalidate because of
(1) - if i only use procedure above, without invalidating performed by
component (TGraphicControl (not overrrided)) , flicker is none, but if I
repeat this procedure fe. 3 times with different masks and bitmaps I've got
parts of awery three bitmaps on the screen.

A propos buffer - how to use as a buffer TPaintBox or simply TCanvas?

Please help!

Thank you.

Sorry for language.

 

Re:Invalidate, Repaint(), HDC, flicker, double-buffering, TGraphicControl problem


Hi Jan --
Quote
> Please tell me, why it doesn't works (just one (black I think) pixel
> appears):
>           HDC hdcMem, hdcMem2, hdcMem3;
>           hdcMem3 = CreateCompatibleDC(Canvas->Handle);
>           hdcMem2= CreateCompatibleDC(Canvas->Handle);
>           hdcMem = CreateCompatibleDC(Canvas->Handle);

These three lines are fine.

Quote
>  SelectObject(hdcMem, FMyBitmap->Handle);

This is OK too.

Quote
>  BitBlt(hdcMem2, 0, 0, Width, Height, hdcMem, Width, 0, SRCAND);
>  BitBlt(hdcMem2, 0, 0, Width, Height, hdcMem, 0, 0, SRCPAINT);

Here, you're trying to blt to a memory device context (hdcMem2) that has no
bitmap object selected into it.  Recall, the bitmap serves as the "memory" of
the memory device context.  You're only getting a single pixel, since a memory
device context is given only a (1x1) bitmap object by default.

Quote
>  SelectObject(hdcMem3, hdcMem2);
>  BitBlt(Canvas->Handle, 0, 0, Width, Height, hdcMem3, 0, 0, SRCCOPY);

Here, you're trying to select a memory device context into a memory device
context?

Quote
> My point is how to realize double-buffered graphics in descendant of
> TGraphicControl?

Let the TBitmap class help you out here.  Here's a simple, rough,
pseudo-example...

// in header...
#include <memory>
    std::auto_ptr<Graphics::TBitmap> FMaskBitmap;
    std::auto_ptr<Graphics::TBitmap> FBackBitmap;    

// in source...
__fastcall TSomeControl::TSomeControl(TComponent* Owner)
    : TGraphicControl(Owner)
{
    FMaskBitmap.reset(new Graphics::TBitmap());
    FMaskBitmap->Width = Width;
    FMaskBitmap->Height = Height;

    FBackBitmap.reset(new Graphics::TBitmap());
    FBackBitmap->Width = Width;
    FBackBitmap->Height = Height;

Quote
}

void __fastcall TSomeControl::Paint()
{
    // (1) need to copy a backround of my component
    // (Canvas of TForm or smth else desc. from TWinControl,
    // etc. or GDI Handle) to component canvas
    BitBlt(FBackBitmap->Canvas->Handle, 0, 0, Width, Height,
           Canvas->Handle, 0, 0, SRCCOPY);

    // (2) next blit mask (SRCAND) (MASK IS NOT ALWAYS 1-BIT (2 colors))
    BitBlt(FMaskBitmap->Canvas->Handle, 0, 0, Width, Height,
           FBackBitmap->Canvas->Handle, 0, 0, SRCAND);

    // (3) next blit image (SRCPAINT)
    BitBlt(FMaskBitmap->Canvas->Handle, 0, 0, Width, Height,
           FBackBitmap->Canvas->Handle, 0, 0, SRCPAINT);

    // (4) finally blit result onto component canvas,
    // all fast and without flicker.
    BitBlt(Canvas->Handle, 0, 0, Width, Height,
           FMaskBitmap->Canvas->Handle, 0, 0, SRCCOPY);

Quote
}

Good luck.

--
Damon Chandler (TeamB)
http://bcbcaq.freeservers.com

Re:Invalidate, Repaint(), HDC, flicker, double-buffering, TGraphicControl problem


Quote
> >  SelectObject(hdcMem, FMyBitmap->Handle);
> This is OK too.

> >  BitBlt(hdcMem2, 0, 0, Width, Height, hdcMem, Width, 0, SRCAND);
> >  BitBlt(hdcMem2, 0, 0, Width, Height, hdcMem, 0, 0, SRCPAINT);

> Here, you're trying to blt to a memory device context (hdcMem2) that has
no
> bitmap object selected into it.  Recall, the bitmap serves as the "memory"
of
> the memory device context.  You're only getting a single pixel, since a
memory
> device context is given only a (1x1) bitmap object by default.

Dear Damon !

Thank You for advice - now I know for sure that  CreateCompatinleDC (hdc)
returns handle to memory device (one pixel, monochromatic).
And to enlarge the size it should be selected the bitmap in this device
context context (memory).
But always?
What about other GDI objects - regions(Width, Height), brushes(bitmaps
8x8?), pens (Width). Nevermi.....

Quote
> > My point is how to realize double-buffered graphics in descendant of
> > TGraphicControl?

> Let the TBitmap class help you out here.  Here's a simple, rough,
pseudo-example...

> // in header...
> #include <memory>
>     std::auto_ptr<Graphics::TBitmap> FMaskBitmap;
>     std::auto_ptr<Graphics::TBitmap> FBackBitmap;    >
> // in source...
> __fastcall TSomeControl::TSomeControl(TComponent* Owner)
>     : TGraphicControl(Owner)
> {
>     FMaskBitmap.reset(new Graphics::TBitmap());
>     FMaskBitmap->Width = Width;
>     FMaskBitmap->Height = Height;
>     FBackBitmap.reset(new Graphics::TBitmap());
>     FBackBitmap->Width = Width;
>     FBackBitmap->Height = Height;
> }

> void __fastcall TSomeControl::Paint()
> {
>     // (1) need to copy a backround of my component
>     // (Canvas of TForm or smth else desc. from TWinControl,
>     // etc. or GDI Handle) to component canvas
>     BitBlt(FBackBitmap->Canvas->Handle, 0, 0, Width, Height,
>            Canvas->Handle, 0, 0, SRCCOPY);

>     // (2) next blit mask (SRCAND) (MASK IS NOT ALWAYS 1-BIT (2 colors))
>     BitBlt(FMaskBitmap->Canvas->Handle, 0, 0, Width, Height,
>            FBackBitmap->Canvas->Handle, 0, 0, SRCAND);

>     // (3) next blit image (SRCPAINT)
>     BitBlt(FMaskBitmap->Canvas->Handle, 0, 0, Width, Height,
>            FBackBitmap->Canvas->Handle, 0, 0, SRCPAINT);

>     // (4) finally blit result onto component canvas,
>     // all fast and without flicker.
>     BitBlt(Canvas->Handle, 0, 0, Width, Height,
>            FMaskBitmap->Canvas->Handle, 0, 0, SRCCOPY);
> }
> Good luck.
> Damon Chandler (TeamB)

I do not know if I understand.

Let me clearly explain my problem (it could be long - sorry):

An App:

One TForm instance,
three TButtons instance,
five TImage (TImage->Picture = *TBitmap) instance
and one TPainBox instance (ResultPB)(represents instance of my component -
descendant of TGraphicControl (this->Canvas works on the same rule - if
handle is needed it is taken from Parent window)).
On the whole Form is an TImage instance, which represents changeable
environment of my component.

Header is not important there - you should know how it looks.

Bitmaps pointers: (to simplify in all (including TPaintBox instance) Width =
Height = constans)
BackBufferImg - off-screen bitmap used to build image blitted to Canvas of
TPaintBox instance
MaskOneImg - Mask for ImageOneBmp (masked region - white, non masked -
black)
MaskTwoImg - Mask for ImageTwoBmp (masked region - white, non masked -
black)(masks are different)
ImageOneImg - Image one (black background)
ImageTwoImg - Image two (black background)(images are different)

OnClick functions for buttons:

ButtonOne:
    BitBlt(BackBitmapImg->Canvas->Handle, 0, 0, BackBitmap->Width,
BackBitmap->Height,
            Canvas->Handle, ResultPB->Left, ResultPB->Top, SRCCOPY);
/*   Canvas->Handle=Form1->Canvas->Handle, equivalent for GetDC((TWinControl
*)Parent->Handle) in my component */

    BitBlt(BackBitmapImg->Canvas->Handle, 0, 0, Width, Height,
            MaskOneImg->Canvas->Handle, 0, 0, SRCAND);
    BitBlt(BackBitmapImg->Canvas->Handle, 0, 0, Width, Height,
            ImageOneImg->Canvas->Handle, 0, 0, SRCPAINT);

    BitBlt(
            ResultPB->Canvas->Handle,                    /*<-------HERE
ONE*/
            0, 0, Width, Height,
            BackBitmapImg->Canvas->Handle, 0, 0, SRCCOPY);

ButtonTwo:
    BitBlt(BackBitmapImg->Canvas->Handle, 0, 0, BackBitmap->Width,
BackBitmap->Height,
            Canvas->Handle,
/*<-------HERE TWO*/
            ResultPB->Left, ResultPB->Top, SRCCOPY);
/*   Canvas->Handle=Form1->Canvas->Handle, equivalent for GetDC((TWinControl
*)Parent->Handle) in my component      */

    BitBlt(BackBitmapImg->Canvas->Handle, 0, 0, Width, Height,
            MaskOneImg->Canvas->Handle, 0, 0, SRCAND);
    BitBlt(BackBitmapImg->Canvas->Handle, 0, 0, Width, Height,
            ImageOneImg->Canvas->Handle, 0, 0, SRCPAINT);

    BitBlt(ResultPB->Canvas->Handle, 0, 0, Width, Height,
            BackBitmapImg->Canvas->Handle, 0, 0, SRCCOPY);

ButtonThree:
Repaint();      /*   Form1->Repaint()     */

AND NOW:

I run App,

click ButtonOne - everything is Ok,
click ButtonTwo - and in first BitBlt in OnClick for this button
(<-------HERE TWO)
                                use the same handle as fourth BitBlt in
OnClick for ButtonTwo (<-------HERE ONE)
                                so I copy the result of operations in
OnClick for ButtonOne onto BackBitmapImg

now i repaint form (ButtonThree), and

click ButtonOne - everything is Ok,
clckButtonThree - result of previous operation is erased
click ButtonTwo - everything is Ok,

Back to my first announce:

Quote
>>(1) I need to copy the backround of my component (desc. from TWinControl)
to back-buffer
>>...
>>Important is that I prefer (now- must) to use Repaint() method to

invalidate because of (1)
- what causes flicker

So how to access the data (An image rendered in Repaint()) without rendering
it ?
How to redirect these from device context handled by
Canvas->Handle=Form1->Canvas->Handle,
equivalent for GetDC((TWinControl *)Parent->Handle) in my component to my
BackBitmapImg?
Sorry again for long explain.
Maybe I should give up and base my component on TWinControl? (If yes - is it
only way? - I prefer TGraphicControl).

Thank You!

Jan Szczepaniak
amad...@hot.pl

Other Threads