Board index » cppbuilder » Please help me with TImage or BitBlt function

Please help me with TImage or BitBlt function


2003-07-12 04:53:19 AM
cppbuilder89
It happen that when i use this function to draw (BitBlt) it doesn't work
fine:
i can see the drawing produced immediatley, i can see it just after i scroll
the image or i cover the TImage by another window...
It seem that it draw really not just with the calling to BitBlt but after
when the form redraw itself or if i call the functions:
Image->Repaint(); or Image->Refresh();
but if i use this calling every time when i move the mouse it flickers!
how can make it works fine?
this is the code:
I make the image at the first time wheni click a button:
Image->Width = w;
Image->Height = h;
pCanvas = pBitmap->Canvas;
BitBlt(Image->Canvas->Handle, 0, 0, row, col, pCanvas->Handle, 0, 0,
SRCCOPY);
(here i can see the image it works pretty fine)
but when i move the mouse it doesn't work, i get ever the same image without
lines:
void __fastcall TForm1::Source1Move(TObject *Sender, TShiftState Shift,
int X, int Y)
{
pCanvas = pBitmap->Canvas;
pCanvas->Pen->Color = clRed;
pCanvas->MoveTo(X*30, Y*30);
pCanvas->LineTo(X*30+31, Y*30);
pCanvas->Pen->Color = clBlack;
BitBlt(Image->Canvas->Handle, 0, 0, row, col, pCanvas->Handle, 0, 0,
SRCCOPY); <------- doesn't show the image drawing in Image->Canvas Why??
}
 
 

Re:Please help me with TImage or BitBlt function

set the brush.style := bsclear;
b wrote:
Quote
It happen that when i use this function to draw (BitBlt) it doesn't work
fine:
i can see the drawing produced immediatley, i can see it just after i scroll
the image or i cover the TImage by another window...
It seem that it draw really not just with the calling to BitBlt but after
when the form redraw itself or if i call the functions:
Image->Repaint(); or Image->Refresh();
but if i use this calling every time when i move the mouse it flickers!
how can make it works fine?

this is the code:

I make the image at the first time wheni click a button:

Image->Width = w;
Image->Height = h;
pCanvas = pBitmap->Canvas;
BitBlt(Image->Canvas->Handle, 0, 0, row, col, pCanvas->Handle, 0, 0,
SRCCOPY);

(here i can see the image it works pretty fine)
but when i move the mouse it doesn't work, i get ever the same image without
lines:

void __fastcall TForm1::Source1Move(TObject *Sender, TShiftState Shift,
int X, int Y)
{
pCanvas = pBitmap->Canvas;
pCanvas->Pen->Color = clRed;
pCanvas->MoveTo(X*30, Y*30);
pCanvas->LineTo(X*30+31, Y*30);
pCanvas->Pen->Color = clBlack;
BitBlt(Image->Canvas->Handle, 0, 0, row, col, pCanvas->Handle, 0, 0,
SRCCOPY); <------- doesn't show the image drawing in Image->Canvas Why??
}
 

Re:Please help me with TImage or BitBlt function

Hi,
The reason your not seeing immediate changes to the Image is because
you're directing your output to a *memory* device context. Specifically,
when you use Image->Canvas->Handle, your accessing the Canvas property of
the TBitmap object contained in the Image; if the Image is empty, a TBitmap
is created for you. The Canvas property of TBitmap returns a pointer to
TBitmapCanvas object whose Handle property returns a handle to a memory
device context (DC). If you then call BitBlt() with this memory DC as the
target DC, you won't see the changes on the screen; rather, you'll need to
instruct the Image to redraw its TBitmap (and thus the changes you made) by
using, e.g., the TImage::Refresh() method or by inciting a redraw the
Image's parent window (e.g., by minimizing and then restoring your form).
In general, it's best to use a TImage only for very simple (and small)
bitmaps. The TImage class is particularly inefficient when rendering
stretched and non-screen-format bitmaps. In your specific case, you don't
really need a TImage because you already have a TBitmap in memory (your
pBitmap's object). As I mentioned, the TImage will create its own bitmap
when you access its Canvas property (unless it contains another TGraphic
type, in which case it will throw an exception upon accessing the Canvas),
and it's a waste of resources to have two bitmaps in memory unless you
really need the second bitmap for processing/restoring. Instead, I'd
suggest you use a TPaintBox object, and then call BitBlt() using the
TPaintBox::Canvas::Handle property. Here's a rough example...
//
// in header...
//
#include <memory>
class TForm1 : public TForm
{
__published:
TPaintBox *PaintBox1;
void __fastcall PaintBox1MouseMove(TObject* Sender,
TShiftState Shift, int X, int Y);
void __fastcall PaintBox1Paint(TObject* Sender);
public:
__fastcall TForm1(TComponent* Owner);
private:
std::auto_ptr<Graphics::TBitmap>Bitmap_;
};
//
// in source...
//
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner), Bitmap_(new Graphics::TBitmap())
{
Bitmap_->PixelFormat = pf24bit;
Bitmap_->Width = 350;
Bitmap_->Height = 350;
PaintBox1->SetBounds(
10, 10, Bitmap_->Width, Bitmap_->Height
);
}
// PaintBox1's OnMouseMove event handler
void __fastcall TForm1::PaintBox1MouseMove(
TObject* Sender,
TShiftState Shift,
int X, int Y
)
{
// draw the stuff to your bitmap...
TCanvas& BmpCanvas = *Bitmap_->Canvas;
BmpCanvas.Pen->Color = clRed;
BmpCanvas.MoveTo(X, Y);
BmpCanvas.LineTo(X + 31, Y);
BmpCanvas.Pen->Color = clBlack;
// define the minimal bounding rect of the area to update
X += PaintBox1->Left; Y += PaintBox1->Top;
TRect const RUpdate(X, Y, X + 31, Y + 1);
// invalidate the window (invokes PaintBox1's OnPaint event)
RedrawWindow(PaintBox1->Parent->Handle, &RUpdate, NULL,
RDW_INVALIDATE | RDW_UPDATENOW);
}
// PaintBox1's OnPaint event handler
void __fastcall TForm1::PaintBox1Paint(
TObject* Sender
)
{
// grab the coordinates of the update rect
TRect const RUpdate = PaintBox1->Canvas->ClipRect;
// render Bitmap_ to PaintBox1
BitBlt(
PaintBox1->Canvas->Handle,
RUpdate.Left, RUpdate.Top,
RUpdate.Width(), RUpdate.Height(),
Bitmap_->Canvas->Handle,
RUpdate.Left, RUpdate.Top,
SRCCOPY
);
}
Note that if you need to deploy your application on systems that might use
256-color mode (or less), you'll need to add code to support palettes. In
addition, tou should also have a look at these two articles in the May '02
issue of the C++Builder Dev. Journal...
* Display-optimal DIB section bitmaps
* Fast bitmap zooming and scrolling
They're available here...
www.bridgespublishing.com/articles/articleindex.htm.
Best of luck,
--
Damon (TeamB)
BCBCAQ - bcbcaq.bytamin-c.com
b wrote:
Quote
i can see the drawing produced immediatley, i can see it just after
i scroll the image or i cover the TImage by another window...
It seem that it draw really not just with the calling to BitBlt but
after when the form redraw itself...
[...]
BitBlt(Image->Canvas->Handle, 0, 0, row, col, pCanvas->Handle, 0, 0,
SRCCOPY);
 

{smallsort}

Re:Please help me with TImage or BitBlt function

Really really Thank you.
Do you think i remove the flicker effect in this way?
"Damon Chandler (TeamB)" < XXXX@XXXXX.COM >ha scritto nel messaggio
Quote
Hi,
The reason your not seeing immediate changes to the Image is because
you're directing your output to a *memory* device context. Specifically,
when you use Image->Canvas->Handle, your accessing the Canvas property of
the TBitmap object contained in the Image; if the Image is empty, a
TBitmap
is created for you. The Canvas property of TBitmap returns a pointer to
TBitmapCanvas object whose Handle property returns a handle to a memory
device context (DC). If you then call BitBlt() with this memory DC as the
target DC, you won't see the changes on the screen; rather, you'll need to
instruct the Image to redraw its TBitmap (and thus the changes you made)
by
using, e.g., the TImage::Refresh() method or by inciting a redraw the
Image's parent window (e.g., by minimizing and then restoring your form).

In general, it's best to use a TImage only for very simple (and small)
bitmaps. The TImage class is particularly inefficient when rendering
stretched and non-screen-format bitmaps. In your specific case, you don't
really need a TImage because you already have a TBitmap in memory (your
pBitmap's object). As I mentioned, the TImage will create its own bitmap
when you access its Canvas property (unless it contains another TGraphic
type, in which case it will throw an exception upon accessing the Canvas),
and it's a waste of resources to have two bitmaps in memory unless you
really need the second bitmap for processing/restoring. Instead, I'd
suggest you use a TPaintBox object, and then call BitBlt() using the
TPaintBox::Canvas::Handle property. Here's a rough example...

//
// in header...
//
#include <memory>
class TForm1 : public TForm
{
__published:
TPaintBox *PaintBox1;
void __fastcall PaintBox1MouseMove(TObject* Sender,
TShiftState Shift, int X, int Y);
void __fastcall PaintBox1Paint(TObject* Sender);

public:
__fastcall TForm1(TComponent* Owner);

private:
std::auto_ptr<Graphics::TBitmap>Bitmap_;
};

//
// in source...
//
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner), Bitmap_(new Graphics::TBitmap())
{
Bitmap_->PixelFormat = pf24bit;
Bitmap_->Width = 350;
Bitmap_->Height = 350;
PaintBox1->SetBounds(
10, 10, Bitmap_->Width, Bitmap_->Height
);
}

// PaintBox1's OnMouseMove event handler
void __fastcall TForm1::PaintBox1MouseMove(
TObject* Sender,
TShiftState Shift,
int X, int Y
)
{
// draw the stuff to your bitmap...
TCanvas& BmpCanvas = *Bitmap_->Canvas;
BmpCanvas.Pen->Color = clRed;
BmpCanvas.MoveTo(X, Y);
BmpCanvas.LineTo(X + 31, Y);
BmpCanvas.Pen->Color = clBlack;

// define the minimal bounding rect of the area to update
X += PaintBox1->Left; Y += PaintBox1->Top;
TRect const RUpdate(X, Y, X + 31, Y + 1);
// invalidate the window (invokes PaintBox1's OnPaint event)
RedrawWindow(PaintBox1->Parent->Handle, &RUpdate, NULL,
RDW_INVALIDATE | RDW_UPDATENOW);
}

// PaintBox1's OnPaint event handler
void __fastcall TForm1::PaintBox1Paint(
TObject* Sender
)
{
// grab the coordinates of the update rect
TRect const RUpdate = PaintBox1->Canvas->ClipRect;
// render Bitmap_ to PaintBox1
BitBlt(
PaintBox1->Canvas->Handle,
RUpdate.Left, RUpdate.Top,
RUpdate.Width(), RUpdate.Height(),
Bitmap_->Canvas->Handle,
RUpdate.Left, RUpdate.Top,
SRCCOPY
);
}

Note that if you need to deploy your application on systems that might use
256-color mode (or less), you'll need to add code to support palettes. In
addition, tou should also have a look at these two articles in the May '02
issue of the C++Builder Dev. Journal...

* Display-optimal DIB section bitmaps
* Fast bitmap zooming and scrolling

They're available here...

www.bridgespublishing.com/articles/articleindex.htm.

Best of luck,
--
Damon (TeamB)
BCBCAQ - bcbcaq.bytamin-c.com


b wrote:
>i can see the drawing produced immediatley, i can see it just after
>i scroll the image or i cover the TImage by another window...
>It seem that it draw really not just with the calling to BitBlt but
>after when the form redraw itself...
[...]
>BitBlt(Image->Canvas->Handle, 0, 0, row, col, pCanvas->Handle, 0, 0,
>SRCCOPY);
 

Re:Please help me with TImage or BitBlt function

b wrote:
Quote
Do you think i remove the flicker effect in this way?
Yes, the code that I posted will produce flicker-free rendering in response
to the drawing performed within the OnMouseMove event handler.
However, bear in mind that the flicker that's traditionally encountered in
Windows applications is caused by unnecessary filling of a window's client
area in response to the WM_ERASEBKGND message. The TWinControl class, for
example, calls the FillRect() function in response to this message to fill
its *entire* client area using its Brush. Clearly, if this client area
contains child controls that are later going to draw over this filled area,
there's no need to fill the entire client area, but only those areas not
occupied by child controls. The main reason the code I posted works is
because I've called the RedrawWindow() Win32 specifically specifying flags
that don't incite a WM_ERASEBKGND message (only a WM_PAINT message).
Now, if you include the csOpaque bit in a TGraphicControl descendant's
ControlStyle property, then calling the Invalidate() or Refresh()/Repaint()
methods won't incite a WM_ERASEBKGND message (for the Parent window), and
thus you won't see the TWinControl-related flicker. So, one way to
eliminate VCL-induced flicker is to set the Stretch property of your Image
to true; this effectively adds the csOpaque bit to the ControlStyle
property. But, using the csOpaque bit will only eliminate flicker caused by
using VCL methods such as Invalidate() or Refresh()/Repaint(). It won't
eliminate flicker caused by the WM_ERASEBKGND message sent via other means,
e.g., by using the InvalidateRect() Win32 function with a true bErase
parameter.
FWIW, you're much better off drawing to a TPaintBox (or better yet, to
another TWinControl such as a TFrame) not to reduce flicker, but because a
TImage renders its *entire* bitmap each time the Image is redrawn,
regardless of which (possibly small) portion actually requires updating.
Notice from the code that I posted that I specifically used the ClipRect
property to render only the portion that requires updating.
HTH,
--
Damon (TeamB)
BCBCAQ - bcbcaq.bytamin-c.com
 

Re:Please help me with TImage or BitBlt function

Really i follow your advise but i can't see the result.
Please are you so nice to contact me at XXXX@XXXXX.COM at MSN?
I'm doing what you told me, really, but something doesn't go!
Thank you!
 

Re:Please help me with TImage or BitBlt function

Finally now it works!!! :)
It depended form 2 factors, i controll just another thing after i reffer you
what i wronged...
Now i want ask a thing:
if i decalre these:
Graphics::TBitmap *pBitmap = new Graphics::TBitmap();
TCanvas *pCanvas;
afet i do that:
pCanvas = pBitmap->Canvas;
now pCanvas point at pBitmap->Canvas? Isn't it?
So if i change pCanvas i change also pBitmap, right?
 

Re:Please help me with TImage or BitBlt function

b wrote:
Quote
The question was if i change the pCanvas drawing inside for
example somelines i change automatically also the Bitmap->Canvas?
Yes, drawing to pCanvas is the same as drawing to Bitmap->Canvas if they
both point to the TBitmap::FCanvas member (which they do based on the code
you posted).
Good luck,
--
Damon (TeamB)
BCBCAQ - bcbcaq.bytamin-c.com
 

Re:Please help me with TImage or BitBlt function

How can i change pCanvas without change pBitmap->Canvas, also if these point
at the same object?
"Damon Chandler (TeamB)" < XXXX@XXXXX.COM >ha scritto nel messaggio
Quote
b wrote:
>The question was if i change the pCanvas drawing inside for
>example somelines i change automatically also the Bitmap->Canvas?

Yes, drawing to pCanvas is the same as drawing to Bitmap->Canvas if they
both point to the TBitmap::FCanvas member (which they do based on the code
you posted).

Good luck,
--
Damon (TeamB)
BCBCAQ - bcbcaq.bytamin-c.com
 

Re:Please help me with TImage or BitBlt function

b wrote:
Quote
How can i change pCanvas without change pBitmap->Canvas, also if
these point at the same object?
You'll have to use another TBitmap object.
--
Damon (TeamB)
BCBCAQ - bcbcaq.bytamin-c.com