Preview.jpg

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. And that's when I got the code to make a from transparent. And 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 from.

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
    ' Methods
    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
    ' Properties
    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

First Release - May 22, 2011.

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"