I have dynamically genereted group box with label inside
int dlugoscChuja = 0;
string przedmiot = "";//random strings
for (int i = 0; i < 5; i++)
{
GroupBox g = new GroupBox();
g.AutoSize = true;
g.Visible = true;
g.AutoSizeMode = AutoSizeMode.GrowAndShrink;
var lb = new Label();
lb.AutoSize = true;
lb.Location = new Point(6, 16);
lb.Text = przedmiot;
g.Controls.Add(lb);
dlugoscChuja += lb.Width;
if (i != 0)
{
g.Location = new Point((i*(g.Width+g.Padding.Size.Width)-100), 12);
}
else
{
g.Location = new Point(0, 12);
}
this.Controls.Add(g);
}
how i can put those group boxes next to each other?
my kod (i*(g.Width+g.Padding.Size.Width)-100) of course does not work, is there eany proffesional way to place them? If my labels text is longer of course my group box have more width
You can use Flowlayoutpanel inside your groupbox
We can set the direction of items in Flowlayoutpanel to
TopDown
LeftToRight
RightToLeft
BottomUp
Instead of adding labels to groupBox add it to FlowLayoutpanel
//groupbox must outsideloops
GroupBox g = new GroupBox();
g.AutoSize = true;
g.Visible = true;
g.AutoSizeMode = AutoSizeMode.GrowAndShrink;
var flowPanel;
for (int i = 0; i < 5; i++)
{
flowPanel = new FlowLayoutPanel();
flowPanel.Size = g.Size; // set size of flowpanel to groupbox
flowPanel.Dock = DockStyle.Fill; // Fill parent size
flowPanel.FlowDirection = FlowDirection.TopDown;//Use above directions
var lb = new Label();
lb.AutoSize = true;
lb.Location = new Point(6, 16);
lb.Text = przedmiot;
flowPanel.Controls.Add(lb);//lb your labe
}
g.Controls.Add(flowPanel);//finally add flowpanel to groupbox
this.Controls.Add(g);
I have a WinForms application that has a TableLayoutPanel; this is the definition code:
tableLayoutPanel1 = new TableLayoutPanel();
tableLayoutPanel1.Dock = DockStyle.Fill;
tableLayoutPanel1.AutoScroll = true;
tableLayoutPanel1.RowCount = users.Count + 1;
tableLayoutPanel1.ColumnCount = 1;
tableLayoutPanel1.GrowStyle = TableLayoutPanelGrowStyle.FixedSize;
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
foreach (String user in users)
{
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 600F));
}
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 600F));
int index = 0;
foreach (String user in users)
{
AddDockedControl(index, user);
index++;
}
AddDockedControl(index, null);
panel1.Controls.Add(tableLayoutPanel1);
private void AddDockedControl(int row, String userName)
{
AccountRowUC newUser = new AccountRowUC(this, userName, row);
newUser.BorderStyle = BorderStyle.FixedSingle;
newUser.Dock = DockStyle.Top;
tableLayoutPanel1.Controls.Add(newUser, 0, row);
}
Now, when I want to remove one of the rows, I'm using this code:
public void RemoveRowAtIndex(int index)
{
if (index >= tableLayoutPanel1.RowCount)
return;
// delete all controls of row that we want to delete
for (int i = 0; i < tableLayoutPanel1.ColumnCount; i++)
{
var control = tableLayoutPanel1.GetControlFromPosition(i, index);
tableLayoutPanel1.Controls.Remove(control);
}
// move up row controls that comes after row we want to remove
for (int i = index + 1; i < tableLayoutPanel1.RowCount; i++)
{
for (int j = 0; j < tableLayoutPanel1.ColumnCount; j++)
{
var control = tableLayoutPanel1.GetControlFromPosition(j, i);
if (control != null)
tableLayoutPanel1.SetRow(control, i - 1);
}
}
// remove last row
tableLayoutPanel1.RowStyles.RemoveAt(tableLayoutPanel1.RowCount - 1);
//tableLayoutPanel1.RowStyles.RemoveAt(index);
tableLayoutPanel1.RowCount--;
}
The problem is that when I remove a Row, a big space is left at the bottom of the table: the TableLayoutPanel won't reclaim the size of panel1.
A solution base on the layout described in the comments and this answer, previously posted:
Center multiple rows of controls in a FlowLayoutPanel
Description:
(Full code of a test Form provided at bottom of this post)
Create a new Form (here, named frmTLPTest1)
Add two Panels. One is used to host some buttons, the other one will be the Container of a TableLayoutPanel.
Set the Container panel to AutoScroll = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, set all the Anchors (Left, Top, Right, Bottom)
Inside the Container panel, drop a new TableLayoutPanel: set it to AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, Dock = DockStyle.Top
Remove all Rows and Columns from the TableLayoutPanel except one of each (you cannot remove all). Set the dimensions of both to AutoSize.
Important note (also reported in the linked answer):
In the Form constructor, one of the RowStyles is removed. This is
important: the TLP will keep 2 RowStyles. One is applied to the
existing Row; the second style will be applied to the first Row you
add: to the first one only, not the others. If this style is not
removed, it will compromise the layout.
The core methods used to Add Rows to/Remove Rows from the TableLayoutPanel, make use of a FlowLayoutPanel as the TLP Row content and can also be used as Container of other controls, eventually.
TlpAddRow(TableLayoutPanel tlp, bool addRowCount) method:
Adds a new FlowLayoutPanel to the Cell of the TableLayoutPanel specified and adds a new Row if requested.
Since the Designer won't allow to remove all the Rows, the First Row (FlowLayoutPanel) must not increment the Rows count: the addRowCount argument will be set to false.
private Control TlpAddRow(TableLayoutPanel tlp, bool addRowCount)
{
var flp = new FlowLayoutPanel() {
Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
};
tlp.SuspendLayout();
if (addRowCount) tlp.RowCount += 1;
tlp.Controls.Add(flp, 0, tlp.RowCount - 1);
tlp.ResumeLayout(true);
return flp;
}
TLPRemoveRow(TableLayoutPanel tlp, Control control) method (overloaded):
Allows to remove a Row from the specified TableLayoutPanel. The Row to be removed can be derived from the Control that is used as the Row Container (a FlowLayoutPanel, here, but it could be a Panel, another TableLayoutPanel, or some other type of Container control).
The Row can also be removed by directly specifying the Row index.
private void TLPRemoveRow(TableLayoutPanel tlp, Control control)
{
int ctlRow = tlp.GetRow(control);
TLPRemoveRow(tlp, ctlRow);
}
private void TLPRemoveRow(TableLayoutPanel tlp, int row)
{
if (row < tlp.RowCount - 1) {
for (int i = row; i < tlp.RowCount - 1; i++) {
tlp.SetRow(tlp.GetControlFromPosition(0, i + 1), i);
}
}
tlp.RowCount -= 1;
}
Visual results of this Layout:
Since it's easier to understand how it work by testing rather than explaining, here's the full layout of the Form:
Test Form (frmTLPTest1):
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public partial class frmTLPTest1 : Form
{
public frmTLPTest1()
{
InitializeComponent();
tlp1.RowStyles.RemoveAt(1);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
TlpAddRow(tlp1, false);
}
Random rnd = new Random();
Size[] sizes = new Size[] { new Size(75, 75), new Size(100, 100), new Size(125, 125)};
Color[] colors = new Color[] { Color.Red, Color.LightGreen, Color.YellowGreen, Color.SteelBlue };
Control selectedObject = null;
Control selectedParent = null;
private void btnAddControl_Click(object sender, EventArgs e)
{
Size size = new Size(125, 125);
if (chkRandom.Checked) size = sizes[rnd.Next(sizes.Length)];
var pBox = new PictureBox() {
Anchor = AnchorStyles.None,
BackColor = colors[rnd.Next(colors.Length)],
MinimumSize = size,
Size = size
};
bool drawborder = false;
pBox.MouseEnter += (s, evt) => { drawborder = true; pBox.Invalidate(); };
pBox.MouseLeave += (s, evt) => { drawborder = false; pBox.Invalidate(); };
pBox.MouseDown += (s, evt) => { selectedParent = pBox.Parent;
selectedObject = pBox; pBox.Invalidate();
};
pBox.Paint += (s, evt) => {
if (drawborder) {
ControlPaint.DrawBorder(evt.Graphics, pBox.ClientRectangle,
Color.White, ButtonBorderStyle.Solid);
}
};
if (tlp1.RowCount == 0) TlpAddRow(tlp1, true);
var ctl = tlp1.GetControlFromPosition(0, tlp1.RowCount - 1);
int overallWith = 0;
if (ctl.Controls?.Count > 0) {
overallWith = ctl.Controls.OfType<Control>().Sum(c => c.Width + c.Margin.Left + c.Margin.Right);
}
overallWith += ctl.Margin.Right + ctl.Margin.Left + pBox.Size.Width + pBox.Margin.Left + pBox.Margin.Right;
if (overallWith >= tlp1.Width) {
ctl = TlpAddRow(tlp1, true);
}
ctl.Controls.Add(pBox);
}
private void btnRemoveRow_Click(object sender, EventArgs e)
{
if (selectedParent is null) return;
if (selectedParent.Controls.Count > 0) {
for (int i = 0; i == selectedParent.Controls.Count - 1; i++) {
selectedParent.Controls[i].Dispose();
}
}
TLPRemoveRow(tlp1, selectedParent);
selectedParent.Dispose();
}
private void btnRemoveControl_Click(object sender, EventArgs e)
{
if (selectedObject is null) return;
Control parent = selectedObject.Parent;
selectedObject.Dispose();
if (parent?.Controls.Count == 0) {
TLPRemoveRow(tlp1, parent);
parent.Dispose();
}
}
private Control TlpAddRow(TableLayoutPanel tlp, bool addRowCount)
{
var flp = new FlowLayoutPanel() {
Anchor = AnchorStyles.Top | AnchorStyles.Bottom,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
};
tlp.SuspendLayout();
if (addRowCount) tlp.RowCount += 1;
tlp.Controls.Add(flp, 0, tlp.RowCount - 1);
tlp.ResumeLayout(true);
return flp;
}
private void TLPRemoveRow(TableLayoutPanel tlp, Control control)
{
int ctlRow = tlp.GetRow(control);
TLPRemoveRow(tlp, ctlRow);
}
private void TLPRemoveRow(TableLayoutPanel tlp, int row)
{
if (row < tlp.RowCount - 1) {
for (int i = row; i < tlp.RowCount - 1; i++) {
tlp.SetRow(tlp.GetControlFromPosition(0, i + 1), i);
}
}
tlp.RowCount -= 1;
}
}
Test Form Designer:
partial class frmTLPTest1
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.panToolbar = new System.Windows.Forms.Panel();
this.btnRemoveRow = new System.Windows.Forms.Button();
this.chkRandom = new System.Windows.Forms.CheckBox();
this.btnRemoveControl = new System.Windows.Forms.Button();
this.btnAddControl = new System.Windows.Forms.Button();
this.panBackground = new System.Windows.Forms.Panel();
this.tlp1 = new System.Windows.Forms.TableLayoutPanel();
this.panToolbar.SuspendLayout();
this.panBackground.SuspendLayout();
this.SuspendLayout();
//
// panToolbar
//
this.panToolbar.BackColor = System.Drawing.Color.DarkOliveGreen;
this.panToolbar.Controls.Add(this.btnRemoveRow);
this.panToolbar.Controls.Add(this.chkRandom);
this.panToolbar.Controls.Add(this.btnRemoveControl);
this.panToolbar.Controls.Add(this.btnAddControl);
this.panToolbar.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panToolbar.Location = new System.Drawing.Point(0, 359);
this.panToolbar.Name = "panToolbar";
this.panToolbar.Size = new System.Drawing.Size(552, 55);
this.panToolbar.TabIndex = 2;
//
// btnRemoveRow
//
this.btnRemoveRow.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
this.btnRemoveRow.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
this.btnRemoveRow.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
this.btnRemoveRow.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnRemoveRow.ForeColor = System.Drawing.Color.White;
this.btnRemoveRow.Location = new System.Drawing.Point(261, 11);
this.btnRemoveRow.Name = "btnRemoveRow";
this.btnRemoveRow.Size = new System.Drawing.Size(119, 34);
this.btnRemoveRow.TabIndex = 4;
this.btnRemoveRow.Text = "Remove Row";
this.btnRemoveRow.UseVisualStyleBackColor = false;
this.btnRemoveRow.Click += new System.EventHandler(this.btnRemoveRow_Click);
//
// chkRandom
//
this.chkRandom.AutoSize = true;
this.chkRandom.ForeColor = System.Drawing.Color.White;
this.chkRandom.Location = new System.Drawing.Point(446, 20);
this.chkRandom.Name = "chkRandom";
this.chkRandom.Size = new System.Drawing.Size(94, 19);
this.chkRandom.TabIndex = 3;
this.chkRandom.Text = "Random Size";
this.chkRandom.UseVisualStyleBackColor = true;
//
// btnRemoveControl
//
this.btnRemoveControl.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
this.btnRemoveControl.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
this.btnRemoveControl.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
this.btnRemoveControl.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnRemoveControl.ForeColor = System.Drawing.Color.White;
this.btnRemoveControl.Location = new System.Drawing.Point(136, 11);
this.btnRemoveControl.Name = "btnRemoveControl";
this.btnRemoveControl.Size = new System.Drawing.Size(119, 34);
this.btnRemoveControl.TabIndex = 2;
this.btnRemoveControl.Text = "Remove Control";
this.btnRemoveControl.UseVisualStyleBackColor = false;
this.btnRemoveControl.Click += new System.EventHandler(this.btnRemoveControl_Click);
//
// btnAddControl
//
this.btnAddControl.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
this.btnAddControl.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
this.btnAddControl.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(64)))), ((int)(((byte)(0)))));
this.btnAddControl.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnAddControl.ForeColor = System.Drawing.Color.White;
this.btnAddControl.Location = new System.Drawing.Point(11, 11);
this.btnAddControl.Name = "btnAddControl";
this.btnAddControl.Size = new System.Drawing.Size(119, 34);
this.btnAddControl.TabIndex = 0;
this.btnAddControl.Text = "Add Control";
this.btnAddControl.UseVisualStyleBackColor = false;
this.btnAddControl.Click += new System.EventHandler(this.btnAddControl_Click);
//
// panBackground
//
this.panBackground.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panBackground.AutoScroll = true;
this.panBackground.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.panBackground.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
this.panBackground.Controls.Add(this.tlp1);
this.panBackground.Location = new System.Drawing.Point(0, 0);
this.panBackground.Name = "panBackground";
this.panBackground.Size = new System.Drawing.Size(552, 360);
this.panBackground.TabIndex = 3;
//
// tlp1
//
this.tlp1.AutoSize = true;
this.tlp1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tlp1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32)))));
this.tlp1.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Single;
this.tlp1.ColumnCount = 1;
this.tlp1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tlp1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlp1.Dock = System.Windows.Forms.DockStyle.Top;
this.tlp1.Location = new System.Drawing.Point(0, 0);
this.tlp1.Name = "tlp1";
this.tlp1.RowCount = 1;
this.tlp1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlp1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 1F));
this.tlp1.Size = new System.Drawing.Size(552, 2);
this.tlp1.TabIndex = 4;
//
// frmTLPTest1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.ClientSize = new System.Drawing.Size(552, 414);
this.Controls.Add(this.panBackground);
this.Controls.Add(this.panToolbar);
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Name = "frmTLPTest1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "frmTLPTest1";
this.Load += new System.EventHandler(this.SOfrmTest1_Load);
this.panToolbar.ResumeLayout(false);
this.panToolbar.PerformLayout();
this.panBackground.ResumeLayout(false);
this.panBackground.PerformLayout();
this.ResumeLayout(false);
}
private System.Windows.Forms.Panel panToolbar;
private System.Windows.Forms.Button btnAddControl;
private System.Windows.Forms.Button btnRemoveControl;
private System.Windows.Forms.CheckBox chkRandom;
private System.Windows.Forms.Panel panBackground;
private System.Windows.Forms.TableLayoutPanel tlp1;
private System.Windows.Forms.Button btnRemoveRow;
}
I'm trying to make a form where the user can add group boxes with other controls inside.
groupboxes and other controls are all created dynamically.
Program image. *the button "Adicionar Pergunta" adds a new group box
Inside the groupbox is a combobox where the user can choose the preset of controls inside the groupbox.
each preset have different controls or controls in different locations of the group box.
my problem is that when the user change the preset of one groupbox all the other combobox stop working.
Here is the my script:
Variables:
int groupboxcount = 2;
RadioButton rb1 = new RadioButton();
RadioButton rb2 = new RadioButton();
TextBox tx1 = new TextBox();
TextBox tx2 = new TextBox();
GroupBox gb;
ComboBox cb;
RadioButton rb_1;
RadioButton rb_2;
RadioButton rb_V;
RadioButton rb_F;
TextBox tx_1;
TextBox tx_2;
Button Click:
{
gb = new GroupBox();
NumericUpDown Nud1 = new NumericUpDown();
cb = new ComboBox();
cb.SelectedIndexChanged += new EventHandler(cb2_selectec_index_changed);
RichTextBox RichTextBox2 = new RichTextBox();
Label labelA1 = new Label();
Label labelA2 = new Label();
Label labelA3 = new Label();
gb.Name = "groupBox" + groupboxcount;
gb.Text = "Pergunta ";
gb.Height = 182;
gb.Width = 520;
gb.Location = new Point(groupBox1.Location.X, gb.Location.Y + gb.Height + 125);
Nud1.Height = 20;
Nud1.Width = 41;
Nud1.Location = new Point(6, 37);
Nud1.Value = groupboxcount;
cb.Items.Add("Enunciado");
cb.Items.Add("Pergunta normal");
cb.Items.Add("Escolha multipla");
cb.Items.Add("Verdadeiro/Falso");
cb.Height = 21;
cb.Width = 121;
cb.Location = new Point(53, 36);
RichTextBox2.Height = 80;
RichTextBox2.Width = 249;
RichTextBox2.Location = new Point(211, 37);
labelA1.Text = "Nº";
labelA2.Text = "Tipo de pergunta";
labelA3.Text = "Pergunta";
labelA1.Location = new Point(6, 19);
labelA2.Location = new Point(59, 19);
labelA3.Location = new Point(208, 19);
labelA1.Width = 20;
this.Controls.Add(gb);
gb.Controls.Add(Nud1);
gb.Controls.Add(cb);
gb.Controls.Add(RichTextBox2);
gb.Controls.Add(labelA1);
gb.Controls.Add(labelA2);
gb.Controls.Add(labelA3);
button1.Location = new Point(button1.Location.X, gb.Location.Y + button1.Height + 200);
groupboxcount++;
}
Combobox cb2 selected index changed:
{
if (cb.SelectedIndex == 0)
{
//Apenas mostra enunciado
}
if (cb.SelectedIndex == 1)
{
//recebe resposta
}
if (cb.SelectedIndex == 2)
{
rb_1 = new RadioButton();
rb_2 = new RadioButton();
tx_1 = new TextBox();
tx_2 = new TextBox();
rb_1.Text = "opção 1";
rb_1.Location = new Point(120, 75);
rb_2.Text = "opção 2";
rb_2.Location = new Point(120, 100);
tx_2.Location = new Point(5, 100);
tx_1.Location = new Point(5, 75);
this.gb.Controls.Add(rb_1);
this.gb.Controls.Add(rb_2);
this.gb.Controls.Add(tx_1);
this.gb.Controls.Add(tx_2);
}
else
{
this.gb.Controls.Remove(rb_1);
this.gb.Controls.Remove(rb_2);
this.gb.Controls.Remove(tx_1);
this.gb.Controls.Remove(tx_2);
}
if (cb.SelectedIndex == 3)
{
rb_V = new RadioButton();
rb_F = new RadioButton();
rb_V.Text = "Verdadeiro";
rb_V.Location = new Point(120, 75);
rb_F.Text = "Falso";
rb_F.Location = new Point(120, 100);
this.gb.Controls.Add(rb_V);
this.gb.Controls.Add(rb_F);
}
else
{
this.gb.Controls.Remove(rb_V);
this.gb.Controls.Remove(rb_F);
}
}
I would appreciate if you could help me.
I have a few tablelayoutpanels in my program in order to lay out different controls in rows. Until recently these were all working correctly, but after a change in server this is no longer the case. A potential cause is a change in screen resolution as I noticed similar problems on other computers running my program.
An example of this problem is shown below
Before the data rows are loaded (from database), the sizing is incorrect. A measurement using the VS designer shows that the size in figure 2 is correct. Interestingly, if I add a blank row to this table then the resizing doesn't happen.
public JobOpMainTable()
{
DoubleBuffered = true;
AutoSize = true;
AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
DoubleBuffered = true;
BackColor = Color.White;
CellBorderStyle = TableLayoutPanelCellBorderStyle.Single;
headers();
}
private void headers()
{
string[] names = { "Operation", "Est Lab Hrs", "Est UM Hrs", "Act Lab Hrs", "Act UM Hrs" };
for (int i = 0; i < names.Length; i++) header(names[i], i);
}
private void header(string name, int col)
{
Panel pan = new Panel();
pan.Width = widths[col];
pan.Height = 25;
pan.BackColor = Color.Black;
pan.Dock = DockStyle.Fill;
pan.Margin = new System.Windows.Forms.Padding(0);
TextBox txt = new TextBox();
txt.Font = new System.Drawing.Font("Microsoft sans serif", 8, FontStyle.Bold);
txt.Text = name;
txt.ReadOnly = true;
txt.BackColor = Color.Black;
txt.ForeColor = Color.White;
txt.Dock = DockStyle.Fill;
txt.BorderStyle = System.Windows.Forms.BorderStyle.None
pan.Controls.Add(txt);
Controls.Add(pan, col, 0);
}
private int newRow()
{
int row = Controls.Count / 5;
for (int i = 0; i <= 4; i++)
{
TextBox txt = new TextBox();
txt.Width = widths[i];
txt.BackColor = Color.White;
txt.BorderStyle = System.Windows.Forms.BorderStyle.None;
txt.ReadOnly = true;
txt.Dock = DockStyle.Fill;
txt.Margin = new Padding(0);
txt.Enter += new EventHandler(enterCell);
txt.Leave += new EventHandler(leaveCell);
Controls.Add(txt, i, row);
}
return row;
}
Above is the code I believe is relevant to the problem. The resizing occurs the first time newRow() is called when loading in data: each new box makes the column wider. Again though, the odd thing is this doesn't occur if I add a row from the constructor
This is my code:
for (int i = 0; i < gBoxes.Length; i++)
{
var LabelID = new Label();
gLabels[i] = LabelID;
LabelID.Font = new System.Drawing.Font("Arial", 7.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
LabelID.Name = "label" + i;
LabelID.Text = gColumns[i];
LabelID.Location = new System.Drawing.Point(12, StartLoc);
this.Controls.Add(LabelID);
iPanel.Controls.Add(LabelID);
var BoxID = new TextBox();
gBoxes[i] = BoxID;
BoxID.Font = new System.Drawing.Font("Arial", 7.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
BoxID.Name = "textbox" + i;
BoxID.Text = gContent[i];
BoxID.Location = new System.Drawing.Point(12, StartLoc);
BoxID.Size = new System.Drawing.Size(240, 19);
this.Controls.Add(BoxID);
iPanel.Controls.Add(BoxID);
StartLoc += 25;
}
Which works fine, however, the labels overlap the boxes. Which would be the best method to place the boxes after the labels, and that the boxes are aligned together.
Result:
Set the Label.AutoSize property to true. (The default value when adding them in the designer is true but the default when adding by code is false.) Also set your TextBox.Location to have a larger x value than your label... you have the starting location of label and textbox at the same x value of 12.
You can also use the AutoSize property to determine how wide the labels are and then place the textboxes accordingly. Add your labels with AutoSize = true. Arrange the text boxes by determining the widest label and resetting the TextBox.Location just to the right of them. Here is an example:
public partial class Form1 : Form
{
public int YPos { get; set; }
List<string> Labels = new List<string>();
List<Label> LabelControls = new List<Label>();
List<TextBox> TextBoxControls = new List<TextBox>();
public Form1()
{
InitializeComponent();
AddRow("medium string", "medium");
AddRow("This is a longer string", "long");
AddRow("l", "little");
Arrange();
}
void AddRow(string label, string value)
{
Labels.Add(label);
var LabelID = new Label();
LabelID.AutoSize = true; // make sure to enable AutoSize
LabelID.Font = new System.Drawing.Font("Arial", 7.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
LabelID.Name = "label" + Labels.Count;
LabelID.Text = label;
LabelID.Location = new System.Drawing.Point(12, YPos);
this.Controls.Add(LabelID);
panel1.Controls.Add(LabelID);
LabelControls.Add(LabelID);
var BoxID = new TextBox();
BoxID.Font = new System.Drawing.Font("Arial", 7.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
BoxID.Name = "textbox" + Labels.Count;
BoxID.Text = value;
BoxID.Location = new System.Drawing.Point(12, YPos);
BoxID.Size = new System.Drawing.Size(240, 19);
this.Controls.Add(BoxID);
panel1.Controls.Add(BoxID);
TextBoxControls.Add(BoxID);
// both controls have the same Y location
// and initially will have the same X location
YPos += 25;
}
void Arrange()
{
// determine the widest label sized by the AutoSize
int maxLabelX = 0;
for (int i = 0; i < Labels.Count; i++)
{
maxLabelX = Math.Max(maxLabelX, LabelControls[i].Location.X + LabelControls[i].Size.Width);
}
// move all the text boxes a little to the right of the widest label
for (int i = 0; i < Labels.Count; i++)
{
TextBoxControls[i].Location = new Point(maxLabelX + 10, TextBoxControls[i].Location.Y);
}
}
}
The above code generates properly placed TextBox controls: