Reputation: 85
I'm currently working on a small single instance application that is called by an external application using command line parameter. I'll try to be clear on that ;) So I have a running application that will execute that application I'm developing. This new application has different options based on a command line parameter and is single instance. So, every time the other application calls the new application it just updates the running instance based on that command line parameter (not easy to explain, I hope it's clear).
Everything is working fine but for one thing. The application Form uses a PictureBox to display an image. One of the command line parameter will fade that image into another one. To do this I'm using a PictureBox1_Paint Private Sub in the Form1.vb but I also need it in the ApplicationEvents.vb but I can't get it to work.
If I try the following code in the ApplicationEvents.vb, I'm getting the error message "BC30506 Handles clause requires a WithEvents variable defined in the containing type or one of its base types."
Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
If I remove the "Handles PictureBox1.Paint", no more error message but no redraw of the PictureBox.
Any idea?
Thanks.
============================================================================
Hey, sorry for late reply but I've been quite busy :)
So, I've tried the solution below but can't get it to work... :(
Here is my code so far (with a lot of unneeded stuff removed) for Form1.vb and ApplicationEvents.vb Can you help me on how to apply the solution?
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
Thanks a lot and stay safe !
Upvotes: 0
Views: 71
Reputation: 54457
The only place you handle the Paint
event of the PictureBox
is in the form containing that PictureBox
. That event handler will be executed every time a Paint
event is raised, so that is what you actually need to do from the other code file. In it's simplest form, that would look like this:
Private Sub MyApplication_StartupNextInstance(sender As Object, e As StartupNextInstanceEventArgs) Handles Me.StartupNextInstance
MainForm.Refresh()
End Sub
In the MyApplication
class, the MainForm
property refers to your app's startup form object. By calling its Refresh
method, you force it to repaint, which will also cause your PictureBox
to repaint. Presumably you would want to do something involving the commandline argument(s) before making that call.
If you want to be a bit more efficient, you can force a repaint of the PictureBox
without repainting the rest of the form. To do that, you would start by defining a method in the form that forced a repaint of the PictureBox
:
Public Sub RefreshPictureBox()
PictureBox1.Refresh()
End Sub
You would then call that method from the MyApplication
class:
Private Sub MyApplication_StartupNextInstance(sender As Object, e As StartupNextInstanceEventArgs) Handles Me.StartupNextInstance
DirectCast(MainForm, Form1).RefreshPictureBox()
End Sub
Note that, in this case, you have to cast as the actual type of the startup form because you're calling a member of that type. MainForm
is type Form
and Refresh
is a member of Form
, so that's fine without a cast.
It's also worth noting that you could call Invalidate
rather than Refresh
. If you call Invalidate
then the Paint
event will be raised when the UI thread is next free while, internally, Refresh
calls Invalidate
and then Update
, to force an immediate repaint.
Upvotes: 1