CWinform下动态Draw某一对象

一赫技术 2024-08-11 17:26:35

假想一个需求,有一个库存数据列表,包括库位,数量,需要在winform窗口下绘制这个列表,将每个库位绘制成一个小的长方形,上面写有库位,数量,当数量小于5时显示红色,5到10之间显示黄色,10以上显示绿色。

基本的步骤和代码示例:创建一个新的 WinForms 项目。在窗体中添加一个Panel控件。 将 panel 的 AutoScroll 属性设置为 true,以便在库位数据过多时可以滚动查看。在窗体的代码部分编写绘图逻辑。

using System;namespace WinFormsApp19{ public partial Form1 : Form { private List<InventoryItem> inventoryItems; private System.Timers.Timer timer; public Form1() { InitializeComponent(); InitializeInventoryItems(); // 初始化库存数据 panel1.Paint += new PaintEventHandler(panel1_Paint); // 订阅Paint事件 timer = new System.Timers.Timer(); timer.Interval = 500; timer.Elapsed += Timer_Elapsed; timer.Enabled = false; } private void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e) { Random random = new Random(); int index = random.Next(0, 25); inventoryItems[index].Quantity = random.Next(0, 15); // 仅重绘发生变化的部分 Rectangle rect = GetItemRectangle(index); panel1.Invalidate(rect); } private Rectangle GetItemRectangle(int index) { int xOffset = 10; int yOffset = 10; int width = 120; int height = 80; int padding = 10; int row = index / 3; int col = index % 3; xOffset += col * (width + padding); yOffset += row * (height + padding); return new Rectangle(xOffset, yOffset, width, height); } private void InitializeInventoryItems() { inventoryItems = new List<InventoryItem>(); Random random = new Random(); for (int i = 0; i < 26; i++) // 生成26个库位数据(A-Z) { string location = ((char)(i + 65)).ToString(); int quantity = random.Next(0, 15); inventoryItems.Add(new InventoryItem(location, quantity)); } } private void panel1_Paint(object sender, PaintEventArgs e) { int xOffset = 10; int yOffset = 10; int width = 120; int height = 80; int padding = 10; Graphics g = e.Graphics; foreach (var item in inventoryItems) { // 设置颜色 Color fillColor; if (item.Quantity < 5) fillColor = Color.Red; else if (item.Quantity >= 5 && item.Quantity <= 10) fillColor = Color.Yellow; else fillColor = Color.Green; // 绘制矩形 Rectangle rect = new Rectangle(xOffset, yOffset, width, height); using (SolidBrush brush = new SolidBrush(fillColor)) { g.FillRectangle(brush, rect); } g.DrawRectangle(Pens.Black, rect); // 绘制文本 string text = $"{item.Location}\n{item.Quantity}"; TextRenderer.DrawText(g, text, this.Font, rect, Color.Black, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak); // 更新坐标 yOffset += height + padding; if (yOffset + height > panel1.ClientSize.Height) // 列表超出Panel高度时换列 { yOffset = 10; xOffset += width + padding; } } } public InventoryItem { public string Location { get; set; } public int Quantity { get; set; } public InventoryItem(string location, int quantity) { Location = location; Quantity = quantity; } } private void Form1_Load(object sender, EventArgs e) { panel1.Invalidate(); // 强制重绘 } private void btnStart_Click(object sender, EventArgs e) { timer.Enabled = true; } private void btnStop_Click(object sender, EventArgs e) { timer.Enabled = false; } }}

DoubleBuffered 属性在某些控件(例如 Panel)中并不是直接公开的,但它确实存在于基类 Control 中。我们可以通过创建一个派生类来启用双缓冲。

以下是实现双缓冲的改进代码示例:

创建一个自定义的 BufferedPanel 类,继承自 Panel,并在构造函数中设置双缓冲。使用这个自定义的 BufferedPanel 替代默认的 Panel 控件。创建自定义的 BufferedPanel 类public BufferedPanel: Panel{ public BufferedPanel() { this.DoubleBuffered = true; this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true); this.UpdateStyles(); }}
0 阅读:0

一赫技术

简介:感谢大家的关注