在 运行 时间创建一个新表单并添加事件处理程序

Create a new Form and add event handlers at Run Time

我正在尝试在 Run-Time 创建一个新的 border-less 表单,事件处理程序需要移动没有标题的表单。

表单是一个对话框,可以使用专门的控件显示呈现的二维码。
表单还应自行调整大小以适应不同大小的二维码。

这是我到目前为止写的:

Imports System.Drawing
Imports System.Windows.Forms

Public Class Form1

    Dim schermataqrcode As New Form

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        schermataqrcode.FormBorderStyle = FormBorderStyle.None
        AddHandler schermataqrcode.MouseDown, AddressOf schermataqrcode.MouseDown
        AddHandler schermataqrcode.MouseUp, AddressOf schermataqrcode.MouseUp
        AddHandler schermataqrcode.MouseMove, AddressOf schermataqrcode.MouseMove

        Dim qrcode As New qrcode
        qrcode.Dock = DockStyle.Fill
        schermataqrcode.Controls.Add(qrcode)
        schermataqrcode.StartPosition = FormStartPosition.CenterScreen
        schermataqrcode.Show()
    End Sub

    Public Class schermatacode
        Private IsDraggingForm As Boolean = False
        Private MousePos As New System.Drawing.Point(0, 0)

        Private Sub schermataqrcode_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
            If e.Button = MouseButtons.Left Then
                IsDraggingForm = True
                MousePos = e.Location
            End If
        End Sub

        Private Sub schermataqrcode_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
            If e.Button = MouseButtons.Left Then IsDraggingForm = False
        End Sub

        Private Sub schermataqrcode_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
            If IsDraggingForm Then
                Dim temp As Point = New Point(Me.Location + (e.Location - MousePos))
                Me.Location = temp
                temp = Nothing
            End If
        End Sub
    End Class
End Class

我不确定,因为 VS 错误:

 BC30577    'AddressOf' operand must be the name of a method (without parentheses).
 BC30577    'AddressOf' operand must be the name of a method (without parentheses).
 BC30577    'AddressOf' operand must be the name of a method (without parentheses).
 BC30456    'Location' is not a member of 'Form1.schermatacode'.
 BC30456    'Location' is not a member of 'Form1.schermatacode'.

当前代码中的问题:

  • 选项严格是 Off

  • schermataqrcode 表单的事件应该由 schermatacode class 对象处理,但赋值不指向 schermatacode class 全部:

    AddHandler schermataqrcode.MouseDown, AddressOf schermataqrcode.MouseDown 
    ' should be:
    AddHandler schermataqrcode.MouseDown, AddressOf schermatacode.schermataqrcode_MouseDown
    

    但您没有创建此 class 的实例(它不是静态的,也不可能是静态的)并且在任何情况下都声明了事件处理程序 Private,因此无论如何您都无法访问它们。

  • 即使事件处理程序设置正确,Form 的 ClientArea 也会完全被停靠的 Control 填充,因此它不会接收鼠标事件。

  • 这个:Dim temp As Point = New Point(Me.Location + (e.Location - MousePos))不能用: - Me 不是表单,它是 schermatacode class,它没有 Location 属性.
    - Option Strict Off 向您隐藏了 Me.Location + (e.Location - MousePos) 不是 return 可用的点数。当你设置 Option Strict On.

    时,看看 Point = Point + (Point - Point) 实际上是什么

这里有一些你可以做的事情:

  • 移动 SchermataCode class 对象中的所有逻辑:您只是创建一个包含单个控件的标准表单(根据描述,但您可以添加所有控件你要)。 class 处理表单和 QR 控件的创建,还设置所有需要的事件处理程序。

  • 对所有内容使用单个 class 对象,您只需初始化 class 并在需要时使用它,例如 Dim qrForm = New SchermataCode()

  • SchermataCode 对象然后可以公开 public 方法和属性,允许使用其功能,只需调用方法或检查 属性,就像通常发生的那样与 .Net classes.
    在示例代码中,SchermataCode 公开了一个 ShowForm() public 方法,该方法将窗体显示为对话框。您可以将要呈现为 QR 图像的字符串传递给此方法。这样,您可以使用同一个 class 来显示多个表单,也可以在应用程序的整个生命周期中使用同一个 class 对象。

► 重要的是要注意 SchermataCode 还公开了一个 Dispose() 方法:此方法允许处理表单、QR 控件并删除添加到这些控件的所有处理程序。当您不再需要 SchermataCode 时,调用此方法非常重要 - 就像在 .Net 中一样 - 释放这些对象正在分配的资源。
当然,如果需要,您可以在之后创建另一个实例。


注意: 由于二维码控件占据了表单的整个客户区,border-less 表单移动由二维码控件处理,使用其MouseDownMouseMove 事件而不是表单的事件(因为表单不会接收鼠标事件)。
我不确定 QR 控件是否具有与这些事件相关的某些特定功能(如果您单击它,就会发生一些事情。如果是这样的话请告诉我)。
此外,双击 QR 控件会导致表单关闭。


例如,创建一个SchermataCode实例并按顺序显示两个Form,在一种情况下将ShowForm() return的图像分配给局部变量并分配给PictureBox控件在另一个(我不确定 QR 控件 return 是否是渲染图像,或者即使你需要它,它也是为了展示这个 class 是如何工作的)。

Dim qrForm = New SchermataCode()

' Shown the Dialog using the default Size 
Dim result As Image = qrForm.ShowForm("<Some QR String>")

qrForm.QRImageSize = New Size(200, 200)
PictureBox1.Image = qrForm.ShowForm("<Some Other QR String>")
qrForm.Dispose()

QRImageSize public 属性 允许在显示新对话框之前更改 QR 控件的大小。默认大小为 (500, 500).


修改 SchermataCode class:

Public Class SchermataCode
    Implements IDisposable

    Private qrForm As Form = Nothing
    Private qr As qrcode = Nothing
    Private startPosition As Point = Point.Empty

    Public Sub New()
        qrForm = New Form() With {
            .FormBorderStyle = FormBorderStyle.None,
            .StartPosition = FormStartPosition.CenterScreen
        }

        qr = New qrcode() With {.Size = QRImageSize}
        AddHandler qr.MouseDown, AddressOf qrCode_MouseDown
        AddHandler qr.MouseMove, AddressOf qrCode_MouseMove
        AddHandler qr.DoubleClick, AddressOf qrCode_OnDoubleClick
        qrForm.Controls.Add(qr)
    End Sub

    Public Property QRImageSize As Size = New Size(500, 500)

    Public Function ShowForm(qrString As String) As Image
        If QRImageSize <> qr.Size Then qr.Size = QRImageSize
        qrForm.ClientSize = qr.Size
        qr.Text = qrString
        qrForm.ShowDialog()
        Return qr.Image
    End Function


    Private Sub qrCode_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        If e.Button = MouseButtons.Left Then
            startPosition = e.Location
        End If
    End Sub

    Private Sub qrCode_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
        If e.Button = MouseButtons.Left Then
            qrForm.Location = New Point(
                qrForm.Left + (e.X - startPosition.X),
                qrForm.Top + (e.Y - startPosition.Y))
        End If
    End Sub

    Private Sub qrCode_OnDoubleClick(ByVal sender As Object, ByVal e As EventArgs)
        qrForm.Close()
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overridable Sub Dispose(disposing As Boolean)
        If disposing Then
            If qr IsNot Nothing Then
                RemoveHandler qr.MouseDown, AddressOf qrCode_MouseDown
                RemoveHandler qr.MouseMove, AddressOf qrCode_MouseMove
                RemoveHandler qr.DoubleClick, AddressOf qrCode_OnDoubleClick
            End If
            qr?.Dispose()
            qrForm?.Dispose()
        End If
    End Sub
End Class

此处使用null conditional operator以避免在处置某些对象时检查null(例如qrForm?.Dispose())。

如果您的 VB.Net 版本不允许,请更改它,例如:

If qrForm IsNot Nothing Then qrForm.Dispose()