问题描述
我想让照片编辑器像 MS-Paint 一样。 笔刷模式,当用户点击鼠标并移动鼠标时,会绘制描边。
Private Sub pbPhoto_MouseDown(sender As Object,e As MouseEventArgs) Handles pbPhoto.MouseDown
bStart = true
End Sub
Private Sub pbPhoto_MouseMove(sender As Object,e As MouseEventArgs) Handles pbPhoto.MouseMove
If bStart Then
Dim b As SolidBrush(Color.Red)
pbPhoto.CreateGraphics.FillEllipse(b,e.X,e.Y,10,10)
End If
End Sub
Private Sub pbPhoto_MouseUp(sender As Object,e As MouseEventArgs) Handles pbPhoto.MouseUp
bStart = false
End Sub
画的很好。但是,如果您查看 MS-Paint,则会在光标中心看到一个画笔。它总是显示,但在鼠标按下之前它不会绘制到图片框。如果您更改画笔大小或颜色,您可以在光标处看到预览。
如何在没有油漆的情况下显示笔触?
解决方法
您可以创建一个图像来反映画笔工具的颜色和大小,并使用它为绘图画布创建自定义光标。每当您选择画笔工具或在选择画笔工具时更改颜色/大小时,都应调用此例程。自定义光标的句柄在不再使用时应销毁。例如,当您选择其他绘图工具或关闭表单时。
图片
接近的东西。 penWidth
和 maxWidth
参数用于计算画笔的大小。图片中的红色圆圈。例如,TrackBar
控件的 Value 和 Maximum 属性。
' +
Imports System.Drawing.Drawing2D
' ...
Private Function CreateBrushBitmap(color As Color,penWidth As Integer,maxWidth As Integer) As Bitmap
Dim bmp As New Bitmap(32,32)
Dim rec As New Rectangle(0,32,32)
Using g = Graphics.FromImage(bmp),br = New SolidBrush(color),pn = New Pen(Color.Gray) With {.DashStyle = DashStyle.Dot}
g.SetClip(Rectangle.Inflate(rec,-8,-8),CombineMode.Exclude)
g.DrawLine(pn,(rec.Width - 1) \ 2,rec.Y,rec.Height)
g.DrawLine(pn,rec.X,(rec.Height - 1) \ 2,rec.Width,(rec.Height - 1) \ 2)
g.ResetClip()
Dim ellipseRec = Rectangle.Inflate(rec,-10,-10)
Dim sz = CSng(Math.Round(ellipseRec.Width * penWidth / maxWidth))
Dim r = New RectangleF(
ellipseRec.X + (ellipseRec.Width - sz) / 2 - 1,ellipseRec.Y + (ellipseRec.Height - sz) / 2 - 1,sz,sz)
g.SmoothingMode = SmoothingMode.AntiAlias
g.FillEllipse(br,r)
End Using
Return bmp
End Function
自定义光标
CreateBrushCursor
函数调用下面显示的本机函数来创建自定义光标。 Credit
' +
Imports System.Runtime.InteropServices
' ...
Private Function CreateBrushCursor(bmp As Bitmap,xHotspot As Integer,yHotspot As Integer) As Cursor
Dim inf As New ICONINFO With {
.xHotspot = xHotspot,.yHotspot = yHotspot,.fIcon = False,.hbmMask = bmp.GetHbitmap(),.hbmColor = bmp.GetHbitmap()
}
Dim pnt As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(inf))
Marshal.StructureToPtr(inf,pnt,True)
Dim curPtr As IntPtr = CreateIconIndirect(pnt)
DestroyIcon(pnt)
DeleteObject(inf.hbmMask)
DeleteObject(inf.hbmColor)
Return New Cursor(curPtr)
End Function
Private Structure ICONINFO
Public fIcon As Boolean
Public xHotspot As Integer
Public yHotspot As Integer
Public hbmMask As IntPtr
Public hbmColor As IntPtr
End Structure
<DllImport("user32.dll",EntryPoint:="CreateIconIndirect")>
Private Shared Function CreateIconIndirect(ByVal iconInfo As IntPtr) As IntPtr
End Function
<DllImport("user32.dll",SetLastError:=True)>
Private Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean
End Function
<DllImport("gdi32.dll")>
Private Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
End Function
实施
在选择画笔工具时调用 CreateBrushCursor
方法创建和设置自定义光标,设置画笔的颜色/大小。在本例中,picSelectedColor
、tbPenWidth
是用于创建光标图像的输入控件。 picCanvas
是绘图画布。
Private Sub CreateBrushCursor()
DestroyBrushCursor()
customBrushCursor = CreateBrushCursor(
CreateBrushBitmap(
picSelectedColor.BackColor,tbPenWidth.Value,tbPenWidth.Maximum),16,16)
picCanvas.Cursor = customBrushCursor
End Sub
最后,调用 DestroyBrushCursor
方法进行清理。当您选择其他工具时,关闭绘图表单...等
Private Sub DestroyBrushCursor()
If customBrushCursor IsNot Nothing Then
customBrushCursor.Dispose()
customBrushCursor = Nothing
End If
End Sub
注意:绘图程序无关,因此未列出。