|
-
Jun 10th, 2011, 09:12 PM
#1
Thread Starter
Stack Overflow moderator
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:
-
Jun 11th, 2011, 03:31 PM
#2
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:
Public Class GlowControl Public Sub New(ByVal control As Control) _Control = control If Me.Control Is Nothing Then Throw New ArgumentException("Control cannot be Nothing!") End If AddHandler Me.Control.PaintBackground, AddressOf Control_PaintBackground End Sub Private _GlowEnabled As Boolean Public Property GlowEnabled As Boolean Get Return _GlowEnabled End Get Set(ByVal value As Boolean) _GlowEnabled = value Me.Control.Invalidate() End Set End Property Private _Control As Control Public ReadOnly Property Control As Control Get Return _Control End Get End Property Private Sub Control_PaintBackground(ByVal sender As Object, ByVal pevent As System.Windows.Forms.PaintEventArgs) If Me.GlowEnabled Then '... End If End Sub '... End Class
Usage, for example:
vb.net Code:
Dim g As New GlowControl(Label1) g.GlowColor = Color.Red g.GlowEnabled = True
-
Jun 11th, 2011, 04:45 PM
#3
Thread Starter
Stack Overflow moderator
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.
-
Jun 11th, 2011, 06:09 PM
#4
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.
-
Jun 11th, 2011, 06:32 PM
#5
Thread Starter
Stack Overflow moderator
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.)
-
Jun 12th, 2011, 04:02 AM
#6
Re: Glowing Controls
Even easier: use an Extender Provider to provide a 'Glow' and 'GlowColor' property to any Control.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|