Link to home
Start Free TrialLog in
Avatar of rspahitz
rspahitzFlag for United States of America

asked on

transparent user control

I created a user control that draws an image in the paint event-method.

When I place this on a form, it hides the controls that it overlaps.

When I try to set the BackColor to Transparent, it tell me this is an "invalid property value" and that "This control does not support transparent background colors."

Per the help files, in the New method I added:

SetStyle(ControlStyles.SupportsTransparentBackColor, True)
Me.BackColor = Color.Transparent

This had no apparently effect.

It allows the background of the form to show, but not the control that it overlaps.

How can I get the control beneath it to show through the transparent area of the top control?
SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of rspahitz

ASKER

So, is it possible to embed one form in another so that when the "master" form is moved, the subforms move?  I guess this could be a sort of MDI form.  Does .net support that?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mekanoo
mekanoo

maybe you can combine it with the coded classes you find at:
'Use .NET Forms as Popup Windows'
http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/article.asp
....
>trap the WM_SIZING and WM_MOVING messages

Wow!  What a pain!  I'll have to sychronize at least 30 mini-windows!

All I want is something like the shape component from VB6 (although I eventually want to customize the shape.)

I'm thinking that it may be easier to just code a subroutine into the paint event-method of the form itself!  Talk about going backward...
I'm also thinking about writing a component that will query the parent to determine what image is there and superimpose it onto the control, but that just seems like a lot of work (although not a huge deal in this project since the parent background will not change too often.)

(Also, thanks for the link, mekanoo.  Interesting, for future projects...)
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
hey--any way to intercept the parent paint event?  then I can do everything in the control, but write to the parent at the location of the current control...
OK...how can I capture the area on the parent directly under the current component (including other drawn controls)?
  Then I can paint it on the background of the current control before drawing the shape...

Just an update...I've almost solved this thing

In the control's paint event method, I CreateGraphics on the parent, then draw eveything on that context at the location of the control (me.left, me.top, me.width, me.height)  This must be done with the control's paint event or the drawing has no persistence (and will not show up if it's done while loading.)

This works perfectly and draws the shape directly on the parent.

The problem is that the control is blocking the view of the shape that was draw.

So I figured that all I have to do is make the control transparent, but we already learned that this simply copies the parent's background color to the control.

So I figured I'd hide the control, but apparently this cancels the paint event of the control, so it loses persistence.

So I figured I'd set the control's size to zero, but apparently this is the equivalent of hiding the control since it has zero pixels to paint.

So I tried moving the control to its negative location (me.left = -me.left)  Since this is not in the viewable area, the paint event seems to be ignored.

So I tried resizing the control to 1x1 pixel and it worked perfectly--almost...

Although the control's image is correctly drawn at the desired location:
(1) that one pixel may obscure part of the image, although I guess you could always just redraw the image on the control or just at that point
(2) the control no longer accepts events since it is not at that original location

I'm going to try a few more things, but I think I'll need to figure out how to capture the parent's graphical area an pull it into the control to be repainted.

Any ideas?
Upping the points to 500.
....good thing your direct drawing !

for the other problem i have a link for you to vbaccelerator.com...he manges a popupcontrol to be 'transparent' for mouse events : the thing your looking for-

http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Floating_Controls/article.asp

possibly combining the two solutions could do..
some good ideas there, but it seems to be the opposite of what I want.

the link describes how to make events invisible and show a control.
I want to make the control invisible but allow events...

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
but at this point I'm not looking for a separate form (popup or otherwise)--that was already suggested by Idle in the 2/4 comment

I think that my best option at this point is to draw the control's image onto the form, then capture that part of the form and copy it back to the image.

I have it drawing onto the form.
I need to capture a section of the form (not the background but the graphical display) and transfer that as a bitmap into the control.
I want to reward both you guys for your help, but I don't feel that any answer is what I need at this point.
I will see about reverting this to a 200-pt Q and splitting it between you.

Meanwhile, I'll continue to look for an answer in my spare time (see above comment, paragraph 2)
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sounds right...I'll investigate.  Thx.
Finally got to trying...

(was this an upgrade from VB6?)

Anyway, the form does not seem to show after it loads.  Any ideas?  I see it initialize, but it never shows.
I'll investigate more when I have a bit more time...and check out the GetScreen function.

BTW I'm running here on Win2000 so I don't know if that's different.
OK...the screen capture is working now that I extracted the GetScreen function and related API reference declarations.

The next problem is that when I put the screen capture into the control, it seems to do it in the wrong order.

Is there a way to find the controls in reverse order (i.e. lowest Z-order first, highest z-order last)?  It seems that the ZOrder method is now replaced with the "BringToFront" and "SendToBack" functions.

The problem is that it screen captures for the topmost control first and draws it (which is fine) then the one hidden behind next, which is useless because the one behind needs to have its image drawn on the top image in order to fake transparency.
Hey, Learned....

I never quite got the answer I was seeking and am still trying to get one that works as hoped.

However, I got some other really good info.

The problem I have now is that I bumped up the points and I'm not sure that the responses are worth that amount.  See comment on 2/18.

If you can reset this to 200 points, I will split the points between the experts (Idle_Mind and meekanoo.).
Ultimately, I hope MS creates a shape object, or at least the ability to make a transparent user control.

Meanwhile, some of the ideas above got me going toward a viable solution.  the one that helped the most was capturing a bitmap image and using it to let the user control draw the image onto the parent (and then essentially hide the control.)  The only problem remaining is that overlapping controls are drawn in reverse Z-order, so the top is first, then the one under it--but only the areas not covered by the top control.  Therefore, overlapping circles will not draw correctly.

If I ever figure out how to overcome this problem (and I think I'm close) I will post a solution here.  However, I may abandon the solution so that I can get my project done!
I seem to have worked out a solution, although it's not ideal.

At this point, I can have the control draw the shape directly onto the parent control.  However, this cannot be done through a property but must be done throught a method, which is actually quite simple:

    Public Sub DrawShape(ByVal GraphicsContext As Graphics)
        Dim iObjectLeft as Integer = Me.Left
        Dim iObjectTop as Integer = Me.Top
        Dim iPenThickness as Integer = 1
        Dim objBrush as New SolidBrush(Color.Black)
        Dim objPen = New Pen(Color.FromArgb(m_clrTokenForeColor.ToArgb() Xor &HFFFFFF), iPenThickness)

                With GraphicsContext
                    .FillEllipse(objBrush1, New Rectangle(iObjectLeft , iObjectTop , Me.Width - 1, Me.Height - 1))
                    .DrawEllipse(objPen, New Rectangle(Me.Width / 10 + iObjectLeft , Me.Height / 10 + iObjectTop , Me.Width * 0.8 - 1, Me.Height * 0.8 - 1))
                    .DrawEllipse(New Pen(Color.Silver, iPenThickness), New Rectangle(iObjectLeft , iObjectTop , Me.Width - 1, Me.Height - 1))
                End With
    End Sub

The key to this is that the parent must call this procedure in its Paint event procedure.  This could be from a form or from a panel or whatever.

    Private Sub usrPoint_Paint(ByVal objSender As Object, ByVal pea As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        Dim iControlCntr As Integer
        Dim objControl As Control

        For iControlCntr = Me.Controls.Count - 1 To 0 Step -1
            objControl = Me.Controls(iControlCntr)
            If TypeOf (objControl) Is usrToken Then
                CType(objControl, usrToken).DrawShape(pea.Graphics)
            End If
        Next iControlCntr
    End Sub

Finally, ensure that the controls placed onto the parent (form, panel, etc) have their backcolor set to Transparent so that they inherit the background from the parent.

The only real side-effect that I've seen to this is that any events associated with the shape are going to be intercepted for the entire rectangle of the control, not just the area filled in by the shape.  This could be handled through extra coding, but I just didn't care about it for my purposes.

Also note that I tried doing a CreateGraphics() in the control's paint event method and applying it to the parent, but that didn't seem to work.  Apparently, the only way to access the parent's background is through the parent's paint event.  Anything else is just a layer on top of that and doesn't show up in "transparent" controls.