C#实现打造气泡屏幕保护效果

时间:2022-05-13 10:33:18

本文主要是介绍c#实现打造气泡屏幕保护效果,首先说一下制作要点:1 窗口要全屏置顶 2 模拟气泡的滚动和粘滞效果 3 支持快捷键esc退出

大致就是这3个要点了,其他还有一些细节我们在程序中根据需要再看,ok,开工!

首先是全屏置顶,因为是屏幕保护嘛,这个简单,在窗体的属性设置里把formborderstyle设置为none表示无边框,把showintaskbar设置为false表示不在任务栏出现,最后一个把windowstate设置为maximized表示最大化即可,当然可以设置topmost为true让窗口置顶,不过这个不是绝对的,如果有其他窗口也使用topmost的话会让我们失去焦点,所以我们要注册一个快捷键让程序可以退出!

模拟气泡我们可以用graphics类中的drawellipse方法来画一个圆,当然这个圆我们可以指定不同的颜色和大小,这里重点讲一下怎么模拟粘滞效果!

所谓粘滞效果相信大家到知道,胶体大家都见过吧?就是类似胶体那种有弹性并且可以在改变形状后回复原型的那种效果,当然这里要想模拟这个效果只能说是稍微类似,drawellipse方法中最后两个参数表示圆的大小,我们可以在这里做文章,由于循环的速度很快,我们只要动态改变圆的大小就可以产生类似粘滞的效果,当然这个改变大小的参数不能太大,否则就无效了!

我们在onpaint事件中写入如下代码来绘制一些圆:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
random ra = new random(); //初始化随机数
   bmp = new bitmap(clientsize.width,clientsize.height, e.graphics);
   graphics bmpgraphics = graphics.fromimage(bmp);
   // 绘制圆形     
  for (int i=1;i<=13;i++)//这里绘制13个圆形
   {
     bmpgraphics.drawellipse(new pen(color.fromname(colours[i]),2),//根据事先定义好的颜色绘制不同颜色的圆
      ballarray[i, 1], ballarray[i, 2], 70+ra.next(1, 10), 70+ra.next(1, 10));
      //注意上面的最后两个参数利用随机数产生粘滞效果
   }
   e.graphics.drawimageunscaled(bmp, 0, 0);
   bmpgraphics.dispose();
   bmp.dispose();//这里是非托管的垃圾回收机制,避免产生内存溢出

这样,通过以上代码就可以绘制出一些不同颜色的具有粘滞效果的圆来模拟气泡

下面是注册系统热键,有个api函数registerhotkey可以完成系统快捷键的注册,使用他之前我们要先引用一个系统的dll文件:user32.dll,然后对这个registerhotkey函数进行一下声明:

?
1
2
[dllimport("user32.dll")]//引用user32.dll
public static extern uint32 registerhotkey(intptr hwnd, uint32 id, uint32 fsmodifiers, uint32 vk); //声明函数原型

由于引用了一个dll文件,我们不要忘了在文件头加入dllimport的类声明using system.runtime.interopservices;然后在form1的构造函数中来注册一个系统热键,这里我们注册esc:registerhotkey(this.handle, 247696411, 0, (uint32)keys.escape); 通过以上步骤,我们就可以注册一个或多个系统热键,但是,注册系统热键后我们还不能立即使用,因为我们在程序中还无法对这个消息进行响应,我们重载一下默认的wndproc过程来响应我们的热键消息:

?
1
2
3
4
5
6
7
8
9
protected override void wndproc(ref message m)//注意是保护类型的过程
 {
     const int wm_hotkey = 0x0312;
 }
    if (m.msg == wm_hotkey & & m.wparam.toint32() == 247696411) //判断热键消息是不是我们设置的
       {
        application.exit();//如果消息等于我们的热键消息,程序退出
      }
    base.wndproc(ref m);//其他消息返回做默认处理

好了,通过以上一些步骤,我们就基本完成了这个屏幕保护程序的要点设计,其他的详细过程可以参考源码,程序运行的时候背景是透明的,这个也不难实现

1.this.backcolor = system.drawing.color.fromargb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(192)))));
2.this.transparencykey = system.drawing.color.fromargb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(192)))));

屏幕保护程序代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
using system;
using system.drawing;
using system.collections;
using system.componentmodel;
using system.windows.forms;
using system.runtime.interopservices;
/*
 屏幕保护程序
 使用技术:系统热键,随机数,graphics类绘制圆形
 编译环境:visualstudio 2005
 运行要求:安装.net framework 2.0 框架
 其他:使用esc退出
 
 说明:由于使用了循环控制图形位移,cpu占用在20%-30%左右
 程序具有自动垃圾回收机制避免造成内存溢出
 
 2009年3月15日
 */
namespace animatball
{
  /// <summary>
  /// summary description for form1.
  /// </summary>
  
  public class form1 : system.windows.forms.form
  {
 
    public int[,] ballarray = new int[20,20];
    public string[] colours = new string[16];
  
    public bitmap bmp;
 
    private system.windows.forms.timer timer1;
    private system.componentmodel.icontainer components;
    [dllimport("user32.dll")]
    public static extern uint32 registerhotkey(intptr hwnd, uint32 id, uint32 fsmodifiers, uint32 vk); //api
     //重写消息循环
    
    protected override void wndproc(ref message m)
     {
       const int wm_hotkey = 0x0312;
      
       if (m.msg == wm_hotkey && m.wparam.toint32() == 247696411) //判断热键
       {
         application.exit();
       }
 
       base.wndproc(ref m);
     }
    public form1()
    {
      //
      // required for windows form designer support
      //
      initializecomponent();
      //colours[0]="red";
      colours[1]="red";
      colours[2]="blue";
      colours[3]="black";
      colours[4]="yellow";
      colours[5]="crimson";
      colours[6]="gold";
      colours[7]="green";
      colours[8]="magenta";
      colours[9]="aquamarine";
      colours[10]="brown";
      colours[11]="red";
      colours[12]="darkblue";
      colours[13]="brown";
      colours[14]="red";
      colours[15]="darkblue";
      initializecomponent();
      registerhotkey(this.handle, 247696411, 0, (uint32)keys.escape); //注册热键
      //
      // todo: add any constructor code after initializecomponent call
      //
    }
 
    /// <summary>
    /// clean up any resources being used.
    /// </summary>
 
    protected override void dispose( bool disposing )
    {
      if( disposing )
      {
        if (components != null)
        {
          components.dispose();
        }
      }
      base.dispose( disposing );
    }
 
      #region windows form designer generated code
 
    /// <summary>
    /// required method for designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
 
    private void initializecomponent()
    {
      this.components = new system.componentmodel.container();
      this.timer1 = new system.windows.forms.timer(this.components);
      this.suspendlayout();
      //
      // timer1
      //
      this.timer1.interval = 25;
      this.timer1.tick += new system.eventhandler(this.timer1_tick);
      //
      // form1
      //
      this.autoscalebasesize = new system.drawing.size(6, 14);
      this.backcolor = system.drawing.color.fromargb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(192)))));
      this.clientsize = new system.drawing.size(373, 294);
      this.doublebuffered = true;
      this.formborderstyle = system.windows.forms.formborderstyle.none;
      this.name = "form1";
      this.showintaskbar = false;
      this.text = "小焱屏幕保护";
      this.topmost = true;
      this.transparencykey = system.drawing.color.fromargb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(192)))));
      this.windowstate = system.windows.forms.formwindowstate.maximized;
      this.load += new system.eventhandler(this.form1_load);
      this.resumelayout(false);
 
    }
      #endregion
    /// <summary>
    /// the main entry point for the application.
    /// </summary>
 
    [stathread]
    static void main()
    {
      application.run(new form1());
    }
 
    private void timer1_tick(object sender, system.eventargs e)
    {
      
      for (int i=1;i<=13;i++)
      {  
        //add direction vectors to coordinates
        ballarray[i,1] = ballarray[i,1] + ballarray[i,3];
        ballarray[i,2] = ballarray[i,2] + ballarray[i,4];
        //if ball goes of to right
        if ((ballarray[i,1]+50)>=clientsize.width)
        {     
          ballarray[i,1]=ballarray[i,1]-ballarray[i,3];
          ballarray[i,3]=-ballarray[i,3];
        }
          //if ball goes off bottom
        else if ((ballarray[i,2]+50)>=clientsize.height)
        {
          ballarray[i,2]=ballarray[i,2]-ballarray[i,4];
          ballarray[i,4]=-ballarray[i,4];
        }
          //if ball goes off to left
        else if (ballarray[i,1]<=1)
        {
          ballarray[i,1]=ballarray[i,1]-ballarray[i,3];
          ballarray[i,3]=-ballarray[i,3];
        }        
          //if ball goes over top
        else if (ballarray[i,2]<=1)
        {
          ballarray[i,2]=ballarray[i,2]-ballarray[i,4];
          ballarray[i,4]=-ballarray[i,4];
        }
      }
      this.refresh(); //force repaint of window
    }
    //called from timer event when window needs redrawing
    protected override void onpaint(painteventargs e)
    {
      random ra = new random();
      bmp = new bitmap(clientsize.width,clientsize.height, e.graphics);
      graphics bmpgraphics = graphics.fromimage(bmp);
      // draw here       
      for (int i=1;i<=13;i++)
      {
        bmpgraphics.drawellipse(new pen(color.fromname(colours[i]),2),
          ballarray[i, 1], ballarray[i, 2], 70+ra.next(1, 10), 70+ra.next(1, 10));//利用随机数产生粘滞效果
      }
      e.graphics.drawimageunscaled(bmp, 0, 0);
      //draw ellipse acording to mouse coords.
      
      bmpgraphics.dispose();
      bmp.dispose();
    }     
    private void form1_load(object sender, eventargs e)
    {
      random r = new random();
      //set ball coords and vectors x,y,xv,yv
      for (int i = 1; i <= 13; i++)
      {
        ballarray[i, 1] = +r.next(10) + 1; //+1 means i lose zero values
        ballarray[i, 2] = +r.next(10) + 1;
 
        ballarray[i, 3] = +r.next(10) + 1;
        ballarray[i, 4] = +r.next(10) + 1;
      }
      timer1.start();
    }
   
  }
}

transparencykey可以让窗体的某个颜色透明显示,我们只要把窗体的颜色和transparencykey的颜色设置一致就可以了,这里我设置的是粉红,注意最好设置的颜色是窗体所没有的,否则一旦匹配将会以透明显示!

效果如下:

C#实现打造气泡屏幕保护效果