Label text with border - vb.net

I have a label with text "UserName" in foreground color as white and the form is on a sky-blue color. I would like to add a black border NOT to the label itself, but to the text inside of it.
Is this possible?
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
btnLogin.Enabled = False
centrarVentana(Me)
lblNombreUsuario.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
End Sub
The code obviously is just for show,since it does not do what I want.
Edit FINAL : Thanks so much everybody. It finally worked! I am leaving the code here so everybody can re use. Once you understand it its actually really easy.
Imports System.Drawing.Drawing2D
Public Class BorderLabel
Inherits Label
Public outline_color As Color = Color.Black
Public border_thickness As Integer = 5
Public Sub New()
MyBase.New
End Sub
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
e.Graphics.FillRectangle(New SolidBrush(BackColor), ClientRectangle)
Dim gp As GraphicsPath = New GraphicsPath
Dim outline As Pen = New Pen(Me.outline_color, Me.border_thickness)
Dim sf As StringFormat = New StringFormat
Dim foreBrush As Brush = New SolidBrush(ForeColor)
gp.AddString(Text, Font.FontFamily, CType(Font.Style, Integer), Font.Size, ClientRectangle, sf)
e.Graphics.ScaleTransform(1.3!, 1.35!)
e.Graphics.SmoothingMode = SmoothingMode.HighQuality
e.Graphics.DrawPath(outline, gp)
e.Graphics.FillPath(foreBrush, gp)
End Sub
End Class
NOTE : This question is not an exact duplicate of Setting a Font with outline Color in C# since I am on Visual Basic and had to do code changes for this to work correctly.

Take a look at KeithS answer
also you can create your own label:
Public Class CustomLabel
Inherits Label
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.Red, 5, ButtonBorderStyle.Solid, Color.Red, 5, ButtonBorderStyle.Solid, Color.Red, 5, ButtonBorderStyle.Solid, Color.Red, 5, ButtonBorderStyle.Solid)
End Sub
End Class
And here's how you implement it
Dim newForm As Form = New Form
Dim newLabel As CustomLabel = New CustomLabel
newForm.Controls.Add(newLabel)
newLabel.BackColor = Color.Black
newLabel.Font = New System.Drawing.Font("Microsoft Arial", 18!, FontStyle.Regular, GraphicsUnit.Point, CType(0,Byte))
newLabel.ForeColor = Color.Crimson
newLabel.Text = "Some text on a topmost transparent form window"
newForm.Show
newForm.TopMost = true
newLabel.AutoSize = true
newLabel.Location = New Point(230, 375)

Related

Display rect focus on subitems / cells in Listview

Like the title above, I am trying to display the focus box on the subitem / cell that is clicked.
To get the subitem / cell that is clicked I use the following code:
Private Sub LV_MouseClick(sender As Object, e As MouseEventArgs) Handles LV.MouseClick
Info = LV.HitTest(e.Location)
ClickedColumnLV = Info.Item.SubItems.IndexOf(Info.SubItem)
ClickedRowLV = Info.Item.Index
If e.Button = MouseButtons.Right Then
If LV.FocusedItem.Bounds.Contains(e.Location) Then
CMenu.Show(Cursor.Position)
End If
End If
End Sub
At this point i have Row Index (ClickedRowLV) and Column Index (ClickedColumnLV)
Now I'am trying show focus on that clicked subitem/cell.
How can I do that?
EDIT :
Just to make sure that I didn't click the wrong item. So I want to have a focus rect or a sign if the sub-item is clicked.
Row must be full row select but at subitem /cell there is focus rect inside or outide. For example, please see the picture :
Not quite sure whether you mean something like:
If that is true, then you can handle the MouseDown event of the ListView control as follows:
Private Sub LV_MouseDown(sender As Object, e As MouseEventArgs) Handles LV.MouseDown
Dim selColor = SystemColors.Highlight
Dim item = LV.Items.Cast(Of ListViewItem).
Where(Function(x) x.BackColor.Equals(selColor) OrElse
x.SubItems.Cast(Of ListViewItem.ListViewSubItem).
Any(Function(y) y.BackColor.Equals(selColor))).FirstOrDefault
If item IsNot Nothing Then
item.BackColor = SystemColors.Window
item.ForeColor = SystemColors.WindowText
For Each subItem In item.SubItems.Cast(Of ListViewItem.ListViewSubItem)
subItem.BackColor = SystemColors.Window
subItem.ForeColor = SystemColors.WindowText
Next
End If
Dim ht = LV.HitTest(e.Location)
If ht.SubItem IsNot Nothing Then
ht.Item.UseItemStyleForSubItems = False
ht.SubItem.BackColor = selColor
ht.SubItem.ForeColor = SystemColors.Window
End If
End Sub
Of course this won't work if the FullRowSelect property is enabled.
Edit: Custom ListView
Following up on your comment and update, I don't know any easy way to achieve that. I think you need to create a custom ListView and override the relevant events as follows:
Imports System.Windows.Forms
Imports System.Drawing
Imports System.ComponentModel
<DesignerCategory("Code")>
Public Class ListViewEx
Inherits ListView
Private ht As ListViewHitTestInfo
Sub New()
MyBase.New
DoubleBuffered = True
OwnerDraw = True
FullRowSelect = True
End Sub
Public Property DrawFocusRectangle As Boolean = True
Protected Overrides Sub OnDrawColumnHeader(e As DrawListViewColumnHeaderEventArgs)
e.DrawDefault = True
End Sub
Protected Overrides Sub OnDrawItem(e As DrawListViewItemEventArgs)
If View = View.Details Then Return
If e.Item.Selected Then
e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds)
e.DrawFocusRectangle()
Else
e.DrawBackground()
End If
e.DrawText()
End Sub
Protected Overrides Sub OnDrawSubItem(e As DrawListViewSubItemEventArgs)
Using sf As New StringFormat With {
.Alignment = StringAlignment.Near,
.LineAlignment = StringAlignment.Center,
.Trimming = StringTrimming.EllipsisCharacter,
.FormatFlags = StringFormatFlags.NoWrap
},
br = New SolidBrush(e.SubItem.ForeColor)
Select Case e.Header.TextAlign
Case HorizontalAlignment.Center
sf.Alignment = StringAlignment.Center
Case HorizontalAlignment.Right
sf.Alignment = StringAlignment.Far
End Select
If e.Item.Selected Then
If e.ColumnIndex = 0 OrElse FullRowSelect Then
e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds)
End If
Else
e.DrawBackground()
End If
e.Graphics.DrawString(e.SubItem.Text, e.SubItem.Font, br, e.Bounds, sf)
End Using
'Here you go...
If DrawFocusRectangle AndAlso ht IsNot Nothing AndAlso
e.Item.Focused AndAlso e.SubItem Is ht.SubItem Then
Using pn As New Pen(Color.Orange, 2)
Dim r As New Rectangle(e.Bounds.X,
e.Bounds.Y,
e.Header.Width - 1,
e.Bounds.Height - 1)
e.Graphics.DrawRectangle(pn, r)
'or just draw focus rectangle ...
'ControlPaint.DrawFocusRectangle(e.Graphics, r)
End Using
End If
End Sub
Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
MyBase.OnMouseDown(e)
ht = HitTest(e.Location)
Invalidate()
End Sub
Protected Overrides Sub OnColumnWidthChanged(e As ColumnWidthChangedEventArgs)
MyBase.OnColumnWidthChanged(e)
Invalidate()
End Sub
End Class
Related
How to change default selection color of a ListView?
WinForms: Changing ForeColor of Selected item in ListView
ListView: MultiSelect items with mouse drag

Custom treeview VB.net

I'm looking to create a custom treeview control in VB.net, what I need to do is have a standard treeview control displaying the system file strucure for example, but with an extra icon on the right on the folder/file name that only appears on hover over of the node. So, for instance, if I hover over the folder Sup2 as shown in the pic, then the orange icon appears
I've done some research and from what I can see, I have to override the onpaint event to make this happen but I'm not sure exactly how to do this. I also need to add an onclick event to that new orange icon.
This is not professional but is worth giving a try..
I created a class that inherited from a Treeview control and overrode the constructor - changing the default width and height, setting the DrawMode to TreeViewDrawMode.OwnerDrawText.
Next, I handled the TreeView.DrawNode event, using a PictureBox to display the Image and changing its location based on the currently highlighted item.
I also handled the Click event of the PictureBox.Under that event, You can do whatever you want with the highlighted node.
I used images from My.Resources for ImageList.Images(0) and PictureBox.Image
Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim trv As New MyTreeView
trv.Nodes.Add("Suppliers")
trv.Nodes(0).Nodes.Add("Sup 1")
trv.Nodes(0).Nodes.Add("Sup 2")
trv.Nodes(0).Nodes.Add("Sup 3")
trv.Nodes(0).Nodes.Add("Sup 4")
trv.Nodes(0).Nodes.Add("Sup 5")
Controls.Add(trv)
End Sub
End Class
'Class Starts Here
Public Class MyTreeView
Inherits TreeView
WithEvents myImage As PictureBox
Dim activeItem As TreeNode 'Variable to store active TreeNode
Public Sub New()
MyBase.New() 'Call the base class constructor
'And set some values
Height = 300
Width = 300
Location = New Point(50, 50)
DrawMode = TreeViewDrawMode.OwnerDrawText 'Very neccesary
AddHandler DrawNode, AddressOf MyTreeViewDrawNode
'Add event handlers
AddHandler AfterCollapse, AddressOf MyTreeViewCollapsed
'Set HotTracking event to true to allow for MouseHover
HotTracking = True
ImageList = new ImageList
ImageList.Images.Add(My.Resources.FolderImage)
ImageIndex = 0
Font = New Font(Font.FontFamily, 10)
'Initialize picturebox
myImage = New PictureBox() With
{
.Image = My.Resources.editPencilImage,
.SizeMode = PictureBoxSizeMode.Zoom,
.Size = New Size(10, 10),
.Visible = False
}
Controls.Add(myImage)
End Sub
Private Sub MyTreeViewCollapsed(sender As Object, e As TreeViewEventArgs)
myImage.Visible = False
End Sub
Sub ImageClicked(sender As Object, e As EventArgs) Handles myImage.Click
If (Not activeItem Is Nothing) Then
MessageBox.Show("Clicked Item - " & activeItem.Text)
End If
End Sub
Private Sub MyTreeViewDrawNode(sender As Object, e As DrawTreeNodeEventArgs)
e.DrawDefault = True
If (e.State = TreeNodeStates.Hot) Then
myImage.Visible = True
activeItem = e.Node
Dim tmpSize = TextRenderer.MeasureText(e.Node.Text, Font)
myImage.Location = New Point(e.Node.Bounds.Location.X + tmpSize.Width, e.Node.Bounds.Location.Y)
End If
End Sub
End Class
I think the following example will give you some hints and tips.
Option Explicit On
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Text
Imports System.Runtime.InteropServices
Public Class TreeViewEx
Inherits TreeView
#Region "API"
Private Const TVM_SETEXTENDEDSTYLE As Integer = &H1100 + 44
Private Const TVS_EX_DOUBLEBUFFER As Integer = &H4
<DllImport("user32.dll")>
Private Shared Function SendMessage(ByVal hWnd As IntPtr,
ByVal msg As Integer,
ByVal wp As IntPtr,
ByVal lp As IntPtr) As IntPtr
End Function
#End Region
#Region "Private Fields"
Private ReadOnly RightImage As Bitmap
Private ReadOnly NSF As StringFormat
Private HoverNode As TreeNode
Private RightImageRect As Rectangle
#End Region
#Region "Constructors"
Sub New()
DrawMode = TreeViewDrawMode.OwnerDrawText
RightImage = New Bitmap(My.Resources.Modify)
NSF = New StringFormat With {
.Alignment = StringAlignment.Near,
.LineAlignment = StringAlignment.Center,
.Trimming = StringTrimming.EllipsisCharacter,
.FormatFlags = StringFormatFlags.NoWrap
}
End Sub
#End Region
#Region "Paint"
Protected Overrides Sub OnDrawNode(e As DrawTreeNodeEventArgs)
MyBase.OnDrawNode(e)
If e.Node Is Nothing Then Return
Dim rect As Rectangle = e.Bounds : rect.Inflate(0, 1)
If Not ClientRectangle.IntersectsWith(rect) Then
Return
End If
Dim G As Graphics = e.Graphics
G.SmoothingMode = SmoothingMode.HighQuality
G.TextRenderingHint = TextRenderingHint.ClearTypeGridFit
'Option1: If you want to draw different background color for the selected node.
'If (e.State And TreeNodeStates.Selected) = TreeNodeStates.Selected Then
' Using br As New SolidBrush(Color.LightSteelBlue) '<- suit yourself!
' G.FillRectangle(br, rect)
' End Using
'Else
' Using br As New SolidBrush(If(e.Node.BackColor.Equals(Color.Empty), BackColor, e.Node.BackColor))
' G.FillRectangle(br, rect)
' End Using
'End If
'Option2: If you don't want Option1.
Using br As New SolidBrush(If(e.Node.BackColor.Equals(Color.Empty), BackColor, e.Node.BackColor))
G.FillRectangle(br, rect)
End Using
Using br As New SolidBrush(If(e.Node.ForeColor.Equals(Color.Empty), ForeColor, e.Node.ForeColor))
G.DrawString(e.Node.Text, If(e.Node.NodeFont, Font), br, rect, NSF)
End Using
If ReferenceEquals(e.Node, HoverNode) Then
RightImageRect = New Rectangle(rect.Right + 5,
rect.Y + ((rect.Height - RightImage.Height) / 2),
rect.Height - 4, rect.Height - 4)
G.DrawImage(RightImage,
RightImageRect,
New Rectangle(0, 0, RightImage.Width, RightImage.Height),
GraphicsUnit.Pixel)
End If
End Sub
#End Region
#Region "Other Events"
'You need this to reduce the flickering.
Protected Overrides Sub OnHandleCreated(ByVal e As EventArgs)
SendMessage(
Handle,
TVM_SETEXTENDEDSTYLE,
IntPtr.op_Explicit(TVS_EX_DOUBLEBUFFER),
IntPtr.op_Explicit(TVS_EX_DOUBLEBUFFER)
)
MyBase.OnHandleCreated(e)
End Sub
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
MyBase.OnMouseMove(e)
Dim node = GetNodeAt(e.Location)
If node IsNot Nothing Then
'Avoid unnecessary Invalidate() calls.
If Not ReferenceEquals(node, HoverNode) Then
HoverNode = node
Invalidate()
End If
Else
'Avoid unnecessary Invalidate() calls.
If HoverNode IsNot Nothing Then
HoverNode = Nothing
Invalidate()
End If
End If
End Sub
Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
MyBase.OnMouseDown(e)
If e.Button = MouseButtons.Left AndAlso
RightImageRect.Contains(e.Location) Then
'Notify the container to do something.
OnEditButtonClicked()
End If
End Sub
Protected Overrides Sub OnMouseLeave(e As EventArgs)
MyBase.OnMouseLeave(e)
Invalidate()
End Sub
Protected Overrides Sub Dispose(disposing As Boolean)
MyBase.Dispose(disposing)
If disposing Then
RightImage.Dispose()
NSF.Dispose()
End If
End Sub
#End Region
#Region "Custom Events"
Public Class EditButtonClickArgs
Inherits EventArgs
Public Property Node As TreeNode
Sub New(node As TreeNode)
Me.Node = node
End Sub
End Class
''' <summary>
''' Raised when the right image is clicked.
''' </summary>
Public Event EditButtonClicked As EventHandler(Of EditButtonClickArgs)
''' <summary>
''' Raises the <see cref="EditButtonClicked"/> events.
''' </summary>
Protected Overridable Sub OnEditButtonClicked()
RaiseEvent EditButtonClicked(Me, New EditButtonClickArgs(HoverNode))
End Sub
#End Region
End Class
In the Form that contains the new TreeViewEx control, you can handle the EditButtonClicked to do the necessary:
Public Class Form1
Inherits Form
Private Sub TreeViewEx1_EditButtonClicked(sender As Object, e As TreeViewEx.EditButtonClickArgs) Handles TreeViewEx1.EditButtonClicked
'Do something with the e.Node
End Sub
End Class
And here's a quick demo:
Good luck.

Scrolling a Picturebox inside a Panel with a static label over

I have a PictureBox inside a Panel, to get automatic scrollbars when the picture is big, a Label with the photo title.
If I place the Label over the PictureBox, the "transparent" backcolor shows correctly but the Label remains at the top of the PictureBox and gets out of the screen if I scroll up-down or side-side the Panel's scrollbar!
Instead, if I put the Label outside the Panel (over the Form), the Label remains static on top of the screen, as I want, but the transparent backcolor doesn't show correctly becomes opaque.
Then if I set the Label's Parent property to the PictureBox, the transparent backcolor works fine again, but the static position of the Label is not respected anymore and joins PictureBox again!
How can I get a static Label with transparent backcolor over a PictureBox when using the scrollbars of the Panel?
I've tested the Overlay Form. It seems to work pretty well in your context.
Source Code in PasteBin
Uploaded the modified Project in OneDrive
(I don't have FW 4.5.2, tested with FW 4.5.1 and FW 4.7.1)
An Overlay can be an interesting feature, but, as I already said, this can also be done with TextRender.DrawText() or Graphics.DrawString(), backed by the simple math needed to offset the painted text when the picture container is scrolled.
In your Project, I've eliminated Label1 and all references to it.
Then, I've set this class field:
Private OverlayShown As Boolean = False
In frmPho_Load()
Overlay.Size = New Size(200, 50)
Overlay.OverlayPosition = Overlay.Alignment.Center
Overlay.Reposition(Me.Location, Me.Size)
OverlayShown = True
Overlay.Visible = False
Overlay.Show(Me)
In frmPho_Deactivate():
If OverlayShown = False Then
antip.Width = Me.Width
antip.Height = Me.Height
antip.Visible = True
End If
OverlayShown = False
These are all the changes made to the hosting Form (Form4), the form that uses the Overlay.
Public Class frmPho
Private Overlay As New OverlayForm
Private Sub frmPho_Load(sender As Object, e As EventArgs) Handles Me.Load
Overlay.Size = New Size(200, 50)
Overlay.OverlayPosition = Overlay.Alignment.Center
Overlay.Reposition(Me.Location, Me.Size)
OverlayShown = True
Overlay.Visible = False
Overlay.Show(Me)
'(...)
Overlay.Text = IO.Path.GetFileNameWithoutExtension(_ImageFileNames(_CurrentImage))
End Sub
Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
If CheckBox1.CheckState = False Then
Overlay.Visible = False
Else
OverlayShown = True
Overlay.Visible = True
End If
End Sub
Private Sub ShowPrevImage()
'(...)
OverlayShown = True
Overlay.Text = IO.Path.GetFileNameWithoutExtension(_ImageFileNames(_CurrentImage))
End Sub
Private Sub ShowNextImage()
'(...)
OverlayShown = True
Overlay.Text = IO.Path.GetFileNameWithoutExtension(_ImageFileNames(_CurrentImage))
End Sub
Private Sub frmPho_Deactivate(sender As Object, e As EventArgs) Handles Me.Deactivate
If OverlayShown = False Then
antip.Width = Me.Width
antip.Height = Me.Height
antip.Visible = True
End If
OverlayShown = False
End Sub
Private Sub frmPho_Move(sender As Object, e As EventArgs) Handles Me.Move
Overlay.Reposition(Me.Location, Me.Size)
End Sub
Private Sub frmPho_Resize(sender As Object, e As EventArgs) Handles Me.Resize
Overlay.Reposition(Me.Location, Me.Size)
End Sub
Private Sub frmPho_Shown(sender As Object, e As EventArgs) Handles Me.Shown
ShowOverlay(300)
End Sub
Private Async Sub ShowOverlay(Delay As Integer)
Await Task.Delay(Delay)
Overlay.Visible = True
Me.Focus()
End Sub
And this is the complete OverlayForm:
All Borders/Control Boxes to None (It's a borderless Form)
.StartPosition = Manual
.TransparncyKey = WhiteSmoke <= Depends on the font color (mod. when needed)
.BackColor = WhiteSmoke <= Depends on the font color (mod. when needed)
.ShowInTaskbar = False
Public Class OverlayForm
Private _Text As String
Private TextPosition As Point
Private _Brush As SolidBrush = New SolidBrush(Color.White)
Private _Flags As StringFormatFlags = StringFormatFlags.NoWrap
Public Enum Alignment
Left = 0
Right = 1
Center = 2
End Enum
Public Sub New()
InitializeComponent()
End Sub
Public Overrides Property Text() As String
Get
Return Me._Text
End Get
Set(ByVal value As String)
_Text = value
Me.Invalidate()
End Set
End Property
Public Property OverlayPosition As Alignment
Private Sub OverlayForm_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit
e.Graphics.TextContrast = 12
Dim _Size As SizeF = e.Graphics.MeasureString(Me._Text, Me.Font,
New SizeF(Me.Width, Me.Height),
New StringFormat(Me._Flags))
e.Graphics.DrawString(Me._Text, Me.Font, Me._Brush, New RectangleF(TextAlign(_Size.Width), _Size))
End Sub
Private Sub OverlayForm_ForeColorChanged(sender As Object, e As EventArgs) Handles Me.ForeColorChanged
Me._Brush = New SolidBrush(Me.ForeColor)
Me.Invalidate()
End Sub
Public Sub Reposition(ParentPosition As Point, ParentSize As Size)
Select OverlayPosition
Case Alignment.Left
Me.Location = New Point(ParentPosition.X + 20, ParentPosition.Y + 40)
Case Alignment.Right
Me.Location = New Point(ParentSize.Width - Me.Width - 20, ParentPosition.Y + 40)
Case Alignment.Center
Me.Location = New Point(ParentPosition.X + 20 + (ParentSize.Width \ 2) - (Me.Width \ 2), ParentPosition.Y + 40)
End Select
End Sub
Private Function TextAlign(TextWidth As Single) As PointF
Select Case OverlayPosition
Case Alignment.Left
Return New PointF(1, 1)
Case Alignment.Right
Return New PointF((Me.Width - TextWidth) - 1, 1)
Case Alignment.Center
If TextWidth > Me.Width Then TextWidth = Me.Width - 2
Return New PointF(CSng((Me.Width - TextWidth) / 4) - 1, 1)
End Select
End Function
End Class

Unable To Make Front Control Transparent Over PictureBox

I am trying to place a custom user control over the top of a PictureBox control but I cannot seem for the life of me how to set the transparency of the user control so it doesn't chop out the PictureBox image.
My User Control consists of a RectangleShape with text in the middle to create a 'Badge' icon on top of an image (see pictures below). The PictureBox and User Control both sit inside a Panel control and I have set the PictureBox.SendToBack() property and UserControl.BringToFront() property.
What I am left with is this:
My Code looks like this:
Option Explicit On
Option Strict On
Imports Microsoft.VisualBasic.PowerPacks
Public Class BadgeIcon
Inherits UserControl
Private _value As Integer
Private canvas As New ShapeContainer
Private Badge_Icon As New RectangleShape
Private rect As New Rectangle
Private m_BorderColor As Color = Color.White
Private m_FillColor As Color = Color.Red
Private m_BorderThickness As Integer = 2
Private m_BadgeFont As New Font("Segoe UI", 7, FontStyle.Bold)
Private m_BadgeText As String
Private m_TextColor As New SolidBrush(Color.White)
Private m_TextSize As Size
Private m_TextPadding As Integer = 5
Public Property Value() As Integer
Get
Return _value
End Get
Set(value As Integer)
_value = value
m_BadgeText = CStr(_value)
m_TextSize = TextRenderer.MeasureText(m_BadgeText, m_BadgeFont)
rect.Width = m_TextSize.Width + m_TextPadding
rect.Height = m_TextSize.Height + m_TextPadding
Me.Refresh()
End Set
End Property
Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
Get
Dim cp As CreateParams = MyBase.CreateParams
cp.ExStyle = &H20
Return cp
End Get
End Property
Sub New()
' This call is required by the designer.
InitializeComponent()
SetStyle(ControlStyles.SupportsTransparentBackColor, True)
SetStyle(ControlStyles.Opaque, False)
SetStyle(ControlStyles.DoubleBuffer, True)
SetStyle(ControlStyles.AllPaintingInWmPaint, True)
SetStyle(ControlStyles.UserPaint, True)
Me.BackColor = Color.FromArgb(0, 0, 0, 0)
UpdateStyles()
' Add any initialization after the InitializeComponent() call.
canvas.Parent = Me
Badge_Icon.Parent = canvas
canvas.BackColor = Color.FromArgb(0, 0, 0, 0)
'Create Badge Icon
With Badge_Icon
.BackColor = Color.FromArgb(0, 0, 0, 0)
.BorderColor = m_BorderColor
.BorderWidth = m_BorderThickness
.BorderStyle = Drawing2D.DashStyle.Solid
.CornerRadius = 11
.FillColor = m_FillColor
.FillStyle = FillStyle.Solid
.SelectionColor = Color.Transparent
End With
AddHandler Badge_Icon.Paint, AddressOf BadgeIcon_Paint
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
DrawBadgeIcon(e)
End Sub
Public Sub DrawBadgeIcon(e As PaintEventArgs)
Try
'Alter the size of the icon to fix the text
With Badge_Icon
.Location = New Point(rect.Left + 1, rect.Top + 1)
.Size = New Size(rect.Width, rect.Height - 1)
End With
Catch ex As Exception
ErrorTrap(ex, "cls_NotificationBadgeIcon: DrawBadgeIcon()")
End Try
End Sub
Private Sub BadgeIcon_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
Dim textRect As New Rectangle(2, 2, m_TextSize.Width + m_TextPadding - 1, m_TextSize.Height + m_TextPadding - 2)
'Draw the Text
Dim flags As New StringFormat
flags.Alignment = StringAlignment.Center
flags.LineAlignment = StringAlignment.Center
e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
e.Graphics.DrawString(m_BadgeText, m_BadgeFont, m_TextColor, textRect, flags)
End Sub
End Class
Then to add everything to my main form I call the following:
Dim pic As New PictureBox
pic.Image = My.Resources.Notifications
pic.SizeMode = PictureBoxSizeMode.StretchImage
pic.Location = New Point(21, 221)
pic.Size = New Size(42, 29)
pnlLeftMenuBar.Controls.Add(pic)
pic.SendToBack()
Dim Counter_Notify As New BadgeIcon
Counter_Notify.Location = New Point(50, 240)
pnlLeftMenuBar.Controls.Add(Counter_Notify)
Counter_Notify.BringToFront()
And simply use Counter_Notify.Value = 1 to update the counter value.
How can I remove the square rectangle chopping out the background image? Or should I be setting this up an entirely different way? I'm a little new to User Controls.
Any help appreciated. Thanks
Using the paint event you can draw right on the picturebox itself.
Private Sub pb__Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles pb.Paint
Dim bgRect As New Rectangle({x,y,width,height})
Dim textRect As New Rectangle(bgRect.X - {?}, bgRect.Y = {?}, width, height)
e.Graphics.FillEllipse(New SolidBrush(Color.Red), bgRect)
e.Graphics.DrawEllipse(New Pen(Color.White, 10), bgRect)
Using sf As New StringFormat
sf.LineAlignment = StringAlignment.Center
sf.Alignment = StringAlignment.Center
e.Graphics.DrawString("1", {your font}, {your brush}, textRect, sf)
End Using
End Sub

VB.NET Draw Button Over Another Button

Is it possible to draw a button on top of another button (besides just having a second button and moving it relative to the first button's Left and Top position)? I'm trying to make a little small optional question mark (button) appear in the corner of the main button that will take various actions if clicked.
Otherwise I was toying with the idea of just drawing the question mark on top of the button and getting the relative position of the mouse OnClick, then taking the action if the HasLink property is true and the mouse is in a specific area.
These will be dynamically created as well.
Public Class clsButton
Inherits Button
Private Property HasLink As Boolean = False
Public Sub New(ByVal Image As Image, ByVal ShowLink As Boolean)
Me.BackgroundImage = Image
Me.BackgroundImageLayout = ImageLayout.Center
Me.Height = 100
Me.Width = 200
If ShowLink Then DrawLink()
End Sub
Public Sub DrawLink()
Dim bmpBitmap As New Bitmap(Me.Width, Me.Height)
Dim graGraphic As Graphics = Graphics.FromImage(bmpBitmap)
Dim i As New Bitmap("c:\temp\question_mark.png")
graGraphic.DrawImage(i, (Me.Width - i.Width) - 5, 5)
Me.Image = bmpBitmap
End Sub
Protected Overrides Sub OnClick(e As EventArgs)
MyBase.OnClick(e)
Debug.WriteLine("X: " & MousePosition.X & " Y: " & MousePosition.Y)
Debug.WriteLine(Me.PointToClient(MousePosition))
End Sub
End Class
I think drawing that on top is a good idea and easily accomplished. The entire idea as such may be debatable, but I don't think it's necessarily bad.
Here is a quick example how the event flow can be set up.
Public Class SpecialButton
Inherits Button
Private flagIsHovering As Boolean = False
Private ReadOnly Property r As Rectangle
Get
Return New Rectangle(Me.Width - 20, 5, 15, 15)
End Get
End Property
Public ReadOnly Property clickInSpecialArea(p As Point) As Boolean
Get
Return (Me.r.Contains(p))
End Get
End Property
Private iconBG_normal As Color = Color.White
Private iconBG_hover As Color = Color.DarkOrange
Protected Overrides Sub OnPaint(pevent As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(pevent)
With pevent.Graphics
.FillRectangle(New SolidBrush(If(Me.flagIsHovering, iconBG_hover, iconBG_normal)), r)
.DrawRectangle(Pens.Blue, r)
.DrawString("?", New Font("Verdana", 8), Brushes.Blue, r.Location)
End With
End Sub
Protected Overrides Sub OnMouseMove(mevent As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseMove(mevent)
Dim oldState As Boolean = Me.flagIsHovering
Me.flagIsHovering = (r.Contains(mevent.Location))
If oldState <> Me.flagIsHovering Then Me.Invalidate()
End Sub
Protected Overrides Sub OnMouseLeave(e As System.EventArgs)
MyBase.OnMouseLeave(e)
If Me.flagIsHovering Then
Me.flagIsHovering = False
Me.Invalidate()
End If
End Sub
End Class
Form test code:
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim ct As New SpecialButton
ct.Text = "Text"
ct.Location = New Point(200, 20)
ct.Size = New Size(100, 30)
Me.Controls.Add(ct)
AddHandler ct.MouseClick, Sub(sender_ As Object, e_ As MouseEventArgs)
MessageBox.Show(
"Special click: " &
DirectCast(sender_, SpecialButton).clickInSpecialArea(e_.Location).ToString)
End Sub
End Sub
End Class
You can just position a small button with a question mark on it in the corner of your main button, lets say the small question mark button is called butq , now use the code below:
butq.BringToFront