Accessing a Graphics Object

A few years ago Xojo restricted access to a Graphics object (“g as Graphics”) to the Paint events of (mainly) Windows and Canvases.

I was able to rewire a (large) application to adapt to this new regime. But in starting a new application I find myself jumping through hoops to do things that would be much easier if “g as Graphics” were available elsewhere in the application than just the Paint events.

For example:
1. When dealing with strings it is not umcommon to want to know the width of a string: g.StringWidth(str). This has to be found in the Paint event without doing any actual painting.
2. dealing with animation would be easier in the MouseDrag event instead of arranging to have the Paint event draw just the dragged object only.

Have you found alternatives to the work arounds that I have not managed to avoid?

Thanks for your thoughts.

Well, for some things, like calculations you can keep a 1x1 picture around and use the Picture.Graphics object. Functionally there’s not much difference between the graphics object in the paint event and the graphics object in the picture.

As far as dealing with animation in the MouseDrag event you can invalidate, or is it clear - never sure, just a portion of the canvas and the Paint even will indicate what needs to be redrawn. Not ideal, but that’s what we have to work with.

1 Like

The operating systems are no longer made in such way that it would make sense or would even work at all to have Graphics available elsewhere.

Under the hood the operating systems after all only draw when their supposed to draw and not out of scope just anywhere in the code.

If you need to know string width out of scope of drawing which is a valid case then you create Picture that is 1 pixel size (you can either cache up this picture or not cache it up). And then you measure the string width on the graphics of this picture. (Like in mouse down events for example to figure out if your text was clicked on)

1 Like

You can use .Refresh from within the code handling the MouseDrag event to refresh controls, a canvas or the whole window.

Sounds like we need a pseudo-graphics object of which we can ask questions, such as: if you were a graphics object, how wide would this string be?

1 Like

You basically have it, a image that is 1 x 1 pixel costs almost nothing.

Perhaps we can get @Greg_O or @Sam_Rowlands to stand in for the 1 x 1 pixels picture.

Why do you need someone else to confirme what Björn is writing?

It is basically in the docs

Var p as New Picture(1,1)
Var g as graphics = p.graphics

//Now use any valid Graphics' methods
Var d As Double
d = g.TextWidth("Hello World!")
1 Like

Don’t forget that if you create the 1x1 pixel image and use its graphics object, you must set the font name, size, italics etc to match your requirements. Otherwise you will get the wrong answers, been there forgot that. :slight_smile:

@Jeremie_L you’re answer only works with the default system font.

1 Like

I can tell you right now that I’d never fit into 1x1 pixels.

6 Likes

It is a little complicated to get your head around it, but it does make sense.

Lets consider an intensive animation.

  1. Drawing to the screen is slow and will freeze the main thread while doing so. No matter how much you optimize, this is often the biggest bottleneck, especially when you utilize anti-aliasing, shadows and so on. There is a point as to where you can simply gain no improvements from optimizing your drawing code.
  2. If you can’t optimize drawing code any further, you can still get more frames by performing your logic and layout operations in a separate pre-emptive thread on a separate processor core. I’ve doubled my frame rate this way. It’s not available to Xojo developers in an efficient way out of the box. There is an old (ignored and probably closed) feature request for shared memory, which would help with “Workers”. I’d recommend looking at 3rd party libraries or potentially writing the logic code in a different development tool and language, then including it in your Xojo made application as a custom plugin.

This process can be reversed, in that you can actually move the drawing code of a view to a separate pre-emptive thread and have those updates performed on a separate processor core. However I wouldn’t recommend doing this as Xojo is not multi-core ready, I would expect it to cause problems or crash.

Depending on the design of your animation, you might be able to get away by separating your scene into elements and utilizing Apple’s Core Animation to provide a silky smooth 60fps animation. It’s not supported by Xojo and I’d recommend looking into a 3rd Party declare library for access to this functionality. Using my own library and CA I was able to get a full screen animation to animate 6,000 particles at 30 fps on a 2019 i9 MBP (3,000 @ 60 fps).

BTW: My own library that I used for CoreAnimation is not compatible with Xojo 2.0 ATT, which is why it is no longer publicly available (If Xojo were to handle some feature requests I might consider bringing it back).

It’s what I use, I have a global picture of 10 x 10 and use that graphics object for calculations. I changed to using 10 x 10 some time ago because I found 1 x 1 could sometimes report incorrect text sizes, I don’t know if that’s been fixed or not.

Apple do have functionality for calculating text dimensions without needing a picture or graphics options. Again you’ll need a 3rd Party library to use those.

Edit: was so engrossed with Animation, I forgot a key point. coalesced drawing. With the current design and having your logic calculated separately from the drawing code, this males it easier and faster for the OS to decide when your graphics will actually be drawn to the screen.

A quick note on this.

The Graphics object and the calculations that are done by the underlying frameworks are affected by image resolution (HorizontalResolution & VerticalResolution). For spot-on text calculations, I suggest making your image a multiple of 72 and then set the resolutions to match the screen you are drawing on. For instance, if you’re drawing on a Retina screen (2x), set the resolutions to 144 (2x72). For Windows users, I suggest using 96 instead of 72 so the fractional scale factors always end up being whole numbers.

That’s what I do anyway.

2 Likes