Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何动态创建移动面板_C#_Winforms - Fatal编程技术网

C# 如何动态创建移动面板

C# 如何动态创建移动面板,c#,winforms,C#,Winforms,我目前正在x轴上创建一个移动面板,该面板由我的winform上的一个按钮触发。它工作得很好,但现在我想在每次单击按钮时添加多个面板。问题是,我通过工具箱创建了面板,并将其附加到定时器_tick event上,我相信这只能完成一次,所以我的计划是创建一个动态面板,而定时器不知道这是否是正确的方法 这是我的密码 private void button2_Click(object sender, EventArgs e) { start(); }

我目前正在x轴上创建一个移动面板,该面板由我的
winform
上的一个按钮触发。它工作得很好,但现在我想在每次单击按钮时添加多个面板。问题是,我通过工具箱创建了面板,并将其附加到
定时器_tick event
上,我相信这只能完成一次,所以我的计划是创建一个动态面板,而定时器不知道这是否是正确的方法

这是我的密码

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

您可以通过以下代码创建面板:

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

您可以通过以下代码创建面板:

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

根据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

    }
private List_panels=new List()//用于跟踪面板的类级别列表
私有无效按钮2\u单击(对象发送者,事件参数e)
{
//单击按钮时创建新面板
var p=新面板();
p、 尺寸=新尺寸(10,10);
p、 位置=新点(10,DateTime.Now.Second*(this.Height/60));/“随机”Y,这样它们就不会堆积起来
p、 背景色=颜色。绿色;
this.Controls.Add(p);//将面板添加到窗体
_panels.Add(p);//将panel添加到列表中
timer1.Enabled=true;//设置动画
}
私有无效计时器1_刻度(对象发送方,事件参数e)
{
对于(int i=\u panels.Count-1;i>=0;i--)//使用向后的int索引循环,因为我们可能会从列表中删除项。
{//向后工作是最简单的方法,在删除索引时不必修改索引
var p=_panels[i];//对列表中某个面板的临时引用,与按钮中的“var p”无关
p、 左+=25;//移动它
如果(p.Left>this.Width)//屏幕外的面板?
_panels.RemoveAt(i);//然后停止移动它
}
如果(_panels.Count==0)//没有更多要移动的面板?
timer1.Stop();//停止计时器
}

如果您不再使用这些控件,您应该尝试实现一些逻辑,从
this.Controls
集合中删除不可见的面板

根据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

    }
private List_panels=new List()//用于跟踪面板的类级别列表
私有无效按钮2\u单击(对象发送者,事件参数e)
{
//单击按钮时创建新面板
var p=新面板();
p、 尺寸=新尺寸(10,10);
p、 位置=新点(10,DateTime.Now.Second*(this.Height/60));/“随机”Y,这样它们就不会堆积起来
p、 背景色=颜色。绿色;
this.Controls.Add(p);//将面板添加到窗体
_panels.Add(p);//将panel添加到列表中
timer1.Enabled=true;//设置动画
}
私有无效计时器1_刻度(对象发送方,事件参数e)
{
对于(int i=\u panels.Count-1;i>=0;i--)//使用向后的int索引循环,因为我们可能会从列表中删除项。
{//向后工作是最简单的方法,在删除索引时不必修改索引
var p=_panels[i];//对列表中某个面板的临时引用,与按钮中的“var p”无关
p、 左+=25;//移动它
如果(p.Left>this.Width)//屏幕外的面板?
_panels.RemoveAt(i);//然后停止移动它
}
如果(_panels.Count==0)//没有更多要移动的面板?
timer1.Stop();//停止计时器
}

如果您不再使用这些控件,您应该尝试实现一些逻辑,从
this.Controls
集合中删除不可见的面板

这是我写的一个简单的例子,这里我使用一个计时器来处理所有面板,如果你想让它更平滑,使移动增量更小(从25到更低),并增加计时器的滴答频率,你也可以尝试为每个面板单独使用一个计时器,但我认为这太过分了

编辑:如果您想要真正精确的定位和动画,您需要使用更精确的移动和双精度,并使用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; }
    }
}
public分部类MainForm:Form
{
//X方向速度(以像素/秒为单位)
常数int XSpeed=400;
私有列表_panels=新列表();
公共表格(
{
初始化组件();
}
私有void OnButtonStartClick(对象发送者,System.EventArgs e)
{
AnimationPanel newPanel=新建AnimationPanel
{
边界=新矩形(10,10,50,50),
BorderStyle=BorderStyle.FixedSingle,
};
_面板。添加(新建面板);
控件。添加(新建面板);
newPanel.StartBounds=newPanel.Bounds;
newPanel.StartTime=DateTime.Now;
_timer.Enabled=true;
}
私有void OnTimerTick(对象发送方,System.EventArgs e)
{
对于(int i=\u panels.Count-1;i>=0;i--)
{
动画面板currentPanel=_面板[i];
DateTime startTime=currentPanel.startTime;
int xDelta=(int)Math.Round((DateTime.Now-startTime.TotalSeconds*XSpeed,0);
Point newLocation=新点(currentPanel.StartBounds.X+xDelta,currentPanel.StartBounds.Y);
//在碰撞之前或之后进行检查(在本例中,在替换AnimationPanel之前)