Results 1 to 6 of 6

Thread: Glowing Controls

  1. #1

    Thread Starter
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Glowing Controls

    I've often wanted to implement glowing controls, for various stylistic reasons, and I'm sure I'm not the only one. So, here is a "generic" class that can glow any control with any color. The painted control (OnPaint) needs to have a transparent background (otherwise, how would it know what to glow?) and shouldn't be too large or be mostly opaque, so this works best for Labels and things like that. Still, just change "Inherits Label" here to any control and voilà.

    Code:
    Imports System.Runtime.InteropServices
    Imports System.Drawing.Imaging
    
    Public Class GlowLabel
        Inherits Label
    
        Private _glowColor As Color = Color.White
    
        Public Overridable Property GlowColor() As Color
            Get
                Return _glowColor
            End Get
            Set(ByVal value As Color)
                _glowColor = value
                Me.Invalidate()
            End Set
        End Property
    
        Protected Overrides Sub OnPaintBackground(pevent As System.Windows.Forms.PaintEventArgs)
            MyBase.OnPaintBackground(pevent)
    
            Using b As New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height)
                Using g As Graphics = Graphics.FromImage(b)
                    Dim e As New PaintEventArgs(g, pevent.ClipRectangle)
    
                    Me.OnPaint(e)
                End Using
    
                BlurImage(b)
    
                pevent.Graphics.DrawImageUnscaled(b, 0, 0)
            End Using
        End Sub
    
        <StructLayout(LayoutKind.Explicit)>
        Private Structure ColorArgb
            <FieldOffset(0)> Public Value As Integer
            <FieldOffset(3)> Public A As Byte
            <FieldOffset(2)> Public R As Byte
            <FieldOffset(1)> Public G As Byte
            <FieldOffset(0)> Public B As Byte
        End Structure
    
        Private Sub BlurImage(ByVal b As Bitmap)
            Const Radius As Integer = 1
    
            Dim bd As BitmapData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
            Dim arr(bd.Width * bd.Height - 1) As Integer
            Dim arr2(arr.Length - 1) As Integer
            Marshal.Copy(bd.Scan0, arr, 0, arr.Length)
            Marshal.Copy(bd.Scan0, arr2, 0, arr2.Length)
    
            Dim vals(8) As ColorArgb
            Dim val As ColorArgb
            val.R = Me.GlowColor.R
            val.G = Me.GlowColor.G
            val.B = Me.GlowColor.B
    
            For i As Integer = 1 To Radius
                For x As Integer = 1 To bd.Width - 2
                    For y As Integer = 1 To bd.Height - 2
                        For dX As Integer = -1 To 1
                            For dY As Integer = -1 To 1
                                vals(dY * 3 + dX + 4).Value = arr2((y + dY) * bd.Width + x + dX)
                            Next
                        Next
    
                        val.A = CByte((From z As ColorArgb In vals Select CInt(z.A)).Sum() \ 9)
    
                        arr(y * bd.Width + x) = val.Value
                    Next
                Next
                If i < Radius Then arr2 = DirectCast(arr.Clone(), Integer())
            Next
    
            Marshal.Copy(arr, 0, bd.Scan0, arr.Length)
            b.UnlockBits(bd)
        End Sub
    End Class
    Enjoy! Here's the result:

  2. #2
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Glowing Controls

    Why not make it into a class that wraps any control, instead of inheriting a certain fixed control?

    You could let it accept the control as a parameter in the constructor and attach the OnPaintBackground event, that's all you would need...
    You could then also include a GlowEnabled property that enables/disables the glowing.

    Something like this?
    vb.net Code:
    1. Public Class GlowControl
    2.  
    3.     Public Sub New(ByVal control As Control)
    4.         _Control = control
    5.        
    6.         If Me.Control Is Nothing Then
    7.             Throw New ArgumentException("Control cannot be Nothing!")
    8.         End If
    9.        
    10.         AddHandler Me.Control.PaintBackground, AddressOf Control_PaintBackground
    11.     End Sub
    12.    
    13.     Private _GlowEnabled As Boolean
    14.     Public Property GlowEnabled As Boolean
    15.         Get
    16.             Return _GlowEnabled
    17.         End Get
    18.         Set(ByVal value As Boolean)
    19.             _GlowEnabled = value
    20.             Me.Control.Invalidate()
    21.         End Set
    22.     End Property
    23.    
    24.     Private _Control As Control
    25.     Public ReadOnly Property Control As Control
    26.         Get
    27.             Return _Control
    28.         End Get
    29.     End Property
    30.    
    31.     Private Sub Control_PaintBackground(ByVal sender As Object, ByVal pevent As System.Windows.Forms.PaintEventArgs)
    32.         If Me.GlowEnabled Then
    33.             '...
    34.         End If
    35.     End Sub
    36.    
    37.     '...
    38.    
    39. End Class

    Usage, for example:
    vb.net Code:
    1. Dim g As New GlowControl(Label1)
    2. g.GlowColor = Color.Red
    3. g.GlowEnabled = True

  3. #3

    Thread Starter
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: Glowing Controls

    I did it this way for a couple of reasons:

    1) The style. You don't have to do anything at runtime, and it's guaranteed the OnPaintBackground method will be called at the right time, as opposed to the PaintBackground event, which only happens when the control gets to Control.OnPaintBackground(), which could end up in the wrong order. Whereas using a wrapper, you have to add the code, you can't just drag in the control from your toolbox.

    2) The placement. Although PaintBackground will usually be raised after all the painting (but might be in a different spot) it should actually happen at the right time in the inheritance chain.

    Anyways, feel free to use that code anyways - the cases won't apply most of the time, but, just so you know.

  4. #4
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Re: Glowing Controls

    I don't see how reason 1 and 2 are any different from each other, and any way: you are calling MyBase.OnPaintBackground (which might do some painting and then raises the PaintBackground event) before your own code. That means my way of handling the event is exactly the same. It would not be if you called the base method after your own code, in that case the event would be raised after your own code so the placement would be different. In this case, I don't think it is.

    In your case the base control calls OnPaintBackground. You override this method, but the first thing you do is run the base implementation anyway by calling MyBase.OnPaintBackground, which raises the PaintBackground event. After that, you run your own code.

    In my case the control handles PaintBackground and runs some code. That is the same as running some code after calling MyBase.OnPaintBackground.


    As for the ability to drop the controls on the form and don't needing any code, I guess that's convenient. You'd still need to create a new class for any control you'd want to use this for though so it might end up taking a lot more code depending on how many controls you need it for.
    You might even go really fancy and add some kind of component (which you drop on the form) that allows you to select some controls on that form and make them glow.

  5. #5

    Thread Starter
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: Glowing Controls

    No, when you are creating a custom control, Control.OnPaintBackground may be called whenever.

    The component is a good idea, I'll try to make that in a day or two... I wonder what the best way to implement that would be, though.

    (I just had a thought, though - an extension method MakeGlow(). It could perform multiple glows that way, even.)

  6. #6

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width