110,500
社区成员
发帖
与我相关
我的任务
分享
public partial class Form1 : Form
{
VScrollBar vScrollBar = new VScrollBar();
List<MyElement> elements = new List<MyElement>();
MyElement SelectedElement = null;
public Form1()
{
// 准备一百万个对象。分配不同的位置,颜色和位置
KnownColor[] colors = Enum.GetValues(typeof(KnownColor)) as KnownColor[];
for (int i = 0; i < 1000*1000; i++)
{
MyElement element = new MyElement()
{
Bound = new Rectangle( (i % 5) * 80, (i / 5) * 80, 50,50),
Color = Color.FromKnownColor( colors[ i % colors.Length ] ),
Name = ((char)('A' + i % 26)).ToString() + i,
};
elements.Add(element);
}
// 添加垂直滚动条,并在滚动时要求更新
this.DoubleBuffered = true;
vScrollBar.Dock = System.Windows.Forms.DockStyle.Right;
vScrollBar.Maximum = elements[elements.Count - 1].Location.Y + 80 - this.ClientRectangle.Height;
vScrollBar.ValueChanged += delegate { this.Invalidate(); };
this.Controls.Add(vScrollBar);
}
private int GetWhereAbout(Point location)
{
// 加速寻找,拿出与当前窗口大概相关的对象起始下标。正规算法可以用四分树等等
int where = location.Y / 80 * 5;
return Math.Max(0, where - 10);
}
protected override void OnPaintBackground(PaintEventArgs e){}
protected override void OnPaint(PaintEventArgs e)
{
// 更新需要重画的地方
e.Graphics.TranslateTransform(0, -vScrollBar.Value);
Rectangle clip = Rectangle.Ceiling(e.Graphics.ClipBounds);
int whereAbout = GetWhereAbout(clip.Location);
for (int i = whereAbout; i < elements.Count && i < whereAbout + 100; i++)
{
if (clip.IntersectsWith(elements[i].Bound))
{
elements[i].DrawTo(e.Graphics);
}
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
// 更新鼠标经过的对象
Point cursor = new Point(e.X, e.Y + this.vScrollBar.Value);
int whereAbout = GetWhereAbout(cursor);
for (int i = whereAbout; i < elements.Count && i < whereAbout + 100; i++)
{
if (elements[i].HoverTest(cursor))
{
this.Invalidate();
return;
}
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
// 更新选定的对象
Point cursor = new Point(e.X, e.Y + this.vScrollBar.Value);
if( this.SelectedElement != null)
{
this.SelectedElement.Selected = false;
this.SelectedElement = null;
}
int whereAbout = GetWhereAbout(cursor);
for (int i = whereAbout; i < elements.Count && i < whereAbout + 100; i++)
{
if (elements[i].Bound.Contains(cursor))
{
this.SelectedElement = elements[i];
this.SelectedElement.Selected = true;
this.Invalidate();
return;
}
}
}
}
public class MyElement
{
public string Name { get; set; }
public Rectangle Bound { get; set; }
public Point Location { get { return this.Bound.Location; } }
public Color Color { get; set; }
public bool Selected { get; set; }
public bool Hovered { get; set; }
public bool HoverTest(Point hit)
{
bool oldValue = this.Hovered;
this.Hovered = this.Bound.Contains(hit);
return this.Hovered != oldValue;
}
public void DrawTo(Graphics g)
{
using (Brush brush = new SolidBrush(this.Hovered ? ControlPaint.LightLight(this.Color) : this.Color))
{
g.FillRectangle(brush, this.Bound);
}
{
g.DrawString(this.Name, SystemFonts.MenuFont, Brushes.Black, this.Bound, MyElement.StringFormat);
}
if (this.Selected)
{
g.DrawRectangle(Pens.Red, this.Bound);
}
}
private static StringFormat stringFormat = null;
private static StringFormat StringFormat
{
get
{
if (stringFormat == null)
{
stringFormat = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center,
Trimming = StringTrimming.EllipsisWord,
};
}
return stringFormat;
}
}
}