I’m looking at a new project that will require a LOT of custom controls - basically the entire UI needs to be very custom. So I’ll be building new buttons, labels, checkboxes, etc out of canvases.
In principle this should work fine, and does work in most cases. But I need to have a window with a custom background image, with custom controls layered on top of it. This is causing rectangles to appear around all the custom controls. That won’t work for me.
Here’s an example mock-up:
The “untitled” label there is being drawn in a subclass of canvas by me manually. I don’t want the light grey box around it - just the word alone.
No amount of fiddling with double buffering, transparent, etc gets the thing to actually be transparent.
How is this done? The only idea I have at this point is to create a Picture behind the scenes, and draw to it’s graphics context with a mask, then draw that picture to the canvas. Thought I’d see who had already cracked this nut before I tried that, though.
Which platforms? If you’re targeting OS X only, this should be a piece of cake. If you need to support Windows and Linux, you’ll need to ditch transparency entirely and fake it.
Kimball I had a similar problem today actually. I had to use the “eye dropper” from idraw to detect the RGB Color of my window backcolor. I then used that RGB color on the canvas.backcolor so they matched and looked seamless. Your window is gradient so that may be just a bit harder, but doable.
@Thom McGrath - I do have to target win/mac, so looks like I’ll have to fake it.
@Mike Cotrone - It’s actually nastier than that. These controls will live on windows with arbitrary images for backgrounds. Sometimes there may be a gradient behind it, other times it may be a picture of the eiffel tower, a goldfish, or my breakfast. The point is if I’m going to fake it, about the only way I can think of is to somehow tell the label what the background image was that was drawn on the window, and then draw the same portion of that background image that the label covers such that it meshes seamlessly with the window behind it.
I’ve done this technique in the past with other apps for custom toolbar buttons etc, and it works well but is not a great generalized solution, as you are forced to wire up the UI widgets to at least know what picture was drawn behind them and at what coordinates.
I’ve gotten some good progress on this, and have a solution that is working fine on the mac, but not on windows due to pretty horrible flicker. In my paint event for my canvas: (ignore magic numbers etc for positioning)
[code] dim p as new Picture(g.width, g.height, 32)
dim m as Picture = p.Mask
If your entire UI needs to be very custom, why don’t you try the ‘custom layout’ road as well ?
By that I mean having only one Canvas at all covering your entire Window, then create ‘virtual’ Controls (not derived from Canvas that will be managed by a ‘Layout’ system (derived from Canvas). This way you can make your all UI much faster (and zero flicker) and have much more flexibility. Things such as transparency will be implicit as you will mostly only draw once what you need.
(that’s what I’m working on actually, but on OpenGLSurface)
@Louis Desjardins - this is essentially what I’m looking at having to do - draw the part of the background image again in the custom control to mesh perfectly with the window it sits on.
Is there a reliable way to simply ask a window for the pixels at certain coordinates?
Create a window subclass like WndWithBackground, create a method that returns the background image BackgroundImage, then have your control ask the window for its background image through that method. Once you have it, you can take the slice you need pretty easily. If you’ve stored the image in a window property, this should be speedy enough, and it will be pretty portable.
If you take the ‘copy background to control canvas’ road, rest assured this is exactly what some commercial custom UI toolkits do, So don’t be ashame to do that, you will be fine.
The drawback is that this leads to horribly slow user interfaces when it comes to resize a Window.
(in short, avoid resizable user interface with this approach )
I would go the other route, personally. I would make the canvases be the special case. At runtime, they turn themselves invisible and you pass graphics clips from the main window into their paint events, so they all draw to the same graphics object.
Tim’s idea is one I’d never considered here… just to clarify: When in the paint event of a custom control, rather than drawing onto that control’s graphics context, grab a hold of the graphics of the containing window and draw there instead?
To do this, I’d need to expose the graphics object of the parent window, but that is a possibly cleaner solution than anything else I’ve considered.