简体   繁体   English

如何动态创建移动面板

[英]How to create a moving panel dynamically

I am currently creating a moving panel in x axis triggered by a button on my winform it work great but now i want to add multiple panels every time the button is click. 我目前正在创建一个由winform上的按钮触发的x轴移动面板, winform很好,但是现在我想每次单击按钮时添加多个面板。 The problem is i created the panel via toolbox and attached it on a timer_tick event and i believe this can be done only once so my plan is to create a dynamic panel and a timer don't know if its the correct approach. 问题是我通过工具箱创建了面板,并将其附加到timer_tick event ,我相信这只能完成一次,所以我的计划是创建一个动态面板,而计时器不知道它的正确方法。

Here is my code 这是我的代码

   private void button2_Click(object sender, EventArgs e)
     {
            start();
     } 

    private void start(){

        timer1.Enabled = true;
    }

    private void timer1_Tick(object sender, EventArgs e )
    {
        panel_1.BackColor = Color.Green;
        int x = panel_1.Location.X;
        int y = panel_1.Location.Y;

        panel_1.Location = new Point(x + 25, y);
        xy_text.Text = x + ","+ y;
        if (x > this.Width)
        {
            timer1.Stop();
        }
    }

As per TaW's suggestion - see comments for commentary: 根据TaW的建议-请参阅评论以获取评论:

    private List<Panel> _panels = new List<Panel>(); //class level list to track the panels


    private void button2_Click(object sender, EventArgs e)
    {
        //create a new panel when the button is clicked
        var p = new Panel();
        p.Size = new Size(10, 10);
        p.Location = new Point(10, DateTime.Now.Second * (this.Height / 60)); //"random" Y so they don't pile up
        p.BackColor = Color.Green;

        this.Controls.Add(p);                           //add panel to form
        _panels.Add(p);                                 //add panel to list

        timer1.Enabled = true;                          //animate
    }


    private void timer1_Tick(object sender, EventArgs e)
    {
        for (int i = _panels.Count - 1; i >= 0; i--)    //use a backwards int indexed loop because we are potentially removing items from the list. 
        {                                               //Working backwards is the easiest way to not have to fiddle the index upon removal

            var p = _panels[i];                         //temp reference to a panel in the list, not related to 'var p' in the button click
            p.Left += 25;                               //move it
            if (p.Left > this.Width)                    //panel that is off screen?
                _panels.RemoveAt(i);                    //stop moving it then
        }

        if (_panels.Count == 0)                         //no more panels to move?
            timer1.Stop();                              //stop the timer

    }

You should look to implement some logic that removes your invisible panels from the this.Controls collection, if you don't have a use for them any more. 如果您已不再使用this.Controls面板,则应该实现一些逻辑,以将其从this.Controls集合中删除。

Here is a quick example I wrote, here I use 1 timer to handle all panels, if you want it smoother, make the movement delta smaller (from 25 to something lower) and increase the tick rate of your timer, you could also try to use a timer for each panel individually, but that would be overkill in my opinion. 这是我写的一个简单示例,在这里我使用1个计时器来处理所有面板,如果您希望它更平滑,使运动增量变小(从25减小到更低)并增加计时器的滴答频率,您也可以尝试在每个面板上单独使用一个计时器,但是在我看来,这太过分了。

Edit: If you wanted really accurate positioning and animation, you need to use more exact movement with doubles, and round to integers for the animation itself, use DateTime.Now to determine the distance travelled in a given time very exact, the timer doesn't determine the distance, it only updates the position: 编辑:如果您想要真正准确的定位和动画,则需要使用更精确的运动(使用双精度),并为动画本身舍入为整数,请使用DateTime。现在非常精确地确定给定时间内的行进距离,计时器不会不能确定距离,它只会更新位置:

public partial class MainForm : Form
{
    // X directional speed in pixels per second
    const int XSpeed = 400;

    private List<AnimationPanel> _panels = new List<AnimationPanel>();

    public MainForm()
    {
        InitializeComponent();
    }

    private void OnButtonStartClick(object sender, System.EventArgs e)
    {
        AnimationPanel newPanel = new AnimationPanel
        {
            Bounds = new Rectangle(10, 10, 50, 50),
            BorderStyle = BorderStyle.FixedSingle,
        };

        _panels.Add(newPanel);
        Controls.Add(newPanel);

        newPanel.StartBounds = newPanel.Bounds;
        newPanel.StartTime = DateTime.Now;

        _timer.Enabled = true;
    }

    private void OnTimerTick(object sender, System.EventArgs e)
    {
        for (int i = _panels.Count - 1; i >= 0; i--)
        {
            AnimationPanel currentPanel = _panels[i];

            DateTime startTime = currentPanel.StartTime;
            int xDelta = (int)Math.Round((DateTime.Now - startTime).TotalSeconds * XSpeed, 0);

            Point newLocation = new Point(currentPanel.StartBounds.X + xDelta, currentPanel.StartBounds.Y);

            // Check before or after collision (in this example before replacing the AnimationPanel)
            if (newLocation.X > this.Width)
            {
                // I chose to remove after it reaches the edge, do whatever you want
                _panels.RemoveAt(i);
                Controls.Remove(currentPanel);
            }
            else
            {
                currentPanel.Location = newLocation;
            }
        }

        if (_panels.Count == 0)
        {
            _timer.Enabled = false;
        }
    }

    private class AnimationPanel : Panel
    {
        public Rectangle StartBounds { get; set; }
        public DateTime StartTime { get; set; }
    }
}

You can create your panel from code like this : 您可以使用以下代码创建面板:

        // init properties 
        var newPanel = new Panel
        {
            Name="Panel1",
            BackColor = Color.Green, 
            Location = new Point(0, 0), // set the starting point
            Width = 100, Height = 100
        };


        Controls.Add(newPanel);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM