How to make a control to be painted/refreshed properly - vb.net

I have a control derived from checkbook which I called "SettingBooleanButton", but when any window or dialog is dragged over the control the control keeps signs of the drag
The next image shows the effect of dragging an application window over control
This is the code block that I have for OnPaint()
Public Class SettingBooleanButton
Inherits CheckBox
Private _settingSection As String
Private _settingName As String
Private _associatedSetting As Setting
Public Event StateChange(ByVal affectedSetting As Setting)
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Appearance = Appearance.Button
FlatStyle = FlatStyle.Flat
TextAlign = ContentAlignment.MiddleCenter
AutoSize = False
End Sub
Public Property SettingSection As String
Get
Return _settingSection
End Get
Set(value As String)
_settingSection = value
End Set
End Property
Public Property SettingName As String
Get
Return _settingName
End Get
Set(value As String)
_settingName = value
End Set
End Property
''' <summary>
''' Sets a boolean value to indicate the initial checked state of the control.
''' </summary>
''' <value>
''' <c>true</c> to set it as [checked state]; otherwise, <c>false</c>.
''' </value>
Public Property CheckedState As Boolean
Get
Return Checked
End Get
Set(value As Boolean)
_associatedSetting = New Setting(_settingSection, _settingName, String.Empty)
RemoveHandler CheckedChanged, AddressOf StateChanged
Checked = value
SetText()
AddHandler CheckedChanged, AddressOf StateChanged
End Set
End Property
Private Sub StateChanged(sender As Object, e As EventArgs)
If IsNothing(_associatedSetting) Then
Return
End If
_associatedSetting.Value = Checked.ToString()
SetText()
RaiseEvent StateChange(_associatedSetting)
End Sub
Public Sub SetText()
If Checked Then
Font = New Font(Font.FontFamily, Font.Size, FontStyle.Bold)
ForeColor = Color.WhiteSmoke
Text = Resource.SettingBooleanButton_TrueState
Else
Font = New Font(Font.FontFamily, Font.Size, FontStyle.Regular)
ForeColor = SystemColors.ControlText
Text = Resource.SettingBooleanButton_FalseState
End If
End Sub
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
If Checked Then
ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.Black, ButtonBorderStyle.Solid)
End If
End Sub
End Class

ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, ...)
Using e.ClipRectangle like this is a traditional bug in a Paint event handler. It is not a rectangle that matches the border you want to draw. It is only the part of the control that needs to be painted. Which is usually the entire control, but not always. Such as in your case when you drag a window across your control, only the part that is revealed needs to be repainted. So now you are painting the border in the wrong position, producing those black lines.
You only ever use the ClipRectangle if your painting code is expensive and you want to take the opportunity to skip that expensive code when it isn't needed anyway. Which is pretty rare, clipping in Windows is already pretty efficient.
You'll need to pass the actual rectangle of your border. Fix:
ControlPaint.DrawBorder(e.Graphics, Me.ClientRectangle, _
Color.Black, ButtonBorderStyle.Solid)

Sometimes the simplest solutions (or causes) are overlooked.
I have a panel with 15 buttons on it and each has an image. Depending on rows selected from a data grid they all might be enabled or disabled.
It all worked fine except toggling between enabled and disabled was taking 2+ seconds and caused lag when multi-selecting from the data grid.
Tried a few things, then I thought maybe it was something to do with the images.
The images were all in an imagelist and size was set to 24,24 which was a compromise between 32,32 and 16,16. I changed the size in the imagelist to 32,32 as that is the native size of all the images... and shazam!!! All the buttons are basically rendered instantly now. No idea ATM whether being small PNG images makes a difference... but I'm going to convert all the images I have to ICO format.
Also... as all my buttons are on a panel I enable/disable the panel which in turn enables and disables all the children on it.

Related

How can I apply a MouseHover and MouseLeave to two controls to act as one control?

I have two labels in my form which are placed side-by-side to act as one label. When I hover over the labels, I have a function that fades the labels to different colours, which works well. I am trying to apply the MouseHover and MouseLeave event to both labels, so that when I hover over Label1 and move to Label2 (and vice versa), the function doesn't then fade the colour back to the original colour. Currently, moving between the two labels activates MouseLeave followed by MouseHover again in the new label.
I have tried to add both labels to the event trigger, but this hasn't worked. I have also tried placing both labels in a Panel, but that then doesn't trigger the event.
Private Sub fadeHeaderIn(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseHover, Label2.MouseHover
Call fadeLabel("In")
End Sub
Private Sub fadeHeaderOut(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Label1.MouseLeave, Label2.MouseLeave
Call fadeLabel("Out")
End Sub
If the functionality to change the colour of part of the label existed, I'd not need the two labels, so if there is a better way of doing this altogether, I'm happy to do so. Thanks!
I have also tried placing both labels in a Panel, but that then
doesn't trigger the event.
That should work. The panel would act as the boundaries for both labels. You'll get a MouseLeave, though, when you move from the panel to the labels contained within. To prevent a false trigger, simply check if the mouse is still within the bounds of the panel. You can prevent multiple fade ins when moving from label to label by tracking the faded state with a boolean. It'd look something like this:
Public Faded As Boolean = False
Private Sub fadeHeaderIn(sender As Object, e As EventArgs) Handles Label1.MouseHover, Label2.MouseHover
If Not Faded Then
Faded = True
fadeLabel("In")
End If
End Sub
Private Sub fadeHeaderOut(sender As Object, e As EventArgs) Handles Panel1.MouseLeave
If Not Panel1.ClientRectangle.Contains(Panel1.PointToClient(Cursor.Position)) Then
If Faded Then
Faded = False
fadeLabel("Out")
End If
End If
End Sub
Here's a sample of what has been described in comments.
The Text of a control (here, derived from a standard Label) is split in two sections of the same measure. Each section can have a different color.
The active and inactive colors are custom public properties, they can be set in the designer.
Each section is tracked, meaning that the control is aware of what side the Mouse Pointer is currently hovering.
The size of the text is measured using the TextRenderer.MeasureText method. This size is used to calculate the rectangles that include the sections of text.
The Rectangle.Contains([Point]) method is then used to determine which section of the text the mouse pointer in hovering. [Point] is calculated using the MousePosition property, translated to client coordinates using the Control.PointToClient() method.
When the mouse pointer is moved from one section of text to the other (here, just two sections, more could be defined adding more rectangles), the control is Invalidated, causing a call to the OnPaint method of the control.
If the mouse pointer is not hovering a section of text, base.OnPaint(e) is called (also causing the Paint event to raise), which draws the default text with the default color.
In the OnPaint method, the Graphics region is clipped using the Rectangles that define the text sections. A subsequent call to TextRenderer.DrawText, setting the TextFormatFlags.PreserveGraphicsClipping flag, clips the text in the defined region, so just the section of text that fits in the clipping region is painted.
The Graphics.ExcludeClip() method is used here to define these clipping regions.
The TextFormatFlags.ExternalLeading and TextFormatFlags.TextBoxControl are also used to replicate the default text rendering, so the custom text is rendered in the same relative position.
This is how it behaves:
Custom Control Class to test the functionality:
Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows.Forms
<DesignerCategory("Code")>
Public Class LabelSplitText
Inherits Label
Private m_Text As String = String.Empty
Private m_Sections As RectangleF() = Nothing
Private m_PaintText As Boolean = False
ReadOnly flags As TextFormatFlags = TextFormatFlags.ExternalLeading Or
TextFormatFlags.PreserveGraphicsClipping Or
TextFormatFlags.TextBoxControl
Public Sub New()
InitializeComponent()
End Sub
Private Sub InitializeComponent()
ResizeRedraw = True
End Sub
Public ReadOnly Property ActiveRectangle As RectangleF
Public ReadOnly Property ActiveSide As String = String.Empty
Public Property ActiveColor As Color = Color.White
Public Property InactiveColor As Color = Color.DimGray
Protected Overrides Sub OnLayout(e As LayoutEventArgs)
MyBase.OnLayout(e)
Me.AutoSize = False
m_Text = Me.Text
End Sub
Protected Overrides Sub OnMouseEnter(e As EventArgs)
m_Text = Me.Text
Text = String.Empty
m_PaintText = True
MyBase.OnMouseEnter(e)
Invalidate()
End Sub
Protected Overrides Sub OnMouseLeave(e As EventArgs)
m_PaintText = False
Me.Text = m_Text
MyBase.OnMouseLeave(e)
End Sub
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
MyBase.OnMouseMove(e)
Invalidate()
If m_Sections Is Nothing Then Return
Me._ActiveRectangle = If(m_Sections(0).Contains(e.Location), m_Sections(0), m_Sections(1))
End Sub
Protected Overrides Sub OnMouseClick(e As MouseEventArgs)
Me._ActiveSide = If(m_Sections(0).Contains(e.Location), "left", "right")
MyBase.OnMouseClick(e)
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
If Not m_PaintText Then
MyBase.OnPaint(e)
Return
End If
Dim textSize As SizeF = TextRenderer.MeasureText(e.Graphics, m_Text, Me.Font, Me.ClientSize, flags)
m_Sections = GetTextAreaSections(textSize)
e.Graphics.ExcludeClip(Rectangle.Round(m_Sections(1)))
TextRenderer.DrawText(e.Graphics, m_Text, Me.Font, Point.Empty, GetSectionColor(0), flags)
e.Graphics.ResetClip()
e.Graphics.ExcludeClip(Rectangle.Round(m_Sections(0)))
TextRenderer.DrawText(e.Graphics, m_Text, Me.Font, Point.Empty, GetSectionColor(1), flags)
End Sub
Private Function GetSectionColor(section As Integer) As Color
Return If(m_Sections(section).Contains(PointToClient(MousePosition)),
Me.ActiveColor, Me.InactiveColor)
End Function
Private Function GetTextAreaSections(textSize As SizeF) As RectangleF()
If textSize.Width > Me.ClientSize.Width Then textSize.Width = Me.ClientSize.Width
Dim rectLeft = New RectangleF(PointF.Empty,
New SizeF(textSize.Width / 2.0F, Me.ClientSize.Height))
Dim rectRight = New RectangleF(New PointF(textSize.Width / 2.0F, 0),
New SizeF(textSize.Width / 2.0F, Me.ClientSize.Height))
Return {rectLeft, rectRight}
End Function
End Class

Refining a custom listbox control

I have made a sort of custom list box and have included the ability to add an image to each item.
I want to be able to change these images one by one at will and am not too sure on how to go about it. At the moment you can only select which image you would like in every item.
Public Class CustomListBox
Public label As Label
Public pic As PictureBox
Public panel As Panel
Public itemID As String
Public itemCollection As New Collection
Public bgColor As Color
Public txtEnterColor As Color = Color.FromArgb(80, 80, 80)
Public txtColor As Color = Color.FromArgb(150, 150, 150)
Public bgEntercolor As Color = Color.FromArgb(230, 230, 230)
Public x, y, paddingInt As Integer
Public itemHeight As Integer = 40
Public image As Image = My.Resources.FavNone
Public Event Item_Clicked()
Private Property ItemBackColor As Color
Get
Return BackColor
End Get
Set(ByVal value As Color)
bgColor = value
End Set
End Property
Private Property ItemPadding As Padding
Get
Return Padding
End Get
Set(ByVal value As Padding)
Padding = value
End Set
End Property
Public Property HoverBackColor As Color
Get
Return bgEntercolor
End Get
Set(ByVal value As Color)
bgEntercolor = value
End Set
End Property
Public Property ItemImage As Image
Get
Return image
End Get
Set(ByVal value As Image)
image = value
End Set
End Property
Public Property HoverTextColor As Color
Get
Return txtEnterColor
End Get
Set(ByVal value As Color)
txtEnterColor = value
End Set
End Property
Public Property TextColor As Color
Get
Return txtColor
End Get
Set(ByVal value As Color)
txtColor = value
End Set
End Property
Public Property TrueItemHeight As Integer
Get
Return itemHeight
End Get
Set(ByVal value As Integer)
itemHeight = value
End Set
End Property
Public Sub UpdateItems()
For Each item As String In itemCollection
label = New Label
pic = New PictureBox
panel = New Panel
With pic
.Width = itemHeight
.Height = itemHeight
.SizeMode = PictureBoxSizeMode.Zoom
.Image = image
End With
With label
.BackColor = (bgColor)
.ForeColor = (txtColor)
.Width = Me.Width - itemHeight
.Height = itemHeight
.Tag = item
.Height = itemHeight
.Padding = ItemPadding
.Text = item
.Left = itemHeight
.TextAlign = ContentAlignment.MiddleLeft
AddHandler label.MouseEnter, AddressOf Item_Enter
AddHandler label.MouseLeave, AddressOf Item_Leave
AddHandler label.MouseUp, AddressOf Item_Mousedown
End With
With panel
.Location = New Point(x, y)
.Width = Me.Width
.Height = itemHeight
.Controls.Add(pic)
.Controls.Add(label)
y += .Height + paddingInt
End With
Me.Controls.Add(panel)
Next
End Sub
Private Sub Item_Enter(ByVal sender As Label, ByVal e As EventArgs)
sender.BackColor = (bgEnterColor)
sender.ForeColor = (txtEnterColor)
itemID = sender.Tag
End Sub
Private Sub Item_Leave(ByVal sender As Label, ByVal e As EventArgs)
sender.BackColor = (bgColor)
sender.ForeColor = (txtColor)
End Sub
Private Sub Item_Mousedown(ByVal sender As Label, ByVal e As MouseEventArgs)
Select Case e.button
Case Windows.Forms.MouseButtons.Left
RaiseEvent Item_Clicked()
End Select
End Sub
End Class
I know I'll need to add something into the click event of the items.Possible set a variable with the index number of the label, maybe...?
Also, how do I get auto-suggestions when typing the code. For example, I want to be able to type CustomListBox1.itemCollection.add("Text", imageSrc)...etc I just have no idea what to type into Google apart from looking through loads of custom controls until I find one that includes this.
EDIT
I have looked into this custom Listbox.
I tried to add a MouseMove event to each item so thought it would be as easy as placing this:
Private Sub HoverItem(ByVal item As ColorListboxItem, ByVal e As MouseEventArgs)
msgbox(1)
End Sub
...in the "Methods" region and then
AddHandler .mousemove, AddressOf HoverItem
to the "OnDrawItem" sub. Unfortunately for me, it obviously isn't that easy as no msgbox shows.
Could anybody with experience on this control give a bit of insight as to how it works. And maybe an example of the MouseMove event so then I'll get an idea on how to add in more events (Mouseleave, DblClick...etc)
What #JoshMason said is correct for the most part, but if you insist on doing that, then you need not only an indexed collection/array for your items but also a linked associated collection/array for the corresponding images.
So that way the index of the item/image is accessible to you (properly exposed of course) so that you can assign an image to it like you would assign a text to the item(index) and you need to make sure your code accounts for removing an item also removes the corresponding image, but if you link them properly, that should happen automatically.
EDIT: For inspiration, give this a quick look.
That looks familiar - I have something very similar to house and track a bunch of thumbnails. A few things. The way it is written it is more of a ListBox helper than a custom control. There is nothing wrong with that, but if you want it to show up in the toolbox and be more reusable, consider reworking it:
Public Class CustomListBox
Inherits Panel ' or maybe Component, depending....
The way yours is written, you are trying to emulate ListBox functionality by maintaining a collection of labels and picboxes and panels. If you start to think about each panel+picbox+textbox as its OWN integral thing (control), you can internalize some of the functionality at that level (Event processing for instance) and leave the ListBox helper mainly to manage the interactions with the user or app (or go away). I dont think auto-suggest is going to work until it is an actual control or component.
Private WithEvents mLbl As TextBox ' just recently decided to allow text edits
Private WithEvents mPic As PictureBox
Public Sub New(ByVal uniqueName As String)
mLbl = New TextBox
mPic = New PictureBox
Name = uniqueName
.... set required lbl/txt properties
MyBase.Controls.Add(mLbl) ' we inherit from Panel
.... set pic controls
MyBase.Controls.Add(mPic)
...
...
' no need for AddHandler, each Item comes with its own built in event
Private Sub mPic_DClick(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles mPic.DoubleClick, mLbl.DoubleClick
IsSelected = Not _IsSelected
End Sub
After it is created with default or basic props, the class that is creating it sets the unique ones like Text, Image and location on the scrolling panel before adding it to the scrollpanel:
frmMain.pnlImgList.Controls.Add(newImgItem)
IsSelected (above) is a property, that when it changes from False to True, I raise a new event ItemSelected to notify the app/panel housing each "ImgItem" Control. The app need not know whether it was the textbox or pic clicked because ImgItem will handle that (like edit Text). In your case, this could be changing the color when selected/focused etc. (Breaking it down into 2 pieces would eventually let you get rid of that big procedure to create all new items).
What I dont have is any internal collection of these. They are added to a panel on the form and that panel's controls collection serves that purpose. When a new one of these things is added to the form, it DOES have to be hooked up to events using AddHandler to process events like ItemSelected (there is a ControlAdded/ControlRemoved event that makes a nice spot for hooking/unhooking these to the Selected event handler!)
You could do something similar using a scrolling panel of items which looks and acts like a Listbox.
Before you can do things like change an image, you need a unique identifier so you know WHICH picture to change. It looks like you use the text as the name. Depending on how you use it, that might work but if the user can edit the text, they could create a duplicate; and if the name changes you run the risk of loosing track of things. So, consider tagging them with your own unique name that isnt exposed to the user:
' this would be passed to Sub New when creating a new Item
newName = System.Guid.NewGuid.ToString()
The unique ID (Name) is part of the events args in the ItemSelected event, making it easy to find each control on the form:
ThisCtl = pnlItems.Controls(sender.Name)
To change an image, just expose it at the "item" level:
Friend Property Pic() As Bitmap
Get
' I dont recall why this is this way, maybe an artifact
' from trying different things.
Return CType(mPic.BackgroundImage, Bitmap)
End Get
The form or your helper can then change the image:
ThisCtl = pnlItems.Controls(sender.Name)
ThisCtl.Pic = newImage
Or frmName.pnlItems(sender.Name).Pic = newImage
Re your edit: Some of what you want to do with the mouse (Change colors) might be able to be done on the cheap by changing BackColor in mouse events. Some things though might be better handled by making it a proper component so that you can Shadow and OVerride mouse and paint procedures as needed. If you keep the items in an actual ListBOx, you almost certainly are going to have to hook into the DrawItem paint events. Worry about that after you decide whether or not to convert it to a component.
HTH

Button BackColor (seems to) ignore alpha channel

I built a little Tic-Tac-Toe game in winforms using nothing but layout panels, buttons and labels. Each game has 2 players, and each player is associated with a mark and color. When a player claims a field (clicks a button on a grid), that button's BackColor is changed to that player's color.
What I'd like to do now is have the open fields in the grid become a semi-transparent shade of a player's color while the cursor is over a field.
For some reason, this isn't working for my buttons:
Public Class FieldButton
Inherits Button
' ... Omitting for brevity '
Private _mouseIn As Boolean
Protected Overrides Sub OnMouseEnter(e As EventArgs)
MyBase.OnMouseEnter(e)
_mouseIn = True
End Sub
Protected Overrides Sub OnMouseLeave(e As EventArgs)
MyBase.OnMouseLeave(e)
_mouseIn = False
End Sub
Public Overrides Property BackColor As Color
Get
If Field.HasOwner Then
Return Field.Owner.Color
ElseIf _mouseIn Then
Return Color.FromArgb(16, Presenter.Game.CurrentPlayer.Color)
End If
Return MyBase.BackColor
End Get
Set(value As Color)
MyBase.BackColor = value
End Set
End Property
Private Shared ReadOnly FullPen As New Pen(Brushes.Black, 3)
Private Shared ReadOnly SemiTransparentPen As New Pen(Color.FromArgb(64, Color.Black), 3)
Protected Overrides Sub OnPaint(pevent As PaintEventArgs)
MyBase.OnPaint(pevent)
If Field.HasOwner Then
PaintMark(pevent.Graphics, pevent.ClipRectangle, Field.Owner.Mark, FullPen)
ElseIf _mouseIn And Not Presenter.Game.IsGameOver Then
PaintMark(pevent.Graphics, pevent.ClipRectangle, Presenter.Game.CurrentPlayer.Mark, SemiTransparentPen)
End If
End Sub
' ... '
End Class
In the above code, Field is another object that represents a field in the grid. Each field has an Owner, which is set to the player that claimed the field (or null).
Anyway, the line that is supposed to do the magic:
Return Color.FromArgb(16, Presenter.Game.CurrentPlayer.Color)
Has the following result:
It might be a little difficult to see due to the illusion created by the semi-transparent mark, but the button background color FromArgb(16, ...) is exactly the same as the buttons with alpha channel 255.
What am I not doing right?
EDIT
Turns out that the button's FlatButtonAppearance.MouseOverBackColor property takes precedence over the button's BackColor when FlatStyle = FlatStyle.Flat.
I don't think that explains why my button was still showing purple on mouse-over. I'm guessing that MouseOverBackColor defaults to the current backcolor, but ignores the alpha channel.
Research says this should work for you, add it to your buttons constructor;
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true)
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.setstyle.aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.controlstyles.aspx

Transparent control backgrounds on a VB.NET gradient filled form?

I'm filling the background of some VB.NET 2005 WinForms form with a nice pretty gradient fill (by overriding the OnPaint event). This works fine but the various labels etc on the form show with a solid background even after I set the BackColor to Color.Transparent. Setting the transparency key of the form itself seems to affect this but I cannot get the labels to have a truely transparent BackColor, is there an easy way to get around this or am I looking at custom controls etc?
Add a new class to your project and paste the code shown below. Build. Drop the new control from the top of your toolbox onto your form.
Public Class TransparentLabel
Inherits Label
Public Sub New()
Me.SetStyle(ControlStyles.Opaque, True)
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, False)
End Sub
Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
Get
Dim cp As CreateParams = MyBase.CreateParams
cp.ExStyle = cp.ExStyle Or &H20 ' Turn on WS_EX_TRANSPARENT
Return cp
End Get
End Property
End Class
The flicker might be noticeable, no fix.
After some experimentation I've found that the following works for gradiant filling form backgrounds and preserving label transparency:
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
Dim formGraphics As Graphics = e.Graphics
Dim gradientBrush As New LinearGradientBrush(New Point(0, Height), New Point(0, 0), Me.AppSettings.FormGradiantFrom, Me.AppSettings.FormGradiantTo)
formGraphics.FillRectangle(gradientBrush, ClientRectangle)
End Sub
And in the form load event:
SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.DoubleBuffer Or _
ControlStyles.ResizeRedraw Or ControlStyles.UserPaint, True)

How can I set a form to have a transparent background

I am struggling to get my form to have a transparent background in vb.net
Currently in the form New I set
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, true)
But still the form shows up as having the default grey background
Can anyone help??
EDIT: I need the controls on the form to be visible so I don't think setting the opacity to 0 will work
EDIT: I tried the transparency key solution but it doesn't work. I have a circular image with a black background. OnPaint I set the transparency key to the img pixel at 0,0, this then leaves me with circular image (which I want ) It hides the black background but I am still left with the default grey rectangle of the form.
below is the code I have -
Public Sub New()
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
Me.BackColor = Color.Transparent
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.Timer1.Start()
End Sub
Private Sub frmWoll_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim img As Bitmap = CType(Me.BackgroundImage, Bitmap)
img.MakeTransparent(img.GetPixel(2, 2))
Me.TransparencyKey = img.GetPixel(2, 2)
End Sub
Use TransparencyKey for transparent form.
eg.
TransparencyKey = Color.Red
Button1.BackColor = Color.Red
Now run the form you will find that the button1 has a hole in it.
So using this method you can create a mask image in paint for which part has to be transparent and apply that image to form and voila the form is now transparent.
Edit:
Sorry for late reply.
Following is your code modified to suit your requirement
Public Sub New()
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
Me.BackColor = Color.Transparent
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Dim img As Bitmap = CType(Me.BackgroundImage, Bitmap)
'img.MakeTransparent(img.GetPixel(2, 2))
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
Me.TransparencyKey = img.GetPixel(2, 2)
End Sub
Set Form's TransparencyKey color property same as form's Background color property
There are a few methods you could use.
Use the forms TransparencyKey
Override OnPaintBackground (WM_ERASEBKGND)
Override WndProc and handle the paint messages (WM_NCPAINT, WM_PAINT, etc)
I recommend overriding the window procedure to get optimal results.
Me.Opacity = 0
Be warned that:
This is for the entire form, rather than just the background. There are work-arounds to make certain parts more opague.
It's only psuedo-transparency where it takes a snapshot of what's behind it. It's smart enough to know when you move the form, but not when you move other transparent objects on top of the form.