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