I draw a hexagon at runtime in vbExpress2008:
Private Sub Panel2_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel2.Paint
Dim Hpoint As Point
yada yada yada
e.Graphics.DrawPolygon(p, Points)
End Sub
Now how can I remove it?
As your code is now, you can't remove it. Every time that code is executed, it will draw that shape, so there's nothing to remove. If you want to remove it then there has to be something to remove. That's why you should store the data that represents the drawing in one or more fields and then get the data from there each time you want to draw. If you have a field of type List(Of Point()) then you can add and remove Point arrays as required and then force a Paint event. In the event handler, you get the current data and draw it, so anything you remove from that List will be removed from drawing. E.g.
Private polygons As New List(Of Point())
Private Sub AddPolygon(points As Point())
polygons.Add(points)
Invalidate()
End Sub
Private Sub RemovePolygon(points As Point())
polygons.Remove(points)
Invalidate()
End Sub
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
For Each polygon In polygons
e.Graphics.DrawPolygon(Pens.Black, polygon)
Next
End Sub
Alternatively, if it's just one polygon that you want to show or hide, you could still hard-code it in the Paint event handler but use an If statement that tests a field of type Boolean. You can then just toggle that field and invalidate to hide and show that one polygon.
Related
How do I trigger the instantaneous painting of a rectangle over the top of some specific cell [destination: col2, row4] in a DataGridView by an entirely different cell [trigger: col1, row3] being clicked?
Obviously I picked two random cell locations and I have tried to simplify my problem to the basic chunks. Clearly they cannot be forced as is to work together. I don't have a deep enough understanding of the event handler to call one event within the other due to lack of common signatures. I think frustration has clouded my vision and ability to see any logical possibilities.
Private Sub DataGridView1_Paint(sender As Object, e As PaintEventArgs) Handles DataGridView1.Paint
Using ColBlue As New SolidBrush(Color.Blue)
e.Graphics.FillRectangle(ColBlue, x, y, width, height)
'TODO: decide loc and rect size
End Using
End Sub
Private Sub Datagridview1_CellMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles Datagridview1.CellMouseClick
'TODO: Gain a better understanding of the event handler
End Sub
My intuition tells me to write a custom sub or function, but I am not certain what they require, which eventargs to use or not use.
Thanks to Jimi for the patience in pointing out the main pieces required for my solution.
A simplified version of my code for those that find themselves lost and unable to trigger the painting a rectangle by mouse click.
Results [code]
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
‘Init new list of rectangles
Dim bluegradeT As New List(Of Rectangle) From {}
Dim ablue As New Rectangle
‘Programmatically adding the cells I want to paint to my list beforehand
bluegradeT.Add(DgvTall.GetCellDisplayRectangle(5, 1, False))
bluegradeT.Add(DgvTall.GetCellDisplayRectangle(7, 2, False))
bluegradeT.Add(DgvTall.GetCellDisplayRectangle(5, 5, False))
bluegradeT.Add(DgvTall.GetCellDisplayRectangle(5, 3, False))
bluegradeT.Add(DgvTall.GetCellDisplayRectangle(6, 2, False))
bluegradeT.Add(DgvTall.GetCellDisplayRectangle(4, 2, False))
End Sub
Private Sub DataGridView1_Paint(sender As Object, e As PaintEventArgs) Handles DataGridView1.Paint
‘I have multiple paint events of different colors that I wanted triggered by clicking
‘specific cells in the dgv
If DataGridView1.CurrentCell.ColumnIndex = 2 Then
If DataGridView1.CurrentCell.RowIndex = 1 Then
‘so if the clicked location is {2,1}, then paint
Using ColBlue As New SolidBrush(Color.FromArgb(50, Color.Blue))
‘this particular brush paints blue at 50 opacity
For Each ablue As Rectangle In bluegradeT
‘use a loop to retrieve all the rects stored for this paint
e.Graphics.FillRectangle(ColBlue, ablue)
Next
End Using
End If
End If
End Sub
Private Sub DataGridView1_CellMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseClick
If DataGridView1.Rows(e.RowIndex).Selected Then
If DataGridView1.Columns.(e.ColumnIndex).Selected Then
‘If some cell has been selected…
DataGridView1.Invalidate(ablue)
‘trigger painting of dgv, but only in the area of tbe rectangles list
DataGridView1.Refresh()
‘to make sure the control updates immediately
End if
End If
End Sub
Notes
This began as an experiment to see what methods out on the internet can achieve the best color mixing by the required amount of work. I only really found an endless discussion board post with C++ theories and in various methodologies. I could see the only native method—aside from my clever trick--is colorblend(). Initially, color blend seemed impossibly more complex than my concept, but in truth, it is probably easier than I thought. [I’m sure someone else has done this before me, but I don’t care, today it’s my technique] Overall, it does an excellent job in combining colors that look natural by overlapping semi-transparent color rects on top of already painted DGV cells on the fly. It is undoubtedly faster than mixing colors by hand in Photoshop.
Once I develop a vb6 code to use transparent controls (Dont remember if I use Buttons or PictrureBoxes) with coordinates as invisible tags & invisible labels to show the names of eachone at groupal photos like facebook does. Now Im trying to recreate the same code at vb.net but I can't reach to get it work..
If I use Buttons with transparent .backcolor, no-text and no-borders, flat style, etc. to mark the photo area, they become opaque when I move the mouse over the control. if I disable becomes invisible for the mouse-over function.
If I use empty PictureBoxes instead for the same purpouse, as are empty they became invisible at runtime also for the "mouse over" function...
I dont know wich empty or invisible control must use to this finality. any suggestion?
Here is an example of what I was talking about in my comments:
Public Class Form1
Private ReadOnly actionsByRectangle As New Dictionary(Of Rectangle, Action)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'If the user clicks near the top, left corner, display a message.
actionsByRectangle.Add(New Rectangle(10, 10, 100, 100),
Sub() MessageBox.Show("Hello World"))
'If the user clicks near the bottom, right corner, minimise the form.
actionsByRectangle.Add(New Rectangle(ClientSize.Width - 110,
ClientSize.Height - 110,
100,
100),
Sub() WindowState = FormWindowState.Minimized)
End Sub
Private Sub Form1_MouseClick(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
For Each rectangle As Rectangle In actionsByRectangle.Keys
If rectangle.Contains(e.Location) Then
'We have found a rectangle containing the point that was clicked so execute the corresponding action.
actionsByRectangle(rectangle).Invoke()
'Don't look for any more matches.
Exit For
End If
Next
End Sub
'Uncomment the code below to see the click targets drawn on the form.
'Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
' For Each rectangle As Rectangle In actionsByRectangle.Keys
' e.Graphics.DrawRectangle(Pens.Black, rectangle)
' Next
'End Sub
End Class
Note that I have added code there that can draw the boxes on the form if you want to see them, but those are just representations of the areas, not the Rectangle values themselves.
I have an application where I have around 50 labels. In those labels a number is visible.
When the user clicks on the label the number needs to be written to an edit box.
This works fine, the only problem is that I have added 50 functions like below, and every time it’s the same. I was wondering if there is a common function for this
Remark: The labels have different names. So if its possible that this will work for all the labels on the form.
Private Sub LI_L_Click(sender As Object, e As EventArgs) Handles LI_L.Click
cmbOBJID.Text = LI_L.Text
End Sub
In the form designer, you should be able to set the handler for every label to the same function. Then you can use the "sender" parameter to determine which label is raising the event.
Notice also how all the controls that the function is linked to are listed after the "Handles" keyword. This is another way you could connect the code to all the labels if you prefer this over using the Visual Studio UI properties grid.
Private Sub LI_Click(sender As Object, e As EventArgs) Handles Label1.Click, Label2.Click, Label3.Click
cmdOBJID.Text = DirectCast(sender, Label).Text
End Sub
While it is easy to add several events to one handler in the style of
Private Sub LI_Click(sender As Object, e As EventArgs) Handles Label1.Click, Label2.Click, Label3.Click
It will be tedious for more than just a few labels.
You can add handlers programatically if you can find a way to refer to the labels you need to add handlers to. In this example, I put all the labels in a groupbox named "GroupBoxOptions":
Option Infer On
Option Strict On
Public Class Form1
Sub TransferDataToEditBox(sender As Object, e As EventArgs)
Dim lbl = DirectCast(sender, Label)
tbEditThis.Text = lbl.Text
End Sub
Sub InitLabelHandlers()
For Each lbl In GroupBoxOptions.Controls.OfType(Of Label)
AddHandler lbl.Click, AddressOf TransferDataToEditBox
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitLabelHandlers()
End Sub
End Class
You may have some other way of selecting the labels which use the handler.
A pretty nice and quick solution is to traverse all the label controls on a form, assigning through the AddHandler function the event to run when a user clicks a label.
In code:
For Each c As Control In Me.Controls.OfType(Of Label)
AddHandler c.Click, AddressOf myLabelClick
Next
With the prevous snippet, we loop onto all the winform controls of type Label. A loop like that is useful when we have a lot of labels for which an event must be assigned. For each of them, we associate the event Click of the control with a customized Sub named myLabelClick. That subroutine will look like the following:
Private Sub myLabelClick(sender As Object, e As EventArgs)
cmdObjId.Text = DirectCast(sender, Label).Text
End Sub
Here we use the sender variable (which represents the control for which the click has been done) to access its Text property, and change the cmdObjId.Text accordingly.
Just to complement the solution from BlueMonkMN:
If you are using the DevExpress Tools, you need to import DevExpress.XtraEditors and change Label to LabelControl:
DirectCast(sender, LabelControl).Text
This worked for me.
Okay, so I am trying to make a program that each time you click (doesn't matter where) a random colored, and sized circle appears where you happened to click. however, the only way I can add a shape is via Paint event. here is the code I have now:
Private Sub Form1_Paint(ByVal Sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Using Brush1 As New SolidBrush(Color.Orange)
e.Graphics.FillEllipse(Brush1, MousePosition.X, MousePosition.Y, 100, 100)
End Using
End Sub
I need to know a line of code that I can use in a mouse click event, that will re-run this sub. I know how to change the size, and make it random, I just don't know how to run this sub multiple times, more precisely; run this sub once after each mouse click. If someone can help, I would appreciate it!
Just as Plutonix explained, a refresh is handled by calling the Invalidate method.
The thing you need to remember is that whatever is painted on a surface is not persistent, so you need to redraw the whole screen every time. There are, of course, many ways in which this can be optimized for performance purposes, as this process can be extremely CPU intensive; specially, since GDI+ is not hardware accelerated.
So, what you need to do is:
Record every click (x, y position) and store it
Since the radius of each circle is random, determine the radius when the user clicks the form, then store it along with the x, y position of the click
Then, have the Paint event re-draw each stored sequence of clicks (with their respective radii) and re-draw each circle over and over.
Here's an implementation that will do the trick. Just paste this code inside any Form's class to test it:
Private Class Circle
Public ReadOnly Property Center As Point
Public ReadOnly Property Radius As Integer
Public Sub New(center As Point, radius As Integer)
Me.Center = center
Me.Radius = radius
End Sub
End Class
Private circles As New List(Of Circle)
Private radiusRandomizer As New Random()
Private Sub FormLoad(sender As Object, e As EventArgs) Handles MyBase.Load
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True) ' Not really necessary in this app...
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
Me.SetStyle(ControlStyles.ResizeRedraw, True)
Me.SetStyle(ControlStyles.UserPaint, True)
End Sub
Private Sub FormMouseClick(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
circles.Add(New Circle(New Point(e.X, e.Y), radiusRandomizer.Next(10, 100)))
Me.Invalidate()
End Sub
Private Sub FormPaint(sender As Object, e As PaintEventArgs) Handles Me.Paint
Dim g As Graphics = e.Graphics
g.Clear(Color.Black)
Using p As New Pen(Color.White)
For Each c In circles
g.DrawEllipse(p, c.Center.X - c.Radius \ 2, c.Center.Y - c.Radius \ 2, c.Radius, c.Radius)
Next
End Using
End Sub
Here's what you'll get after a few clicks on the form
I looked at "How do I place an image with a mouse-click in Javascript?" but it had a small snippet of Java; immensely larger than my knowledge of Java. And that is the closest I've come to finding an answer in the past week.
Here's what I would like to do (don't know if its even possible):
I have a panel and a toolstrip with 3 buttons. Each button represents a different image. I want to click on a button (once) and then move into the panel and everytime I click the mouse button it drops the image where ever I clicked. This only ends when either I click back on the same button or one of the other buttons. I do not want to drag an image into the panel each time. In other words the button stays depressed and the event/action stays active.
Any help would be greatly appreciated.
Here is an example application. It's just a form with a ToolStrip on it, along with a couple of buttons with an image added to each button. The key property for each button is CheckOnClick=True, which will keep the button pressed down.
There isn't a radio button like feature for ToolStrips, so you have to "uncheck" the other ToolStripButtons yourself, which I have handled in the ItemClicked event.
Public Class Form1
Private _ActiveImage As Image = Nothing
Private Class ImagePoint
Public Location As Point
Public Image As Image
Public Sub New(ByVal image As Image, ByVal location As Point)
Me.Image = image
Me.Location = location
End Sub
End Class
Private _Images As New List(Of ImagePoint)
Public Sub New()
InitializeComponent()
Me.DoubleBuffered = True
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
For Each imageItem As ImagePoint In _Images
e.Graphics.DrawImage(imageItem.Image, imageItem.Location)
Next
End Sub
Private Sub ToolStrip1_ItemClicked(ByVal sender As Object, ByVal e As ToolStripItemClickedEventArgs) Handles ToolStrip1.ItemClicked
For Each toolButton As ToolStripButton In ToolStrip1.Items.OfType(Of ToolStripButton)()
If toolButton.CheckOnClick Then
If e.ClickedItem.Equals(toolButton) Then
_ActiveImage = e.ClickedItem.Image
Else
toolButton.Checked = False
End If
End If
Next
End Sub
Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseDown
If _ActiveImage IsNot Nothing AndAlso e.Button = MouseButtons.Left Then
_Images.Add(New ImagePoint(_ActiveImage, e.Location))
Me.Invalidate()
End If
End Sub
End Class
This example just uses a simple class to hold which image was placed at what location and the paint event just loops through the list and paints the image.
If deleting images is in your future, then you would have to call e.Graphics.Clear(Color.White) before painting any images.
For the button UI, check out the alternate style for radio buttons/check boxes. They have a "toggle button" mode which sounds like exactly what you need.
You could go through the motions of detecting mouse down events on the panel, getting the coordinates, creating an image control, and placing a copy of the image in it, but there's a better approach.
Fill the panel with a single image control (fill so that it handles resizes, the image control should always be the same size as the panel). Create a new Bitmap the same size as the image control and associate it with it (set the Image property). Obtain a Graphics object for the Bitmap (Graphics.FromImage() I think). Clear() it with the background color (Color.White?).
Preload your three images on startup and write the code to toggle between them, selecting the "active one" every time a different button is selected. On the mouse down event, you can get the coordinates of the click easily. Use myGraphics.DrawImage(...) to draw the active image at that location onto the Bitmap. You can then save the Bitmap to a file or do whatever you want with it. All of these concepts have lots of examples, Google them.
If you want to interact with the images after you "drop" them (like move them around again or something), then you will need to maintain a data structure that tracks what and where you've dropped. A simple class that has a Point and Image reference will be sufficient. Each drop should add an entry to a List(Of ...) these objects. You'll probably then need to write code such as "which image is under the current mouse location?". This can be accomplished by iterating through the list and doing point/rectangle intersection testing.
Private Sub ToolStripSound_Click(sender As Object, e As EventArgs) Handles ToolStripSound.Click
If ToolStripSound.Checked = False Then
ToolStripSound.Checked = True
Else
ToolStripSound.Checked = False
End If
End Sub
Private Sub ToolStripSound_CheckedChanged(sender As Object, e As EventArgs) Handles ToolStripSound.CheckedChanged
' ToolStripSound.Checked = True
If ToolStripSound.Checked = True Then
Me.ToolStripSound.Image = Global.Traffic_Lights.My.Resources.Resources.Oxygen_Icons_org_Oxygen_Status_audio_volume_high
Else
Me.ToolStripSound.Image = Global.Traffic_Lights.My.Resources.Resources.Oxygen_Icons_org_Oxygen_Status_audio_volume_muted
End If
End Sub