为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
ABOUTYOU 2021-12-05 17:03:58
我正在尝试用 c# 模拟 LED 显示板。我需要一个control包含 1536 个可点击的controls 来模拟 LED(宽度为 96,高度为 16)。我为此使用了一个panel命名pnlContainer,用户将panel在运行时添加 1536 个微小的自定义s。这些自定义的panels 应该在运行时通过单击事件更改它们的颜色。一切正常。但是将这个数量的 tiny panels添加到容器需要很长时间(大约 10 秒)。你有什么建议来解决这个问题?任何提示表示赞赏。这是我的客户panel: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;            }        }    }}这是一段代码,它添加了小panels 到pnlContainer: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);            }        }    }
查看完整描述

2 回答

?
慕尼黑5688855

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();

    }

}

我相信这段代码可以有很多改进,但它应该让你知道如何去做。


查看完整回答
反对 回复 2021-12-05
?
慕的地6264312

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);

    }


查看完整回答
反对 回复 2021-12-05
  • 2 回答
  • 0 关注
  • 237 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信