Graphics.DrawRectangle not working in control events - vb.net

First of all thank you for taking the time out of your busy schedule to assist me.
I am developing a project (Win Application) with a Form and 3 textboxes (TextBox1, TextBox2 and TextBox3).
I need draw a rectangle around the textbox when focused this.
The code is:
Private Sub TextBox123_Enter(sender As Object, e As System.EventArgs) Handles TextBox1.Enter, TextBox2.Enter, TextBox3.Enter
Using g As Graphics = Me.CreateGraphics
Dim r As Rectangle = sender.Bounds
r.Inflate(4, 4)
g.DrawRectangle(Pens.Blue, r)
End Using
End Sub
The problem is the following:
The first time the textbox1 gains focus rectangle is not drawn.
The first time the textbox2 gains focus rectangle is not drawn.
Why not the rectangle is drawn when the first two events enter are fired?

Drawing with CreateGraphics is almost always not the correct approach. If you notice also, when you move from one box to another, the old rectangle is not being erased. You need to use the Form_Paint event to get it to work right. Or...perhaps simpler would be to create a UserControls which is 1-2 pixels larger than a child TextBox and set the backcolor of the UserControl canvas, draw your rectangle when the control gets the focus.
For form paint:
Public Class Form1
Private HotControl As Control
If you are only going to do TextBoxes, you can declare it As TextBox. This way it allows you to do the same for other control types. Set/clear the tracker:
Private Sub TextBox3_Enter(sender As Object, e As EventArgs) Handles TextBox3.Enter,
TextBox2.Enter, TextBox1.Enter
HotControl = CType(sender, TextBox)
Me.Invalidate()
End Sub
Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave,
TextBox2.Leave, TextBox3.Leave
HotControl = Nothing
Me.Invalidate()
End Sub
The Me.Invalidate tells the form to redraw itself, which happens in Paint:
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
If HotControl IsNot Nothing Then
Dim r As Rectangle = HotControl.Bounds
r.Inflate(4, 4)
e.Graphics.DrawRectangle(Pens.Blue, r)
End If
End Sub
You should also turn on Option Strict.

Try this in the click event handler
Private Sub TextBox1_Click(sender As Object, e As EventArgs) Handles TextBox1.Click
Using g As Graphics = Me.CreateGraphics()
Dim rectangle As New Rectangle(TextBox1.Location.X - 1, _
TextBox1.Location.Y - 1, _
TextBox1.Size.Width + 1, _
TextBox1.Size.Height + 1)
g.DrawRectangle(Pens.Blue, rectangle)
End Using
End Sub

Related

Not able to clear drawings in PictureBox using VB.NET

I use the following code to make simple free-hand (brush) drawings over PictureBox1. Drawing is fine, but not able to clear the drawings I made permanently. If I click Button1 the drawings will be cleared, but once I move over PictureBox1 all old drawings (and PictureBox1 image) appear again. Any suggestions?
Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
If e.Button = MouseButtons.Left Then
mousePath.StartFigure()
End If
End Sub
Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
'// slide annotations
If e.Button = MouseButtons.Left Then
Try
mousePath.AddLine(e.X, e.Y, e.X, e.Y) 'Add mouse coordiantes to mousePath
Catch
End Try
End If
PictureBox1.Invalidate()
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
'// slide annotations
Try
'// drwaing options
myUserColor = System.Drawing.Color.Red
myAlpha = 255
myPenWidth = 3
CurrentPen = New Pen(myUserColor, myPenWidth)
e.Graphics.DrawPath(CurrentPen, mousePath)
Catch
End Try
End Sub
Private Sub Button1_Click_2(sender As Object, e As EventArgs) Handles Button1.Click
Dim g As Graphics
g = PictureBox1.CreateGraphics()
g.Clear(PictureBox1.BackColor)
g.Dispose()
End Sub
NEVER call CreateGraphics. ALWAYS do ALL your drawing in the Paint event handler. Your are creating a Graphics object in your Click event handler and clearing that, but what use is that when you do the drawing again in Paint event handler the next time that event is raised?
What you need to do is store all the data that represents your drawing in one or more fields, update that data whenever you want to change the drawing and draw using that data in the Paint event handler. If you want to clear the drawing, you clear that data and then force a repaint by calling Invalidate. In your Paint event handler you are drawing a GraphicsPath stored in the mousePath field. That means that, in your Click event handler, you need to clear that GraphicsPath and then call Invalidate. That will then prompt a Paint event that will first clear the existing drawing and then do the new. As there is no new to do, it will remain clear.

Change focus color when button clicked

I have few buttons on my system and I tried to change the color focus when button is clicked. So far my coding is only able to change the button color when clicked but I want my system be able to reset the button color back to it's normal color as well when other button is clicked.
I tried to find solution on website but I don't really understand how because their sample is too complicated for me.
Here is my simple coding to change the button color focus.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Button1.BackColor = Color.Gainsboro
Me.Button1.ForeColor = Color.Black
End Sub
Kindly to help me. Thank you.
Since the user can focus on buttons without click, it's better to handle GotFocus and LostFocus events for buttons and put your logic there.
In below code, I assigned a handler to those events for all buttons in form and stored original ForeColor and BackColor in a data structure in Tag property. Then in GotFocus I set the ForeColor and BackColor to desired focusedForeColor and focusedBackColor. Also in LostFocus I restore original forecolor and backcolor that I stored previously in Tag.
It's enough to paste this code in your form code and it will work for all buttons:
'Change these to your desired color
Private focusedForeColor As Color = Color.Black
Private focusedBackColor As Color = Color.Gainsboro
Private Function GetAllControls(control As Control) As IEnumerable(Of Control)
Dim controls = control.Controls.Cast(Of Control)()
Return controls.SelectMany(Function(ctrl) GetAllControls(ctrl)).Concat(controls)
End Function
Public Sub New()
InitializeComponent()
Me.GetAllControls(Me).OfType(Of Button)().ToList() _
.ForEach(Sub(b)
b.Tag = Tuple.Create(b.ForeColor, b.BackColor)
AddHandler b.GotFocus, AddressOf b_GotFocus
AddHandler b.LostFocus, AddressOf b_LostFocus
End Sub)
End Sub
Private Sub b_LostFocus(sender As Object, e As EventArgs)
Dim b = DirectCast(sender, Button)
Dim colors = DirectCast(b.Tag, Tuple(Of Color, Color))
b.ForeColor = colors.Item1
b.BackColor = colors.Item2
End Sub
Private Sub b_GotFocus(sender As Object, e As EventArgs)
Dim b = DirectCast(sender, Button)
b.ForeColor = focusedForeColor
b.BackColor = focusedBackColor
End Sub
In the declarations section create 2 Color variables, one for the background property and another for the forecolor property. You have to assign the Background color and Foreground color properties of Button1 to these variables in the event Load of the form. When you click Button1 it changes with the code you did and when you click the other button it restored the Button1 colors through the use of the color variables. I hope this explanation help you. Below is the full code for further clarification.
Public Class Form1
Dim bgColor, foColor As Color
Private Sub Button1_Click(sender As Object, e As EventArgs) _
Handles Button1.Click
Button1.BackColor = Color.Yellow
Button1.ForeColor = Color.Blue
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) _
Handles Button2.Click
Button1.BackColor = bgColor
Button1.ForeColor = foColor
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) _
Handles MyBase.Load
bgColor = Button1.BackColor
foColor = Button1.ForeColor
End Sub
End Class

Dynamically change pen color & paint when clicked

The Program
I'm playing around and learning about graphics using visual basic (coming from C++). I've made a program and I want to do two things: paint when the left mouse button is pressed, and stop when released, and also I want to be able to change the pen color using a colordialog. After hours of frustration, I've yet to combat these two problems.
The Code (Snippet)
Private obj As Graphics
Dim rect As Rectangle
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
obj = RichTextBox1.CreateGraphics
End Sub
Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
obj.Dispose()
End Sub
Private Sub RichTextBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles RichTextBox1.MouseMove
With rect
.X = e.X
.Y = e.Y
.Width = TrackBar1.Value
.Height = TrackBar1.Value
End With
If ToolStripButton1.Checked = True Then
obj.DrawEllipse(Pens.Black, rect)
ElseIf ToolStripButton2.Checked = True Then
obj.DrawRectangle(Pens.Black, rect)
End If
ToolStripStatusLabel2.Text = (e.X & ", " & e.Y)
End Sub
Past Attempts (and frustrations)
My idea originally was to do this:
Dim myPen = New Pen(ButtonWithDC1.BackColor)
But doing so gave me an error message. I looked at Microsoft's documentation, but it wasn't useful for what I'm trying to do. I can create a pen just fine, but I'd like for the user to be able to change the color while the app is currently running.
GUI Layout
I don't have an attempt at my other problem (drawing while pressing the mouse down, not just by moving the mouse -- like a normal paint program), I don't even have a starting point for that solution. Thanks to everyone in advance.
Place a button (Button1) and picturebox (PictureBox1) on a form, also add a colordialog (ColorDialog1).
This code will allow you to draw on the picture box and choose the color using a color you select from the colordialog. The MouseDown event writes a flag that the mouse is down, and stores the last location. The MouseUp does similar. The MouseMove actually draws. Use a line and the last location.
Public Class Form1
Private myColor As Color = Color.Black
Private mouseIsDown As Boolean = False
Private previousLocation As System.Nullable(Of System.Drawing.Point) = Nothing
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
myColor = If(ColorDialog1.ShowDialog() = Windows.Forms.DialogResult.OK, ColorDialog1.Color, myColor)
End Sub
Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
mouseIsDown = True
previousLocation = e.Location
End Sub
Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
If mouseIsDown Then
If previousLocation IsNot Nothing Then
Using g As Graphics = Graphics.FromImage(PictureBox1.Image)
g.DrawLine(New Pen(myColor), previousLocation.Value, e.Location)
End Using
PictureBox1.Invalidate()
End If
previousLocation = e.Location
End If
End Sub
Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
mouseIsDown = False
previousLocation = Nothing
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.PictureBox1.Image = New Bitmap(PictureBox1.Width, PictureBox1.Height)
End Sub
End Class
Your question is a bit more involved than you think, and SO is not keen on multiple questions per post (not in your nest interest either - someone might know A and not B so wont bother answering).
To draw on Mousemove when the mouse is down, you need to track when the mouse is down (question A):
Private _mouseDown As Boolean
Private _mouseLoc As Point
Private _mouseNewLoc As Point
sub Ctl_MouseDown(sender...
' ToDo: add logic to check which button....
_mouseDown = True
_mouseLoc = New Point(e.X, e.Y)
End Sub
sub Ctl_MouseUp(sender...
_mouseDown = False
End Sub
Then mousemove can be used to capture the current location
Sub Ctl_MouseMove(sender....
If _mouseDn Then
_mouseNewLoc = New Point(e.X, e.Y)
Ctl.invalidate ' call to paint
End If
End Sub
' selected color from dialog or whereever
Private myColor As Color
Sub Ctl_Paint(sender....
If _mouseDn Then
' Pen ctor is overloaded...(Question B)
Using p As New Pen(myColor)
e.Graphics.DrawLine(p, _mouseLoc, _mouseNewLoc)
' plus more....
End Using
End If
This only addresses the questions posed; the bigger issue you have is tracking what has already been drawn. This will draw a line only while the mouse is down, but for a polygon or shape, you have to add code to redraw those parts. Either a List of the points which make up a polygon, or maybe save what you have to a bitmap and add to it. Thats a bit outside the scope of the question and depends on app factors. You also need a Drawing start/stop or way to signal when to stop adding lines or ovals or whatever (ovals are sort of simple: one at a time, lines as part of a shape will take some work).
Either way all painting has to take place in the Paint event (or OnPaint) if you want to see the shape/drawing/image develop.

Draw rectangle around Textbox inside a Groupbox

I want to add a custom border around a TextBox control which is in a GroupBox.
Since I'm new to this Graphic stuff I'm having a hard time figuring out the problem.
This is the code i'm using:
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
Dim _g As Graphics = Me.GroupBox1.CreateGraphics
Dim pen As New Pen(Color.Red, 2.0)
_g.DrawRectangle(pen, New Rectangle(TextBox1.Location, TextBox1.Size))
pen.Dispose()
End Sub
This form is a secondary form that shows when I click on a button from the Main form. The Red Border appears for a second when the form loads and then disappears.
You need to handle the GroupBox paint event, not the form.
Private Sub HandleGroupBox1Paint(sender As Object, e As PaintEventArgs) Handles GroupBox1.Paint
Using p As New Pen(Color.Red, 2.0)
e.Graphics.DrawRectangle(p, Me.TextBox1.bound)
End Using
End Sub

Picturebox / Panel tearing when drag vb.net

I'm trying to make VB.net program and UI is like normal desktop. I have images in picture
boxes as desktop shortcuts. So user can drag them around in form. Btw im not skilled just started
to do things like this.
I can move picture boxes with mouse events its fine But pictures in pictureboxes are tearing when dragging. i have a big background picture, i guess this is the problem but i need help to get rid of tearing. heres code thx.
i also tryed as a panel and get same result.
Edit : pictures about dragging is png , 50x50 , transparent BG.
Public Class testform
Dim drag As Boolean
Dim mousex, mousey As Integer
Private Sub testform_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.BackgroundImage = My.Resources.worldmap 'approx 1.03mb Picture size
End Sub
Private Sub dragbox_MouseDown(sender As Object, e As MouseEventArgs) Handles dragbox.MouseDown
If e.Button = Windows.Forms.MouseButtons.Left Then
drag = True
mousex = Windows.Forms.Cursor.Position.X - dragbox.Left
mousey = Windows.Forms.Cursor.Position.Y - dragbox.Top
Else
End If
End Sub
Private Sub dragbox_MouseMove(sender As Object, e As MouseEventArgs) Handles dragbox.MouseMove
If drag = True Then
dragbox.Left = Windows.Forms.Cursor.Position.X - mousex
dragbox.Top = Windows.Forms.Cursor.Position.Y - mousey
End If
End Sub
Private Sub dragbox_MouseLeave(sender As Object, e As EventArgs) Handles dragbox.MouseLeave
drag = False
End Sub
End Class
You need to make the picture form double buffered. That means that it will no longer tear as it will first completely make sure it's all in place before showing the next frame.