VB.Net (WinForms) Drawing a Line to Follow the Cursor - vb.net

The Problem
I am trying to have the line draw to the cursors current position as it moves. I've tried adding the code below to the MouseMove event in the form; however, nothing changed. I have been able to successfully draw the line, but regardless of what I do I just can't seem to get the line to follow the mouse. Also, it would be nice to be able to achieve this with reliable code without using a timer (for resources sake), but whatever works, works.
Code
The program is simply a blank form. So far this is all I got for code (this is all of the code):
Public Class drawing
Public xpos = MousePosition.X
Public ypos = MousePosition.Y
Public Sub DrawLineFloat(ByVal e As PaintEventArgs)
' Create pen.
Dim blackPen As New Pen(Color.Black, 2)
' Create coordinates of points that define line.
Dim x1 As Single = xpos
Dim y1 As Single = ypos
Dim x2 As Single = 100
Dim y2 As Single = 100
' Draw line to screen.
e.Graphics.DrawLine(blackPen, x1, y1, x2, y2)
End Sub
Private Sub drawing_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
DrawLineFloat(e)
End Sub
End Class
As you can see, I tried to modify the code for the MouseMove event, but it failed (I'm just including it anyways so you can see the previous attempt). Thanks in advance for any help.

This will do what you need:
private Point? startPoint;
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (startPoint.HasValue)
{
Graphics g = e.Graphics;
using (Pen p = new Pen(Color.Black, 2f))
{
g.DrawLine(p, startPoint.Value, new Point(100, 100));
}
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
this.startPoint = e.Location;
this.Invalidate();
}
this refers to the Form instance.
Code translated to Vb.Net using http://converter.telerik.com/
Private startPoint As System.Nullable(Of Point)
Protected Overrides Sub OnPaint(e As PaintEventArgs)
MyBase.OnPaint(e)
If startPoint.HasValue Then
Dim g As Graphics = e.Graphics
Using p As New Pen(Color.Black, 2F)
g.DrawLine(p, startPoint.Value, New Point(100, 100))
End Using
End If
End Sub
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
MyBase.OnMouseMove(e)
Me.startPoint = e.Location
Me.Invalidate()
End Sub

Related

Custom Control changing properties itself everytime I close Visual Studio

Almost everytime I close VisualStudio my custom ToggleControl changes it's properties (size, location, margin) so it moves around in Designer, and gets bigger and bigger...
As I checked now location was set to 32000;32000, margin to 3;69000;3;69000 and size also some big number.
What could be the issue with this? I can't really find anything.
On another Tabcontrol I have the same ToggleControl that works fine, I tried to copy it but result is same.
Edit: Added control code
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Public Class Toggle
Inherits System.Windows.Forms.UserControl
Private _checked As Boolean
Public Property Checked As Boolean
Get
Return _checked
End Get
Set(ByVal value As Boolean)
If Not _checked.Equals(value) Then
_checked = value
Me.OnCheckedChanged()
End If
End Set
End Property
Protected Overridable Sub OnCheckedChanged()
RaiseEvent CheckedChanged(Me, EventArgs.Empty)
End Sub
Public Event CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
Protected Overrides Sub OnMouseClick(e As MouseEventArgs)
Me.Checked = Not Me.Checked
Me.Invalidate()
MyBase.OnMouseClick(e)
End Sub
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
Me.OnPaintBackground(e)
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
Using path = New GraphicsPath()
Dim d = Padding.All
Dim r = Me.Height - 2 * d
path.AddArc(d, d, r, r, 90, 180)
path.AddArc(Me.Width - r - d, d, r, r, -90, 180)
path.CloseFigure()
e.Graphics.FillPath(If(Checked, Brushes.DarkGray, Brushes.LightGray), path)
r = Height - 1
Dim rect = If(Checked, New System.Drawing.Rectangle(Width - r - 1, 0, r, r), New System.Drawing.Rectangle(0, 0, r, r))
e.Graphics.FillEllipse(If(Checked, Brushes.Green, Brushes.LightSlateGray), rect)
End Using
End Sub
End Class
This code is from several sources over the years and has some minor tweaks. It appears it exist in various forms on different sites so it's unclear who to attribute.

Changing 'lamp' Colour Indicator within the Graphical User Interface (Visual Studio 2019)

I would like to change the colour within a single circular indicator within a Graphical User Interface, so that it shows when an action is completed or when it fails ['two tone green/red LED']. I've looked through the inbuilt presets within the Toolbox but have been unable find anything.
I would therefore be grateful for any assistance.
I've found this code on the msdn.microsoft.com forum, which changes the colour of the centre of the 'dot' when you press the RadioButton.
Private Sub RadioButton_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles RadioButton1.Paint, RadioButton2.Paint
If DirectCast(sender, RadioButton).Checked Then
e.Graphics.FillEllipse(Brushes.Red, New RectangleF(2.5, 4.7, 7.2, 7.2))
End If
So have incorporated it into my code, its not at all elegant and there is clearly room for improvement, but it does work.
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
If My.Computer.Network.Ping("192.168.0.1") Then
RadioButton1.ForeColor = Color.Green
RadioButton1.ForeColor = Color.Black
Else
RadioButton1.ForeColor = Color.Red
RadioButton1.ForeColor = Color.Black
End If
End Sub
Private Sub RadioButton_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles RadioButton1.Paint
If My.Computer.Network.Ping("192.168.0.1") Then
e.Graphics.FillEllipse(Brushes.Green, New RectangleF(2.5, 4.7, 7.2, 7.2))
Else
e.Graphics.FillEllipse(Brushes.Red, New RectangleF(2.5, 4.7, 7.2, 7.2))
End If
End Sub
Explanation: when the 'Test Network' button is pressed it sends out a network ping, and depending upon the return the Network RadioButton 'dot' changes colour to either Green or Red,
Here's ON/OFF LED control.
Add a new class to your project, name it say OnOffLed.vb, copy the code below and paste it in the new class.
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Drawing.Drawing2D
Public Class OnOffLed
Inherits Panel
Public Enum LedState
[On]
Off
End Enum
Sub New()
SetStyle(ControlStyles.AllPaintingInWmPaint Or
ControlStyles.OptimizedDoubleBuffer Or
ControlStyles.ResizeRedraw Or
ControlStyles.UserPaint, True)
UpdateStyles()
End Sub
Private _state As LedState = LedState.Off
Public Property State As LedState
Get
Return _state
End Get
Set(value As LedState)
_state = value
Invalidate()
End Set
End Property
Private _onText As String
Public Property OnText As String
Get
Return _onText
End Get
Set(value As String)
_onText = value
Invalidate()
End Set
End Property
Private _offText As String
Public Property OffText As String
Get
Return _offText
End Get
Set(value As String)
_offText = value
Invalidate()
End Set
End Property
Protected Overrides Sub OnPaint(e As PaintEventArgs)
Dim rec As New Rectangle(2, 2, Height - 5, Height - 5)
Dim recText As New Rectangle(Height + 2, 1, Width - (Height - 2), Height)
Dim G As Graphics = e.Graphics
G.SmoothingMode = SmoothingMode.AntiAlias
G.Clear(Parent.BackColor)
If _state = LedState.On Then
Dim cb As New ColorBlend With {
.Colors = {Color.Green, Color.DarkGreen, Color.Green},
.Positions = {0, 0.5, 1}
}
Using lgb As New LinearGradientBrush(rec, Color.Empty, Color.Empty, 90.0F) With {.InterpolationColors = cb}
G.FillEllipse(lgb, rec)
End Using
Else
Dim cb As New ColorBlend With {
.Colors = {Color.Red, Color.DarkRed, Color.Red},
.Positions = {0, 0.5, 1}
}
Using lgb As New LinearGradientBrush(rec, Color.Empty, Color.Empty, 90.0F) With {.InterpolationColors = cb}
G.FillEllipse(lgb, rec)
End Using
End If
G.TextRenderingHint = Drawing.Text.TextRenderingHint.ClearTypeGridFit
Using br As New SolidBrush(ForeColor)
Using sf As New StringFormat With {.Alignment = StringAlignment.Near, .LineAlignment = StringAlignment.Center}
G.DrawString(If(_state = LedState.On, _onText, _offText), Font, br, recText, sf)
End Using
End Using
End Sub
End Class
Rebuild your project.
In the ToolBox under your project's component tab, you'll find the new control. OnOffLed. Drop it in your form as you drop any other control.
You can toggle the state through the State property, set different text if you need that for each state through the OnText and OffText properties.
Usage Example:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
If My.Computer.Network.Ping("192.168.2.01") Then
OnOffLed1.State = OnOffLed.LedState.On
Else
OnOffLed1.State = OnOffLed.LedState.Off
End If
End Sub
Good luck.

Transparent image over two controls with different back colors

I am trying to place a transparent image over two adjacent controls that have different background colors.
I want the image to remain transparent, meaning the Image needs to show the backcolor of each control.
The controls are two Panels set to different background colors and the Image (PictureBox or otherwise) is placed between the two panel controls.
Public Class frmMain
Private Img1 As Image = Image.FromFile("C:\xxxx.png")
Private Sub frmMain_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
e.Graphics.DrawImage(Img1, 5, 5)
End Sub
End Class
Let's try this.
Create a new class in the Project, call it TPanel and paste in the custom Panel class you can find below, overwriting the existing definition.
Compile the Project then find the new TPanel control in the ToolBox and drop one instance inside a Form.
On the Form, not inside one of the Colored Panels, otherwise it will become child of another control and it will be confined inside its bounds.
Add an event handler to the Paint event of the TPanel and insert this code inside the handler method:
Private Sub TPanel1_Paint(sender As Object, e As PaintEventArgs) Handles TPanel1.Paint
Dim canvas As Control = DirectCast(sender, Control)
Dim rect As Rectangle = ScaleImageFrame(imgBasketBall, canvas.ClientRectangle)
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
e.Graphics.CompositingMode = CompositingMode.SourceOver
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half
e.Graphics.DrawImage(imgBasketBall, rect)
End Sub
Private Function ScaleImageFrame(sourceImage As Bitmap, destinationFrame As Rectangle) As Rectangle
Dim rect As RectangleF = New RectangleF(0, 0, sourceImage.Width, sourceImage.Height)
'Define the ratio between the Image Rectangle and the Container ClientRectangle
Dim ratio As Single = CType(Math.Max(destinationFrame.Width, destinationFrame.Height) /
Math.Max(rect.Width, rect.Height), Single)
rect.Size = New SizeF(rect.Width * ratio, rect.Height * ratio)
'Use Integer division to avoid negative values
rect.Location = New Point((destinationFrame.Width - CInt(rect.Width)) \ 2,
(destinationFrame.Height - CInt(rect.Height)) \ 2)
Return Rectangle.Round(rect)
End Function
In the Form, create an instance of a Bitmap object that will contain the Image; also set the Location of the Panel (TPanel)
The Controls called panColored1 and panColored2 are supposed to be the names of the two existing Panels where the Image must be positioned. The sample code positions the Image in the middle of the 2 Panels, using TPanel1.Location( (...) )
Private imgBasketBall As Bitmap = Nothing
Public Sub New()
InitializeComponent()
imgBasketBall = DirectCast(Image.FromStream(New MemoryStream(File.ReadAllBytes("basketball.png"))), Bitmap)
TPanel1.Size = New Size(120, 120)
TPanel1.Location = New Point(panColored1.Left + (panColored1.Width - TPanel1.Width) \ 2,
panColored1.Top + (panColored1.Height + panColored2.Height - TPanel1.Height) \ 2)
TPanel1.BringToFront()
End Sub
Result:
Bitmap Size Bitmap Size
(1245x1242) (1178x2000)
The TPanel (Transparent Panel) class:
Imports System.ComponentModel
<DesignerCategory("Code")>
Public Class TPanel
Inherits Panel
Private Const WS_EX_TRANSPARENT As Integer = &H20
Public Sub New()
SetStyle(ControlStyles.AllPaintingInWmPaint Or
ControlStyles.UserPaint Or
ControlStyles.Opaque Or
ControlStyles.ResizeRedraw, True)
SetStyle(ControlStyles.OptimizedDoubleBuffer, False)
End Sub
Protected Overrides Sub OnPaint(e As PaintEventArgs)
e.Graphics.FillRectangle(Brushes.Transparent, Me.ClientRectangle)
MyBase.OnPaint(e)
End Sub
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim parameters As CreateParams = MyBase.CreateParams
parameters.ExStyle = parameters.ExStyle Or WS_EX_TRANSPARENT
Return parameters
End Get
End Property
End Class
There is also something you can also try, It may not be professional but it works. Split the images into two halves. Draw the first half on one of the panels and the second half on the other panel.
Be Sure to Import System.IO in Your project.
The code for the splitting goes like this:
Imports System.IO
...
Public Function SplitImage(ByVal imgpath As String) As Image()
Dim img As Image = Image.FromFile(imgpath)
Dim bmp As Bitmap = DirectCast(img, Bitmap)
Dim i As Integer = bmp.Height / 2
Dim image1 As Bitmap = New Bitmap(bmp.Width, i)
Dim image2 As Bitmap = New Bitmap(bmp.Width, i)
Dim yPos As Integer = 0
For x As Integer = 0 To image1.Width - 1
For y As Integer = 0 To image1.Height - 1
image1.SetPixel(x, y, bmp.GetPixel(x, y))
yPos = y
Next
Next
yPos += 1
Dim ycount As Integer = 0
For x As Integer = 0 To image2.Width - 1
For y As Integer = yPos To bmp.Height - 1
If ycount = i Then
ycount -= 1
End If
image2.SetPixel(x, ycount, bmp.GetPixel(x, y))
ycount += 1
Next
ycount = 0
Next
Dim ms As MemoryStream = New MemoryStream
Dim ms1 As MemoryStream = New MemoryStream
image1.Save(ms, Imaging.ImageFormat.Png)
image2.Save(ms1, Imaging.ImageFormat.Png)
Dim returnedImage(2) As Image
returnedImage(0) = image1
returnedImage(1) = image2
Return returnedImage
End Function
Create Two panels on your form (Panel1 and Panel2) and a Button(Button1).
Place The two panels the way you want it, set the BackgroundImageLayout property of the panels to StretchImage.
Then from your code you can call the function like this, i.e From the Button's click event:
Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim pic() As Image = SplitImage("C:\xxxx.png")
Panel1.BackgroundImage = pic(0)
Panel2.BackgroundImage = pic(1)
End Sub
For More Information about the Bitmap Class, Check out this link Bitmap Class

getting control object with Graphics from class instance

i dont have much experience with Graphics class in winforms.
i am only in the sketching stage of it (also the code i have added).
my problem is that i am trying to create a panel: clockPanel with some graphics on it, no exception is thrown but the panel (as i can see in the UI) have no graphics on it. tryed to look for examples but i cant find mistakes or something i missed in my code. probably its an easy one for those of you that experienced with graphics.
thank you for your time an consideration.
VB CODE:
adding 'clockpanel' panel to other pannel ('secondaryPannel') via instance to GoalsClock class
Public Class ManagersTab
...
Public Sub BuiledDashBoard()
...
Dim p As GoalsClock = New GoalsClock(100, 100, 0.8)
p.Create()
p.clockPanel.Location = New Point(200, 100)
secondaryPannel.Controls.Add(p.clockPanel)
...
End Sub
...
End Class
Create() method is the most relevant part:
Class GoalsClock
Private Gclock As Graphics
Private clockWidth As Int16
Private clockHeight As Int16
Private xPos As Int16
Private yPos As Int16
Public clockPanel As Panel
Private panelColor As Color
Private PercentTextColor As Color
' rectangles to store squares
Protected OuterRect As Rectangle
Protected InnerRect As Rectangle
Protected InnerStringBrush As Brush
Protected InnerStringColor As Color
Protected InnerStringFontSize As Byte
' inner square
Private InnerSquarePen As Pen
Private InnerSquarePen_Color As Color
Private InnerSquarePen_Width As Byte
' outer square
Private OuterSquarePen As Pen
Private OuterSquarePen_Color As Color
Private OuterSquarePen_Width As Byte
Private _PercentOfGoals As Single ' to calculate the goals deg arc
Public Property PercentOfGoals() As Single
Get
Return _PercentOfGoals * 100
End Get
Private Set(ByVal value As Single)
If value <= 1.0F Then
_PercentOfGoals = value
Else
value = 0
End If
End Set
End Property
Sub New(ByVal clockWidth As Int16, ByVal clockHeight As Int16, ByVal GoalsPercent As Single)
Me.clockWidth = clockWidth
Me.clockHeight = clockHeight
PercentOfGoals = GoalsPercent
' values for test
xPos = 0
yPos = 0
InnerStringFontSize = 12
OuterSquarePen = New Pen(Color.Gray)
InnerSquarePen = New Pen(Color.Cyan)
OuterSquarePen_Width = 23
InnerSquarePen_Width = 15
End Sub
''' <summary>
'''
''' create graphics of the goals clock on clockPanel
''' </summary>
''' <remarks></remarks>
Public Sub Create()
' panel
clockPanel = New Panel()
clockPanel.Size = New Size(clockWidth, clockHeight)
clockPanel.BackColor = Color.Beige
Gclock = clockPanel.CreateGraphics()
' create outer rectangle
OuterRect = New Rectangle(xPos, yPos, clockWidth, clockHeight)
' create inner rectangle
Dim w, h, x, y As Integer
getInnerRectSizeAndLocation(w, h, x, y)
InnerRect = New Rectangle(x, y, w, h)
' draw goals string inside inner rect
InnerStringBrush = Brushes.Cyan
Gclock.DrawString(getPercentString(), New Font("ARIAL", InnerStringFontSize, FontStyle.Bold), InnerStringBrush, InnerRect)
' create outer square
OuterSquarePen = New Pen(OuterSquarePen_Color, OuterSquarePen_Width)
Gclock.DrawArc(OuterSquarePen, OuterRect, 1.0F, 360.0F)
' create inner square
InnerSquarePen = New Pen(InnerSquarePen_Color, InnerSquarePen_Width)
Dim sweepAngle As Short = getSweepAngleFromGoalsPercent()
Gclock.DrawArc(InnerSquarePen, OuterRect, -90.0F, sweepAngle)
End Sub
Private Sub getInnerRectSizeAndLocation(ByRef w As Integer, ByRef h As Integer, ByRef x As Integer, ByRef y As Integer)
' values for test
w = 40
h = 40
x = 64
y = 65
End Sub
Private Function getPercentString() As String
Return PercentOfGoals.ToString() & "%"
End Function
Private Function getSweepAngleFromGoalsPercent() As Single
' value for test
Return 0.0F
End Function
End Class
You must subscribe to the panel's Paint event and perform all drawing there. The AddHandler statement is used to dynamically subscribe to events.
The Graphics class will not store any information about what you draw, so when your panel is redrawn everything you previously drew will be gone unless you draw it again. This is where the Paint event comes into play: it will be raised every time your panel is redrawn, passing an instance of a Graphics class in its PaintEventArgs so you can draw your stuff onto the panel again.
Public Sub Create()
' panel
clockPanel = New Panel()
clockPanel.Size = New Size(clockWidth, clockHeight)
clockPanel.BackColor = Color.Beige
' subscribe to the panel's paint event
AddHandler clockPanel.Paint, AddressOf clockPanel_Paint
End Sub
Private Sub clockPanel_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
Dim Gclock As Graphics = e.Graphics 'Local variable only, as the Graphics object might change.
' create outer rectangle
OuterRect = New Rectangle(xPos, yPos, clockWidth, clockHeight)
' create inner rectangle
Dim w, h, x, y As Integer
getInnerRectSizeAndLocation(w, h, x, y)
InnerRect = New Rectangle(x, y, w, h)
' draw goals string inside inner rect
InnerStringBrush = Brushes.Cyan
Gclock.DrawString(getPercentString(), New Font("ARIAL", InnerStringFontSize, FontStyle.Bold), InnerStringBrush, InnerRect)
' create outer square
OuterSquarePen = New Pen(OuterSquarePen_Color, OuterSquarePen_Width)
Gclock.DrawArc(OuterSquarePen, OuterRect, 1.0F, 360.0F)
' create inner square
InnerSquarePen = New Pen(InnerSquarePen_Color, InnerSquarePen_Width)
Dim sweepAngle As Short = getSweepAngleFromGoalsPercent()
Gclock.DrawArc(InnerSquarePen, OuterRect, -90.0F, sweepAngle)
End Sub
As you also might've seen I am constantly redeclaring a new Gclock variable in the Paint event. This is because the Graphics instance used to draw your panel with might change, so you shouldn't store it any longer than the time the Paint event lasts (so I highly recommend you remove the declaration in the top of your class).

Draw triangle VB.NET

Dear forum members I have to make a triangle class.
My problem is that I the public overrides sub teken does not work
IN MY CLASS FORM (FUNCTION RANDOMSTRAAL)
Private Function RandomStraal() As Int32
Return 20 + _Random.Next(Me.ClientSize.Width\2)
End Function
IN MY CLASS FORM (SUB MAAKTRIANGLE)
Private Sub MaakTriangle(x As Integer, y As Integer)
Dim tria As New Triangle(RandomKleur, RandomKleur, New Point(x, y), New Point(x, y + RandomStraal()), New Point(x + RandomStraal(), y))
tria.PenDikte = _Random.Next(1, 6)
_Tekening.Add(tria)
'_Tekening.Teken(Me.CreateGraphics)
Invalidate()
End Sub
MY CLASS TRIANGLE
Friend Class Triangle
Inherits Figuur
Public Property Point1() As Point
Public Property Point2() As Point
Public Property Point3() As Point
Private _Pointers() As Point = {Point1, Point2, Point3}
Public Sub New(penKleur As Color, vulKleur As Color, point1 As Point, point2 As Point, point3 As Point)
MyBase.New(penKleur, vulKleur)
Me.Point1 = point1
Me.Point2 = point2
Me.Point3 = point3
End Sub
Public Overrides Sub Teken( doek As Graphics)
Using borstel As New SolidBrush(VulKleur),
pen As New Pen(PenKleur, PenDikte)
Dim tria As New Rectangle(_Pointers) **'<--the problem**
doek.FillPolygon(borstel, tria)
doek.DrawPolygon(pen, tria)
End Using
End Sub
End Class
what should happen to do this work
thanks in advance
Two problems:
The Rectangle object doesn't take an array of pointers, and besides, you are trying to make a triangle, not a rectangle. Eliminate this:
' Dim tria As New Rectangle(_Pointers)
The second problem is you are referencing the _Pointers array, but they are not updated with the new coordinates. The points are all (0, 0):
Try it like this:
Public Overrides Sub Teken(doek As Graphics)
Using borstel As New SolidBrush(VulKleur), _
pen As New Pen(Me.PenKleur, Me.PenDikte)
Dim myPoints() As Point = New Point() {Point1, Point2, Point3}
doek.FillPolygon(borstel, myPoints)
doek.DrawPolygon(pen, myPoints)
End Using
End Sub
Side note: make sure you to use the Paint event of your control:
Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) _
Handles Panel1.Paint
e.Graphics.Clear(Color.White)
Dim tria As New Triangle(Color.Blue, Color.Red, New Point(64, 64), _
New Point(96, 96), _
New Point(32, 96))
tria.Teken(e.Graphics)
End Sub
or override the OnPaint method if drawing directly on a form.