BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

TPaintBox refresh problem I don't understand...

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Graphics
View previous topic :: View next topic  
Author Message
dMessett
Guest





PostPosted: Tue Nov 16, 2004 8:27 am    Post subject: TPaintBox refresh problem I don't understand... Reply with quote



Greetings people.

I've spent the last several hours trying to figure this one out, and
I've come up with a workaround, but I'm not sure that I understand the
nature of the problem, that of why the PaintBox contents *sometimes*
disappear when first written, but contents appear when written a second
time.

Ya see, I have a simple game app (minesweeper ripoff) that uses a
function to configure stuff, which resizes visual controls amongst which
is, the paintbox that is my lament. The function itself does not do
anything to the paintbox other than resize it, and enable it.

This function is called in Form1.OnCreate, after which my procedures
that draw on the canvas of the paintbox, deliver immediate results.

Now here's the part that confuses me. If I call my function a second
time once the app is running, with the *same* parameters as were used
when calling this function in Form1.OnCreate (which would set
paintbox.width & height to what they were already set at within
Form1.OnCreate), I can afterward draw on the paintbox and have the
results appear immediately. If however I invoke my function (second
time, given that it was already invoked in Form1.OnCreate) with
different arguments (which resizes the paintbox), writing the paintbox
afterward flashes briefly & disappears on the first try, but on the
second try, it's fine.

The simple trial & error fix-all was to stick a seemingly redundant
'refresh' at the tail end of my function, but the drawing operations
themselves are outside of the scope of that function, thus I don't get
why "refreshing" the paintbox BEFORE its canvas is drawn somehow
corrects the problem of otherwise having to draw its canvas TWICE within
the app if the paintbox is resized (within the app), given that I only
have to draw ONCE (within the app) if the paintbox was sized ONCE (again
via my function) from within Form1.OnCreate... does that make sense?
Sizing of the paintbox within the IDE is dissimilar to that which I set
it as (by default or otherwise) within the app BTW, and doublebuffering
whether true or false has no relevancy.

If you can shed light on this situation, I would be grateful for any
insight. I've remedied the problem, but I don't understand its exact
cause. Any thoughts?

TIA, DHM
Back to top
Yorai Aminov (TeamB)
Guest





PostPosted: Tue Nov 16, 2004 9:05 am    Post subject: Re: TPaintBox refresh problem I don't understand... Reply with quote



dMessett wrote:

Quote:
why the PaintBox contents
sometimes disappear when first written, but contents appear when
written a second time.

When are you painting your PaintBox? You should only draw things in the
OnPaint event handler.

--
Yorai Aminov (TeamB)
(TeamB cannot answer questions received via email.)
Shorter Path - http://www.shorterpath.com
Yorai's Page - http://www.yoraispage.com

Back to top
RandomAccess
Guest





PostPosted: Tue Nov 16, 2004 1:05 pm    Post subject: Re: TPaintBox refresh problem I don't understand... Reply with quote



Here's how I do stuff like this :

a) I always create 2 bitmaps the same size as my paintbox. A "work"
bitmap and a "display" bitmap. ( NOTE : The bitmaps MUST change size if the
paintbox changes size - and this will require some special handling by you).

b) I always draw new "frames" to my "work" bitmap and NOT to the paintbox.
When a new frame is drawn, the bitmap that was drawn to becomes the
"display" bitmap and the other bitmap becomes the "work" bitmap. You will
need to create some special flags (variables) to manage this. The best
thing to do is to wrap it all into a class.

c) The paintbox OnPaint event simply draws my "display" TBitmap.
ie MyPaintBox.Canvas.Draw(0, 0, DisplayBitmap);

What (c) does, is it gaurentees the paintbox always draws the last fully
built frame. The on-paint event of the paintbox can fire for any number of
different reasons, so that's why you need this code here.

AFTER drawing a NEW frame into your "work" bitmap, you will want to
obviously draw it to the screen immediately. I prefer to make a direct call
to the on-paint handler of the paint box once a frame is drawn - instead of
calling something like MyPaintbox.Repaint.

ie

.... drawing the frame
SwapBitmaps; // Swap flags for Work and Display bitmaps
MyPaintBoxPaint(MyPaintBox); // Call the event handler directly

Actually, my paintbox event handler calls a blitting routine, and that's
the routine that I call AFTER creating a new frame. In any case it's all
the same thing.

hope this helps.


Best Regards


Back to top
dMessett
Guest





PostPosted: Wed Nov 17, 2004 8:26 am    Post subject: Re: TPaintBox refresh problem I don't understand... Reply with quote

Yorai Aminov (TeamB) wrote:
Quote:
dMessett wrote:


why the PaintBox contents
sometimes disappear when first written, but contents appear when
written a second time.


When are you painting your PaintBox? You should only draw things in the
OnPaint event handler.


Drawing on the PaintBox is performed immediately after it is resized by
using FillRect then a barrage of Paintbox.Canvas.Draw(x,y,image), at
which point the application sits & waits... The whole process is
instantiated by an OnClick event.

procedure Form1.Option1Click(Sender: TObject);
begin
SomeFunction(x,y); // resizes paintbox, form, etc.
StartGame; // draws stuff which immediately disappears.
end;

If however I insert PaintBox1.Refresh, PaintBox1.Repaint, or
Application.ProcessMessages after SomeFunction, the problem disappears
(no pun intended), and I can draw happily with immediate results.

I'll research OnPaint as you suggest, as it was not an approach that I
had considered due to lack of familiarity.

Thankyou kindly for your response,
Dustin.




Back to top
dMessett
Guest





PostPosted: Thu Nov 18, 2004 5:27 am    Post subject: Re: TPaintBox refresh problem I don't understand... Reply with quote

RandomAccess wrote:
Quote:
Here's how I do stuff like this :

a) I always create 2 bitmaps the same size as my paintbox. A "work"
bitmap and a "display" bitmap. ( NOTE : The bitmaps MUST change size if the
paintbox changes size - and this will require some special handling by you).

b) I always draw new "frames" to my "work" bitmap and NOT to the paintbox.
When a new frame is drawn, the bitmap that was drawn to becomes the
"display" bitmap and the other bitmap becomes the "work" bitmap. You will
need to create some special flags (variables) to manage this. The best
thing to do is to wrap it all into a class.

c) The paintbox OnPaint event simply draws my "display" TBitmap.
ie MyPaintBox.Canvas.Draw(0, 0, DisplayBitmap);

What (c) does, is it gaurentees the paintbox always draws the last fully
built frame. The on-paint event of the paintbox can fire for any number of
different reasons, so that's why you need this code here.

AFTER drawing a NEW frame into your "work" bitmap, you will want to
obviously draw it to the screen immediately. I prefer to make a direct call
to the on-paint handler of the paint box once a frame is drawn - instead of
calling something like MyPaintbox.Repaint.

ie

... drawing the frame
SwapBitmaps; // Swap flags for Work and Display bitmaps
MyPaintBoxPaint(MyPaintBox); // Call the event handler directly

Actually, my paintbox event handler calls a blitting routine, and that's
the routine that I call AFTER creating a new frame. In any case it's all
the same thing.

hope this helps.


Best Regards



Indeed that does help tremendously! Though I did solve the disappearing
paintbox problem in another manner, I'm already working with off-screen
bitmaps as it is (tiny ones) which are tiled within the paintbox.

What led to my problem was the act of resizing the paintbox, then
*immediately* attempting to draw... Three fixes which remedied the image
disappearance are indicated in this cobbled (and tested) procedure:

procedure TForm1.SizeAndFill(X,Y,Color: Integer);
var
Coords: TRect;
begin
Form1.PaintBox1.Width := X;
Form1.PaintBox1.Height := Y;
PaintBox1.Refresh; // (*PUT THIS HERE!*)
// PaintBox1.Repaint ;// OR this,
// Application.ProcessMessages ; // OR this.
Coords.Left := 0;
Coords.Top := 0;
Coords.Bottom := Form1.PaintBox1.Height-1;
Coords.Right := Form1.PaintBox1.Width-1;
PaintBox1.Canvas.Brush.Color := Color;
Form1.PaintBox1.Canvas.FillRect(Coords); // background color
// yadda yadda draw a bunch of tiny images (grid style)
end;

What confused the heck out of me was that refreshing the control before
drawing on it (rather than after) worked... Well, moving on.

As I gather from your response, it is prudent to do these sorts of
things to an off-screen bitmap and avoid potential display jarring
problems. The two bitmaps example makes me think of page-flipping, and
if I understand correctly, your purpose for invoking OnPaint in favor of
MyPaintbox.Repaint, is that the latter is a 'request', not an order, and
the O/S would simply queue the request. (Never thought about that
before... Alas something to research!)

I comprehend the idea of making the determination of 'which' image to
draw in the OnPaint event, and immediately a global variable IF-THEN or
CASE scenario springs to mind, or something more elegant such as
manipulating a pointer (POKE), or an array of pointers for that matter.
(nice...)

Again, I appreciate your example as it was concise, comprehensive, and
aside from offering a solution, it gave me some new ideas...

Cheers,
Dustin




Back to top
RandomAccess
Guest





PostPosted: Thu Nov 18, 2004 1:05 pm    Post subject: Re: TPaintBox refresh problem I don't understand... Reply with quote

Hi Dustin,


Quote:
I comprehend the idea of making the determination of 'which' image to
draw in the OnPaint event, and immediately a global variable IF-THEN or
CASE scenario springs to mind, or something more elegant such as
manipulating a pointer (POKE), or an array of pointers for that matter.
(nice...)


Consider this :

// SETUP OF THE BITMAPS
var
bmp1, bmp2 : TBitmap;
DisplayBitmap : TBitmap;
begin
DisplayBitmap := Bmp1;
.....
end;

Now After drawing a new frame to the work bitmap
you should make it the display bitmap. So....

// Pass in the "Work" bitmap to the renderer
procedure RenderFrame(Bmp : TBitmap);
begin
// Render here.....
// Update status
DisplayBitmap := Bmp; // Swap the display bitmap
// Refresh Paintbox
PaintBoxPaint(PaintBox); // Blit the new frame immediately
end;


// Paintbox blitter (OnPaint - handler for the paintbox)
procedure PaintBoxPaint(Sender : TObject);
begin
PaintBox.Canvas.Draw(0, 0, DisplayBitmap);
end;


// Call RenderFrame like this so that the
// WORK bitmap is passed in.
if DisplayBitmap = Bmp1 then
RenderFrame(Bmp2)
else
RenderFrame(Bmp1);


The RenderFrame routine should perform the re-assignment of the display
bitmap once it has finished as I've shown.

Best Regards



Back to top
Roger Lascelles
Guest





PostPosted: Fri Nov 19, 2004 11:31 am    Post subject: Re: TPaintBox refresh problem I don't understand... Reply with quote


"Yorai Aminov (TeamB)" <yaminov (AT) gmail (DOT) com> wrote

Quote:
dMessett wrote:

When are you painting your PaintBox? You should only draw things in the
OnPaint event handler.

--

The OnPaint handler is called in response to the WM_PAINT message from
Windows and signals that you need to repaint the area in TCanvas.ClipRect.
Typically this happens when your window needs a redraw after being obscured
by another app window on top of it.

It is often convenient to put all your painting code in the OnPaint handler
and simply repaint the whole control when you change anything. However,
this soon becomes inadequate, when you write anything of real use - from a
text editor to a drawing program to a game - all require direct writing to
the TCanvas outside of the OnPaint handler.

For example, imagine an application which draws a line in response to mouse
movement. You write directly to the TCanvas inside of the OnMouseMove, not
in the OnPaint handler.

The OnPaint handler is called in response to the WM_PAINT message from
Windows and signals that you need to repaint the area in TCanvas.ClipRect.
Typically this happens when your window needs a redraw after being obscured
by another app window on top of it.




Back to top
dMessett
Guest





PostPosted: Sat Nov 20, 2004 1:32 am    Post subject: Re: TPaintBox refresh problem I don't understand... Reply with quote

Roger Lascelles wrote:
Quote:
The OnPaint handler is called in response to the WM_PAINT message from
Windows and signals that you need to repaint the area in TCanvas.ClipRect.
Typically this happens when your window needs a redraw after being obscured
by another app window on top of it.

OK, so like if you minimize/maximize probably too. Thankyou for the
explanation.

Dustin

Back to top
dMessett
Guest





PostPosted: Sat Nov 20, 2004 1:49 am    Post subject: Re: TPaintBox refresh problem I don't understand... Reply with quote

RandomAccess wrote:
Quote:
// Paintbox blitter (OnPaint - handler for the paintbox)
procedure PaintBoxPaint(Sender : TObject);
begin
PaintBox.Canvas.Draw(0, 0, DisplayBitmap);
end;


// Call RenderFrame like this so that the
// WORK bitmap is passed in.
if DisplayBitmap = Bmp1 then
RenderFrame(Bmp2)
else
RenderFrame(Bmp1);


I see, the determination of what to paint is not made (at all) within
OnPaint. rather, the determination of what (where) to render, is made by
that which renders. Thx for pointing that out, as I was thinking of a
needlessly complicated flag example where paint figures out which is the
active surface, and the renderer figures out which surface to draw on,
and updates flags accordingly. OnPaint need not care how many surfaces
there are at all, and their status as there are separate handlers for
each paintable object, and the object can only display one thing at a
time (duh). I think I need more sleep.

Cheers,
Dustin


Back to top
RandomAccess
Guest





PostPosted: Sat Nov 20, 2004 10:23 am    Post subject: Re: TPaintBox refresh problem I don't understand... Reply with quote


You've got it exactly. I learned this after doing stuff like this for years
and endlessly tweaking my code. There are some down-sides though. If the
paintbox is too big and the renderer is too slow, you'll definately
notice - because the technique is better suited when used with DirectX or
something like that which can helk with rendering speed.

So generally all you can do is make the renderer as fast as possible.
Some people like to render directly in On-paint without buffering and this
actually works quite well if you use a modified paintbox which doesn't erase
the background. But I myself usaully prefer double buffering as I've
pointed out.

The application itself will determine the best approach to use.

best regards


Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi Graphics All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.