For Programmers: Free Programming Magazines  


Home > Archive > Visual Basic > April 2006 > drawings









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author drawings
petehill789@yahoo.co.uk

2006-04-30, 6:56 pm

I am drawing plans (gardens, kitchens and things) into a picture box
and I would like to change from using normal VB methods to using API
methods so that I can gain some speed. The problem is that I use my own
scale in the picture box so that I can draw the same design into it
whatever size it happens to be, but the API only works in pixels and I
am having some problems converting. Has anyone done this before?

Pete

Mike Williams

2006-04-30, 6:56 pm

<petehill789@yahoo.co.uk> wrote in message
news:1146424761.885974.291020@e56g2000cwe.googlegroups.com...

> . . . The problem is that I use my own scale in the picture
> box so that I can draw the same design into it whatever
> size it happens to be, but the API only works in pixels
> and I am having some problems converting. Has anyone
> done this before?


Actually the conversion is quite simple. In fact the VB ScaleX and ScaleY
methods will do it all for you:

x2 = Me.ScaleX(x1, Me.ScaleMode, vbPixels)

In the above code, x1 is the value you wish to convert and x2 is the
equivalent value in pixels. It will work whatever VB ScalMode you use,
including "User". However, rather than doing the conversion for all of your
drawing coordinates you can instead set up your picture box so that is uses
the API equivalent of a VB User Scalemode.

Many VB programmers mistakenly believe that if you draw using the various
API functions you can use only pixels, but in fact the API routines can use
a number of different modes. The available modes are as follows:



MM_TEXT device pixels

MM_LOENGLISH 0.01 inches

MM_HIENGLISH 0.001 inches

MM_LOMETRIC 0.01 centimetres

MM_HIMETRIC 0.001 centimetres

MM_TWIPS 1/1440 inch

MM_ANISOTROPIC similar to VB User ScaleMode

MM_ISOTROPIC same, but x and y units are identical



Visual Basic itself always uses MM_TEXT mode (device pixels), regardless of
the VB ScaleMode you use, and it handles your choice of VB Scalemode by
performing "under the hood" conversions of your coordinates from the chosen
VB ScaleMode to device pixels before passing the appropriate pixel values
onto the API routines it uses.



If you're using the API for your drawings you can set the "API ScaleMode" to
any of the available modes, including "User" (or MM_ANISOTROPIC). However,
when you use the API graphic routines instead of the VB routines for drawing
then you can use only whole numbers for the coordinates, because you can
only use Longs for the various API drawing functions (whereas VB allows you
to use floating point values) so you need to choose your units with a bit of
care. For example, if you have a VB picture box that you set to a VB "User
ScaeMode" size of 100 x 60 units you can use floating point coordinates to
draw anywhere you want in that picture box (and VB will draw it at the
nearest whole pixel position). However, if you used the same values (100 x
60 units) for the "API Scale Mode" you would be restricted to whole numbers
(Longs) for your coordinates, which would limit you somewhat in your
positioning. So, when setting up your picture box to an API User Mode you
would be wise to use 10000 x 6000 units (instead of 100 x 60) and that would
allow you to specify coordinates with just as much accuracy as you can with
the VB User Scale Mode.



One other point to be aware of (which can easily confuse you unless you know
about it) is the fact that only the modes MM_TEXT, MM_ANISOTROPIC and
MM_ISOTROPIC behave in the same way as VB with respect to the x and y axis
(with positive x coordinates moving towards the right and positive y
coordinates moving downwards). The other settings reverse the y axis and
cause positive y coordinates to move upwards from the origin).



Anyway, here is some sample code to show you how to use both pixel and User
scale modes with both the standard VB drawing methods and with the
alternative API drawing methods. I've put plenty of comments in the code to
explain what is going on. To try it, start a new VB project and place one
picture box and four command buttons on your Form. Then paste in the
following code, making sure it completely replaces any snippets of code that
VB may have already placed there for you.



Mike



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 Declare Function GetMapMode Lib "gdi32" _
(ByVal hdc As Long) As Long
Private Declare Function GetViewportExtEx Lib "gdi32" _
(ByVal hdc As Long, lpSize As POINTAPI) As Long
Private Declare Function GetWindowExtEx Lib "gdi32" _
(ByVal hdc As Long, lpSize As POINTAPI) As Long
Private Declare Function SetMapMode Lib "gdi32" _
(ByVal hdc As Long, ByVal nMapMode As Long) As Long
Private Declare Function SetViewportExtEx Lib "gdi32" _
(ByVal hdc As Long, ByVal nX As Long, _
ByVal nY As Long, lpSize As Any) As Long
Private Declare Function SetWindowExtEx Lib "gdi32" _
(ByVal hdc As Long, ByVal nX As Long, _
ByVal nY As Long, lpSize As Any) As Long
Private Declare Function GetClientRect Lib "user32" _
(ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function LineTo Lib "gdi32" _
(ByVal hdc As Long, ByVal x As Long, ByVal y As Long) _
As Long
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type POINTAPI
x As Long
y As Long
End Type
Private Const MM_ANISOTROPIC = 8 'equiv of vbUser
Private Const MM_HIENGLISH = 5
Private Const MM_HIMETRIC = 3
Private Const MM_ISOTROPIC = 7
Private Const MM_LOENGLISH = 4
Private Const MM_LOMETRIC = 2
Private Const MM_TEXT = 1 'equiv of vbPixels
Private Const MM_TWIPS = 6 'equiv of vbTwips
Dim OldMapMode As Long
Dim OldWindowExt As POINTAPI
Dim OldViewport As POINTAPI
Dim OldOrg As POINTAPI
Dim Dummy As POINTAPI
Dim ClientRect As RECT

Private Sub Form_Load()
Dim y As Single
Command1.Caption = "API User Scale"
Command2.Caption = "API Pixel Scale"
Command3.Caption = "VB Pixel Scale"
Command4.Caption = "VB User Scale"
Picture1.Move 0, 0, Me.ScaleWidth, Me.ScaleHeight * 0.75
y = Me.ScaleHeight * 0.8
Command1.Move Command1.Width * 0.1, y
Command2.Move Command1.Left + Command1.Width * 1.1, y
Command3.Move Command2.Left + Command2.Width * 1.1, y
Command4.Move Command3.Left + Command3.Width * 1.1, y
End Sub

Private Sub Command1_Click()
' This code shows the API method in the MM_ANISOTROPIC
' MapMode (the equivalent of the VB User ScaleMode)
Dim n As Long, x As Long, y As Long
Dim widthscale As Long, heightscale As Long
' NOTE: The DrawWidth (line width) is also affected by
' the MapMode you use, so that if you use ANISOTROPIC
' (the equivalent of vbUser) and you SetWindowExtEx to
' a client area of (say) 10 x 10 units then the lowest
' possible line width (1) will be one tenth of the
' width (or height) of the window. Because of this, it
' is best use a user scale of (say) at least 2000 units
' so that on virtually all machines a line width of 1
' (the minimum available)will be "one two thousandth" of
' the width or height of the Form or picture box, making
' a line width of 1 pixel always available. So, if you
' want a picture box with a scale of (say) 60 units wide
' and 50 units deep you would be better off setting it to
' 6000 x 5000, or perhaps 60000 x 50000, so that you can
' position your stuff accurately. (Remember that, unlike the
' native VB ScaleMode, you can specify only integers (Longs)
' when passing values to the API drawing routines).
' NOTE: In Win95/98 the GDI is 16 bit and so even though
' you pass standard 32 bit Longs to the API drawing
' functions they in fact only look at the lower 16 bits.
' This means that you cannot have an API "User" scale of
' more than 32767.
' Further Note:
' If you change the "drawing origin" of a VB Autoredraw
' picture box to something other than the default (0, 0)
'(Not done here)it is important to reset the ViewPortOrgEx
' values and various other values to their default conditions
'(as this routine already does) otherwise every Refresh and
' Paint will cause the image to be incorrectly transferred
' from the Autoredraw device context to the "on screen"
' device context and the picture box will in general not be
' updated or redrawn properly.
' An alternative (not used here) is to set both the
' Autoredraw hDC *and* the Non Autoredraw hDC to the same
' ViewPortOrgEx values, so that both origins "match".
'
Picture1.AutoRedraw = True
Picture1.ForeColor = vbBlue
Picture1.Cls
' save existing mode
OldMapMode = GetMapMode(Me.hdc)
Call GetViewportExtEx(Me.hdc, OldViewport)
Call GetWindowExtEx(Me.hdc, OldWindowExt)
widthscale = 6000: heightscale = 5000
' change to new mode (in this case, vbUser) and set the
' equivalent of ScaleWidth to the value contained in the
' variable widthscale and the equivalent of ScaleHeight to
' the value contained in heightscale
Call GetClientRect(Picture1.hwnd, ClientRect) ' get size of
' picture box client area (always returned in pixels):
Call SetMapMode(Picture1.hdc, MM_ANISOTROPIC)
Call SetWindowExtEx(Picture1.hdc, widthscale, _
heightscale, ByVal 0&)
Call SetViewportExtEx(Picture1.hdc, ClientRect.Right, _
ClientRect.Bottom, ByVal 0&)
' set origin to 0, 0 (even though it probably is already
' set to that). Origin is the equivalent of VB ScaleLeft
' and ScaleTop and it is always in device units (pixels).
' You can set the origin to any point you want, and that
' point will be location (0, 0) for drawing purposes.
Call SetViewportOrgEx(Picture1.hdc, 0, 0, OldOrg)
' draw a line to the centre using the API
x = widthscale \ 2
y = heightscale \ 2
LineTo Picture1.hdc, x, y
' restore original values
Call SetMapMode(Picture1.hdc, OldMapMode)
Call SetViewportExtEx(Picture1.hdc, OldViewport.x, _
OldViewport.y, ByVal 0&)
Call SetWindowExtEx(Picture1.hdc, OldWindowExt.x, _
OldWindowExt.y, ByVal 0&)
Call SetViewportOrgEx(Picture1.hdc, OldOrg.x, OldOrg.y, Dummy)
'Picture1.Refresh
End Sub

Private Sub Command2_Click()
' This code shows the API method in the standard
' MM_Text ("pixels") MapMode ("ScaleMode"). It is not
' significantly faster than using the MM_ANISOTROPIC
' ("User") mode, so User mode (which is often the best
' mode to work in for various reasons) does not degrade
' performance significantly
Dim wide As Long, high As Long
Dim n As Long, x As Long, y As Long
Picture1.ScaleMode = vbPixels
Picture1.AutoRedraw = True
Picture1.ForeColor = vbRed
Picture1.Cls
wide = Picture1.ScaleWidth
high = Picture1.ScaleHeight
x = wide \ 2: y = high \ 2
LineTo Picture1.hdc, x, y
Picture1.Refresh
End Sub

Private Sub Command3_Click()
' This code show the VB method using vbPixels ScaleMode
Dim wide As Long, high As Long
Dim n As Long, x As Long, y As Long
Picture1.ScaleMode = vbPixels
Picture1.AutoRedraw = True
Picture1.ForeColor = vbMagenta
Picture1.Cls
wide = Picture1.ScaleWidth
high = Picture1.ScaleHeight
x = wide \ 2: y = high \ 2
Picture1.Line -(x, y)
Picture1.Refresh
End Sub

Private Sub Command4_Click()
' This code shows the VB methods using "User"
' ScaleMode
Dim wide As Long, high As Long
Dim n As Long, x As Long, y As Long
Picture1.ScaleMode = 0
Picture1.ScaleWidth = 5000
Picture1.ScaleHeight = 5000
Picture1.AutoRedraw = True
Picture1.ForeColor = vbGreen
Picture1.Cls
wide = Picture1.ScaleWidth
high = Picture1.ScaleHeight
x = wide \ 2: y = high \ 2
Picture1.Line -(x, y)
Picture1.Refresh
End Sub















Mike D Sutton

2006-04-30, 6:56 pm

>I am drawing plans (gardens, kitchens and things) into a picture box
> and I would like to change from using normal VB methods to using API
> methods so that I can gain some speed. The problem is that I use my own
> scale in the picture box so that I can draw the same design into it
> whatever size it happens to be, but the API only works in pixels and I
> am having some problems converting. Has anyone done this before?


Have a look at this old post for how to synchronise the API scalemode with
VB's:
http://groups.google.co.uk/group/mi...910c2a4c7321592
Hope this helps,

Mike


- Microsoft Visual Basic MVP -
E-Mail: EDais@mvps.org
WWW: Http://EDais.mvps.org/


Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com