要实现的效果:鼠标点击winform上任意两点构成直线,点击第一个按钮,出现一个圆沿直线做往返运动,点击第二个按钮,同时出现三条直线,每条直线上有三个圆沿直线做往返运动。这个效果已实现,三个圆之间无闪屏
问题:解决三个圆之间的闪屏
界面:两个button,三个timer
代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace PictureSport
{
public partial class Test_DongYuan : Form
{
public Test_DongYuan()
{
//this.DoubleBuffered = true;
InitializeComponent();
}
public Graphics g;//封装一个gdi+绘图图面
private Bitmap bmp;
public Point p1;//默认第一条线点的起始坐标
public Point p2;//默认第一条线点的结束坐标
public Point p3;
public Point p4;
public Point p5;
public Point p6;
private int n = 0; //运动点离起点的距离
private bool bDirect = true;//true为从起点向终点运行,false从终点向起点运行
Point pt = new Point(0, 0); //当前点
public int i = 1;//记录循环次数
public int m;//总距离
private void Test_DongYuan_Load(object sender, EventArgs e)
{
//1、在内存中建立一块“虚拟画布”
bmp = new Bitmap(this.Width, this.Height);//创建和窗体大小的画布
//2、获取这块内存画布的Graphics引用
g = Graphics.FromImage(bmp); ;//获取画布
timer1.Enabled = false;//一开始不画圆
timer2.Enabled = false;
timer3.Enabled = false;
}
private void Test_DongYuan_MouseClick(object sender, MouseEventArgs e)
{
if (i == 1)
{
p1 = new Point();
p1.X = e.Location.X;
p1.Y = e.Location.Y;
i++;
}
else
{
if (i == 2)
{
p2 = new Point();
p2.X = e.Location.X;
p2.Y = e.Location.Y;
g.DrawLine(Pens.Black, p1, p2);
g.DrawImage(bmp, new Point(0, 0));
this.BackgroundImage = bmp;//位图是虚拟的,所以直线只存在在位图上,只在位图上显示,要想真实显示出来就得以位图填充背景
g.Dispose();
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
button1_Click(sender, e);
}
private void timer2_Tick(object sender, EventArgs e)
{
//第一条直线上的直线
p3.X = p1.X;
p3.Y = p1.Y - 50;
p4.X = p2.X;
p4.Y = p2.Y - 50;
//第一条直线下的直线
p5.X = p1.X;
p5.Y = p1.Y + 50;
p6.X = p2.X;
p6.Y = p2.Y + 50;
bmp = new Bitmap(this.Width, this.Height);//创建和窗体大小的画布
g = Graphics.FromImage(bmp); ;//获取画布
g.DrawLine(Pens.Black, p1, p2);
g.DrawLine(Pens.Black, p3, p4);
g.DrawLine(Pens.Black, p5, p6);
DongYuan(p3, p4);
g.DrawImage(bmp, new Point(0, 0));
this.BackgroundImage = bmp;//位图是虚拟的,所以直线只存在在位图上,只在位图上显示,要想真实显示出来就得以位图填充背景
g.Dispose();
}
private void timer3_Tick(object sender, EventArgs e)
{
//第一条直线上的直线
p3.X = p1.X;
p3.Y = p1.Y - 50;
p4.X = p2.X;
p4.Y = p2.Y - 50;
//第一条直线下的直线
p5.X = p1.X;
p5.Y = p1.Y + 50;
p6.X = p2.X;
p6.Y = p2.Y + 50;
bmp = new Bitmap(this.Width, this.Height);//创建和窗体大小的画布
g = Graphics.FromImage(bmp); ;//获取画布
g.DrawLine(Pens.Black, p1, p2);
g.DrawLine(Pens.Black, p3, p4);
g.DrawLine(Pens.Black, p5, p6);
DongYuan(p5, p6);
g.DrawImage(bmp, new Point(0, 0));
this.BackgroundImage = bmp;//位图是虚拟的,所以直线只存在在位图上,只在位图上显示,要想真实显示出来就得以位图填充背景
g.Dispose();
}
/// <summary>
/// 动圆
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
DongYuan(p1,p2);
timer1.Enabled = true;
}
/// <summary>
/// 动圆方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void DongYuan(Point p_first,Point p_last)
{
//Math.Pow() Pow返回指定数字的指定次幂 pow(X,y)就是计算X的Y次方
m = (int)Math.Pow(Math.Pow((p_last.X - p_first.X), 2) + Math.Pow((p_last.Y - p_first.Y), 2), 0.5);//总距离
if (n == m)//运动点离起点的距离=总距离
bDirect = false;//false从终点向起点运行
if (n == 0)//运动点离起点的距离=0
bDirect = true;//true为从起点向终点运行
if (bDirect)//从起点向终点运行
n++;//运动点离起点的距离不断自加
else
n--;//运动点离起点的距离不断自-
//Pen p11 = new Pen(Color.Black);
Pen p_double = new Pen(Color.Red);
Graphics g = this.CreateGraphics();
if (pt.X != 0 && pt.Y != 0) //清除上次的运动点
{
//减去圆半径
g.DrawEllipse(new Pen(this.BackColor), pt.X - 15, pt.Y - 15, 30, 30); //清除上次的运动点
}
g.DrawLine(Pens.Black,p_first, p_last);//画起点到终点的线
g.DrawImage(bmp, new Point(0, 0));
this.BackgroundImage = bmp;//位图是虚拟的,所以直线只存在在位图上,只在位图上显示,要想真实显示出来就得以位图填充背景
//总距离不为0
if (m != 0)
{
pt.X = ((p_last.X - p_first.X) * n) / m + p_first.X;
pt.Y = ((p_last.Y - p_first.Y)) * n / m + p_first.Y;
g.DrawEllipse(p_double, pt.X - 15, pt.Y - 15, 30, 30); //画运动的点
g.Dispose();//释放资源
}
}
/// <summary>
/// 分批
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
timer2.Enabled = true;
timer3.Enabled = true;
//第一条直线上的直线
p3.X = p1.X;
p3.Y = p1.Y - 50;
p4.X = p2.X;
p4.Y = p2.Y - 50;
//第一条直线下的直线
p5.X = p1.X;
p5.Y = p1.Y + 50;
p6.X = p2.X;
p6.Y = p2.Y + 50;
bmp = new Bitmap(this.Width, this.Height);//创建和窗体大小的画布
g = Graphics.FromImage(bmp); ;//获取画布
g.DrawLine(Pens.Black,p1,p2);
g.DrawLine(Pens.Black, p3, p4);
g.DrawLine(Pens.Black, p5, p6);
g.DrawImage(bmp, new Point(0, 0));
this.BackgroundImage = bmp;//位图是虚拟的,所以直线只存在在位图上,只在位图上显示,要想真实显示出来就得以位图填充背景
button1_Click(sender, e);
}
}
}
留个邮箱或QQ,我把代码发你?
邮箱:2220552727@qq.com
@随风起舞: 发你邮件了,没做往返功能,只是为了演示不闪烁。
@Firen: 已经收到了案例,完美解决问题了。
我现在有点怕用gdi+做动画了,你还是用wpf做吧,保证不闪
不会用wpf
@随风起舞: 事实上,用gdi+画这个根本没压力,是你方法没用对
@上帝之城: 如果你会的话,求教
@随风起舞: 用gdi+,就要学习局部绘图技术,你每次都完整的绘制了一帧,不卡才怪。
@上帝之城: 那应该怎么修改代码?
你需要使用双缓冲,才能解决闪屏问题
双缓冲用过了好几种,都没有效果
@随风起舞: 你的代码里确实用到了双缓冲,要不你把整个项目发给我,有空我帮你调调?
@刘宏玺: 好的
@刘宏玺: 我发份压缩包到你的邮箱吧,有空麻烦帮我看一下