LZ關鍵問題是沒有註意到圖形在某位“位置”繪制後,如果該位置發生的移動,或其他圖形遮擋了後會出現什麽,如下圖:
用其他什麽東西,例如QQ遮擋 了壹下原圖形就沒有了...因為在此之後沒有人重新繪制了該圖形,基於類似原因,即便妳使用了Scoll,也無法看到後面的圖形
妳的程序我改造了壹下,可以根據需求繪制圖形,去掉Panel自帶的HorizontalScroll,新增了壹個hScrollBar(HorizontalScroll沒有嘗試成功,所以替換了,LZ可以多嘗試下)
?private?struct?ImageContainerType{
public?Rectangle?theImage;?//?圖形容器--矩形
public?SolidBrush?theBrush;//?繪制該圖形所用的畫筆
};
//?繪制的圖形的"容器"--這裏用來存放繪制的矩形
List<ImageContainerType>?imageList;
//?用於控制繪圖位置的全局變量
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<ImageContainerType>(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("繪制完成");
}
///?<summary>
///?實際的圖形繪制方法
///?</summary>
///?<param?name="start">所需繪制圖形的起始編號</param>
///?<param?name="end">所需繪制圖形的結束編號,如果end在start則繪制所有剩下圖形</param>
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);
}
}
///?<summary>
///?在Scroll實際中重繪Panel內容
///?</summary>
///?<param?name="sender"></param>
///?<param?name="e"></param>
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事件中的繪圖方法就可以達到所需要的效果了
///?<summary>///?在Scroll實際中重繪Panel內容
///?</summary>
///?<param?name="sender"></param>
///?<param?name="e"></param>
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);