C# 如何在Windows窗体中实例化大量按钮?
我正在开发一个剧院预订软件。我使用的是Windows窗体,座位由二维数组表示。我画的按钮如下:C# 如何在Windows窗体中实例化大量按钮?,c#,.net,windows,winforms,C#,.net,Windows,Winforms,我正在开发一个剧院预订软件。我使用的是Windows窗体,座位由二维数组表示。我画的按钮如下: public void DrawSeats() { // pnl_seats is a Panel pnl_seats.Controls.Clear(); // Here I store all Buttons instance, to later add all buttons in one call (AddRange) to the Panel var btns
public void DrawSeats()
{
// pnl_seats is a Panel
pnl_seats.Controls.Clear();
// Here I store all Buttons instance, to later add all buttons in one call (AddRange) to the Panel
var btns = new List<Control>();
// Suspend layout to avoid undesired Redraw/Refresh
this.SuspendLayout();
for (int y = 0; y < _seatZone.VerticalSize; y++)
{
for (int x = 0; x < _seatZone.HorizontalSize; x++)
{
// Check if this seat exists
if (IsException(x, y))
continue;
// Construct the button with desired properties. SeatSize is a common value for every button
var btn = new Button
{
Width = SeatSize,
Height = SeatSize,
Left = (x * SeatSize),
Top = (y * SeatSize),
Text = y + "" + x,
Tag = y + ";" + x, // When the button clicks, the purpose of this is to remember which seat this button is.
Font = new Font(new FontFamily("Microsoft Sans Serif"), 6.5f)
};
// Check if it is already reserved
if (ExistsReservation(x, y))
btn.Enabled = false;
else
btn.Click += btn_seat_Click; // Add click event
btns.Add(btn);
}
}
// As said before, add all buttons in one call
pnl_seats.Controls.AddRange(btns.ToArray());
// Resume the layout
this.ResumeLayout();
}
编辑;有人向我指出,这在Windows窗体中不起作用强> 好吧,你正在按顺序完成它。 如果一次迭代花费1秒,整个过程将花费400*1的时间 也许你应该试着收集你的对象,并“并行”处理它 尝试.Net framework(4及以上版本)“parallel foreach”方法: 编辑:所以,如果你有一个列表按钮名,你可以说
buttonNames.ForEach(x=>CreateButton(x));
而您的CreateButton()方法如下所示:
public void DrawSeats()
{
// pnl_seats is a Panel
pnl_seats.Controls.Clear();
// Here I store all Buttons instance, to later add all buttons in one call (AddRange) to the Panel
var btns = new List<Control>();
// Suspend layout to avoid undesired Redraw/Refresh
this.SuspendLayout();
for (int y = 0; y < _seatZone.VerticalSize; y++)
{
for (int x = 0; x < _seatZone.HorizontalSize; x++)
{
// Check if this seat exists
if (IsException(x, y))
continue;
// Construct the button with desired properties. SeatSize is a common value for every button
var btn = new Button
{
Width = SeatSize,
Height = SeatSize,
Left = (x * SeatSize),
Top = (y * SeatSize),
Text = y + "" + x,
Tag = y + ";" + x, // When the button clicks, the purpose of this is to remember which seat this button is.
Font = new Font(new FontFamily("Microsoft Sans Serif"), 6.5f)
};
// Check if it is already reserved
if (ExistsReservation(x, y))
btn.Enabled = false;
else
btn.Click += btn_seat_Click; // Add click event
btns.Add(btn);
}
}
// As said before, add all buttons in one call
pnl_seats.Controls.AddRange(btns.ToArray());
// Resume the layout
this.ResumeLayout();
}
私有按钮CreateButton(按钮的字符串名称){Button b=new
Button();b.Text=nameOfButton;//做任何你想做的事。。。
返回b;}
不使用实际的按钮控件,只需绘制座椅的图像,然后当用户单击座椅时,平移鼠标X、Y坐标以确定单击了哪个座椅。这样会更有效率。当然,缺点是您必须编写将x,y坐标转换为座椅的方法,但这并不是那么困难 假设您将保留和排除的数组更改为
public List<string> _seatsExceptions = new List<string>();
public List<string> _seatsReservations = new List<string>();
您对排除和预订的检查可以更改为
bool IsException(int x, int y)
{
string key = x.ToString() + ";" + y.ToString();
return _seatsExceptions.Contains(key);
}
bool ExistsReservation(int x, int y)
{
string key = x.ToString() + ";" + y.ToString();
return _seatsReservations.Contains(key);
}
当然,我不知道你是否能在你的程序中做出这样的改变。然而,考虑早晚改变你的数组的搜索。
编辑我做了一些测试,虽然20x20按钮组成的虚拟网格工作正常(平均31毫秒0.775毫秒),但更大的按钮速度明显减慢。在200x50时,计时跳至10秒(平均10675秒)。因此,或许需要一种不同的方法。绑定DataGridView可能是一个更简单的解决方案,并且相对容易处理。我也不会使用如此多的控件来实现这样的事情。相反,您可能应该创建自己的UserControl,它将所有座椅绘制为图像,并对单击事件作出反应 为了让你更容易一点,我创建了这样一个简单的用户控件,它将绘制所有的座位,并在鼠标点击改变状态时做出反应。这是:
public enum SeatState
{
Empty,
Selected,
Full
}
public partial class Seats : UserControl
{
private int _Columns;
private int _Rows;
private List<List<SeatState>> _SeatStates;
public Seats()
{
InitializeComponent();
this.DoubleBuffered = true;
_SeatStates = new List<List<SeatState>>();
_Rows = 40;
_Columns = 40;
ReDimSeatStates();
MouseUp += OnMouseUp;
Paint += OnPaint;
Resize += OnResize;
}
public int Columns
{
get { return _Columns; }
set
{
_Columns = Math.Min(1, value);
ReDimSeatStates();
}
}
public int Rows
{
get { return _Rows; }
set
{
_Rows = Math.Min(1, value);
ReDimSeatStates();
}
}
private Image GetPictureForSeat(int row, int column)
{
var seatState = _SeatStates[row][column];
switch (seatState)
{
case SeatState.Empty:
return Properties.Resources.emptySeat;
case SeatState.Selected:
return Properties.Resources.choosenSeat;
default:
case SeatState.Full:
return Properties.Resources.fullSeat;
}
}
private void OnMouseUp(object sender, MouseEventArgs e)
{
var heightPerSeat = Height / (float)Rows;
var widthPerSeat = Width / (float)Columns;
var row = (int)(e.X / widthPerSeat);
var column = (int)(e.Y / heightPerSeat);
var seatState = _SeatStates[row][column];
switch (seatState)
{
case SeatState.Empty:
_SeatStates[row][column] = SeatState.Selected;
break;
case SeatState.Selected:
_SeatStates[row][column] = SeatState.Empty;
break;
}
Invalidate();
}
private void OnPaint(object sender, PaintEventArgs e)
{
var heightPerSeat = Height / (float)Rows;
var widthPerSeat = Width / (float)Columns;
e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
for (int row = 0; row < Rows; row++)
{
for (int column = 0; column < Columns; column++)
{
var seatImage = GetPictureForSeat(row, column);
e.Graphics.DrawImage(seatImage, row * widthPerSeat, column * heightPerSeat, widthPerSeat, heightPerSeat);
}
}
}
private void OnResize(object sender, System.EventArgs e)
{
Invalidate();
}
private void ReDimSeatStates()
{
while (_SeatStates.Count < Rows)
_SeatStates.Add(new List<SeatState>());
if (_SeatStates.First().Count < Columns)
foreach (var columnList in _SeatStates)
while (columnList.Count < Columns)
columnList.Add(SeatState.Empty);
while (_SeatStates.Count > Rows)
_SeatStates.RemoveAt(_SeatStates.Count - 1);
if (_SeatStates.First().Count > Columns)
foreach (var columnList in _SeatStates)
while (columnList.Count > Columns)
columnList.RemoveAt(columnList.Count - 1);
}
}
公共枚举座位状态
{
空的,,
挑选出来的,
满满的
}
公共部分类席位:UserControl
{
专用int_列;
私有整数行;
私人名单(SeatStates);;
公众席()
{
初始化组件();
this.DoubleBuffered=true;
_SeatStates=新列表();
_行=40;
_列=40;
ReDimSeatStates();
MouseUp+=OnMouseUp;
油漆+=油漆;
Resize+=OnResize;
}
公共int列
{
获取{return\u Columns;}
设置
{
_列=数学最小值(1,值);
ReDimSeatStates();
}
}
公共整数行
{
获取{返回_行;}
设置
{
_行=Math.Min(1,值);
ReDimSeatStates();
}
}
私有图像GetPictureForSeat(int行,int列)
{
var seatState=_SeatStates[行][列];
开关(座椅状态)
{
箱座状态。空:
返回Properties.Resources.emptySeat;
案例座位状态。已选择:
返回Properties.Resources.choosenSeat;
违约:
箱座状态。完整:
返回Properties.Resources.fullSeat;
}
}
MouseUp上的私有void(对象发送器、MouseEventArgs e)
{
var heightPerSeat=高度/(浮动)行;
var widthPerSeat=宽度/(浮动)列;
变量行=(整数)(e.X/T);
变量列=(整数)(e.Y/高度);
var seatState=_SeatStates[行][列];
开关(座椅状态)
{
箱座状态。空:
_SeatStates[行][列]=SeatState.选中;
打破
案例座位状态。已选择:
_SeatStates[行][列]=SeatState.Empty;
打破
}
使无效();
}
私有void OnPaint(对象发送方,PaintEventArgs e)
{
var heightPerSeat=高度/(浮动)行;
var widthPerSeat=宽度/(浮动)列;
e、 Graphics.CompositingQuality=System.Drawing.Drawing2D.CompositingQuality.HighQuality;
e、 Graphics.InterpolationMode=System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
e、 Graphics.PixelOffsetMode=System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
e、 Graphics.SmoothingMode=System.Drawing.Drawing2D.SmoothingMode.HighQuality;
对于(int row=0;row行)
_SeatStates.RemoveAt(_SeatStates.Count-1);
if(_SeatStates.First().Count>列)
foreach(var列列表在_SeatStates中)
while(columnList.Count>列)
columnList.RemoveAt(columnList.Count-1);
}
}
这将当前绘制40行和40列(因此有800个座位),您可以单击每个座位来更改其状态
这是
public enum SeatState
{
Empty,
Selected,
Full
}
public partial class Seats : UserControl
{
private int _Columns;
private int _Rows;
private List<List<SeatState>> _SeatStates;
public Seats()
{
InitializeComponent();
this.DoubleBuffered = true;
_SeatStates = new List<List<SeatState>>();
_Rows = 40;
_Columns = 40;
ReDimSeatStates();
MouseUp += OnMouseUp;
Paint += OnPaint;
Resize += OnResize;
}
public int Columns
{
get { return _Columns; }
set
{
_Columns = Math.Min(1, value);
ReDimSeatStates();
}
}
public int Rows
{
get { return _Rows; }
set
{
_Rows = Math.Min(1, value);
ReDimSeatStates();
}
}
private Image GetPictureForSeat(int row, int column)
{
var seatState = _SeatStates[row][column];
switch (seatState)
{
case SeatState.Empty:
return Properties.Resources.emptySeat;
case SeatState.Selected:
return Properties.Resources.choosenSeat;
default:
case SeatState.Full:
return Properties.Resources.fullSeat;
}
}
private void OnMouseUp(object sender, MouseEventArgs e)
{
var heightPerSeat = Height / (float)Rows;
var widthPerSeat = Width / (float)Columns;
var row = (int)(e.X / widthPerSeat);
var column = (int)(e.Y / heightPerSeat);
var seatState = _SeatStates[row][column];
switch (seatState)
{
case SeatState.Empty:
_SeatStates[row][column] = SeatState.Selected;
break;
case SeatState.Selected:
_SeatStates[row][column] = SeatState.Empty;
break;
}
Invalidate();
}
private void OnPaint(object sender, PaintEventArgs e)
{
var heightPerSeat = Height / (float)Rows;
var widthPerSeat = Width / (float)Columns;
e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
for (int row = 0; row < Rows; row++)
{
for (int column = 0; column < Columns; column++)
{
var seatImage = GetPictureForSeat(row, column);
e.Graphics.DrawImage(seatImage, row * widthPerSeat, column * heightPerSeat, widthPerSeat, heightPerSeat);
}
}
}
private void OnResize(object sender, System.EventArgs e)
{
Invalidate();
}
private void ReDimSeatStates()
{
while (_SeatStates.Count < Rows)
_SeatStates.Add(new List<SeatState>());
if (_SeatStates.First().Count < Columns)
foreach (var columnList in _SeatStates)
while (columnList.Count < Columns)
columnList.Add(SeatState.Empty);
while (_SeatStates.Count > Rows)
_SeatStates.RemoveAt(_SeatStates.Count - 1);
if (_SeatStates.First().Count > Columns)
foreach (var columnList in _SeatStates)
while (columnList.Count > Columns)
columnList.RemoveAt(columnList.Count - 1);
}
}