Introduction
Many users have questions about creating screensavers for their projects. And many users wish to create splash screens which are shaped the same as a transparent PNG, GIF, etc. This project is a Bubbles screensaver in Windows 7. Users can also use this code to make transparent forms.
Background
Earlier, I had tried to create a Super Bar like the Windows 7 Super Bar. That's when I got the code to make a form transparent. Then, I decided to create this amazing screensaver using that code.
Using the Code
First, I will talk about creating a transparent from. I have used the PerPixelFrom
library from Sbar
on CodePlex to create a transparent form.
PerPixelAlphaForm.vb
Imports System.Windows.Forms
Imports system.Runtime.InteropServices
Imports Screen_Saver.Win32
Public Class PerPixelAlphaForm
Inherits Form
Public StartLeft As Integer
Public StartTop As Integer
Public Ang As Double
Public WithEvents tim As New Timer
Public Sub New()
MyBase.FormBorderStyle = Windows.Forms.FormBorderStyle.None
MyBase.ShowInTaskbar = False
End Sub
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
MyBase.Dispose(disposing)
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
Public Sub SetBitmap(ByVal bitmap As Bitmap)
Me.SetBitmap(bitmap, &HFF)
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
Public Sub SetBitmap(ByVal bitmap As Bitmap, ByVal opacity As Byte)
If (bitmap.PixelFormat <> Imaging.PixelFormat.Format32bppArgb) Then
Throw New ApplicationException("The bitmap must be 32ppp with alpha-channel.")
End If
Dim screenDc As IntPtr = Win32.GetDC(IntPtr.Zero)
Dim memDc As IntPtr = Win32.CreateCompatibleDC(screenDc)
Dim hBitmap As IntPtr = IntPtr.Zero
Dim oldBitmap As IntPtr = IntPtr.Zero
Try
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0))
oldBitmap = Win32.SelectObject(memDc, hBitmap)
Dim size As New Size(bitmap.Width, bitmap.Height)
Dim pointSource As New Point(0, 0)
Dim topPos As New Point(MyBase.Left, MyBase.Top)
Dim blend As New BLENDFUNCTION
blend.BlendOp = 0
blend.BlendFlags = 0
blend.SourceConstantAlpha = opacity
blend.AlphaFormat = 1
Win32.UpdateLayeredWindow(MyBase.Handle, screenDc, (topPos), _
(size), memDc, (pointSource), 0, (blend), 2)
Finally
Win32.ReleaseDC(IntPtr.Zero, screenDc)
If (hBitmap <> IntPtr.Zero) Then
Win32.SelectObject(memDc, oldBitmap)
Win32.DeleteObject(hBitmap)
End If
Win32.DeleteDC(memDc)
Win32.DeleteDC(screenDc)
Win32.DeleteObject(oldBitmap)
Win32.DeleteObject(screenDc)
Win32.DeleteObject(memDc)
GC.Collect()
GC.WaitForPendingFinalizers()
End Try
End Sub
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim cp As CreateParams = MyBase.CreateParams
cp.ExStyle = (cp.ExStyle Or &H80000)
cp.ExStyle = (cp.ExStyle Or &H80)
Return cp
End Get
End Property
End Class
For any form, we can use this code to make it transparent:
Dim frm As New PerPixelAlphaForm
frm.SetBitmap(My.Resources.Blue)
frm.Show()
This code makes frm
(Form
) transparent like the blue bubble image (as shown in the above image).
Now we will talk about how to show different colors of bubbles. I have used different images to show different colored bubbles.
First, I have defined a random number. Then according to it, we can set different images to bubbles. When Timer1
ticks, a random number is generated and a bubble comes out. I have combined them to close the screensaver when the cursor moves in timer1_tick
code.
Timer1_tick
Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
If MposL <> System.Windows.Forms.Cursor.Position.X Or _
MposT <> System.Windows.Forms.Cursor.Position.Y Then
Timer1.Enabled = False
Me.Close()
Exit Sub
End If
k = New PerPixelAlphaForm
Dim a As New System.Random
Select Case a.NextDouble
Case Is < 0.1
k.SetBitmap(My.Resources.Blue)
Case Is < 0.2
k.SetBitmap(My.Resources.Green)
Case Is < 0.3
k.SetBitmap(My.Resources.Orange)
Case Is < 0.4
k.SetBitmap(My.Resources.Other1)
Case Is < 0.5
k.SetBitmap(My.Resources.Other2)
Case Is < 0.6
k.SetBitmap(My.Resources.Pink)
Case Is < 0.7
k.SetBitmap(My.Resources.Red)
Case Is < 0.8
k.SetBitmap(My.Resources.Violate)
Case Else
k.SetBitmap(My.Resources.Yellow)
End Select
If TotalBub < txtBubbles.Text Then
k.Ang = 1.57 * a.NextDouble
k.Show()
TotalBub += 1
End If
k = Nothing
End Sub
Now the difficulty was how to send bubbles in different directions and get them to move back when they collide with the edge of the screen. Again, I used a random number and some math functions to send them in different angles and when the position becomes beyond the screen width, they go in other directions. I have added a Timer
to get the position and angle in PerPixelAlphaForm.vb.
Editing in PerPixelAlphaForm.vb
Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles tim.Tick
If Me.Left < 0 Or Me.Top < 0 Or Me.Left > _
Screen.PrimaryScreen.WorkingArea.Width - _
185 Or Me.Top > Screen.PrimaryScreen.WorkingArea.Height - 185 Then
Ang += 1.57 * Date.Now.Millisecond / 1000
If Me.Left < 0 Then Me.Left = 0
If Me.Top < 0 Then Me.Top = 0
If Me.Right > Screen.PrimaryScreen.WorkingArea.Width Then Me.Left = _
Screen.PrimaryScreen.WorkingArea.Width - 185
If Me.Bottom > Screen.PrimaryScreen.WorkingArea.Height Then Me.Top = _
Screen.PrimaryScreen.WorkingArea.Height - 185
Else
Me.Left += Math.Cos(Ang) * 10
Me.Top -= Math.Sin(Ang) * 10
End If
End Sub
I have set timer1.interval
to 2
to give speed and reality to bubbles when they load.
Private Sub PerPixelAlphaForm_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
tim.Enabled = True
tim.Interval = 2
Me.Top = Screen.PrimaryScreen.WorkingArea.Height - 200
Me.Left = 0
End Sub
History
- 22nd May, 2011: First release