From: Mike Williams on

"Andrew Elder" <aelder(a)melbpc.org.au> wrote in message
news:uJ8Y6cc3KHA.1452(a)TK2MSFTNGP06.phx.gbl...

> I cured the first problem [Command Buttons inside a Frame
> disappearing] by setting the Clipcontrols for the Frame to False.

That's why I mentioned ClipControls in my previous response. There are all
sorts of possibilities and you might, for example, have had the Form's
ClipControls set to False and the Frame's ClipControls set to True, which
definitely causes incorrect painting and which is a condition that is
specifically mentioned in the help files. Setting the Frame's ClipControls
to False in that case does usually fix the problem, but unless you have a
very specific reason for having the Form's ClipControl's property set to
False (which is very rarely a requirement on modern machines) then the best
thing is to set them both to True, which is the default and which also fixes
the problem.

> I still do not fully understand what this does, despite reading
> the help several time, but it seems to have fixed this one!

The ClipControls property does a couple of important things, but the main
thing it does when set to True on a specific object (the default setting) is
that it creates a drawing region for that object which contains "rectangular
clipping holes" in all the places where contained controls (Command Buttons,
Text Boxes, etc) are placed within it. This prevents any drawing methods or
Cls method (where applicable) from drawing or painting over any of those
Controls. This of course means that your own drawings will not overwrite any
such contained controls (if you or VB happen to draw in those places) and it
also means that after performing a Cls then VB does not need to redraw any
of the contained controls (Command Buttons Text Boxes or whatever) because
the "ClipControls True" prevented Cls from painting over them in the first
place, whereas if ClipControls is False then a VB Cls method will "clear"
the Form completely, painting over its contained controls as well and
causing them to disappear, and then the VB Cls method will immediately and
automatically redraw those controls that it painted over. This redrawing of
the painted over controls goes wrong if, for example, you have ClipControls
False on the Form and True on the Frame.

To see what difference ClipControls makes as far as drawing methods (lines,
circles, paintpicture, etc) are concerned try the following code in a Form
containing lots of different controls including one Frame control that
itself has lots of contained controls. First set the ClipControls property
of both the Form and the Frame to True in the IDE (the default setting) and
run the program and click one or other (or both) of the two buttons (the
ones with bold captions on them). Then come back to the IDE and set either
the Form or the Frame (or both) ClipControls property to False and run it
again:

Mike

Option Explicit
Private Declare Function GetDC Lib "user32" _
(ByVal hwnd As Long) As Long
Private Declare Function LineTo Lib "gdi32" _
(ByVal hdc As Long, ByVal x As Long, _
ByVal y As Long) As Long

Private Sub Form_Load()
Command1.Font.Bold = True
Command2.Font.Bold = True
Command1.Caption = "Draw Lines in Frame"
Command2.Caption = "Draw Lines in Form"
End Sub

Private Sub Command1_Click()
Dim n As Long, DC As Long
Me.ScaleMode = vbPixels
DC = GetDC(Frame1.hwnd)
For n = 1 To 20
LineTo DC, Rnd * Frame1.Width, Rnd * Frame1.Height
Next n
End Sub

Private Sub Command2_Click()
Dim n As Long
Me.ScaleMode = vbPixels
Me.ForeColor = vbBlue
For n = 1 To 20
LineTo Me.hdc, Rnd * ScaleWidth, Rnd * ScaleHeight
Next n
End Sub


From: Mike Williams on
"Andrew Elder" <aelder(a)melbpc.org.au> wrote in message
news:uJ8Y6cc3KHA.1452(a)TK2MSFTNGP06.phx.gbl...

> The second problem [a PictureBox problem] "just got better"!
> I was tesing various combinations of Clipcontrols and Autoredraw,
> and it all started to work properly again . . so I am happy. But,
> I don't fully understand what I did to fix it, so I am not happy!

Autoredraw, as you probably already know, causes your drawing to become
"automatically persistent" because your drawing goes into a memory bitmap
which VB then draws into the visible PictureBox whenever it needs to do so.
The only "rider" to this is that if you draw into an Autoredraw PicBox using
/only/ GDI methods (as opposed to native VB drawing methods) then VB does
not know you have drawn anything into its memory bitmap and so it will not
perform its otherwise automatic update of the displayed PictureBox. So,
whenever you do draw into it using only GDI methods you need to "tell the
PictureBox you have drawn something", either by using a PicBox.Refresh or by
using one of its native VB drawing methods. Autoredraw being True also stops
the PictureBox Paint event from firing, so if you have drawing code in its
Paint event it will not execute whilst Autoredraw is True. One other thing
is that the VB Autoredraw mechanism redraws /only/ those parts of the
PictureBox that actually need redrawing (the usually very narrow band that
for example might have otherwise been "wiped" at each mouse movement when
dragging the PicBox on and off the edge of the display). This is almost
never a problem because it is in fact the only portion that needs redrawing,
but it is worth bearing in mind if you are ever doing anything a bit unusual
with the PictureBox for some reason.

Also, regarding the ClipControls property, the other important thing which
ClipControls does (referring to my mention of "a couple of important things"
in my previous response) is that it changes the behaviour of the Paint event
in a non-Autoredraw PictureBox. When ClipControls is True (the default
setting) then the Paint event (each time it fires) peforms whatever drawing
code you have placed into it without performing any clipping, so that if
your drawing code fills the PictureBox with a graph or whatever then the
entire graph will be drawn at each Paint event. On the other hand, when
ClipControls is False then the Paint event sets up a clipping region which
encompasses only the part of the PictureBox that actually currently needs
redrawing (for example the narrow band of it that has just been moved off
the edge of the display and back again). This often (but not always) means
that the redraw is performed faster, because instead of the entire drawing
being done only part of its has actually been drawn, with the rest being
"clipped". As far as the "persistence" of the drawing (your graph or
whatever) is concerned there is usually no visible difference between the
two (ClipControls True or False) because in a lot of cases your Paint event
code is simply reedrawing the same graph. The only difference in such cases
is the speed of the redrawing. To see what I mean as far as the visible
aspect is concerned try the following code which has been written
specifically so that you can see the difference between ClipControls True
and False, because instead of drawing the same drawing each time in the
Paint event it draws a randomly placed selection of dots, which of course
will be a different dot pattern each time.

If you run the code as it stands (with ClipControls being set to True, the
default setting) you will see a random pattern of dots in the PictureBox. If
you then move the Form so that an edge of the PictureBox goes on and off the
screen you will see that the Paint event each time draws another random
pattern of dots. The small band of the PictureBox that was "wiped" by going
on and off the edge of the screen will contain just one pattern of dots
(replacing the pattern that was "wiped" in that area) but the rest of the
PictureBox will have both the old pattern of dots and the newly drawn
pattern of dots as well, becoming slightly darker each time.

Now change the code so that ClipControls is False and try the same thing,
moving the Form so that an edge of the pictureBox goes on and off the screen
as before. This time it will be obvious that even though the drawing code
was attempting to draw the pattern of dots over the whole PictureBox, the
only the part of that drawing which was actually drawn is the part that
"needed redrawing because it had been wiped", with the rest of the drawing
not being done because it was "clipped".

So, as should now be apparent, the many different combinations of Autoredraw
and ClipControls on your Form and your PictureBoxes (and to an extent on
your Frames) can cause your program to behave in a number of different ways
under various different circumstances, and many of the things that people
say are apparently "random behaviour" are not random at all, although having
said that, there will always be the odd occasion when something you have
done (or something VB has done) has caused VB itself to get confused, and in
some cases rebuilding (or even just partially rebuilding and recompiling)
you app can sometimes fix some things ;-)

By the way, I've used the Line method in the following code to draw each dot
rather than the PSet method because Vista has a bug when it is not running
its Aero desktop which causes both VB Pset and GDI SetPixel fail to draw the
dot whenever bit 8 is set in the X coordinate. That's something else you
would be wise to remember whenever you need to draw individual dots.

Mike

Option Explicit
Private Sub Form_Load()
Picture1.AutoRedraw = False
Picture1.ClipControls = True
End Sub

Private Sub Picture1_Paint()
Picture1.ScaleMode = vbPixels
Dim n As Long, x As Long, y As Long
For n = 1 To 1000
x = Rnd * Picture1.ScaleWidth
y = Rnd * Picture1.ScaleHeight
Picture1.Line (x, y)-(x + 1, y)
Next n
End Sub