After a bunch of fail on Google searches finally I thought for asking for experts here to help me at this problem as this site always helped me.
What I want?
I want to create a Highlighter for my some kind of drawing application. I want this to be similar to the highlighter you can see on the Windows Snipping Tool.
What is my problem?
The problem is that although I can draw the semitransparent or opaque rectangles using the code,
gfx.FillRectangle(New SolidBrush(Color.FromArgb(100, Colors.GreenYellow)), x, y, width, height)
, but if I draw another rectangle overlapping any previous rectangles the colors gets darker and reduces the transparency of the rectangles where they overlapped.
Code:
Public Class Form1
Dim drag As Boolean
Dim mouseX, mouseY As Integer
Dim prev As Point
Dim initi As Point
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
Dim grx As Graphics = Panel1.CreateGraphics
grx.DrawString("+", New Font("Arial", 144, FontStyle.Regular), New SolidBrush(Color.FromArgb(100, Color.GreenYellow)), New Point(200, 200))
End Sub
Private Sub Panel1_MouseDown(sender As Object, e As MouseEventArgs) Handles Panel1.MouseDown
drag = True
mouseX = MousePosition.X - Me.Left - 8
mouseY = MousePosition.Y - Me.Top - 34
initi = New Point(mouseX, mouseY)
End Sub
Private Sub Panel1_MouseMove(sender As Object, e As MouseEventArgs) Handles Panel1.MouseMove
If drag Then
mouseX = MousePosition.X - Me.Left - 8
mouseY = MousePosition.Y - Me.Top - 34
End If
End Sub
Private Sub Panel1_MouseUp(sender As Object, e As MouseEventArgs) Handles Panel1.MouseUp
drag = False
prev = New Point(0, 0)
Dim grx As Graphics = Panel1.CreateGraphics
grx.FillRectangle(New SolidBrush(Color.FromArgb(100, Color.GreenYellow)), initi.X, initi.Y, (mouseX - initi.X), (mouseY - initi.Y))
End Sub
End Class
Screenshot of the application (Showing the problem)
Well. I've never really used graphics, but the only thing I could come up with is to create a list of the highlights to be drawn and then each time the mouse_up event fires, create a new bitmap, draw each rectangle pixel by pixel, with semi-transparent pixels to the bitmap and then draw the resulting bitmap to the panel using the panel's paint event handler that fires when you refresh the panel. This seems the built-in alpha blending that .net does automatically.
Add this to your form's variable declarations
Dim highlightsList As New List(Of Rectangle)
Dim bmp1 As Bitmap
alter your form_shown event to
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
bmp1 = New Bitmap(Panel1.Width, Panel1.Height)
End Sub
add this sub which handles the addition of the rectangles to the list and the creation of the bitmap
Private Sub addRectangle(gr As Graphics, x As Integer, y As Integer, v1 As Integer, v2 As Integer)
Dim newRectangle As New Rectangle(x, y, v1, v2)
highlightsList.Add(newRectangle)
Using G As Graphics = Graphics.FromImage(bmp1)
G.Clear(Color.White)
End Using
bmp1.MakeTransparent(Color.White)
For Each rect As Rectangle In highlightsList
For i As Integer = rect.X To rect.X + rect.Width - 1
For j As Integer = rect.Y To rect.Y + rect.Height - 1
bmp1.SetPixel(i, j, Color.FromArgb(100, Color.GreenYellow))
Next
Next
Next
Panel1.Refresh()
End Sub
add a handler for the panel's paint event so that when you refresh the panel, the bitmap is drawn onto it
Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
e.Graphics.DrawImage(bmp1, 0, 0)
End Sub
and change your mouse_up event to use the above sub to do the drawing
Private Sub Panel1_MouseUp(sender As Object, e As MouseEventArgs) Handles Panel1.MouseUp
drag = False
prev = New Point(0, 0)
Dim grx As Graphics = Panel1.CreateGraphics
'grx.Clear(Panel1.BackColor)
addRectangle(grx, initi.X, initi.Y, (mouseX - initi.X), (mouseY - initi.Y))
End Sub
This seems to work, but if you're using the panel for anything other that showing highlights, it may not work as expected.