如何在c#winform中将面板拆分为可点击的部分?

如何在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

我试图用c#模拟LED显示板。我需要一个
控件
,它包含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);
    }