From: Dee Earley on
On 25/11/2009 04:30, Webbiz wrote:
> On Tue, 24 Nov 2009 13:02:22 +0000, Dee Earley
> <dee.earley(a)icode.co.uk> wrote:
>> Even with this, I was getting some flickering as VB insisted on
>> redrawing some parts of the screen in WM_PAINT before firing the Paint
>> event, despite me eating the WM_ERASEBACKGROUND message.
>>
>> I ended up handling WM_PAINT myself then passing direct to the paint event:
>> Case WM_PAINT
>> 'We handle WM_PAINT ourselves as VB6 seems to explicitly draw the
>> background in its handler
>> hDC = BeginPaint(hWnd, PaintInfo)
>> GraphFrame_Paint
>> EndPaint hWnd, PaintInfo
>> 'We've handled it so VB doesn't do anything further
>> SubClassed_WindowProc = 0
>> Handled = True
>
>
> Forgive my inexperience, but exactly where did you place this
> Select...Case code?

It's in a subclass handler for the picturebox.
Exactly where/how you use it depends on the sub class handler you're using.

--
Dee Earley (dee.earley(a)icode.co.uk)
i-Catcher Development Team

iCode Systems
From: Mike Williams on
"Webbiz" <nospam(a)forme.thanks.com> wrote in message
news:q97pg5h5kfp2q0s1168mbabi9os593ng55(a)4ax.com...

> So if I undertand correctly, I should replace the picturebox
> being referenced by my current drawing code to one that is
> not visible and has Autoredraw = true, correct?
> And then, when the drawing is completed, have it sent to
> the picture box I'm currently using.
> Is that right?

You could do it that way if you wish to, but you don't actually need to use
a separate PictureBox. Using just one PictureBox will be fine (subject to
certain limitations). The important thing is that you create your drawing in
a non visible memory bitmap and then transfer the bitmap to the display only
when the drawing is fully complete.

This is possible using just a single Autoredraw PictureBox because all
drawings using either native VB drawing methods or API drawing methods are
drawn into the hidden memory bitmap of an Autoredraw PictureBox. If you're
using only API drawing methods on the PictureBox then the finished drawing
will never be sent from the hidden memory bitmap into the "screen presence"
of the PictureBox until you do something to specifically cause it to do so
(using Picture1.Refresh is the standard way of doing this, and so you should
use Picture1.Refresh as soon as your API drawing code has fully finished the
drawing).

However, if your drawing code uses any native VB drawing methods on the
Autoredraw PictureBox (Picture1.Line etc) then each of those methods will
effectively tell the PictureBox to Refresh itself (tell it to transfer the
hidden memory bitmap into its screen presence) as soon as it gets the chance
to do so. As it happens, the "Refresh when you get the chance" message
simply ends up sitting in a queue whilst your code is actually running, and
so the message will not be actioned until your drawing code finishes, at
which point the completed drawing will be sent to the "screen presence" of
the PictureBox, giving exactly the same results as the "API only drawing"
outlines above, but without you needing to explicity issue a
Picture1.Refresh at the end of your drawing code. This is fine, but there
are things that can upset it. For example, if anywhere in your drawing code
there is a DoEvents statement then the "queued PictureBox Refresh" message
will be actioned by the DoEvents, which is not what you want because your
drawing code has not yet finished the drawing.

By the way, in Vista drawing into an Autoredraw PictureBox (or into any
other similar memory DC) is generally faster than the same drawing into a
non Autoredraw PictureBox (directly to the display), so you should see an
increase in speed even though it takes a little time at the end for the
Refresh to occur. Also, in Vista using the FillRect API to draw vertical or
horizontal lines of more than one pixel thickness is faster than either the
API LineTo or the VB Line method (using either one two-pixel thick line or
more than one single pixel thick lines) and when drawing into an Autoredraw
PictureBox the speed advantage of FillRect is even more pronounced. To give
you an idea of the difference, here are the results of some tests I've just
carried out which draws a lot of long vertical and horizontal two pixel
thick lines (although I've only tried it on this one specific Vista machine
at the moment):

NON Autoredraw PictureBox:
VB Line / API LineTo method: 7.6 to 9.6 milliseconds (Aero / Not Aero)
API FillRect method: 5.5 to 3.3 milliseconds (Aeor / Not
Aero)

Autoredraw PictureBox:
VB Line / API LineTo method: 5.7 to 5.7 milliseconds (Aero / Not Aero)
API FillRect method: 1.6 to 1.5 milliseconds (Aeor / Not
Aero)

As you can see, FillRect into an Autoredraw PictureBox (on this specific
Vista machine) is about 5 times faster than the VB Line / API LineTo method
into a non Autoredraw PictureBox.

Mike



From: Mike Williams on
"Webbiz" <nospam(a)forme.thanks.com> wrote in message
news:vkcpg5h1pp45tc0daljhgtsuqfuec7ti36(a)4ax.com...
>> On Tue, 24 Nov 2009 13:02:22 +0000, Dee Earley
>> <dee.earley(a)icode.co.uk> wrote:
>> Even with this, I was getting some flickering as VB insisted on
>> redrawing some parts of the screen in WM_PAINT before
>> firing the Paint event . . . I ended up handling WM_PAINT
>> myself then passing direct to the paint event:
>> Case WM_PAINT
>> hDC = BeginPaint(hWnd, PaintInfo)
>> . . . etc
>
> Forgive my inexperience, but exactly where did you
> place this Select...Case code?

Don't worry too much about that, Webbiz. I think Dee was deliberately being
a little bit obtuse when she told you to just place it in your subclass
handler . . . but then that's what you can expect of Londoners ;-) (Sorry,
Dee, just a little Scouse joke!).

I think Dee was referring to problems she needed to solve in certain
circumstances concerning drawings in the PictureBox (or Form) Paint event,
which fires /after/ VB has itself dealt with the system WM_PAINT event, and
/after/ VB has effectively cleared out the "dirty rectangle" information,
which can then not effectively be read in the VB Paint event, even if you
use the GetUpdateRect API. This can result in any VB Paint event drawing
causing some flicker if for some reason you perform a Cls or clear an area
as part of a transparent blit or whatever during your drawing, because your
drawing is not clipped to the "dirty rectangle" and fills parts of the
PictureBox (or Form) other than the parts that actually required painting
(the usually very small "dirty rectangle" for example as a user drags a Form
off the edges of the display and back again). Subclassing the WM_PAINT
(which effectively means "getting at it" at a fairly low level and before
the VB Paint event fires, and whilst the "dirty rectangle" information is
still available and valid, enables you to do things that you could not
otherwise do.

This should not be a problem in your own code though, and should not be
required, because I assume you will be using an Autoredraw PictureBox, and
VB Paint events do not actually fire in a PictureBox whilst Autoredraw is
True (although the lower level WM_PAINT events still fires of course, and is
handled by VB itself). In an Autoredraw PictureBox VB very effectively
handles the redrawing of the "dirty rectangle" for you in the WM_PAINT event
as the user moves the Form (PictureBox) on and off the edges of the display,
and in other circumstances. VB is quite good at this, painting /only/ the
required dirty rectangle from the contents of the hidden Autoredraw memory
bitmap (the Autoredraw bitmap that I mentioned in my previous response), so
as far as maintaining the contents of the PictureBox as the user drags the
Form on and off the edges of the display (and other things) you can
effectively forget all about it when using an Autoredraw PictureBox and
simply let the VB Autoredraw mechanism get on with the job for you.

The only thing you need to concern yourself with is the initial drawing of
the new PictureBox contents each time the user uses the scroll bar (or arrow
keys or whatever) to require a different part of your stock and share data
to be drawn, which is something I covered in my previous response,.

Mike



From: Dee Earley on
On 25/11/2009 22:27, Mike Williams wrote:
> "Webbiz" <nospam(a)forme.thanks.com> wrote in message
> news:vkcpg5h1pp45tc0daljhgtsuqfuec7ti36(a)4ax.com...
>>> On Tue, 24 Nov 2009 13:02:22 +0000, Dee Earley
>>> <dee.earley(a)icode.co.uk> wrote:
>>> Even with this, I was getting some flickering as VB insisted on
>>> redrawing some parts of the screen in WM_PAINT before
>>> firing the Paint event . . . I ended up handling WM_PAINT
>>> myself then passing direct to the paint event:
>>> Case WM_PAINT
>>> hDC = BeginPaint(hWnd, PaintInfo)
>>> . . . etc
>>
>> Forgive my inexperience, but exactly where did you
>> place this Select...Case code?
>
> Don't worry too much about that, Webbiz. I think Dee was deliberately
> being a little bit obtuse when she told you to just place it in your
> subclass handler . . . but then that's what you can expect of Londoners
> ;-) (Sorry, Dee, just a little Scouse joke!).

Londoner!!
I'm from further south than that :)

> I think Dee was referring to problems she needed to solve in certain
> circumstances concerning drawings in the PictureBox (or Form) Paint
> event, which fires /after/ VB has itself dealt with the system WM_PAINT
> event, and /after/ VB has effectively cleared out the "dirty rectangle"
> information, which can then not effectively be read in the VB Paint
> event, even if you use the GetUpdateRect API.

I seemed to get this even when redrawing quickly when I tried to draw
things the "Windows" way.

I was invalidating the rect when I knew there was an update, then left
it up to windows to tell me when it needed to redraw (the windows
weren't always visible)

As for using AutoRedraw, I'd forgotton about it as I stopped using it
long ago as a lot of the data we rendered was "live" or at least
frequently updating and wanted to improve performance.

--
Dee Earley (dee.earley(a)icode.co.uk)
i-Catcher Development Team

iCode Systems
From: Webbiz on
On Wed, 25 Nov 2009 11:41:50 -0000, "Mike Williams"
<Mike(a)WhiskyAndCoke.com> wrote:

>"Webbiz" <nospam(a)forme.thanks.com> wrote in message
>news:q97pg5h5kfp2q0s1168mbabi9os593ng55(a)4ax.com...
>
>> So if I undertand correctly, I should replace the picturebox
>> being referenced by my current drawing code to one that is
>> not visible and has Autoredraw = true, correct?
>> And then, when the drawing is completed, have it sent to
>> the picture box I'm currently using.
>> Is that right?
>
>You could do it that way if you wish to, but you don't actually need to use
>a separate PictureBox. Using just one PictureBox will be fine (subject to
>certain limitations). The important thing is that you create your drawing in
>a non visible memory bitmap and then transfer the bitmap to the display only
>when the drawing is fully complete.
>
>This is possible using just a single Autoredraw PictureBox because all
>drawings using either native VB drawing methods or API drawing methods are
>drawn into the hidden memory bitmap of an Autoredraw PictureBox. If you're
>using only API drawing methods on the PictureBox then the finished drawing
>will never be sent from the hidden memory bitmap into the "screen presence"
>of the PictureBox until you do something to specifically cause it to do so
>(using Picture1.Refresh is the standard way of doing this, and so you should
>use Picture1.Refresh as soon as your API drawing code has fully finished the
>drawing).
>
>However, if your drawing code uses any native VB drawing methods on the
>Autoredraw PictureBox (Picture1.Line etc) then each of those methods will
>effectively tell the PictureBox to Refresh itself (tell it to transfer the
>hidden memory bitmap into its screen presence) as soon as it gets the chance
>to do so. As it happens, the "Refresh when you get the chance" message
>simply ends up sitting in a queue whilst your code is actually running, and
>so the message will not be actioned until your drawing code finishes, at
>which point the completed drawing will be sent to the "screen presence" of
>the PictureBox, giving exactly the same results as the "API only drawing"
>outlines above, but without you needing to explicity issue a
>Picture1.Refresh at the end of your drawing code. This is fine, but there
>are things that can upset it. For example, if anywhere in your drawing code
>there is a DoEvents statement then the "queued PictureBox Refresh" message
>will be actioned by the DoEvents, which is not what you want because your
>drawing code has not yet finished the drawing.
>
>By the way, in Vista drawing into an Autoredraw PictureBox (or into any
>other similar memory DC) is generally faster than the same drawing into a
>non Autoredraw PictureBox (directly to the display), so you should see an
>increase in speed even though it takes a little time at the end for the
>Refresh to occur. Also, in Vista using the FillRect API to draw vertical or
>horizontal lines of more than one pixel thickness is faster than either the
>API LineTo or the VB Line method (using either one two-pixel thick line or
>more than one single pixel thick lines) and when drawing into an Autoredraw
>PictureBox the speed advantage of FillRect is even more pronounced. To give
>you an idea of the difference, here are the results of some tests I've just
>carried out which draws a lot of long vertical and horizontal two pixel
>thick lines (although I've only tried it on this one specific Vista machine
>at the moment):
>
>NON Autoredraw PictureBox:
>VB Line / API LineTo method: 7.6 to 9.6 milliseconds (Aero / Not Aero)
>API FillRect method: 5.5 to 3.3 milliseconds (Aeor / Not
>Aero)
>
>Autoredraw PictureBox:
>VB Line / API LineTo method: 5.7 to 5.7 milliseconds (Aero / Not Aero)
>API FillRect method: 1.6 to 1.5 milliseconds (Aeor / Not
>Aero)
>
>As you can see, FillRect into an Autoredraw PictureBox (on this specific
>Vista machine) is about 5 times faster than the VB Line / API LineTo method
>into a non Autoredraw PictureBox.
>
>Mike
>
>


Hello Mike.

Here is a section of my 'current' code that draws a bar chart using
the .Line method.

==========

For i = gFirstBarRecNum To gLastBarRecNum

If i > 1 Then
If MarketData(i - 1).TTCLow <> 0 Then
sngLastLow = MarketData(i - 1).TTCLow
sngLastHigh = MarketData(i - 1).TTCHigh
End If
End If

If MarketData(i).TTCHigh <> 0 And MarketData(i).TTCLow <> 0 Then
dblLowPoint = frmChart.pctChart.ScaleHeight -
((MarketData(i).TTCLow - gMinValue) * sngInterval)
dblHighPoint = frmChart.pctChart.ScaleHeight -
((MarketData(i).TTCHigh - gMinValue) * sngInterval)
dblOpenPoint = frmChart.pctChart.ScaleHeight -
((MarketData(i).TTCOpen - gMinValue) * sngInterval)
dblClosePoint = frmChart.pctChart.ScaleHeight -
((MarketData(i).TTCClose - gMinValue) * sngInterval)

If dblHighPoint < -300000 Or dblLowPoint > 300000 Then: Exit
Sub

'we now draw the bar lines using the info we just calculated
for the bar
'each bar is separated horizontally by gHSpace in screen
coordinates
'last two lines draw the Open and Close horizontal lines with
different colors
If giChartType = ColorBars And i > 1 Then
If MarketData(i).TTCHigh > sngLastHigh And
MarketData(i).TTCLow >= sngLastLow Then
lngColor = Green
ElseIf MarketData(i).TTCLow < sngLastLow And
MarketData(i).TTCHigh <= sngLastHigh Then
lngColor = Red
ElseIf MarketData(i).TTCHigh > sngLastHigh And
MarketData(i).TTCLow < sngLastLow Then
lngColor = Blue
Else
lngColor = BLACK 'inside bar
End If
Else
lngColor = BLACK
End If

'Draw the main bar
frmChart.pctChart.Line ((i - (gFirstBarRecNum)) * gHSpace,
dblLowPoint)-((i - (gFirstBarRecNum)) * gHSpace, dblHighPoint),
lngColor

frmChart.pctChart.Line ((i - (gFirstBarRecNum)) * gHSpace,
dblOpenPoint)-(((i - (gFirstBarRecNum)) * gHSpace) - Int(gHSpace / 2),
dblOpenPoint), lngColor
frmChart.pctChart.Line ((i - (gFirstBarRecNum)) * gHSpace,
dblClosePoint)-(((i - (gFirstBarRecNum)) * gHSpace) + Int(gHSpace /
2), dblClosePoint), lngColor
End If


Next i


=============

When you discussed the thinkness of the line being more than 1 pixel,
I suppose you are referring to when my app sets the DrawWidth > 1,
right?

Let's take one of these line draws as an example.

'Draw the main vertical bar
frmChart.pctChart.Line ((i - (gFirstBarRecNum)) * gHSpace,
dblLowPoint)-((i - (gFirstBarRecNum)) * gHSpace, dblHighPoint),
lngColor

Break it down to...

X1 = (i - (gFirstBarRecNum)) * gHSpace
Y1 = dblLowPoint
X2 = ((i - (gFirstBarRecNum)) * gHSpace) - Int(gHSpace / 2)
Y2 = dblHighPoint

frmChart.pctChartLine (X1, Y1) - (X2, Y2)

If I were to replace the above line with the FillRect API code, what
would be the approach? This ...

Dim r as RECT
Dim retval as Long
Dim brush as Long

' Set the coordinates of the bar/rectangle
retval = SetRect(r, X1, Y1, X2, Y2)
brush = CreateSolidBrush(lngColor)

retval = FillRect(frmChart.pctChart.hDC, r, brush)


I would assume that the 'brush' is set once if all the bars will have
the same color. Then for every .Line code, replace it with two lines,
the SetRect and FillRect lines.

Does that fit what you are suggesting?

Thanks.

Webbiz
First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9
Prev: Snapshot of screen
Next: HTTPS File Uploads