From: Ivar on
Webbiz, Mike
I thought I might throw in an alternative here! Mike, you gave me this idea
and a few pointer on doing this a few years ago, and it is used in an old
program of mine and works well. In fact believe I sent you a half done
version of the prog for you to play with. Remember the card games?
The playing card symbols were created with a font creator, then installed on
to the users system when prog was first used, (remember that any prog of
mine must be able to run by copying the exe file only). As and when needed
draw a char where needed. I expect the same thing would work very well here.

Ivar

From: Mike Williams on
"Webbiz" <nospam(a)noway.com> wrote in message
news:dblro5tiqingfoajr3uthtkpmeriannhan(a)4ax.com...
> On Tue, 2 Mar 2010 21:54:07 -0000, "Mike Williams"

> Looking over the functions, I got a bit confused with
> SetWindowOrgEx. I know it's used to change the
> coordinates of 0,0 or something like that . .

Yep. That is exactly what it does. For example if you use it to set the
origin to (-80, -50) then it causes the top left pixel of the window to have
those pixel coordinates (the units are pixels because the GDI drawing
functions work in pixels by default). Thereafter, if you for example plotted
a pixel at location (-80, -50) then that pixel will be plotted at the top
left corner if the window, where coordinate (0, 0) used to be. If you plot a
pixel at location (0, 0) then of course it will end up at a position 80
pixels to the right and 50 pixels below the top left corner of the window.
The other way of looking at it (and perhaps the best description) is to say
that if you use SetWindowOrgEx to set the origin to the negative values
(-x, -y) then the effect is to move the origin (logical coordinate (0, 0))
to the physical positive position (x, y).

SetWindowOrgEx is in fact (almost) the equivalent of the VB ScaleLeft and
ScaleTop properties, although ScaleLeft and ScaleTop work in the PictureBox
ScaleMode units whereas SetWindowOrg works in pixels. The problem with VB
ScaleLeft and ScaleTop though is that they do not affect the GDI drawing
functions. In fact VB always leaves its SetWindowOrgEx origin at the default
location (0, 0) regardless of the values you use for ScaleLeft and ScaleTop
and it performs any required conversions of your VB drawing parameters
"under the hood". In other words, the native VB ScaleLeft and ScaleTop
properties affect /only/ native VB drawing functions, and have no effect on
anything you draw using GDI functions. That is why it is no use for our own
purposes when we want to position the output of our call to the Polygon GDI
function, and so that is why we use SetWindowOrgEx instead.

> but it's the part of restoring that puzzled me.

Yeah. I must admit that it does look a little confusing at first. The call
to SetWindowOrgEx is as follows:

Private Declare Function SetWindowOrgEx Lib "gdi32" _
(ByVal hdc As Long, ByVal nX As Long, ByVal nY As Long, _
lpPoint As POINTAPI) As Long

So, if you wanted to set the origin to location (-80, -50) you would use
something like the following (where p1 is a POINTAPI):

SetWindowOrgEx pic.hdc, -80, -50, p1

This would set the new origin to coordinates (-80, -50) and it would also
place the x and y values of the old origin (the origin that was in effect
immediately before you made the call) into p1 (the POINTAPI). Then, when you
have finished drawing whatever it is you wanted to draw using the new
origin, you must set the origin back to its old setting, so you must use
SetWindowOrgEx again in the following manner:

SetWindowOrgEx pic.hdc, p1.x, p1.y, p2

The above call sets the origin back to what it was before, which are the
values that are held in p1.x and p1.y from our first call, (which is the
only part of the call we are interested in this time) and it also places the
old setting in the p2 POINTAPI. However, we are not interested in the "old
values" this time because we don't need to know them (they are in fact the
80, -50 values that we set the origin to in the first call). In my own
example you were probably puzzled by the fact that in the second call (the
one to set the origin back to what it was before) I had actually used:

SetWindowOrgEx pic.hdc, p1.x, p1.y, p1

In other words, I had used p1 for all three parameters. That's just a habit
of mine, and I did it simply because p1 was already available and was not
required for anything else so I might as well use it as the third parameter
of the call, which in this case is really just used as a dummy. This second
call to SetWindowOrg itself will use the values held in p1.x and p1.y to set
the origin back to the old settings BEFORE it fills in the third parameter
(again p1) with the x and y values of the old settings, so the call will
still work as we want it to. In this specific case the third parameter p1 is
used simply as a "dummy". That's probably what caused your initial
confusion, and I must admit it is a rather silly way for me to have coded
it, at least as far as code readability is concerned . . . but then that's
just the way I am in the habit of working ;-) It actually would probably
have been clearer (and it would have been obvious that the third parameter
p1 was in this case really being used just as a dummy) if I had used a Null
in that position instead of using p1. Using a Null as the third parameter is
a valid way to call the function if you are not interested in finding out
what the origin was just before you made the call, but using a Null would
have meant changing the declaration slightly and so I didn't do it that way.

By the way, it is very important that we immediately set the origin back to
what it previously was (as our code indeed does) after we have done our
Polygon or whatever else it is we are doing. This is because VB itself
ALWAYS has the PictureBox origin set to (0, 0) under all conditions and if
we accidentally leave it at some other setting then as soon as VB itself
starts to do its own things with the PictureBox it will become very confused
if the origin is not at (0, 0) and it will in most cases corrupt the
contents. In fact, "a picture tells a thousand words" so to illustrate the
importance of this point try commenting out the second call to
SetWindowOrgEx (the call which sets the origin back to what it was before)
and click the button to draw your arrow. Then drag the Form around the
display, so that the PictureBox moves on and off the screen, and see what
happens.

Sorry for all the "waffle" (which seems to be becoming a habit of mine
lately!) but these days I don't seem to have the knack (as other people
often have) of distilling things down to their most important details and
leaving out all the extraneous stuff. When I started to write this response
I knew exactly what I wanted to say, and inside my head it seemed like just
a few small sentences, but as soon as I started putting pen to paper (so to
speak) it turned into another novel! Must be the effects of old age. I'll
probably get worse as time goes on ;-)

Mike




From: Mike Williams on
"Ivar" <ivar.ekstromer000(a)ntlworld.com> wrote in message
news:OBwSboquKHA.5936(a)TK2MSFTNGP04.phx.gbl...

> Webbiz, Mike. I thought I might throw in an alternative here!
> Mike, you gave me this idea and a few pointer on doing this
> a few years ago . . Remember the card games?

A few years ago, Ivar? Sheesh! At my age things I did even a few weeks ago
are hidden in the mists of time ;-)

Actually I'm just joking (well, sort of half joking!) and now that you have
reminded me I do remember your card game and my suggestion about the fonts,
although I don't remember the details. Your idea that Webbiz might like to
consider using fonts for his arrows seems like a good one, especially as I
seem to recall Webbiz having other little shapes he needs to draw from time
to time in his application. If that is the case then he could create a font
that contains his arrows and as many different shapes as he wishes, and he
can then set the text colour to whatever he wants and print them wherever he
wants in his PictureBox using a standard PicBox.Print or, better still,
using the equivalent GDI TextOut method. The Windows font rasterising stuff
seems to be pretty well optimized and TrueType characters are drawn quite
quickly, and that fact (coupled with the fact that Vista has severely
crippled the speed of the GDI Polygon function) means that your idea of
using fonts for WebBiz's arrows will probably be at least as fast, if not
faster . . .

.. . . in fact I've just tested your idea, using a TrueType character of a
similar size and shape as the arrow he is currently drawing using Polygon,
and your character method when drawing a normal solid single colour
character is actually a bit faster than Polygon (up to twice as fast in some
cases) on my own Vista laptop (you need to use TextOut rather than
Picbox.Print to get the best speed). And if Webbiz (sorry to keep talking
about you in the third person here, Webbiz!) . . if he wants some of his
arrows in a "filled outline" style with one colour for the outline and
another for the fill (as the Polygon method he is currently using is doing
in the test code) then he can still use your idea of printing the character
in TrueType font, but wrapping the TextOut method inside a BeginPath /
EndPath pair and then "printing" the character using the GDI
StrokeandFillPath function, which will draw his character as a filled
outline using the ForeColor and FillColor and FillStyle settings in much the
same way as his Polygon is currently doing. I've just tried that method as
well and it does slow the printing down quite a bit, so that it takes up to
three times as long as the same kind of output from Polygon, but even then
it is still fast enough for Webbiz's needs, and actually faster than Polygon
is he needs only solid shapes without an outline.

One other thing to bear in mind here Ivar, and something which I think on
its own might make Webbiz actually move over to using your own idea of
creating and using a font containing his arrows and other shapes, is that he
will very easily be able to set the size of his "arrows" (something else
which he said he wanted to do) simply by setting the font point size to an
appropriate value, so all in all it seems like a very good idea. He would
need to add a little more code to position the "arrow character" so that its
point is at the desired location, but that shouldn't present much of a
problem.

Good idea that, Ivar.

Mike



From: Norm Cook on
"Mike Williams" <Mike(a)WhiskyAndCoke.com> wrote in message
news:uC9cUXruKHA.800(a)TK2MSFTNGP04.phx.gbl...
> "Webbiz" <nospam(a)noway.com> wrote in message
> news:dblro5tiqingfoajr3uthtkpmeriannhan(a)4ax.com...
>> On Tue, 2 Mar 2010 21:54:07 -0000, "Mike Williams"
>

Mike, while we're discussing graphics, a slightly OT question

oldPen = SelectObject(pic.hdc, pen1)

For the above, I've seen it written

DeleteObject SelectObject(pic.hdc, pen1)

It alleviates the need for oldPen, but is it ok coding, resource wise?


From: Ivar on
Na, the idea was yours, I just remembered it.
Just to add another point, I think DrawText would be a better option than
TextOut. I say this because of the alignment parameter. If the point of the
arrow or whatever needs to be in a certain position then it can be aligned
to whatever edge of a RECT rather than having a right or down pointing arrow
always aligned top left.
At least, I think that's how it works, It's been a while since I did any of
this stuff.

Ivar