Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Right, so...long story short, I have a panel with curved corners. I need the portion of the panel outside the curve to be transparent. La-dee-da, that's easy as pie...done did it.

Problem: Due to the amount of graphical processing in the app (and the use of this panel ALL over the place), when the application raises an event or resizes there is alot of "flickering". I traced the issue down to the fact that the application is redrawing the background and for a split second it is showing through all the controls (on each of the panels in the application...so it causes alot of visual nastiness).

Now, the true problem arises in that, when I override OnPaintBackground...this flickering stops flat out...but I can't get the outside corners to draw transparent.

I've tried alot of different things and come to the conclusion that you CANNOT use transparency if you Override OnPaintBackground (and do nothing in it). I pray that I am wrong about that conclusion and was hoping someone here would konw a way that I can.

 

for reference sake my panel is based off this example.

 

Here is a shot of the panel before overriding OnPaintBackground:

http://www.livethislife.net/images/ForWork/panelbefore.gif

 

and here is a shot after overriding OnPaintBackground:

http://www.livethislife.net/images/ForWork/panelafter.gif

 

 

So...anyone know of a way for me to draw a transparent rectangle as the background without actually drawing the background?

 

To further complicate matters...I need to do this over gradients.

Posted

guess no one wants to touch this one with a 10 foot pole eh?

 

let me try to make it easier.

 

How could I write a procedure to do Transparency just like Color.Transparent would do in VB.Net.

That's the gist of it...I need to write what M$ already wrote because theirs only works if OnPaintBackground isn't overridden.

Posted

sadly no...that does allow me to make the corners transparent without calling MyBase.OnPaintBackground...but it raises a whole host of other issues like not fully drawing the controls until events are raised...though I'm sure that this is my code interfering with what works from that example...but I can't for the life of me figure out why.

:(

Posted

It's going to be incredibly hard to be any more helpfull without seeing more code as there are many variables that may be causing you trouble, are you calling the main draw code from the paint event or from other events (which cause changes). Are you drawing directly to screen or to some kind of memory buffer?

 

On a side note I assume you haven't accidently caused a loop by calling InvalidateEx from the OnPaint Event?

Anybody looking for a graduate programmer (Midlands, England)?
Posted

well...it's gonna be pretty tough to show all the relevant code because 1) it's huge and 2) it's code for my company and I can't show much of it (I always hate that rule).

 

Mainly, I think one of my problems with that example is that our program uses this panel for other controls.

See, this is a panel that was built for this company by a different programmer who no longer works here...he did it solely for the purpose of creating rounded edges in a panel. Then, when they asked for buttons with rounded edges and labels with rounded edges and tab-controls with rounded edges he (stupidly in my opinion) used this panel to create them. For the label, he created a control with this panel and a windows label inside of it. This means that on any given form I have lots of instances of this panel, all of which are trying to be transparent and I end up with controls not completely drawing for some reason...

From what I understand this whole WS_EX_Transparent thing just tells the control to wait to draw after it's children and parents...but what happens when a control with this setting is a child of another control with this setting?

Posted
Maybe I'm missing the point here, but that surely doesn't help at all, and is infact quite likely to be the method Pselus is using. The links you provide basically talk about drawing a rounded rectangle. Pselus control already does that. The problem is it's being drawn onto a square control and what Pselus wants is the areas its not being drawn on to show whatever is behind the control.
Anybody looking for a graduate programmer (Midlands, England)?
Posted

but will this get over the issue of the form redrawing when events are raised?

I've come up with PLENTY of ways to get around the Transparency thing, but so far none of them have solved that particular problem...

now that I think about it...I'm not sure I even mentioned that problem here...hmmm....

 

ah, yes, I did:

I traced the issue down to the fact that the application is redrawing the background and for a split second it is showing through all the controls

 

so yeah, overriding OnPaintBackground stops this flickering...but then the transparency problem comes up.

 

I will look into the links you posted...I hope they help me.

Posted
Maybe I'm missing the point here' date=' but that surely doesn't help at all, and is infact quite likely to be the method Pselus is using. The links you provide basically talk about drawing a rounded rectangle. Pselus control already does that. The problem is it's being drawn onto a square control and what Pselus wants is the areas its not being drawn on to show whatever is behind the control.[/quote']

 

YES!

exactly.

:P

 

my current thing I'm looking into is trying to basically "capture" a rectangle on the parent at certain coordinates (specifically, where the corner is outside the curve) and draw that onto the control to mimic transparency....but I have no clue how to actually GET that rectangle from the parent that I need.

Posted
I'm sure the method I outlined is probably your best solution, but I can't really say for sure untill i've tested it as a designtime control (which i don't know how todo) so i'll have a look into that and get back to you.
Anybody looking for a graduate programmer (Midlands, England)?
Posted

I'm pretty sure that your method is the overall best solution as well...however, there are so many other things dependant upon it now that I don't think it's the FASTEST way.

My boss has already said that we will take the time to go back and rewrite the controls later...so all I need to find now is a quick fix...when I redesign them I will most definatly use your method.

Posted

Try using Control.SuspendLayout() and ResumeLayout() when redrawing...without the need to override OnPaintBackground.

 

Also...is the username/password rectangle a user control? What is the need for the panel?

  • Leaders
Posted
So, are you considering setting a region for the panel? Basically, taking a GraphicsPath, adding a RoundedRectangle identical to yours (but starting at 0,0), turning the GraphicsPath into a Region object and then setting the Panel region to the Region that you just created?

Iceplug, USN

One of my coworkers thinks that I believe that drawing bullets is the most efficient way of drawing bullets. Whatever!!! :-(

Posted

we've already tried the SuspendLayout, ResumeLayout route.

the Login is just a form, it happens to have one of these panels on it.

I can show you what it looks like with the control working properly...I have highlighted in green all the places just in one screen of the app that use this panel (ignore the red background...it's me trying to test things):

http://www.livethislife.net/images/ForWork/system.png

 

then this is what it looks like with OnPaintBackground overridden (the places that don't work are highlighted green, the places that do are blue):

http://www.livethislife.net/images/ForWork/system2.png

 

honestly, for the life of me I can't figure out why some of those things work fine when others don't...

 

I must say...I used to hate doing bugs...now I just hate doing Graphics bugs when the graphics were designed by an incompetant programmer...I can't tell you how many places just have arbitrary Color.Transparent assignments...

Posted

literally the difference in those 2 pictures is when I go into this control and comment out (or uncomment) the single line: Mybase.OnPaintBackground.

doing that one thing in 1 control causes that much change in the application.

Posted
Setting the Region setting seems to be the best solution, I just gave it a quick test. Create a region using a graphics path (if your not already doing that), if you are just set this.Region = new Region(myGraphicsPath), you will need to make this calculation everytime you resize the control etc but it should work fine.
Anybody looking for a graduate programmer (Midlands, England)?
Posted

ok, I only partially get what you're saying there Cags.

you are saying that I should set the controls region using a graphics path..I understand that part...but what exactly should this graphics path consist of? If I make the graphicspath based on the rounded edges, is it going to still need MyBase.OnPaintBackground to paint the transparent corners? If so, well...that's the whole issue...painting the background normally is the origional problem because it creates alot of flickering.

Posted
No it will not need the onPaintBackground as the control only draws what is within the region and yes the region is made up of the 4 lines and 4 corners that make the shape of your control.
Anybody looking for a graduate programmer (Midlands, England)?
Posted

Cags, I just got around to trying the Region thing and it is so very very close to what I need. If I weren't in a place of business I'd be giggling like a schoolgirl.

A few problems though:

1) My app just slowed waaaaaaaaaaaaaaaaay down after doing that.

For reference sake, here is my Paint code for the uctrlPanel control:

 Dim filler As System.Drawing.Drawing2D.LinearGradientBrush
           Dim rect As System.Drawing.Rectangle = Me.ClientRectangle
           Dim topCorn As Rectangle
           Dim graphPath As System.Drawing.Drawing2D.GraphicsPath

           If memGraphics.CanDoubleBuffer() Then
               If Not Me._HasDrawn Then
                   '''Me._HasDrawn = True

                   ' Draw the curved border
                   graphPath = Me.GetPath()
                   If Me.ClientRectangle.Width = 0 Then
                       rect.Width += 1
                   End If

                   If Me.ClientRectangle.Height = 0 Then
                       rect.Height += 1
                   End If

                   If Me._GradientMode = LinearGradientMode.None Then
                       filler = New System.Drawing.Drawing2D.LinearGradientBrush(rect, Me._BackColour1, Me._BackColour1, System.Drawing.Drawing2D.LinearGradientMode.Vertical)
                   Else
                       '''filler = New System.Drawing.Drawing2D.LinearGradientBrush(rect, Me._BackColour1, Me._BackColour1, CType(Me._GradientMode, System.Drawing.Drawing2D.LinearGradientMode))
                       filler = New System.Drawing.Drawing2D.LinearGradientBrush(rect, Me._BackColour1, Me._BackColour2, CType(Me._GradientMode, System.Drawing.Drawing2D.LinearGradientMode))
                   End If

                   memGraphics.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias

                   memGraphics.Graphics.FillPath(filler, graphPath)

                   Me.Region = New Region(graphPath)

                   Select Case Me._BorderStyle
                       Case System.Windows.Forms.BorderStyle.FixedSingle
                           Dim borderPen As New System.Drawing.Pen(Me._BorderColour, Me._BorderWidth)
                           memGraphics.Graphics.DrawPath(borderPen, graphPath)
                           borderPen.Dispose()

                       Case System.Windows.Forms.BorderStyle.Fixed3D
                           Me.DrawBorder3D(memGraphics.Graphics, Me.ClientRectangle)

                       Case System.Windows.Forms.BorderStyle.None

                   End Select

                   ' Render to the form
                   memGraphics.Render(e.Graphics)

                   filler.Dispose()
                   graphPath.Dispose()
               End If
           End If

 

Is there something in there I shouldn't be doing? Something I should do different? I am so new to this whole GDI+ thing that I'm learning on the fly (though you have been very helpful so far).

 

There are a couple other problems right now (not drawing all of the border, not drawing all of the controls, etc.) but I'll go one at a time...for now the speed of the app is a big thing.

Posted

couple other relevant code pieces:

Protected Function GetPath() As System.Drawing.Drawing2D.GraphicsPath

           Dim graphPath As New System.Drawing.Drawing2D.GraphicsPath

           If Me._BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D Then
               graphPath.AddRectangle(Me.ClientRectangle)
           Else

               Try

                   Dim curve As Integer = 0

                   Dim rect As System.Drawing.Rectangle = Me.ClientRectangle
                   Dim offset As Integer = 0

                   Select Case Me._BorderStyle

                       Case System.Windows.Forms.BorderStyle.FixedSingle
                           If Me._BorderWidth > 1 Then
                               offset = DoubleToInt(Me.BorderWidth / 2)
                           End If
                           curve = Me.adjustedCurve

                       Case System.Windows.Forms.BorderStyle.Fixed3D

                       Case System.Windows.Forms.BorderStyle.None
                           curve = Me.adjustedCurve

                   End Select

                   If curve = 0 Then
                       graphPath.AddRectangle(rect.Inflate(rect, -offset, -offset))
                   Else

                       Dim rectWidth As Integer = rect.Width - 1 - offset
                       Dim rectHeight As Integer = rect.Height - 1 - offset
                       Dim curveWidth As Integer = 1

                       If (Me._CurveMode And CornerCurveMode.TopRight) <> 0 Then
                           curveWidth = (curve * 2)
                       Else
                           curveWidth = 1
                       End If
                       graphPath.AddArc(rectWidth - curveWidth, offset, curveWidth, curveWidth, 270, 90)

                       If (Me._CurveMode And CornerCurveMode.BottomRight) <> 0 Then
                           curveWidth = (curve * 2)
                       Else
                           curveWidth = 1
                       End If
                       graphPath.AddArc(rectWidth - curveWidth, rectHeight - curveWidth, curveWidth, curveWidth, 0, 90)

                       If (Me._CurveMode And CornerCurveMode.BottomLeft) <> 0 Then
                           curveWidth = (curve * 2)
                       Else
                           curveWidth = 1
                       End If
                       graphPath.AddArc(offset, rectHeight - curveWidth, curveWidth, curveWidth, 90, 90)

                       If (Me._CurveMode And CornerCurveMode.TopLeft) <> 0 Then
                           curveWidth = (curve * 2)
                       Else
                           curveWidth = 1
                       End If
                       graphPath.AddArc(offset, offset, curveWidth, curveWidth, 180, 90)

                       graphPath.CloseFigure()

                   End If

               Catch ex As System.Exception
                   graphPath.AddRectangle(Me.ClientRectangle)
               End Try

           End If

           Return graphPath

       End Function

And

        Public Sub Render(ByVal g As Graphics)
           If Not Me._memoryBitmap Is Nothing Then
               g.DrawImage(Me._memoryBitmap, New Rectangle(0, 0, Me._width, Me._height), 0, 0, Me._width, Me._height, GraphicsUnit.Pixel)
           End If
       End Sub

Posted (edited)

Well I thought I might reply now, just incase you have chance to look at this before I'm available to check more closely tomorrow. If my post doesn't make sense I appologise, I have been drinking.

 

As I'm only looking at sections of your code it's hard to tell, but I notice that in your Render method you are attempting to draw a local bitmap to your screen. Does this mean that all drawing is done to a local bitmap and then the paint method simply draws the local bitmap? If this is the case then an application witch uses alot of instances of this control could use a lot of memory. I suppose this might cause some slowdown. I can see no particular reason why the basic code behind drawing a curved rectangle should cause a slowdown in your application. I will look at your code further tomorrow, but if you could give me an approximation of how many of this control may be on screen at once, then that would be very helpfull.

 

EDIT: I nearly forgot to mention, you say your entire controls doesn't draw correctly, I could be wrong but i'm guessing by this you mean part of the border is missing. If this is the case it is perhaps because you are setting the region of the control to the size of the border, wheras infact this region should be large enough to entirely encase the border (i.e at least 2 pixel larger in either direction).

Edited by Cags
Anybody looking for a graduate programmer (Midlands, England)?
Posted
After another look at your code I would also suggest trying to eliminate the Try Statements as they shouldn't be neccessary in this case. If you store the path of the border locally it will prevent you having to call GetPath everytime you paint, instead calling it only when the control is resized.
Anybody looking for a graduate programmer (Midlands, England)?

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...