My goal is to have a grid of buttons which represent my 2d array using a TableLayoutPanel.
Currently I can get the correct amount of columns and rows and it adds the buttons in the right place.
The problem I am having is the scaling of the buttons. I've already tried other solutions but they don't seem to work.
Filling the table
int[,] testArr = new int[,] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 16 } };
tableLayoutPanel_TopView.ColumnCount = testArr.GetLength(0);
tableLayoutPanel_TopView.RowCount = testArr.GetLength(1);
tableLayoutPanel_TopView.AutoSize = true;
for (int y = 0; y < testArr.GetLength(1); y++)
{
for (int x = 0; x < testArr.GetLength(0); x++)
{
Button btn = new Button
{
Text = x.ToString() + "." + y.ToString(),
Dock = DockStyle.Fill,
};
tableLayoutPanel_TopView.Controls.Add(btn);
}
}
Single percHeight = ((Single)1 / (Single)tableLayoutPanel_TopView.RowStyles.Count) * 100;
Single percWidth = ((Single)1 / (Single)tableLayoutPanel_TopView.ColumnStyles.Count) * 100;
foreach (ColumnStyle style in tableLayoutPanel_TopView.ColumnStyles)
{
style.SizeType = SizeType.Percent;
style.Width = percWidth;
}
foreach (RowStyle style in tableLayoutPanel_TopView.RowStyles)
{
style.SizeType = SizeType.Percent;
style.Height = percHeight;
}
TableLayoutPanel settings
this.tableLayoutPanel_TopView.ColumnCount = 1;
this.tableLayoutPanel_TopView.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel_TopView.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel_TopView.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel_TopView.Name = "tableLayoutPanel_TopView";
this.tableLayoutPanel_TopView.RowCount = 1;
this.tableLayoutPanel_TopView.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel_TopView.Size = new System.Drawing.Size(638, 463);
this.tableLayoutPanel_TopView.TabIndex = 0;
However, this gives the following result:
Current table
As you can see, the width and the height of each button only seems to make sense starting from the second column and second row. What can I do so that each button has the same size?
Solution
I've fixed it by clearing both the ColumnStyles and RowStyles and adding a new style for each row and column. Each style has it's SizeType set to Percent and the width/height is calculated.
Code
I have replaced testArr with sortedContainers, a collection the function was made for.
// above code hasn't changed
Single percHeight = ((Single)1 / (Single)tableLayoutPanel_TopView.RowStyles.Count) * 100;
Single percWidth = ((Single)1 / (Single)tableLayoutPanel_TopView.ColumnStyles.Count) * 100;
tableLayoutPanel_TopView.ColumnStyles.Clear();
tableLayoutPanel_TopView.RowStyles.Clear();
for (int x = 0; x < sortedContainers.Width; x++)
{
tableLayoutPanel_TopView.ColumnStyles.Add(new ColumnStyle
{
SizeType = SizeType.Percent,
Width = percWidth
});
}
for (int y = 0; y < sortedContainers.Length; y++)
{
tableLayoutPanel_TopView.RowStyles.Add(new RowStyle
{
SizeType = SizeType.Percent,
Height = percHeight
});
}
Related
I am coding a chart. This is my code:
for (int i = 0; i < 2; i++)
{
Val= new ChartValues<ObservablePoint>(); // added
Val.Clear(); // added
lineSeries = new LineSeries
{
Title = "Graph " + i,
Values = Val,
Stroke = Brushes.Blue,
Fill = Brushes.Transparent,
LineSmoothness = 0,
PointGeometry = null
};
for (int jj = 0; jj < 2; jj++)
{
Val.Add(new ObservablePoint
{
X = jj+i+1,
Y = jj+i+1
});
}
Col.Add(lineSeries);
}
The problem is that in my Col variable (collection) all series are getting the latest values of the loop, which results are lineSeries are the same.
When I use the lineSeries = new LineSeries{}, it should create a new independent object right? Or do I have to erase and create it?
Any help is appreciated.
The issue is that you're reusing the same variable Val to store the actual values. Where is it declared, is it a list? Create a new one each time inside the outer loop and then use it to construct the LineSeries.
for (int i = 0; i < 2; i++)
{
var Val = new ChartValues<ObservablePoint>();
for (int jj = 0; jj < 2; jj++)
{
Val.Add(new ObservablePoint
{
X = jj+i+1,
Y = jj+i+1
});
}
var lineSeries = new LineSeries
{
Title = "Graph " + i,
Values = Val,
Stroke = Brushes.Blue,
Fill = Brushes.Transparent,
LineSmoothness = 0,
PointGeometry = null
};
Col.Add(lineSeries);
}
the problem is in line series, you use the same variable, and you are adding the same variable. It it changing each time, and in the end have the last data
lineSeries = new LineSeries
{
......
};
should be
var lineSeries = new LineSeries
{
......
};
I have table layout panel. Inside each one I create a Panel to insert two different controls in each cell.
I want to fill TableLayoutPanel with all my data, in this case I have 16 should have 16 different cells. So I try:
private void AddRow(IList<DeliveryBreakdownGetViewModel> rModel)
{
tpnlDeliveryBreakdown.RowCount = rModel.Count / 4; //rModel count = 16
tpnlDeliveryBreakdown.ColumnCount = 4;
var row = 0;
var column = 0;
var fullRow = 1;
for (int i = 0; i < rModel.Count; i++)
{
var panel = new Panel();
Labels.Add(rModel[i].DesignGroupName);
var label = new Label
{
AutoSize = true,
Name = "label" + Labels.Count,
Text = rModel[i].DesignGroupName,
Location = new Point(12, YPos)
};
this.Controls.Add(label);
tpnlDeliveryBreakdown.Controls.Add(panel, column, row);
panel.Controls.Add(label);
DeliveryBreakdownLabelsModel.Add(label);
var numericUpDown = new NumericUpDown
{
Name = "numericUpDown" + Labels.Count,
Maximum = decimal.MaxValue,
Minimum = decimal.MinValue,
Value = Decimal.Round(rModel[i].ContractedAmount, 2),
Location = new Point(12, YPos),
Size = new Size(60, 19),
DecimalPlaces = 2,
Tag = rModel[i].DesignGroupId
};
this.Controls.Add(numericUpDown);
panel.Controls.Add(numericUpDown);
DeliveryBreakdownNumericUpDownModel.Add(numericUpDown);
if (fullRow % 4 == 0)
{
row++;
}
fullRow++;
if(column == 4)
{
column = 0;
}
else
{
column++;
}
}
}
But it only show 2 columns and 7 cells:
Why is not showing all cells and it only show 2 columns instead 4. Regards
I want to create an array of 361 labels(i.e., label, label1, label2, etc..) and have them physical positioned and showing up on my Form1.cs [Design].
public Form1()
{
InitializeComponent();
Label[] board = new Label[361];
for (int i = 1; i < 362; i++)
{
board[i] = new Label { Name = "label" + i, Height = 55, Width = 55, MinimumSize = new Size(55, 55), Text = "label " + i };
}
int x = 0;
int y = 0;
foreach (var Label in board)
{
if (x >= 580)
{
x = 0;
y = y + Label.Height + 55;
}
Label.Location = new Point(x, y);
this.Controls.Add(Label);
x += Label.Width;
}
}
I get an error with the text = "label" + 1. Not sure why. Thank you for any help.
Arrays are 0-indexed in C#, your last loop iteration will go over the max index.
Label[] board = new Label[361];
this creates an array of Label with indexes 0 - 360. Simply alter your `for loop to:
for (int i = 0; i < 361; i++)
this will also fix your NullReferenceException, which you were seeing because the first item in the array was never initialized
Change the for loop from
Label[] board = new Label[361];
for (int i = 1; i < 362; i++) {
board[i] = new Label { Name = "label" + i, Height = 55, Width = 55, MinimumSize = new Size(55, 55), Text = "label " + i };
}
To
Label[] board = new Label[361];
for (int i = 0; i < 361; i++) {
board[i] = new Label { Name = "label" + i, Height = 55, Width = 55, MinimumSize = new Size(55, 55), Text = "label " + i };
}
your board array is of size 361, So max would be board[360]
in your for loop i<362.. which means it will try to get value for board[360
I modified the value of int in the loop, is this what you want?
for (int i = 0; i < 361; i++)
{
board[i] = new Label { Name = "label" + i, Height = 55, Width = 55, MinimumSize = new Size(55, 55), Text = "label " + i };
}
int x = 0;
int y = 0;
foreach (var Label in board)
{
if (x >= 580)
{
x = 0;
y = y + Label.Height + 55;
}
Label.Location = new Point(x, y);
this.Controls.Add(Label);
x += Label.Width;
}
I want dynamic allocation datagridview in tablelayout.
For example, I choose number of grids, (2, 4, 9, 16...)
next, create this number of datagridview controls and place them in tablelayout.
Example:
So, how can I allocate dynamically allocate a number of Datagridview using one tablelayout
i created new Form (Form1), added new TableLayoutPanel with name t and added this code for form contructor:
public Form1()
{
InitializeComponent();
int row = 1; // number of rows
int col = 2; // number of columns (change them to see effect)
var grids = new DataGridView[row,col];
// create rows and set their height
t.RowCount = row;
t.RowStyles.Clear();
for (int r = 0; r < row; r++)
{
var style = new RowStyle();
style.SizeType = SizeType.Percent;
style.Height =(float)(1.0/row);
t.RowStyles.Add(style);
}
// create columns and set their width
t.ColumnCount = col;
t.ColumnStyles.Clear();
for (int c = 0; c < col; c++)
{
var style = new ColumnStyle();
style.SizeType = SizeType.Percent;
style.Width = (float)(1.0 / col);
t.ColumnStyles.Add(style);
}
// dynamically add grid in necessary place in layout
for(int r = 0; r<row; r++)
for (int c = 0; c < col; c++)
{
grids[r,c] = new DataGridView()
{
Dock = DockStyle.Fill,
};
t.Controls.Add(grids[r, c], c, r);
}
}
First of all, I'm a rookie in programming and I'm not English, I'm sorry if I had a mistake expressing myself :D
I'm doing a program that represents a booking system bus. I had created 64 buttons at Runtime with an array of buttons, but that isn't the problem.
The problem is to represent each text button corresponding to the number of seats of the bus. Here is my code:
var buttonArray = new Button[64];
for (var i = 1; i <= 4; i++)
{
buttonArray[i] = new Button();
buttonArray[i].Size = new Size(75, 23);
buttonArray[i].Name = "button" + i;
buttonArray[i].Text = "Seat " + i;
buttonArray[i].Location = new Point(-50 + (i*100), 10);
panel1.Controls.Add(buttonArray[i]);
for (var j = 5; j <= 19; j++)
{
buttonArray[j] = new Button();
buttonArray[j].Size = new Size(75, 23);
buttonArray[j].Name = "button" + j;
buttonArray[j].Text = "Seat " + j;
buttonArray[j].Location = new Point(-50 + (i * 100), -105 + (j * 30));
panel1.Controls.Add(buttonArray[j]);
}
}
The result would be 64 buttons represented with 4 columns and 16 rows, for example:
Here's how I would do it: Just loop from zero to 63, and calculate the row and column on the fly. Then you set the button properties and add it to the panel. You can change the size of the seats by adjusting the seatWidth and seatHeight variables. Also note that I added a little extra space between the first two columns and the second two columns, because it looks like that's what you had in your diagram. You can adjust this with the middleRowWidth variable. You can also customize the distance between the seats by adjusting the seatSpacing value:
const int seatSpacing = 4;
const int middleRowWidth = 20;
const int seatWidth = 55;
const int seatHeight = 20;
panel1.Width = 4 * (seatWidth + seatSpacing) + seatSpacing + middleRowWidth;
var buttonSize = new Size(seatWidth, seatHeight);
for (var i = 0; i < 64; i++)
{
// Calculate the location for this seat
int thisRow = i / 4;
int thisColumn = i % 4;
int seatTop = thisRow * (seatHeight + seatSpacing);
int seatLeft = thisColumn * (seatWidth + seatSpacing);
// Add some extra distance down the middle
if (thisColumn >= 2) seatLeft += middleRowWidth;
// Create a new button
var thisButton = new Button
{
Size = buttonSize,
Name = "button" + (i + 1),
Text = "Seat " + (i + 1),
Location = new Point(seatLeft, seatTop),
Visible = true,
};
// Add it to the panel
panel1.Controls.Add(thisButton);
}
Result:
UPDATE
After thinking about how to make this more generic, I thought about how some airplanes have their seats laid out. Some have two seats on each side, some have three, some have two on each side with a column of three down the middle. In order to accommodate different types of layouts, I modified the code slightly. Below code has customizable variables for your layout. The one below is for a 2-3-2 layout, where the numbers are the seat count and - are aisles. It also includes two "exit row" aisles running horizontally:
// Seating Layout
const int numberOfRows = 20;
const int numberOfColumns = 7;
const int numberOfSeats = numberOfRows * numberOfColumns;
var columnsToInsertAisleAfter = new List<int> {1, 4};
var rowsToInsertAisleAfter = new List<int> {6, 12};
// Seat sizing
const int seatWidth = 35;
const int seatHeight = 20;
const int seatSpacing = 4;
const int aisleWidth = 20;
var seatSize = new Size(seatWidth, seatHeight);
// Panel and form layout
panel1.Size = new Size(
numberOfColumns * (seatWidth + seatSpacing) + seatSpacing +
aisleWidth * columnsToInsertAisleAfter.Count,
numberOfRows * (seatHeight + seatSpacing) + seatSpacing +
aisleWidth * rowsToInsertAisleAfter.Count);
this.Size =
new Size(panel1.Size.Width + (panel1.Left * 2),
panel1.Size.Height + (panel1.Top * 2)) +
new Size(this.Width - this.ClientSize.Width,
this.Height - this.ClientSize.Height);
// Add seats to panel
for (var i = 0; i < numberOfSeats; i++)
{
// Calculate the location for this seat
int thisRow = i / numberOfColumns;
int thisColumn = i % numberOfColumns;
int seatTop = thisRow * (seatHeight + seatSpacing);
int seatLeft = thisColumn * (seatWidth + seatSpacing);
// Add some extra distance for aisles
var aislesBeforeThisColumn =
columnsToInsertAisleAfter.Count(col => col < thisColumn);
seatLeft += aislesBeforeThisColumn * aisleWidth;
var aislesBeforeThisRow =
rowsToInsertAisleAfter.Count(row => row < thisRow);
seatTop += aislesBeforeThisRow * aisleWidth;
// Add a new button to the panel
panel1.Controls.Add(new Button
{
Size = seatSize,
Name = "button" + (i + 1),
Text = (i + 1).ToString(),
Location = new Point(seatLeft, seatTop),
Visible = true,
});
}
Large Airplane Layout:
This should do what you want,
Point pt;
int y = 20;
int x = 0;
for (int i = 0; i < 16; i++)
{
x = 20;
for (int j = 1; j <= 4; j++)
{
pt = new Point(x, y);
Button btn = new Button() { Location = pt, Size = new Size(75, 23) };
btn.Name = i.ToString() + j.ToString();
btn.Text = string.Format("{0} {1:D2}", "Seat", i * 4 + j);
panel1.Controls.Add(btn);
x += 90;
}
y += 30;
}