Использование PictureBox_Paint из ApplicationEvents.vb - PullRequest
0 голосов
/ 26 марта 2020

В настоящее время я работаю над небольшим приложением с одним экземпляром, которое вызывается внешним приложением с использованием параметра командной строки. Я постараюсь прояснить это;) Итак, у меня есть работающее приложение, которое будет выполнять то приложение, которое я разрабатываю. Это новое приложение имеет различные параметры в зависимости от параметра командной строки и является единичным экземпляром. Таким образом, каждый раз, когда другое приложение вызывает новое приложение, оно просто обновляет запущенный экземпляр на основе этого параметра командной строки (не легко объяснить, я надеюсь, это понятно).

Все работает нормально, но с одной стороны. Форма заявки использует PictureBox для отображения изображения. Один из параметров командной строки превратит это изображение в другое. Для этого я использую Private Sub PictureBox1_Paint в Form1.vb, но он мне также нужен в ApplicationEvents.vb, но я не могу заставить его работать.

Если я попробую следующий код в ApplicationEvents.vb, я получаю сообщение об ошибке "Для предложения BC30506 Handles требуется переменная WithEvents, определенная в содержащем типе или одном из его базовых типов."

Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint

Если я удаляю "Handles PictureBox1.Paint ", больше нет сообщения об ошибке, но нет перерисовки PictureBox.

Есть идеи?

Спасибо.

===================== ================================================== ============

Эй, извините за поздний ответ, но я был довольно занят :)

Итак, я попробовал решение ниже, но могу заставить его работать ...: (

Вот мой код (с удалением большого количества ненужных вещей) для Form1.vb и ApplicationEvents.vb. Можете ли вы помочь мне с тем, как применить решение? ?

Form1.vb

Public Class Form1

    Dim TickTime As Integer = My.Settings.TransitionTime / 100
    Private _fadeOpacity As Single = 0
    Private CurrentImage As Bitmap
    Private NextImage As Bitmap

    Private Function FadeBitmap(ByVal bmp As Bitmap, ByVal opacity As Single) As Bitmap
        Dim bmp2 As New Bitmap(bmp.Width, bmp.Height, Imaging.PixelFormat.Format32bppArgb)
        opacity = Math.Max(0, Math.Min(opacity, 1.0F))
        Using ia As New Imaging.ImageAttributes
            Dim cm As New Imaging.ColorMatrix
            cm.Matrix33 = opacity
            ia.SetColorMatrix(cm)
            Dim destpoints() As PointF = {New Point(0, 0), New Point(bmp.Width, 0), New Point(0, bmp.Height)}
            Using g As Graphics = Graphics.FromImage(bmp2)
                g.DrawImage(bmp, destpoints,
                New RectangleF(Point.Empty, bmp.Size), GraphicsUnit.Pixel, ia)
            End Using
        End Using
        Return bmp2
    End Function

    Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
        If _fadeOpacity < 100 AndAlso CurrentImage IsNot Nothing Then
            e.Graphics.DrawImageUnscaled(CurrentImage, Point.Empty)
        End If
        If _fadeOpacity > 0 AndAlso NextImage IsNot Nothing Then
            Using fadedImage As Bitmap = FadeBitmap(NextImage, _fadeOpacity)
                e.Graphics.DrawImageUnscaled(fadedImage, Point.Empty)
            End Using
        End If
    End Sub

    Private Sub StartTransition(ImageName As String)
        ' In settings I have a parameter for the transition type, CUT or DISSOLVE. This sends the new image to load in the approriate function
        Select Case My.Settings.TransitionType
            Case 0
                Transition_CUT(ImageName)
            Case 1
                Transition_Dissolve(ImageName)
        End Select
    End Sub

    Private Sub Transition_CUT(ImageName As String)
        ' Replaced the image in PictureBox1
        CurrentImage = New Bitmap(Image.FromFile(ImageName), Me.PictureBox1.Size)
        Me.PictureBox1.Refresh()
    End Sub

    Private Sub Transition_Dissolve(ImageName As String)
        ' Fade between current image and new image over the defined time in My.Settings (in ms)
        NextImage = New Bitmap(Image.FromFile(ImageName), Me.PictureBox1.Size)
        'fade to newimage
        Dim TickTime As Integer = My.Settings.TransitionTime / 100
        For i = 0 To 1 Step 0.01
            _fadeOpacity = CSng(i)
            Me.PictureBox1.Invalidate()
            wait(TickTime)
        Next
        wait(100)
        CurrentImage = New Bitmap(Image.FromFile(ImageName), Me.PictureBox1.Size)
        _fadeOpacity = CSng(0)
        Me.PictureBox1.Invalidate()
    End Sub

    Private Sub wait(ByVal interval As Integer)
        ' custom timer
        Dim stopW As New Stopwatch
        stopW.Start()
        Do While stopW.ElapsedMilliseconds < interval
            ' Allows UI to remain responsive
            Application.DoEvents()
        Loop
        stopW.Stop()
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ' Load default image at startup
        CurrentImage = New Bitmap(Image.FromFile(My.Settings.DefaultBackgroundImage), Me.PictureBox1.Size)
        Me.PictureBox1.Refresh()

        ' For easy communication between form1 and ApplicationEvents, the command line argument has been passed to Label6
        If Label6.Text.StartsWith("/init") Then
            ' Initialize the application and load default background image from xml settings
            StartTransition(My.Settings.DefaultBackgroundImage)
        ElseIf Label6.Text.StartsWith("/load") Then
            ' Check existance and load the specified image
            Dim inputArgument As String = "/load="
            Dim inputName As String = ""
            If Label6.Text.StartsWith(inputArgument) Then
                inputName = Label6.Text.Remove(0, inputArgument.Length)
            End If
            If inputName = "" Then
                ' No image name specified, load the image not specified image
                StartTransition(My.Settings.ImageNotSpecified)
            Else
                If My.Computer.FileSystem.FileExists(My.Settings.ImagesFolder & inputName & ".jpg") Then
                    ' Image has been found and is displayed
                    StartTransition(My.Settings.ImagesFolder & inputName & ".jpg")
                Else
                    ' Image not found, displaying the not found message
                    StartTransition(My.Settings.ImageNotFound)
                End If
            End If
        ElseIf Label6.Text.StartsWith("/quit") Then
            ' Quit application
            Me.Close()
        Else
            ' No parameter sent, showing instructions
        End If
    End If

    End Sub

    Private Function argument() As String
        Throw New NotImplementedException
    End Function

End Class

ApplicationEvents.vb

Namespace My

    ' The following events are available for MyApplication:
    ' 
    ' Startup: Raised when the application starts, before the startup form is created.
    ' Shutdown: Raised after all application forms are closed.  This event is not raised if the application terminates abnormally.
    ' UnhandledException: Raised if the application encounters an unhandled exception.
    ' StartupNextInstance: Raised when launching a single-instance application and the application is already active. 
    ' NetworkAvailabilityChanged: Raised when the network connection is connected or disconnected.
    Partial Friend Class MyApplication

        Public Shared argument As String
        Private _fadeOpacity As Single = 0
        Private CurrentImage As Bitmap
        Private NextImage As Bitmap

        Private Sub StartTransition(ImageName As String)
            Select Case My.Settings.TransitionType
                Case 0
                    Transition_CUT(ImageName)
                Case 1
                    Transition_Dissolve(ImageName)
            End Select
        End Sub

        Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
            If _fadeOpacity < 100 AndAlso CurrentImage IsNot Nothing Then
                e.Graphics.DrawImageUnscaled(CurrentImage, Point.Empty)
            End If
            If _fadeOpacity > 0 AndAlso NextImage IsNot Nothing Then
                Using fadedImage As Bitmap = FadeBitmap(NextImage, _fadeOpacity)
                    e.Graphics.DrawImageUnscaled(fadedImage, Point.Empty)
                End Using
            End If
        End Sub

        Private Function FadeBitmap(ByVal bmp As Bitmap, ByVal opacity As Single) As Bitmap
            Dim bmp2 As New Bitmap(bmp.Width, bmp.Height, Imaging.PixelFormat.Format32bppArgb)
            opacity = Math.Max(0, Math.Min(opacity, 1.0F))
            Using ia As New Imaging.ImageAttributes
                Dim cm As New Imaging.ColorMatrix
                cm.Matrix33 = opacity
                ia.SetColorMatrix(cm)
                Dim destpoints() As PointF = {New Point(0, 0), New Point(bmp.Width, 0), New Point(0, bmp.Height)}
                Using g As Graphics = Graphics.FromImage(bmp2)
                    g.DrawImage(bmp, destpoints,
                New RectangleF(Point.Empty, bmp.Size), GraphicsUnit.Pixel, ia)
                End Using
            End Using
            Return bmp2
        End Function

        Private Sub Transition_CUT(ImageName As String)
            CurrentImage = New Bitmap(Image.FromFile(ImageName), Form1.PictureBox1.Size)
            _fadeOpacity = CSng(0)
            Form1.PictureBox1.Invalidate()
        End Sub

        Private Sub Transition_Dissolve(ImageName As String)
            NextImage = New Bitmap(Image.FromFile(ImageName), Form1.PictureBox1.Size)
            'fade to newimage
            Dim TickTime As Integer = CInt(Form1.TextBox_Time.Text) / 100
            For i = 0 To 1 Step 0.01
                _fadeOpacity = CSng(i)
                Form1.PictureBox1.Invalidate()
                wait(TickTime)
            Next
            wait(100)
            CurrentImage = New Bitmap(Image.FromFile(ImageName), Form1.PictureBox1.Size)
            _fadeOpacity = CSng(0)
            Form1.PictureBox1.Invalidate()
        End Sub

        Private Sub wait(ByVal interval As Integer)
            Dim stopW As New Stopwatch
            stopW.Start()
            Do While stopW.ElapsedMilliseconds < interval
                ' Allows your UI to remain responsive
                Application.DoEvents()
            Loop
            stopW.Stop()
        End Sub

        Private Sub MyApplication_Startup(
            ByVal sender As Object,
            ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs
        ) Handles Me.Startup

            ' Clean the command line parameter container (label6)
            Form1.Label6.Text = "none"

            For Each s As String In e.CommandLine
                Form1.Label6.Text = s.ToLower
            Next
        End Sub

        Private Sub MyApplication_StartupNextInstance(
            ByVal sender As Object,
            ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs
        ) Handles Me.StartupNextInstance

            For Each s As String In e.CommandLine
                If s.ToLower.StartsWith("/quit") Then
                    'Quit the application
                    Form1.Close()
                ElseIf s.ToLower.StartsWith("/init") Then
                    'Initialize the application and load default background image from xml settings
                    StartTransition(My.Settings.DefaultBackground)
                ElseIf s.ToLower.StartsWith("/load") Then
                    'Check existance and load the specified image
                    Dim inputArgument As String = "/load="
                    Dim inputName As String = ""
                    For Each i As String In e.CommandLine
                        If i.ToLower.StartsWith(inputArgument) Then
                            inputName = i.Remove(0, inputArgument.Length)
                        End If
                    Next
                    If inputName = "" Then
                        ' No image name specified, load the image not specified image
                        StartTransition(My.Settings.ImageNotSpecified)
                    Else
                        If My.Computer.FileSystem.FileExists(My.Settings.ImagesFolder & inputName & ".jpg") Or My.Computer.FileSystem.FileExists(My.Settings.ImagesFolder & inputName & ".swf") Then
                            ' Image has been found and is displayed
                            StartTransition(My.Settings.ImagesFolder & inputName & ".jpg")
                        Else
                            ' Image not found, displaying the not found message
                            StartTransition(My.Settings.ImageNotFound)
                        End If
                    End If
                ElseIf s.ToLower.StartsWith("") Then
                    'No parameter sent, showing instructions
                End If
            Next
        End Sub
    End Class
End Namespace

Большое спасибо и будь в безопасности!

1 Ответ

1 голос
/ 26 марта 2020

Единственное место, где вы обрабатываете событие Paint для PictureBox, находится в форме, содержащей это PictureBox. Этот обработчик событий будет выполняться каждый раз, когда возникает событие Paint, поэтому именно это вам и нужно сделать из другого файла кода. В простейшей форме это будет выглядеть так:

Private Sub MyApplication_StartupNextInstance(sender As Object, e As StartupNextInstanceEventArgs) Handles Me.StartupNextInstance
    MainForm.Refresh()
End Sub

В классе MyApplication свойство MainForm относится к объекту формы запуска вашего приложения. Вызывая метод Refresh, вы заставляете его перерисовываться, что также вызывает перерисовку вашего PictureBox. Предположительно, вы хотели бы сделать что-то с аргументом (ами) командной строки перед выполнением этого вызова.

Если вы хотите быть немного более эффективным, вы можете принудительно перекрасить PictureBox, не перекрашивая остальную часть форма. Для этого вы должны начать с определения метода в форме, которая вынудит перерисовать PictureBox:

Public Sub RefreshPictureBox()
    PictureBox1.Refresh()
End Sub

Затем вы вызовете этот метод из класса MyApplication:

Private Sub MyApplication_StartupNextInstance(sender As Object, e As StartupNextInstanceEventArgs) Handles Me.StartupNextInstance
    DirectCast(MainForm, Form1).RefreshPictureBox()
End Sub

Обратите внимание, что в этом случае вы должны приводить в качестве фактического типа формы запуска, потому что вы вызываете член этого типа. MainForm имеет тип Form, а Refresh является членом Form, так что это нормально без приведения.

Стоит также отметить, что вы можете звонить Invalidate вместо Refresh. Если вы вызываете Invalidate, то событие Paint будет вызываться, когда поток пользовательского интерфейса будет свободен, в то время как внутренне Refresh вызывает Invalidate, а затем Update, чтобы вызвать немедленную перерисовку.

...