это мой первый вопрос после нахождения этого сайта.
В настоящее время я пытаюсь создать пользовательский элемент управления VB.NET, содержащий панель, на которой должны отображаться некоторые графические объекты (круги, прямоугольники, линии). нарисовано во время события Paint. Это может упростить случай, когда панель всегда будет квадратной (ширина = высота). Использование Picturebox для рисования, к сожалению, не вариант для меня. Я также не хочу использовать автопрокрутку и иметь видимые полосы прокрутки.
Панель должна панорамироваться / масштабироваться пользователем. Панорамирование должно быть выполнено нажатием средней кнопки мыши, а масштабирование - прокруткой колесика мыши. Я уже нашел хорошие примеры, как реализовать эти функции, и пока они работают очень хорошо. Теперь я также хочу добавить функцию, позволяющую пользователю масштабировать определенную (квадратную) область панели с помощью прямоугольника выбора, который отображается, когда он нажимает левую кнопку мыши, и его размер регулируется во время перемещения мыши. с нажатой левой кнопкой. (Это должно быть похожее поведение, например, масштабирование в документе PDF). Вот где я застрял.
Я извлек часть кода, которая отвечает за панель и ее события, и это то, что я до сих пор:
Public Class Form1
Private zoomstart as Point
Private zoomfirst as Point
Private zoomwidth as Integer
Private zoomrect as Rectangle
Private WithEvents tmrMarch as New Timer
Private MarchOffset as Integer = 0
Private OffsetDelta as Integer = 2
Private DashPattern() as Single = {5, 5}
Private zoom As Single = 1.0
Private startx as Integer = 0
Private starty as Integer = 0
Private offsetx as Integer = 0
Private offsety as Integer = 0
Private mouseDownPt as Point
Private initialwidth As Integer
Public WithEvents Canvas1 As New Canvas
Private Enum T_MouseAction
RectangleZooming
WheelZooming
Panning
None
End Enum
Private MouseAction As T_MouseAction = T_MouseAction.None
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Canvas1.Size = New Size(Me.ClientSize.Width, Me.ClientSize.Width)
Canvas1.AutoScroll = False
initialwidth = Canvas1.Width
Me.Controls.Add(Canvas1)
End Sub
Private Sub Canvas1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Canvas1.Paint
Select Case MouseAction
Case T_MouseAction.None
e.Graphics.TranslateTransform(offsetx, offsety)
e.Graphics.ScaleTransform(zoom, zoom)
Case T_MouseAction.Panning
e.Graphics.TranslateTransform(offsetx, offsety)
e.Graphics.ScaleTransform(zoom, zoom)
Case T_MouseAction.RectangleZooming
e.Graphics.TranslateTransform(offsetx, offsety)
e.Graphics.ScaleTransform(zoom, zoom)
Case T_MouseAction.WheelZooming
e.Graphics.ScaleTransform(zoom, zoom)
e.Graphics.TranslateTransform(offsetx, offsety)
End Select
Call DrawImage(e.Graphics)
e.Graphics.ResetTransform
If MouseAction = T_MouseAction.RectangleZooming Then
MarchOffset = MarchOffset + OffsetDelta
Dim pen as New Pen(Color.Black, 2)
pen.DashPattern = DashPattern
pen.DashOffset = MarchOffset
pen.Color = Color.Red
e.Graphics.DrawRectangle(pen, zoomrect)
End If
End Sub
Private Sub DrawImage(ByVal gr As Graphics)
Dim rect As Rectangle
rect = New Rectangle(0, 0, initialwidth, initialwidth)
gr.FillEllipse(Brushes.LightGreen, rect)
gr.DrawEllipse(Pens.Green, rect)
rect = New Rectangle(0.375 * initialwidth, 0.375 * initialwidth, 0.25 * initialwidth, 0.375 * initialwidth)
gr.FillEllipse(Brushes.LightBlue, rect)
gr.DrawEllipse(Pens.Blue, rect)
rect = New Rectangle(0.1875 * initialwidth, 0.25 * initialwidth, 0.625 * initialwidth, 0.625 * initialwidth)
gr.DrawArc(Pens.Red, rect, 20, 140)
rect = New Rectangle(0.1875 * initialwidth, 0.1875 * initialwidth, 0.1875 * initialwidth, 0.25 * initialwidth)
gr.FillEllipse(Brushes.White, rect)
gr.DrawEllipse(Pens.Black, rect)
rect = New Rectangle(0.25 * initialwidth, 0.25 * initialwidth, 0.125 * initialwidth, 0.125 * initialwidth)
gr.FillEllipse(Brushes.Black, rect)
rect = New Rectangle(0.625 * initialwidth, 0.1875 * initialwidth, 0.1875 * initialwidth, 0.25 * initialwidth)
gr.FillEllipse(Brushes.White, rect)
gr.DrawEllipse(Pens.Black, rect)
rect = New Rectangle(0.6875 * initialwidth, 0.25 * initialwidth, 0.125 * initialwidth, 0.125 * initialwidth)
gr.FillEllipse(Brushes.Black, rect)
End Sub
Private Sub tmrMarch_Tick(ByVal sender as Object, ByVal e as EventArgs) Handles tmrMarch.Tick
Canvas1.Refresh
End Sub
Private Sub Canvas1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Canvas1.MouseDown
If e.Button = Windows.Forms.MouseButtons.Middle Then
MouseAction = T_MouseAction.Panning
mouseDownPt = e.Location
startx = offsetx
starty = offsety
End If
If e.Button = Windows.Forms.MouseButtons.Left Then
zoomstart = e.Location
tmrMarch.Interval = 100
tmrMarch.Enabled = True
End If
End Sub
Private Sub Canvas1_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Canvas1.MouseUp
Cursor = Cursors.Default
tmrMarch.Enabled = False
If MouseAction = T_MouseAction.RectangleZooming Then
Dim oldzoom as Single = zoom
zoom = 1 ' <=== ?
zoom = Math.Truncate(zoom / 0.2) * 0.2
Dim oldoffsetx, oldoffsety as Integer
Dim newoffsetx, newoffsety as Integer
oldoffsetx = CInt(zoomrect.X / oldzoom)
oldoffsety = CInt(zoomrect.Y / oldzoom)
newoffsetx = CInt(zoomrect.X / zoom)
newoffsety = CInt(zoomrect.Y / zoom)
offsetx = newoffsetx - oldoffsetx + offsetx ' <=== ?
offsety = newoffsety - oldoffsety + offsety ' <=== ?
End If
MouseAction = T_MouseAction.None
Canvas1.Refresh
End Sub
Private Sub Canvas1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Canvas1.MouseMove
If e.Button = Windows.Forms.MouseButtons.Middle
Cursor = Cursors.Hand
Dim mousePosNow as Point = e.Location
Dim deltaX, deltaY as Integer
deltaX = mousePosNow.X - mouseDownPt.X
deltaY = mousePosNow.Y - mouseDownPt.Y
offsetx = CInt(startx + deltaX)
offsety = CInt(starty + deltaY)
MouseAction = T_MouseAction.Panning
Canvas1.Refresh
End If
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim loc as Point
loc = e.Location
Dim sizex, sizey as Integer
sizex = Math.Abs(zoomstart.X - loc.X)
sizey = Math.Abs(zoomstart.Y - loc.Y)
zoomwidth = Math.Max(sizex, sizey)
If loc.X < zoomstart.X Then
zoomfirst.X = loc.X
Else
zoomfirst.X = zoomstart.x
End If
If loc.Y < zoomstart.Y Then
zoomfirst.Y = loc.Y
Else
zoomfirst.Y = zoomstart.Y
End If
If zoomwidth > 10 Then
MouseAction = T_MouseAction.RectangleZooming
End If
zoomrect = New Rectangle(zoomfirst, New Size(zoomwidth, zoomwidth))
Canvas1.Refresh
End If
End Sub
Private Sub Canvas1_MouseWheel(ByVal sender as Object, ByVal e as MouseEventArgs) Handles Canvas1.MouseWheel
If MouseAction = T_MouseAction.Panning Then
Exit Sub
End If
Dim oldzoom as Single = zoom
If e.Delta > 0 Then
zoom = zoom + 0.2
End If
If e.Delta < 0 Then
zoom = Math.Max(zoom - 0.2, 0.2)
End If
Dim mousePosNow as Point = e.Location
Dim x, y as Integer
x = mousePosNow.X
y = mousePosNow.Y
Dim oldoffsetx, oldoffsety as Integer
Dim newoffsetx, newoffsety as Integer
oldoffsetx = CInt(x / oldzoom)
oldoffsety = CInt(y / oldzoom)
newoffsetx = CInt(x / zoom)
newoffsety = CInt(y / zoom)
offsetx = newoffsetx - oldoffsetx + offsetx
offsety = newoffsety - oldoffsety + offsety
MouseAction = T_MouseAction.WheelZooming
Canvas1.Refresh
End Sub
Private Sub Canvas1_MouseEnter(ByVal sender as Object, ByVal e as EventArgs) Handles Canvas1.MouseEnter
Canvas1.Focus
End Sub
Private Sub Canvas1_MouseLeave(ByVal sender as Object, ByVal e as EventArgs) Handles Canvas1.MouseLeave
Me.Focus
End Sub
End Class
Public Class Canvas
Inherits Panel
Public Sub New
Me.DoubleBuffered = True
End Sub
End Class
Кредиты идут наРод Стивенс для кода смайлика, который в данном случае является просто заполнителем для графики, которая будет позже нарисована в пользовательском элементе управления. (http://csharphelper.com/blog/2014/11/scale-a-drawing-so-it-fits-a-target-area-in-c/)
Прямоугольник масштабирования (марширующие муравьи) уже правильно создан в событии MouseMove. В событии MouseUp я хочу применить масштабирование и масштабировать выбранную область до размера панели. Событие рисования, фактическое масштабирование обрабатывается операциями ScaleTransform и TranslateTransform.
Но я не могу понять, как рассчитать соответствующий коэффициент масштабирования и смещения по x / y, чтобы выбранная область масштабировалась до размера панели. ориентироваться на код, который используется для масштабирования колесика мыши. Я немного запутался, поскольку мне кажется, что на самом деле задействованы два коэффициента масштабирования: один, на который влияет работа колеса мыши, и тот, который связан соперация выделения прямоугольника. Я также пытался вычислить коэффициент масштабирования как что-то вроде «selection.width / panel.width», но это только приводит к «скачкообразному» поведению на панели навигации и не масштабируется должным образом.
Любая помощь будет оценена. Большое спасибо заранее.