如何将矩形区域选择添加到可平移/缩放的VB.Net Winforms控件中?

这是我找到此网站后的第一个问题。

我目前正在尝试创建一个VB.NET用户控件,该控件包含一个面板,在该面板上一些 在Paint事件期间应绘制图形对象(圆形,矩形,直线)。 可以简化面板始终为正方形(宽度=高度)的情况。 不幸的是,使用图片框进行绘制不是我的选择。我也不要 使用自动滚动并具有可见的滚动条。

该面板应可由用户平移/缩放。平移应通过按 鼠标中键和缩放应通过滚动鼠标滚轮来完成。 我已经找到了很好的示例,说明如何实现这些功能,到目前为止,它们都有效 很好。 现在,我还想添加用户应该能够缩放到特定位置的功能 面板的(正方形)区域,由他按下时显示的选择矩形 按下鼠标左键时,鼠标左键的大小会调整 左键。 (这应该是类似的行为,例如,放大到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,zoom)
            Case T_Mouseaction.Rectanglezooming
                e.Graphics.TranslateTransform(offsetx,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,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.625 * initialwidth,0.625 * initialwidth)
        gr.DrawArc(Pens.Red,rect,20,140)
        rect = New Rectangle(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.125 * initialwidth,0.125 * initialwidth)
        gr.FillEllipse(brushes.Black,rect)
        rect = New Rectangle(0.625 * initialwidth,rect)
        rect = New Rectangle(0.6875 * initialwidth,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

请向Rod Stephens索取笑脸代码,在这种情况下,该代码只是一个占位符 以便稍后在用户控件中绘制图形。 (http://csharphelper.com/blog/2014/11/scale-a-drawing-so-it-fits-a-target-area-in-c/

在MouseMove事件中已经正确创建了缩放矩形(行进蚂蚁)。 在MouseUp事件中,我要应用缩放并将选定区域缩放为大小 面板的。在Paint事件中,实际缩放由ScaleTransform和 TranslateTransform操作。

但是我不知道如何计算适当的缩放系数和x / y偏移量,因此 所选区域将缩放为面板尺寸。我试图定位用于以下代码 鼠标滚轮缩放。我有点困惑,因为在我看来 实际上涉及两个缩放因子:一个受鼠标滚轮操作影响 另一个链接到选择矩形操作。 我还尝试将缩放系数计算为“ selection.width / panel.width”, 但这只会给面板导航带来“跳跃”的行为,并且无法正确缩放。

任何帮助将不胜感激。预先非常感谢。

sadsasafsa 回答:如何将矩形区域选择添加到可平移/缩放的VB.Net Winforms控件中?

所以我自己弄清楚了。 在Paint事件中只需要一个转换顺序。 缩放到矩形的内容在MouseUp事件中处理。 缩放区域无法100%适应缩放选择的边界 矩形,但实现的解决方案足以满足我的需求。

这是可行的解决方案:

Public Class Form1

    Private zoomstart as Point
    Private zoomfirst as Point
    Private zoomwidth as Integer    
    Private zoomrect as Rectangle
    Private maxzoom As Decimal = 5
    Private minzoom As Decimal = 0.2
    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 Decimal = 1
    Private startx as Integer = 0
    Private starty as Integer = 0
    Private offsetx as Integer
    Private offsety as Integer
    Private mouseDownPt as Point
    Private initialwidth As Integer

    Public WithEvents Canvas1 As New Canvas

    Private Enum T_MouseAction
        RectangleZooming
        Panning
        None
    End Enum

    Private MouseAction As T_MouseAction = T_MouseAction.None


    Private Sub Form1_Load(ByVal sender As Object,ByVal e As 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
        e.Graphics.ScaleTransform(CSng(zoom),CSng(zoom))
        e.Graphics.TranslateTransform(offsetx,offsety)        
        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,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.625 * initialwidth,0.625 * initialwidth)
        gr.DrawArc(Pens.Red,rect,20,140)
        rect = New Rectangle(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.125 * initialwidth,0.125 * initialwidth)
        gr.FillEllipse(Brushes.Black,rect)
        rect = New Rectangle(0.625 * initialwidth,rect)
        rect = New Rectangle(0.6875 * initialwidth,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 = MouseButtons.Middle Then
            MouseAction = T_MouseAction.Panning
            mouseDownPt = e.Location
            startx = offsetx
            starty = offsety
        End If
        If e.Button = 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 Decimal = zoom
            zoom = Canvas1.Width / zoomrect.Width * zoom
            zoom = Math.Round(zoom / 0.2) * 0.2
            zoom = Math.Max(zoom,minzoom)
            zoom = Math.Min(zoom,maxzoom)
            Dim oldoffsetx,oldoffsety as Integer
            Dim newoffsetx,newoffsety as Integer
            oldoffsetx = CInt((zoomrect.X + zoomrect.Width / 2) / oldzoom)
            oldoffsety = CInt((zoomrect.Y + zoomrect.Height / 2) / oldzoom)
            newoffsetx = CInt((zoomrect.X + zoomrect.Width / 2) / zoom)
            newoffsety = CInt((zoomrect.Y + zoomrect.Height / 2) / 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 = MouseButtons.Middle
            Cursor = Cursors.Hand
            Dim mousePosNow as Point = e.Location
            Dim deltaX,deltaY as Integer
            deltaX = CInt((mousePosNow.X - mouseDownPt.X) / zoom)
            deltaY = CInt((mousePosNow.Y - mouseDownPt.Y) / zoom)
            offsetx = CInt(startx + deltaX)
            offsety = CInt(starty + deltaY)
            Canvas1.Refresh
        End If

        If e.Button = 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 Decimal = zoom
        If e.Delta > 0 Then
            zoom = Math.Min(zoom + 0.2,maxzoom)
        End If
        If e.Delta < 0 Then
            zoom = Math.Max(zoom - 0.2,minzoom)
        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
        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
本文链接:https://www.f2er.com/3141238.html

大家都在问