效果图
using System;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Test.QiPao
{
public partial class FrmBubble : Form
{
///
/// 当前气泡数量
///
public static int BubbleCount = 1;
private string _name1 = "姓名1", _name2 = "姓名2";
private readonly Random _random = new Random();
///
/// 气泡移动时间间隔,单位:毫秒
///
private int _nInterval = 10;
///
/// 气泡每次移动的距离
///
private float _step = 5;
///
/// 气泡的直径
///
private int _size = 300;
///
/// 气泡移动的直线方程k,b值
///
private float _dK = -1, _dB = 3;
///
/// 气泡上次位置
///
private PointF _lastPoint;
///
/// 气泡(左上角)活动的范围
///
private int _dScreenWidth, _dScreenHeight;
///
/// 气泡移动的方向
///
private E_LF _eLf = E_LF.RIGHT;
///
/// 现场运行状态
///
private bool _isRunning = true;
private Label _lblBubbleText;
///
/// 气泡碰撞
///
public FrmBubble()
{
if (BubbleCount > 10) return;
InitializeComponent();
this.ContextMenuStrip = Bubble.GetBubbleContextMenuStrip(() => { Bubble.RefreshForm(this, () => new FrmBubble().Show()); });
this.FormClosing += (sender, args) => _isRunning = false;
Init();
}
private void Init()
{
var maxSize = Math.Min(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
_size = Math.Max(120, Math.Min(_size, maxSize));
_lblBubbleText = Bubble.GetLabel(_size);
this.Controls.Add(_lblBubbleText);
SetBubbleStyle();
this.Region = new Region(Bubble.CreateHeartPath(this, _size));
_dScreenWidth = Screen.PrimaryScreen.Bounds.Width - this.Width;
_dScreenHeight = Screen.PrimaryScreen.Bounds.Height - this.Height;
_dK = BubbleCount++ % 2 == 0 ? -1 : 1;
_dB = _random.Next(0, _dScreenHeight);
if (_dB > _dScreenHeight) _dB = 1;
_lastPoint = new PointF(_dK < 0 ? 0 : _dScreenWidth, _dB);
new Task(BubbleMoveThread).Start();
}
private void BubbleMoveThread()
{
while (_isRunning)
{
try
{
Thread.Sleep(_nInterval);
UpdataLocation(out float x, out float y);
_lastPoint.X = x;
_lastPoint.Y = y;
Bubble.RefreshForm(this, () =>
{
this.Left = (int)_lastPoint.X;
this.Top = (int)_lastPoint.Y;
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
private void SetBubbleStyle()
{
Bubble.RefreshForm(this, () =>
{
try
{
var index = _random.Next(0, Bubble.BubbleColor.Length);
this.BackColor = Bubble.BubbleColor[index];
_lblBubbleText.Text = _dK > 0 ? _name1 : _name2;
_lblBubbleText.ForeColor = Bubble.GetInverseColor(Bubble.BubbleColor[index]);
}
catch
{
}
});
}
private void UpdataKB()
{
SetBubbleStyle();
_dK *= -1;
_dB = _lastPoint.Y - _dK * _lastPoint.X;
}
private void UpdataLocation(out float x, out float y)
{
x = _lastPoint.X + (_eLf == E_LF.RIGHT ? _step : -_step);
if (x > _dScreenWidth)
{
UpdataKB();
_eLf = E_LF.LEFT;
}
if (x < 0)
{
UpdataKB();
_eLf = E_LF.RIGHT;
}
x = _lastPoint.X + (_eLf == E_LF.RIGHT ? _step : -_step);
y = GetY(x);
if (y < 0 || y > _dScreenHeight)
{
UpdataKB();
UpdataLocation(out x, out y);
}
}
private float GetY(float x) => _dK * x + _dB;
public enum E_LF { LEFT, RIGHT }
}
}
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Test.QiPao
{
public class Bubble
{
///
/// 存储气泡颜色集合
///
public static Color[] BubbleColor;
static Bubble()
{
BubbleColor = GetCommonColors();
}
///
/// 设置气泡窗体的基本属性
///
///
private static void SetFormStyle(Form form, float size)
{
form.ShowInTaskbar = false;
form.FormBorderStyle = FormBorderStyle.None; //先把窗体设置为无边框的样式
form.TopMost = true;
form.Opacity = 0.7; //设置窗体的不透明度为0.7相反就是窗体的透明度为0.3
form.Size = new Size((int)size, (int)size);
}
///
/// 获取圆形
///
public static GraphicsPath CreateCirclePath(Form form, float size)
{
SetFormStyle(form, size);
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, size, size);
return path;
}
///
/// 获取心形
///
public static GraphicsPath CreateHeartPath(Form form, float size)
{
SetFormStyle(form, size);
GraphicsPath path = new GraphicsPath();
float width = size;
float height = size - size / 8;
// 定义心形的参数方程
float t;
for (t = 0; t <= 2 * Math.PI; t += 0.01f)
{
float x = 16 * (float)Math.Pow(Math.Sin(t), 3);
float y = -(13 * (float)Math.Cos(t) - 5 * (float)Math.Cos(2 * t) - 2 * (float)Math.Cos(3 * t) - (float)Math.Cos(4 * t));
// 将参数方程的坐标转换为窗体的坐标
x = x * width / 32 + width / 2;
y = y * height / 26 + height / 2;
if (t == 0)
{
path.StartFigure();
}
else
{
path.AddLine(new PointF(x, y), new PointF(x, y));
}
}
path.CloseFigure();
return path;
}
///
/// 气泡标签
///
///
///
public static Label GetLabel(float formSize)
{
Label lbl = new Label
{
Dock = DockStyle.Fill,
Font = new Font("华文楷体", formSize / 10, FontStyle.Regular, GraphicsUnit.Point, 134),
Location = new Point(0, 0),
TabIndex = 0,
TextAlign = ContentAlignment.MiddleCenter
};
return lbl;
}
///
/// 获取颜色的互补色
///
public static Color GetInverseColor(Color color)
{
int red = 255 - color.R;
int green = 255 - color.G;
int blue = 255 - color.B;
return Color.FromArgb(red, green, blue);
}
///
/// 获取常见颜色
///
public static Color[] GetCommonColors()
{
var colors = new List<Color>();
var properties = typeof(Color).GetProperties(BindingFlags.Public | BindingFlags.Static);
for (var index = 0; index < properties.Length; index++)
{
var property = properties[index];
if (property.PropertyType == typeof(Color))
{
Color color = (Color)property.GetValue(null);
colors.Add(color);
}
}
return colors.ToArray();
}
public static ContextMenuStrip GetBubbleContextMenuStrip(Action callback)
{
var contextMenuStrip = new ContextMenuStrip();
//var comboBox = new ToolStripComboBox();
//comboBox.DropDownStyle = ComboBoxStyle.Simple;
//for (int i = 1; i < 11; i++)
//{
// comboBox.Items.Add(i.ToString());
//}
//comboBox.SelectedIndex = 0;
//contextMenuStrip.Items.Add(comboBox);
var menuAddBubble = new ToolStripMenuItem { Text = "添加气泡" };
menuAddBubble.Click += (sender, args) =>
{
//int.TryParse(comboBox.Text, out var count);
int count = 3;
new Task(() =>
{
for (int i = 0; i < count; i++)
{
Thread.Sleep(1000);
callback?.Invoke();
}
}).Start();
};
contextMenuStrip.Items.Add(menuAddBubble);
return contextMenuStrip;
}
public static void RefreshForm(Form form, Action eventRefresh)
{
if (form.InvokeRequired)
{
form.Invoke(new EventHandler(delegate { RefreshForm(form, eventRefresh); }));
}
else
{
eventRefresh?.Invoke();
}
}
}
}