LZ关键问题是没有注意到图形在某位“位置”绘制后,如果该位置发生的移动,或其他图形遮挡了后会出现什么,如下图:
用其他什么东西,例如QQ遮挡 了一下原图形就没有了...因为在此之后没有人重新绘制了该图形,基于类似原因,即便你使用了Scoll,也无法看到后面的图形
你的程序我改造了一下,可以根据需求绘制图形,去掉Panel自带的HorizontalScroll,新增了一个hScrollBar(HorizontalScroll没有尝试成功,所以替换了,LZ可以多尝试下)
private struct ImageContainerType
{
public Rectangle theImage; // 图形容器--矩形
public SolidBrush theBrush; // 绘制该图形所用的画笔
};
// 绘制的图形的"容器"--这里用来存放绘制的矩形
ListimageList;
// 用于控制绘图位置的全局变量
int indexDraw = 0;
private void button1_Click(object sender, EventArgs e)
{
/*
调整思路
* 方案A:静态绘图
* 1、将所有绘制的图形保存到imageList容器中
* 2、在需要时再执行绘制,例如拖动Scoll时触发
* 缺点:如果绘制的图形较多,将消耗大量内存
* 优点:只需要执行一次图形创建过程,以后随时可以使用,节省CPU或GPU资源
* 且算法简单
*
* 方案B:动态绘图
* 1、先绘制当前所需要的图形(在可见区间内)
* 2、在需要时如Scoll,重新(在可见区间内)绘制所需要的图形
*/
int[] nums = new int[10000];
// 初始化图形容器
imageList = new List(100);
ImageContainerType tempImage;
Random random = new Random(); //随机数值
for (int i = 0; i < 100; i++)
{
nums[i] = random.Next(0, 2);
}
for (int i = 0; i < 100; i++)
{
if (nums[i] == 1)
{
SolidBrush r1 = new SolidBrush(Color.Red);//定义单色画刷
Rectangle rect = new Rectangle(20 * i, 0, 10, 50);
//grap.FillRectangle(r1, rect);//填充这个矩形
// 将当前图形存入容器
tempImage = new ImageContainerType();
tempImage.theBrush = new SolidBrush(Color.Red);
tempImage.theImage = new Rectangle(20 * i, 0, 10, 50);
imageList.Add(tempImage);
}
else
{
SolidBrush b1 = new SolidBrush(Color.Blue);//定义单色画刷
Rectangle rect = new Rectangle(20 * i, 0, 10, 50);
//grap.FillRectangle(b1, rect);//填充这个矩形
tempImage = new ImageContainerType();
tempImage.theBrush = new SolidBrush(Color.Blue);
tempImage.theImage = new Rectangle(20 * i, 0, 10, 50);
imageList.Add(tempImage);
}
}
// [关键]设置Scorll的新值
this.hScrollBar1.Maximum = 100;
// 绘制全部图形
DrawImage(0, imageList.Count - 1);
MessageBox.Show("绘制完成");
}
///
/// 实际的图形绘制方法
///
/// 所需绘制图形的起始编号
/// 所需绘制图形的结束编号,如果end在start则绘制所有剩下图形
void DrawImage(int start, int end)
{
// 1、判定绘图容器是否存在
if (imageList == null || imageList.Count <= 0)
{
MessageBox.Show("还没有生成图形");
return;
}
// 2、绘图区间判定
if (start >= imageList.Count || end >= imageList.Count)
{
MessageBox.Show("不在有效绘图区间");
return;
}
// 3、
if (start <= end)
{
// 绘制从起始位置,到结束位置所有图形
end = imageList.Count - 1;
}
// 4、绘制图形
Graphics grap = pChart.CreateGraphics();
grap.Clear(Color.White);
Pen blue = new Pen(Color.Blue);
Pen red = new Pen(Color.Red);
for(int index=start;index<= end;index++)
{
grap.FillRectangle(imageList[index].theBrush, imageList[index].theImage);
}
}
///
/// 在Scroll实际中重绘Panel内容
///
///
///
private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
// 每次重绘"当前位置"直至结尾的所有图形
DrawImage(e.NewValue, imageList.Count - 1);
}
得到的效果是:
你可以看到,Scoll正确发挥了作用,但貌似图形不正确阿....前面的没有了?
原因在于现有的重绘访法是
// 每次重绘"当前位置"直至结尾的所有图形
DrawImage(e.NewValue, imageList.Count - 1);
而在imageList容器中存放的图形其坐标已经固定了,因此绘制结果也就可以预期了——这距离使用Scoll拖动图形距离不远了:>
其实关键就是图形和界面之间相对位置的处理了——界面是静止的,那么只有让图动起来,看我的改造:
注意上面两个图形的坐标,0-99和9~99,然后看相应的图形。的确界面没动,但图形动了,看起来就像是Panel向右滑动了10个单位一样。修改Scoll事件中的绘图方法就可以达到所需要的效果了
///
/// 在Scroll实际中重绘Panel内容
///
///
///
private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
int theValue = e.NewValue;
int theNewImageX_Index = 0;
// 要想实现“动态效果”的关键是重新计算图形与“静止”的界面
// 之间的相对位置,即“界面不动”图形动(我不动那就麻烦你动一下了:>)
// 这将消耗一定的CPU资源
// --尝试将图形的位置根据当前"位置"进行移动
// --将当前图形设定为"相对于界面"的第一个图形,后面的图形依次+1
for (int index = theValue; index < imageList.Count; index++)
{
ImageContainerType temp = new ImageContainerType();
temp.theImage = new Rectangle(20 * theNewImageX_Index, 0, 10, 50);
temp.theBrush = imageList[index].theBrush;
imageList[index] = temp;
theNewImageX_Index++;
}
// 然后重新绘制图形
DrawImage(theValue, imageList.Count - 1);
}
这里最关键的就是重新计算图形的坐标
new Rectangle(20 * theNewImageX_Index, 0, 10, 50);
private void panel1_Paint(object sender, PaintEventArgs e) { DrawMe(e.Graphics); }private void DrawMe(Graphics g){g.FillRectangle(blueBrush, x, y, width, height);...这里绘制 主意:绘制结束后不要使用 g.Dispone() 因为这个g来自控件绘制本身 不能销毁 }