如何在c#winform中将面板拆分为可点击的部分?
我试图用c#模拟LED显示板。我需要一个如何在c#winform中将面板拆分为可点击的部分?,c#,winforms,performance,runtime,panel,C#,Winforms,Performance,Runtime,Panel,我试图用c#模拟LED显示板。我需要一个控件,它包含1536个可点击的控件s来模拟LED(96宽16高)。为此,我使用了一个名为pnlContainer的面板,用户将在运行时添加1536个小型定制面板s。这些自定义的面板应在运行时通过单击事件更改其颜色。一切正常。但是,将这个数量的微型面板添加到容器中需要很长时间(大约10秒)。你对解决这个问题有什么建议?任何提示都将不胜感激 这是我的客户面板: public partial class LedPanel : Panel { public
控件
,它包含1536个可点击的控件
s来模拟LED(96宽16高)。为此,我使用了一个名为pnlContainer
的面板
,用户将在运行时添加1536个小型定制面板
s。这些自定义的面板应在运行时通过单击事件更改其颜色。一切正常。但是,将这个数量的微型面板添加到容器中需要很长时间(大约10秒)。你对解决这个问题有什么建议?任何提示都将不胜感激
这是我的客户面板
:
public partial class LedPanel : Panel
{
public LedPanel()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (this.BackColor == Color.Black)
{
this.BackColor = Color.Red;
}
else
{
this.BackColor = Color.Black;
}
}
}
}
这段代码将微小的面板
s添加到pnl容器
:
private void getPixels(Bitmap img2)
{
pnlContainer.Controls.Clear();
for (int i = 0; i < 96; i++)
{
for (int j = 0; j < 16; j++)
{
Custom_Controls.LedPanel led = new Custom_Controls.LedPanel();
led.Name = i.ToString() + j.ToString();
int lWidth = (int)(pnlContainer.Width / 96);
led.Left = i * lWidth;
led.Top = j * lWidth;
led.Width = led.Height = lWidth;
if (img2.GetPixel(i, j).R>numClear.Value)
{
led.BackColor = Color.Red;
}
else
{
led.BackColor = Color.Black;
}
led.BorderStyle = BorderStyle.FixedSingle;
pnlContainer.Controls.Add(led);
}
}
}
private void getPixels(位图img2)
{
pnlContainer.Controls.Clear();
对于(int i=0;i<96;i++)
{
对于(int j=0;j<16;j++)
{
Custom_Controls.LedPanel led=新的Custom_Controls.LedPanel();
led.Name=i.ToString()+j.ToString();
int lWidth=(int)(pnlContainer.Width/96);
led.左=i*L宽度;
led.Top=j*L宽度;
发光二极管宽度=发光二极管高度=发光二极管宽度;
if(img2.GetPixel(i,j).R>numClear.Value)
{
led.BackColor=Color.Red;
}
其他的
{
led.BackColor=Color.Black;
}
led.BorderStyle=BorderStyle.FixedSingle;
pnlContainer.Controls.Add(发光二极管);
}
}
}
是否有更好的方法或更好的控制
来代替面板
我同意@TaW的建议。不要在表单上放置1000+个控件。使用某种数据结构,比如数组来跟踪哪些LED需要点亮,然后在面板的绘制事件中绘制它们
这里有一个例子。在窗体上放置一个面板,并将其命名为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();
}
}
公共部分类表单1:表单
{
//适当设置这些变量
int矩阵宽度=96;
int-matrixHeight=16;
//用于容纳必须点亮的LED的阵列
bool[,]ledMatrix=null;
//用于随机填充LED阵列
随机rnd=新随机();
公共表格1()
{
初始化组件();
LED面板。背景色=颜色。黑色;
ledPanel.Resize+=ledPanel\u Resize;
//通过初始化新阵列来清除阵列
ledMatrix=新布尔[矩阵宽度,矩阵高度];
//强制面板重新喷漆
ledPanel.Invalidate();
}
私有无效LED面板_调整大小(对象发送器,事件参数e)
{
//如果面板调整大小,则重新绘制。
ledPanel.Invalidate();
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
//通过初始化新阵列来清除阵列
ledMatrix=新布尔[矩阵宽度,矩阵高度];
//随机设置250个“LED”;
对于(int i=0;i<250;i++)
{
ledMatrix[rnd.Next(0,矩阵宽度),rnd.Next(0,矩阵高度)]=真;
}
//使面板重新喷漆
ledPanel.Invalidate();
}
私有void LED面板_Paint(对象发送器,PaintEventArgs e)
{
//根据面板宽度计算每个LED的宽度和高度
//和高度,并允许每个LED之间有一条线
int cellWidth=(ledPanel.Width-1)/(matrixWidth+1);
int cellHeight=(ledPanel.Height-1)/(矩阵高度+1);
//在布尔数组中循环并绘制一个填充矩形
//对于每个设置为true的
对于(int i=0;i
我相信这段代码可以有很多改进,但它应该会给我们带来一些好处
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);
}