2 回答
TA贡献1848条经验 获得超2个赞
我同意@TaW 的建议。不要在一个表单上放置 1000 多个控件。使用某种数据结构,如数组来跟踪哪些 LED 需要点亮,然后在面板的 Paint 事件中绘制它们。
这是一个例子。将面板放在窗体上并将其命名为ledPanel。然后使用类似于以下的代码。我只是随机设置布尔数组的值。您需要适当地设置它们以响应单击鼠标。我没有包含该代码,但基本上您需要获取鼠标单击的位置,确定需要设置(或取消设置)哪个数组条目,然后使面板无效,以便它重新绘制自己。
public partial class Form1 : Form
{
//set these variables appropriately
int matrixWidth = 96;
int matrixHeight = 16;
//An array to hold which LEDs must be lit
bool[,] ledMatrix = null;
//Used to randomly populate the LED array
Random rnd = new Random();
public Form1()
{
InitializeComponent();
ledPanel.BackColor = Color.Black;
ledPanel.Resize += LedPanel_Resize;
//clear the array by initializing a new one
ledMatrix = new bool[matrixWidth, matrixHeight];
//Force the panel to repaint itself
ledPanel.Invalidate();
}
private void LedPanel_Resize(object sender, EventArgs e)
{
//If the panel resizes, then repaint.
ledPanel.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
//clear the array by initializing a new one
ledMatrix = new bool[matrixWidth, matrixHeight];
//Randomly set 250 of the 'LEDs';
for (int i = 0; i < 250; i++)
{
ledMatrix[rnd.Next(0, matrixWidth), rnd.Next(0, matrixHeight)] = true;
}
//Make the panel repaint itself
ledPanel.Invalidate();
}
private void ledPanel_Paint(object sender, PaintEventArgs e)
{
//Calculate the width and height of each LED based on the panel width
//and height and allowing for a line between each LED
int cellWidth = (ledPanel.Width - 1) / (matrixWidth + 1);
int cellHeight = (ledPanel.Height - 1) / (matrixHeight + 1);
//Loop through the boolean array and draw a filled rectangle
//for each one that is set to true
for (int i = 0; i < matrixWidth; i++)
{
for (int j = 0; j < matrixHeight; j++)
{
if (ledMatrix != null)
{
//I created a custom brush here for the 'off' LEDs because none
//of the built in colors were dark enough for me. I created it
//in a using block because custom brushes need to be disposed.
using (var b = new SolidBrush(Color.FromArgb(64, 0, 0)))
{
//Determine which brush to use depending on if the LED is lit
Brush ledBrush = ledMatrix[i, j] ? Brushes.Red : b;
//Calculate the top left corner of the rectangle to draw
var x = (i * (cellWidth + 1)) + 1;
var y = (j * (cellHeight + 1) + 1);
//Draw a filled rectangle
e.Graphics.FillRectangle(ledBrush, x, y, cellWidth, cellHeight);
}
}
}
}
}
private void ledPanel_MouseUp(object sender, MouseEventArgs e)
{
//Get the cell width and height
int cellWidth = (ledPanel.Width - 1) / (matrixWidth + 1);
int cellHeight = (ledPanel.Height - 1) / (matrixHeight + 1);
//Calculate which LED needs to be turned on or off
int x = e.Location.X / (cellWidth + 1);
int y = e.Location.Y / (cellHeight + 1);
//Toggle that LED. If it's off, then turn it on and if it's on,
//turn it off
ledMatrix[x, y] = !ledMatrix[x, y];
//Force the panel to update itself.
ledPanel.Invalidate();
}
}
我相信这段代码可以有很多改进,但它应该让你知道如何去做。
TA贡献1817条经验 获得超6个赞
这是一个类似于@Chris 的代码,但将显示逻辑隔离在一个单独的类中。(@Chris 在我编写代码时回答了您的问题 :))))
只需创建一个二维数组来初始化类并将其传递给 Initialize 方法。
public class LedDisplayer
{
public LedDisplayer(Control control)
{
_control = control;
_control.MouseDown += MouseDown;
_control.Paint += Control_Paint;
// width and height of your tiny boxes
_width = 5;
_height = 5;
// margin between tiny boxes
_margin = 1;
}
private readonly Control _control;
private readonly int _width;
private readonly int _height;
private readonly int _margin;
private bool[,] _values;
// call this method first of all to initialize the Displayer
public void Initialize(bool[,] values)
{
_values = values;
_control.Invalidate();
}
private void MouseDown(object sender, MouseEventArgs e)
{
var firstIndex = e.X / OuterWidth();
var secondIndex = e.Y / OuterHeight();
_values[firstIndex, secondIndex] = !_values[firstIndex, secondIndex];
_control.Invalidate(); // you can use other overloads of Invalidate method for the blink problem
}
private void Control_Paint(object sender, PaintEventArgs e)
{
if (_values == null)
return;
e.Graphics.Clear(_control.BackColor);
for (int i = 0; i < _values.GetLength(0); i++)
for (int j = 0; j < _values.GetLength(1); j++)
Rectangle(i, j).Paint(e.Graphics);
}
private RectangleInfo Rectangle(int firstIndex, int secondIndex)
{
var x = firstIndex * OuterWidth();
var y = secondIndex * OuterHeight();
var rectangle = new Rectangle(x, y, _width, _height);
if (_values[firstIndex, secondIndex])
return new RectangleInfo(rectangle, Brushes.Red);
return new RectangleInfo(rectangle, Brushes.Black);
}
private int OuterWidth()
{
return _width + _margin;
}
private int OuterHeight()
{
return _height + _margin;
}
}
public class RectangleInfo
{
public RectangleInfo(Rectangle rectangle, Brush brush)
{
Rectangle = rectangle;
Brush = brush;
}
public Rectangle Rectangle { get; }
public Brush Brush { get; }
public void Paint(Graphics graphics)
{
graphics.FillRectangle(Brush, Rectangle);
}
}
这是它在表单中的使用方式:
private void button2_Click(object sender, EventArgs e)
{
// define the displayer class
var displayer = new LedDisplayer(panel1);
// define the array to initilize the displayer
var display = new bool[,]
{
{true, false, false, true },
{false, true, false, false },
{false, false, true, false },
{true, false, false, false }
};
// and finally
displayer.Initialize(display);
}
- 2 回答
- 0 关注
- 274 浏览
添加回答
举报