Re: event before autoredraw
- From: "Mike Williams" <Mike@xxxxxxxxxxxxxxxxx>
- Date: Mon, 1 Aug 2005 00:50:34 +0100
"Markus" <maka3@xxxxxxxxxxx> wrote in message
news:1122836454.661759.110540@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
> Hi, Thanks for your answer. Now I will exactly explain what I want
> to do :-) Drawing to the Picturebox takes place in a C-DLL, which
> receives the DC of the PictureBox. There, amongst others, I change
> the viewport of the DC with SetViewPortOrgEx. Unfortunately Visual
> Basic displays the drawing displaced. I suspect that the problem
> lies in the BitBlt function, probably called automatically by VB,
> wich takes the wrong source position. I want to set the the viewport
> back to 0/0 before VB paints and afterwards back to the original value.
The plot thickens! As is usual in these cases, it isn't easy to see exactly
what you are doing without seeing your code. Perhaps you can post it here.
Mind you, you would then have to give me your C DLL (which you might not
want to do). I don't actually program in C, so giving me a sample of your C
DLL source code wouldn't help I'm afraid.
I don't know what VB code you (or your users) are using to call your C DLL
but if, for example, you are setting the picture box Autoredraw to True
before calling your DLL (and presumably passing it the hDC property of the
picture box), nothing that your DLL draws to the hDC (presumably using the
various API drawing methods) will be displayed in the visible "on screen"
picture box until *after* the block of VB code that called your DLL has
finished executing, and even then it won't get displayed until something
triggers a "Refresh" (perhaps a VB drawing instruction or a Cls or whatever
(that might reside anywhere in the code block or that might be in some code
block that is run afterwards). By this time (of course) your DLL call will
have done its job and you will (presumably) have set the viewport back to
0/0. Perhaps you would like to explain exactly what job your DLL is doing,
and exactly how it is typically called in the VB code that uses it. Maybe
then I might be in a position to help you further.
I'm still a bit confused about your specific problem, but perhaps if I give
you a quick run through of "what happens in these cases" it might just
trigger something in your mind that you have perhaps forgotten to do . . .
The SetViewPointOrgEx API function that you are using (as I'm sure you
already know) is the equivalent of the VB ScaleLeft and ScaleTop properties,
and they both set the coordinates of the "drawing origin" within a Picture
Box. The only difference is that the VB ScaleLeft and ScaleTop properties
use the current ScaleMode setting, whereas the SetViewPointOrgEx (in common
with most other API drawing functions) by default always uses pixels
(MM_TEXT), unless you have changed this setting with the SetMapMode API.
Also (and this is quite possibly the source of your problem) Visual Basic
does *not* work in the way that someone used to using the API might expect
it to work. For example, Visual Basic (under the hood) *always* uses a
MapMode of pixels (MM_TEXT), regardless of what you set the ScaleMode
property to. Instead of changing the MapMode, it simply sets it to Pixels
and then performs the necessary conversion of your VB drawing function
parameters and converts those values from the current "ScaleMode" to "pixel"
values before finally calling the appropriate API drawing function. This is
not an oversight on the part of the people who wrote VB. In fact it is quite
deliberate, and it is done this way so as to allow the VB programmer to set
his ScaleMode to whatever units he wishes *and* to enable him to use
floating point values for his drawing coordinates (something which most API
routines do not allow, because most of them can use only integer values for
the drawing parameters). A similar thing happens with the ScaleLeft and
ScaleTop properties. Changing the VB ScaleLeft property, for example, does
*not* change the underlying API origin (SetViewPortOrgEx). It leaves those
values at zero, and VB performs the necessary conversion on your VB drawing
function parameters before passing them to the appropriate API drawing
routine. So you've got to be a bit careful. Basically, in order to ensure
that you get the desired result in any code (or DLL) that changes any of
these things before it draws something then you *must* ensure that you set
them all back to their original conditions *before* your code (or DLL)
returns control to VB, and specifically before any code that generates a
Refresh, otherwise you will get unexpected results.
For example, suppose you are using the standard pixels mode in a VB
Autoredraw picture box and you use the SetViewportOrgEx API to set the
drawing origin to location 80, 30. If you then use the SetPixel API to draw
a single dot at location (10, 20) the result will be a dot at the "real"
location of (90, 50). This, of course, will be drawn into the hidden picture
box Autoredraw Image in memory, and *not* to the screen display of the
picture box. The next time something happens that causes VB to "Refresh" the
picture box (a Cls or any VB drawing method that is either in the "queue" in
your code block or performed at a later stage, for example) then VB will
transfer the Image from the hidden Autoredraw memory block to the picture
box as it is visible on the screen. That hidden Autoredraw Image will, of
course, contain a single dot at pixel location (90, 50), and if the "API
origin" of the Autoredraw picture box is where VB expects it to be (location
0, 0) then the "screen copy" of the picture box will be updated correctly,
and the dot on the screen picture box will also be at pixel location (90,
50). However, if the "API origin" of the picture box has been changed to
something other than (0, 0) then VB will dump the Autoredraw Image into the
wrong place in the "on screen" picture box. So, before your C DLL returns
control to VB it *must* set the origin of the picture box back to (0, 0), or
more explicitly, it must set it to "whatever values it had before".
I've got to say that I'm gettin' a little bit drunk now! I've had a few
glasses of Lambs Navy rum (with Coke® of course!) and now I'm finishing off
these last two cans of Budweiser, so maybe it's time for a little code
sample (before I fall asleep!). Here's something that I prepared earlier (as
they say in all the best cookery programs on TV!) . . .
Option Explicit
Private Declare Function SetViewportOrgEx Lib "gdi32" _
(ByVal hdc As Long, ByVal nX As Long, _
ByVal nY As Long, lpPoint As POINTAPI) As Long
Private Type POINTAPI
x As Long
y As Long
End Type
Private Declare Function SetPixel Lib "gdi32" _
(ByVal hdc As Long, _
ByVal x As Long, ByVal y As Long, _
ByVal crColor As Long) As Long
Private Sub Command2_Click()
Dim OldOrg As POINTAPI
Picture1.ScaleMode = vbPixels
Picture1.AutoRedraw = True
SetViewportOrgEx Picture1.hdc, 80, 30, OldOrg
SetPixel Picture1.hdc, 10, 20, vbRed
' try commenting out the following line
SetViewportOrgEx Picture1.hdc, OldOrg.x, OldOrg.y, OldOrg
'
Picture1.Refresh
End Sub
Run the code as it stands (on a VB Form containing one picture box and one
command button). You should find that the dot drawn at location (90, 50) by
the combination of the first SetViewportOrgEx line and the SetPixel line
gets transferred correctly to the visible "on screen" picture box by the
"Picture1.Refresh" line (so that on the screen a dot appears in the visible
picture box at location 90, 50). This is exactly where the dot should be,
because the first SetViewportOrgEx line changed the origin to location (80,
30) and the SetPixel line drew a dot at an offset of 10, 20 from that
position (the SetViewportOrgEx and the SetPixel lines simulate the kind of
thing that might be happenning in your own C DLL).
Now try commenting out the second SetViewportOrgEx line (so that the origin
does not get restored to the state that VB expects it to be) and you'll see
the difference. In this case the dot gets drawn to the "on screen" picture
box at location 10, 20 (exactly where it would have been if your C DLL had
not altered the origin in the first place).
The lesson here is to ensure that if you change anything about the Picture
Box in your DLL you should ensure that you change it back to its original
condition *before* your DLL code returns control to VB.
Does any of this stuff help you? If not, then post again.
Mike
.
- References:
- event before autoredraw
- From: Markus
- Re: event before autoredraw
- From: Mike Williams
- Re: event before autoredraw
- From: Markus
- event before autoredraw
- Prev by Date: How to disable the double click event (DlbClick) of a ListView
- Next by Date: Re: Sending message to a broswer window
- Previous by thread: Re: event before autoredraw
- Next by thread: Re: event before autoredraw
- Index(es):
Loading