New topic: 

Multiple PictureBoxes to a single Canvas?

<http://forums.realsoftware.com/viewtopic.php?t=45750>

         Page 1 of 1
   [ 4 posts ]                 Previous topic | Next topic          Author  
Message        RBnoob2012          Post subject: Multiple PictureBoxes to a 
single Canvas?Posted: Sun Oct 28, 2012 8:34 pm                         
Joined: Sat Aug 18, 2012 11:23 am
Posts: 13                Hello all,

I just purchased a hobbyist version of RB as I look at moving a VB2010 game 
over to RB. 

In VB2010 I use multiple PictureBoxes to control how much of the screen has to 
be re-drawn at any given moment, it also gave me easier access to Mouse events.

For example:

XXXXXXXXXXXXXX <- A PictureBox that has 6 buttons I draw.

YYYYYYYYYYYYYY <- A PictureBox that has 24 image icons I display scaled as 
necessary

ZZZZZZZZZZZZZZ
Z    Z
Z    Z
Z    Z
Z    Z <- A PictureBox where the main drawing takes place.
Z    Z
Z    Z
Z    Z
ZZZZZZZZZZZZZZ


Based on what I've read, in RB multiple canvases is not the way to go. I tried 
creating the screen above drawing each of the X, Y, and Z elements every time 
any event was raised. It takes longer than I'd like, and also seems to be a 
waste of resources since, for instance, maybe only Icon Image 13 is "depressed" 
by a mouse click, but the whole screen has to be redrawn.

I'm wondering if I'm missing something. I've seen posts here where it's been 
mentioned that a Canvas control can be used as a ToolTip. But I'm not sure how 
to bring it to the front.

Which makes me wonder if there's some use of .Visible = True/False that I 
should be using.

I also looked at the Clip graphics method but I couldn't figue out if it was 
possible to keep sections of the "clip" persistent as I redrew other "clips" of 
the screen.

Anyway, I apologize for rambling. Basically, I'm trying to break my old VB 
habits and join the RB lifestyle.

Can anyone point me toward a solution to my X, Y, Z example?

Is redrawing the whole screen the best way to go?

Is it possible to compartmentalize drawing without having to redraw the whole 
screen?

Thank you,
 RBnoob   
                             Top                charonn0          Post subject: 
Re: Multiple PictureBoxes to a single Canvas?Posted: Sun Oct 28, 2012 9:42 pm   
                              
Joined: Mon Apr 02, 2007 2:08 am
Posts: 946
Location: San Francisco, CA, USA                RBnoob2012 wrote:Is redrawing 
the whole screen the best way to go?

This is how I usually do it, which isn't recommended for Mac OS X apps but 
under Windows it works well

Quote:Is it possible to compartmentalize drawing without having to redraw the 
whole screen?

Thank you,
 RBnoob

Drawing to the screen is expensive, but drawing someplace else is less so. If 
you have multiple calls to g.Draw* in your Canvas' Paint event, things can be 
very slow indeed (again, this is a RB on Windows perspective; Mac devs here 
have told me otherwise.)

What I do is create a Picture object and do all my drawing to it in the 
background. Then, when the Canvas' Paint event fires, just draw the Picture 
once. 

So, for example this:
Sub Paint(g As Graphics)
  g.DrawRect(10, 10, 15, 15)
  g.FillOval(30, 30, 15, 15)
End Sub

  
becomes this:
Sub Paint(g As Graphics)
  Dim Buffer As New Picture(g.Width, g.Height, 32)
  Buffer.Graphics.DrawRect(10, 10, 15, 15)
  Buffer.Graphics.FillOval(30, 30, 15, 15)
  g.DrawPicture(Buffer, 0, 0)
End Sub


Making the Buffer a property of the window (or someplace else more persistent 
than the local scope) also allows you to compartmentalize the drawing since 
other methods and objects can draw to the buffer at any time, even if the Paint 
event hasn't been raised. This also means that the Paint event can be Raised 
without redrawing the buffer.

As an example, take a look at the DragCanvas class in this project: 
https://github.com/charonn0/RB-Custom-Controls 

With a little work, the Canvas can do a lot: 
https://www.youtube.com/watch?v=8DqTvcPZuvkl      
_________________
Boredom Software  
                             Top                RBnoob2012          Post 
subject: Re: Multiple PictureBoxes to a single Canvas?Posted: Sun Oct 28, 2012 
11:43 pm                         
Joined: Sat Aug 18, 2012 11:23 am
Posts: 13                charonn0,

First, thanks for stopping by to help. I looked at your example, did you mean 
the DragContainter Class in your DragCanvas project? That's the one I looked 
at. Thanks for the example.

You said that redrawing the whole screen isn't recommended for Mac. Do you know 
what is?

In your example code on GitHub I noticed you used Refresh(false) and 
Invalidate(false). I've seen this a few other times, and I think it's the key 
to what I'm missing in terms of buffering and/or double-buffering. 

So ... if I understand your example of "this becomes this" (in your reply post, 
not your github code) ... I would move all of my screen drawing routines (i.e. 
Sub RedrawTopSection, Sub RedrawMidSection, Sub RedrawMainSection) to the Paint 
event of my Canvas1 canvas, correct? And in each of these subs that draws a 
section of the screen, I would be using a global gBuffer so that each is 
drawing to the same memory block, right?

Then at the end I:
g.DrawPicture(gBuffer, 0, 0)
which puts the gBuffer image into Canvas1, correct?

I have been using Canvas1.BackDrop = gBuffer ... maybe that's why I'm getting 
flickering. 

Okay ... I'm not sure I'm clear on how I force the Paint event. Assuming that 
my drawing subs have been moved to Paint ... when a user "clicks" an image 
icon, I capture the Mouse, determine which Icon it is, then redraw the screen 
with that Icon in its "Down" image, and then g.DrawPicture(). Is that right? 
The whole screen would be redrawn with the Clicked Icon in its Down position, 
and then the MouseUp capture redraws the whole thing again, with all icons in 
their "Up" position. 

Am I on the right track? Would .Refresh(False) or .Invalidate(False) be better 
for the situation I described, or should I use g.DrawPicture() as you indicated?

Thanks again for your help. I'm really grateful.

Regards,
RBnoob   
                             Top                charonn0          Post subject: 
Re: Multiple PictureBoxes to a single Canvas?Posted: Mon Oct 29, 2012 12:23 am  
                               
Joined: Mon Apr 02, 2007 2:08 am
Posts: 946
Location: San Francisco, CA, USA                Quote:You said that redrawing 
the whole screen isn't recommended for Mac. Do you know what is?
>From the highest authority: viewtopic.php?p=247297#p247297

RBnoob2012 wrote:charonn0,
did you mean the DragContainter Class in your DragCanvas project
Well, both. The DragContainer class specifically and the DragCanvas project 
generally.

In the DragContainer.Paint event, I do this:

Sub Paint(g As Graphics)
  If lastWidth <> Me.Width Or lastHeight <> Me.Height Then
  //The canvas has been resized, so we need to regen the buffer
  buffer = New Picture(Me.Width, Me.Height, 24)
  lastWidth = Me.Width
  lastHeight = Me.Height
  Update()
  End If
  g.DrawPicture(buffer, 0, 0)
End Sub


The Update() method of the DragContainer example is where all the actual 
drawing gets done. If the Canvas hasn't been resized then the only thing the 
Paint event does is draw the unmodified buffer, otherwise it calls Update() and 
then draws the newly generated buffer. Other events or methods also call Update 
if they've modified anything (and they may or may not call Refresh/Invalidate 
to force a Paint.) You can certainly have a different method each draw 
different or even overlapping regions on the buffer, calling them as needed 
(and as little as possible from the Paint event.)

Drawing to the screen will always be expensive, and multiple Paint events can 
fire in a very short period of time. The core idea is that you want to get in 
and get out of the Paint event as quickly as possible since there may be 10 
more coming quick.

Quote:when a user "clicks" an image icon, I capture the Mouse, determine which 
Icon it is, then redraw the screen with that Icon in its "Down" image, and then 
g.DrawPicture(). Is that right? The whole screen would be redrawn with the 
Clicked Icon in its Down position, and then the MouseUp capture redraws the 
whole thing again, with all icons in their "Up" position. 

Yes. The buffer is the current state of the canvas, which you modify as 
needed/wanted. When the Paint event fires you just call g.DrawPicture(Buffer, 
0, 0). Since the buffer persists until it's explicitly destroyed, you don't 
necessarily need to redraw everything, but you would need to devise a way of 
determining what needs to be redrawn and what doesn't. The DragContainer 
example just redraws everything when Update is called.

Quote:In your example code on GitHub I noticed you used Refresh(false) and 
Invalidate(false).

Refresh triggers the Paint event, Invalidate merely suggests a Paint event. 
Passing True to either one will erase the canvas first, whereas passing false 
will not. Erasing the background is a case-by-case thing, since it can be good 
but it's also more expensive.      
_________________
Boredom Software  
                             Top             Display posts from previous: All 
posts1 day7 days2 weeks1 month3 months6 months1 year Sort by AuthorPost 
timeSubject AscendingDescending          Page 1 of 1
   [ 4 posts ]      
-- 
Over 1500 classes with 29000 functions in one REALbasic plug-in collection. 
The Monkeybread Software Realbasic Plugin v9.3. 
http://www.monkeybreadsoftware.de/realbasic/plugins.shtml

[email protected]

Reply via email to