Rounded Column in custom Button Control - vb.net

I'm trying to create a class for custom button control that will have 2 ingradient top and bottom color with rounded corners.
Below is the code that gives me two gradients color on top and bottom. However, I'm facing some issue with this where mouse hover property is not working and image also not showing (since new ingredients color overlaping the button text and image that is hidden in the back of ingradients color)
Can somebody help me with this control where all the control should work like they work with windows button control in addition to gradient color and rounded corners?
Please let me know in case you require any additional information.
Thanks in advance.
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Class MyButton
Inherits Button
Private m_TopColor As Color = Color.LightGreen
Private m_BottomColor As Color = Color.Orange
Public Property TopColor As Color
Get
Return m_TopColor
End Get
Set(ByVal value As Color)
m_TopColor = value
Me.Invalidate()
End Set
End Property
Public Property BottomColor As Color
Get
Return m_BottomColor
End Get
Set(ByVal value As Color)
m_BottomColor = value
Me.Invalidate()
End Set
End Property
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
Using lgb As LinearGradientBrush = New LinearGradientBrush(Me.ClientRectangle, m_TopColor, m_BottomColor, 90.0F)
Using textBrush As SolidBrush = New SolidBrush(Me.ForeColor)
Using format As StringFormat = New StringFormat()
format.Alignment = GetHorizontalAlignment()
format.LineAlignment = GetVerticalAlignment()
e.Graphics.FillRectangle(lgb, Me.ClientRectangle)
e.Graphics.DrawString(Me.Text, Me.Font, textBrush, Me.ClientRectangle, format)
End Using
End Using
End Using
End Sub
Private Function GetVerticalAlignment() As StringAlignment
Return CType(Math.Log(Me.TextAlign, 2D) / 4, StringAlignment)
End Function
Private Function GetHorizontalAlignment() As StringAlignment
Return CType(Math.Log(Me.TextAlign, 2D) Mod 4, StringAlignment)
End Function
End Class

customize a rounded button,code:
Imports System.Drawing.Drawing2D
Class MyButton
Inherits Button
Private m_TopColor As Color = Color.LightGreen
Private m_BottomColor As Color = Color.Orange
Public Property TopColor As Color
Get
Return m_TopColor
End Get
Set(ByVal value As Color)
m_TopColor = value
Me.Invalidate()
End Set
End Property
Public Property BottomColor As Color
Get
Return m_BottomColor
End Get
Set(ByVal value As Color)
m_BottomColor = value
Me.Invalidate()
End Set
End Property
Public Sub New()
FlatStyle = FlatStyle.Flat
FlatAppearance.BorderSize = 0
FlatAppearance.BorderColor = Color.FromArgb(0, 0, 0, 0)
FlatAppearance.MouseDownBackColor = Color.Transparent
FlatAppearance.MouseOverBackColor = Color.Transparent
BackColor = Color.Transparent
Me.BackgroundImageLayout = ImageLayout.Zoom
AddHandler Me.MouseMove, AddressOf MyMouseMove
AddHandler Me.MouseLeave, AddressOf MyMouseLeave
End Sub
Private Sub MyMouseLeave(ByVal sender As Object, ByVal e As EventArgs)
End Sub
Private Sub MyMouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
End Sub
Private Sub Draw(ByVal rectangle As Rectangle, ByVal g As Graphics, ByVal cusp As Boolean)
Dim span As Integer = 2
g.SmoothingMode = SmoothingMode.AntiAlias
Dim myLinearGradientBrush As LinearGradientBrush = New LinearGradientBrush(Me.ClientRectangle, m_TopColor, m_BottomColor, 90.0F)
g.FillPath(myLinearGradientBrush, DrawRoundRect(rectangle.X, rectangle.Y, rectangle.Width - span, rectangle.Height - 1, 20))
End Sub
Private Function DrawRoundRect(ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, ByVal radius As Integer) As GraphicsPath
Dim gp As GraphicsPath = New GraphicsPath()
gp.AddArc(x, y, radius, radius, 180, 90)
gp.AddArc(width - radius, y, radius, radius, 270, 90)
gp.AddArc(width - radius, height - radius, radius, radius, 0, 90)
gp.AddArc(x, height - radius, radius, radius, 90, 90)
gp.CloseAllFigures()
Return gp
End Function
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
MyBase.OnPaint(e)
Draw(e.ClipRectangle, e.Graphics, False)
End Sub
Private Function GetVerticalAlignment() As StringAlignment
Return CType(Math.Log(Me.TextAlign, 2D) / 4, StringAlignment)
End Function
Private Function GetHorizontalAlignment() As StringAlignment
Return CType(Math.Log(Me.TextAlign, 2D) Mod 4, StringAlignment)
End Function
End Class

Related

Prevent Docking on Drawn Rectangle

I try to create a borderless form with this code
Public Partial Class Form1
Inherits Form
Public Sub New()
InitializeComponent()
Me.FormBorderStyle = FormBorderStyle.None
Me.DoubleBuffered = True
Me.SetStyle(ControlStyles.ResizeRedraw, True)
End Sub
Private Const cGrip As Integer = 16
Private Const cCaption As Integer = 32
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
Dim rc As Rectangle = New Rectangle(Me.ClientSize.Width - cGrip, Me.ClientSize.Height - cGrip, cGrip, cGrip)
ControlPaint.DrawSizeGrip(e.Graphics, Me.BackColor, rc)
rc = New Rectangle(0, 0, Me.ClientSize.Width, cCaption)
e.Graphics.FillRectangle(Brushes.DarkBlue, rc)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = &H84 Then
Dim pos As Point = New Point(m.LParam.ToInt32())
pos = Me.PointToClient(pos)
If pos.Y < cCaption Then
m.Result = CType(2, IntPtr)
Return
End If
If pos.X >= Me.ClientSize.Width - cGrip AndAlso pos.Y >= Me.ClientSize.Height - cGrip Then
m.Result = CType(17, IntPtr)
Return
End If
End If
MyBase.WndProc(m)
End Sub
End Class
the problem is that if I should add a control like Panel and dock it to the top, it stays on top of the Blue rectangle that was painted.
I want every docking to start below the painted rectangle

To make the custom trackbar smaller by changing more than 1 value in one scroll move

I have created a custom trackbar that gives values between 100-1600. The problem is that i havent been able to reduce the size of the trackbar. The trackbar has to have the width as 1600 for a user to be able to access all the values and keep the thumb in the trackbar at the same time. Here is my code :
Public Class myTrackBar
Inherits Control
'Public Value As Integer
Private Pointer As New Bitmap(25, 30)
Private Rect As New Rectangle(100, 0, 20, 30)
Public Event Scroll(ByVal Sender As Object, ByVal e As ValueChangedEventArgs)
Private Moving As Boolean
Private Offset As Integer
Public Sub New()
'Size = New Size(210, 50)
DoubleBuffered = True
Using g As Graphics = Graphics.FromImage(Pointer)
g.Clear(Color.White)
g.FillRectangle(Brushes.DarkBlue, New Rectangle(0, 0, 50, 50))
'g.FillPolygon(Brushes.Blue, New Point() {New Point(0, 15), New Point(5, 20), New Point(10, 15)})
'g.FillEllipse(Brushes.DarkBlue, 0, 0, 19, 19)
End Using
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
e.Graphics.FillRectangle(Brushes.White, New Rectangle(0, 0, Width - 100, Height))
Dim X As Integer = 15
' For count As Integer = 1 To 10
e.Graphics.DrawLine(New Pen(Brushes.Green, 16), New Point(0, 15), New Point(Width - 100, 15))
' X += 20
'Next
' Using P As New Pen(Brushes.Black, 1)
'P.DashStyle = Drawing2D.DashStyle.Dot
'e.Graphics.DrawRectangle(P, New Rectangle(100, 1, Width - 5, Height - 5))
'End Using
e.Graphics.DrawImage(Pointer, Rect)
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
End Sub
Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
If Rect.Contains(e.Location) Then
Moving = True
Offset = (e.Location.X - Rect.X)
End If
End Sub
Protected Overrides Sub OnMouseup(ByVal e As System.Windows.Forms.MouseEventArgs)
Moving = False
End Sub
Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
If Moving Then
Rect.X = Math.Min(Math.Max(e.Location.X - Offset, 0), 1500)
Invalidate()
RaiseEvent Scroll(Me, New ValueChangedEventArgs(Rect.X))
End If
End Sub
Public Property Value As Integer
Get
Return CInt((Rect.X + 100))
End Get
Set(ByVal value As Integer)
Rect.X = CInt(value)
End Set
End Property
End Class
There are various dlls available online for trackbars. If you want to simply use it in a project you can simply import the dll files into the project and use them like any other element.

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

Picturebox - Get image inside drawn rectangle and show in another Picturebox

I made a search and successfully found a solution to draw a rectangle inside my Picturebox while mousemoving using a class named Rectangulo:
Public Class Form1
Dim SelectionBoxObj As New Rectangulo()
Dim IsMouseDown As Boolean = False
Public SelectedObjPoint As Point
Private Sub PictureBox1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
If e.Button = Windows.Forms.MouseButtons.Left Then
IsMouseDown = True
SelectedObjPoint = New Point(e.X, e.Y)
End If
End Sub
Private Sub PictureBox1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
If IsMouseDown = True Then
If e.X < SelectionBoxObj.X Then
SelectionBoxObj.X = e.X
SelectionBoxObj.Width = SelectedObjPoint.X - e.X
Else
SelectionBoxObj.X = SelectedObjPoint.X
SelectionBoxObj.Width = e.X - SelectedObjPoint.X
End If
If e.Y < SelectedObjPoint.Y Then
SelectionBoxObj.Y = e.Y
SelectionBoxObj.Height = SelectedObjPoint.Y - e.Y
Else
SelectionBoxObj.Y = SelectedObjPoint.Y
SelectionBoxObj.Height = e.Y - SelectedObjPoint.Y
End If
Me.Refresh()
End If
End Sub
Private Sub PictureBox1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
IsMouseDown = False
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
If SelectionBoxObj.Width > 0 And SelectionBoxObj.Height > 0 Then
Dim oGradientBrush As Brush = New Drawing.Drawing2D.LinearGradientBrush(SelectionBoxObj.RectangleF, SelectionBoxObj.FillColor, SelectionBoxObj.FillColor, Drawing.Drawing2D.LinearGradientMode.Vertical)
e.Graphics.FillRectangle(oGradientBrush, SelectionBoxObj.RectangleF)
Dim TempPen = New Pen(SelectionBoxObj.BorderLineColor, SelectionBoxObj.BorderLineWidth)
TempPen.DashStyle = SelectionBoxObj.BorderLineType
e.Graphics.DrawRectangle(TempPen, SelectionBoxObj.RectangleF.X, SelectionBoxObj.RectangleF.Y, SelectionBoxObj.RectangleF.Width, SelectionBoxObj.RectangleF.Height)
End If
End Sub
End Class
And the Rectangle Class code:
Public Class Rectangulo
Private m_BorderLineColor As Color = Drawing.Color.FromArgb(255, 51, 153, 255)
Private m_FillColor As Color = Drawing.Color.FromArgb(40, 51, 153, 255)
Private m_BorderLineType As Drawing2D.DashStyle = Drawing2D.DashStyle.Solid
Private m_BorderLineWidth As Integer = 1
Private m_X As Single
Private m_Y As Single
Private m_Width As Single
Private m_Height As Single
Private m_RectangleF As RectangleF
Public Property BorderLineWidth() As Integer
Get
Return m_BorderLineWidth
End Get
Set(ByVal value As Integer)
m_BorderLineWidth = value
End Set
End Property
Public Property BorderLineType() As Drawing2D.DashStyle
Get
Return m_BorderLineType
End Get
Set(ByVal value As Drawing2D.DashStyle)
m_BorderLineType = value
End Set
End Property
Public Property BorderLineColor() As Color
Get
Return m_BorderLineColor
End Get
Set(ByVal value As Color)
m_BorderLineColor = value
End Set
End Property
Public Property FillColor() As Color
Get
Return m_FillColor
End Get
Set(ByVal value As Color)
m_FillColor = value
End Set
End Property
Public Property X() As Single
Get
Return m_RectangleF.X
End Get
Set(ByVal value As Single)
m_RectangleF.X = value
End Set
End Property
Public Property Y() As Single
Get
Return m_RectangleF.Y
End Get
Set(ByVal value As Single)
m_RectangleF.Y = value
End Set
End Property
Public Property Width() As Single
Get
Return m_RectangleF.Width
End Get
Set(ByVal value As Single)
m_RectangleF.Width = value
End Set
End Property
Public Property Height() As Single
Get
Return m_RectangleF.Height
End Get
Set(ByVal value As Single)
m_RectangleF.Height = value
End Set
End Property
Public Property RectangleF() As RectangleF
Get
Return m_RectangleF
End Get
Set(ByVal value As RectangleF)
m_RectangleF = value
End Set
End Property
End Class
So far I found this article and adjusted with my code in mousemove event like this:
Dim top As Integer = Integer.Parse(SelectionBoxObj.Y)
Dim left As Integer = Integer.Parse(SelectionBoxObj.X)
Dim width As Integer = Integer.Parse(SelectionBoxObj.Width)
Dim height As Integer = Integer.Parse(SelectionBoxObj.Height)
' Make a Bitmap to hold the result.
If width > 0 And height > 0 Then
Dim bm As New Bitmap(width, height)
' Associate a Graphics object with the Bitmap
Using gr As Graphics = Graphics.FromImage(bm)
' Define source and destination rectangles.
Dim src_rect As New Rectangle(left, top, width, _
height)
Dim dst_rect As New Rectangle(0, 0, width, height)
' Copy that part of the image.
gr.DrawImage(PictureBox1.Image, dst_rect, src_rect, _
GraphicsUnit.Pixel)
End Using
' Display the result.
PictureBox2.Image = bm
And It's almost done! But the only problem now is the points are incorrect, the image displayed is always from the middle of selection to right and not his full size of selection
Thanks in advance