I have a for loop which I'm attempting to use to generate and lay out the contents of a Form.
This is what I've gotten to so far:
public void RefreshSkillDialog()
{
Point nPt = new Point(25, 25);
for (int x = 0; x < Enum.GetNames(typeof(Character.Skill)).Length; x++ )
{
GenerateFields(x,nPt);
Console.Write(this.Controls.Count + "\n");
Console.WriteLine(this.Controls[x].ToString() + "\n");
}
}
public void GenerateFields(int it, Point pt)
{
Label tLbl = new Label();
tLbl.Location = new Point(pt.X + (it * _vSpace), pt.Y);
tLbl.Name = Enum.GetName(typeof(Character.Skill), it);
tLbl.Text = this.Controls.Count.ToString();
this.Controls.Add(tLbl);
}
_vSpace is an integer initialized to 10 in the constructor.
The result of this code is:
I thought the issue was in reusing the tLbl variable, but as far as I can tell, it should work fine since I'm re-initializing it at the beginning of every iteration.
When you create a new Label, it is 100px wide by default.
You're changing the location (x-coordinate) of each new Label, but not by enough. Each new Label is overlapping the previous one, such that's it's covering up the text.
You can fix this by setting AutoSize = true on each Label:
Label tLbl = new Label();
tLbl.AutoSize = true;
...
Or by resizing it so that it's not as wide:
Label tLbl = new Label();
tLbl.Size = new Size(10, 23);
...
You might also consider just using a FlowLayoutPanel, since it will handle the layout for you. Add each new control to it, and don't bother with setting a Location.
Label tLbl = new Label();
tLbl.Name = Enum.GetName(typeof(Character.Skill), it);
tLbl.Text = flowLayoutPanel1.Controls.Count.ToString();
flowLayoutPanel1.Controls.Add(tLbl);
If you do that, you'll have to change your Console.WriteLine statement in the other method too:
Console.WriteLine(flowLayoutPanel1.Controls[x].ToString() + "\n");
Related
I use this code to add some labels to a windows form in c#:
Label[] lbl = new Label[temp+1];
for (int i = 0; i <= temp; i++) {
lbl[i] = new Label();
lbl[i].Text = "" + i;
lbl[i].Location = new Point(30 + (i * unit), 380);
lbl[i].Visible = true;
this.Controls.Add(lbl[i]);
}
There is not a serious problem but my code works for temps less than 5 and for temps greater than 5 it shows only the first one.
What you think? where is the problem?
Make the labels automatically adjust their size to their content by setting their AutoSize property to true:
lbl[i] = new Label();
lbl[i].Text = "" + i;
lbl[i].Location = new Point(30 + (i * unit), 380);
lbl[i].Visible = true;
lbl[i].AutoSize = true;
this.Controls.Add(lbl[i]);
Without this, the labels have a fixed size. When this fixed size is greater than unit, the labels overlap and hide each other's text. With more labels to add, unit becomes smaller and then smaller than the default width of the labels when temp is ≥ 5.
Alternatively, you could set the labels' width to unit to make sure that they do not overlap.
I am writing my Windows Forms app. And I have some problem with TableLayoutContainer element. Or rows are superpose (without needed scroll bar) or there is a big interval between first and second row.
I need a container with dynamic changing sizes according to Form size, with auto vertical scroll (if the container's size to big). Please help me to correct my code or container's properties.
Label LabelG = new Label[len];
NumericUpDown NumberControlBars = new NumericUpDown[len];
for (int i = 0; i < len; i++)
{
TablePanelContainer.RowCount++;
TablePanelContainer.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25F));
LabelG[i] = new System.Windows.Forms.Label();
LabelG[i].Name = "Label" + i.ToString();
LabelG[i].Size = new System.Drawing.Size(40, 23);
LabelG[i].Text = Groups[i].ToString();
LabelG[i].Dock = DockStyle.Right;
LabelG[i].Anchor = (AnchorStyles.Right | AnchorStyles.Top);
LabelG[i].TextAlign = ContentAlignment.MiddleRight;
TablePanelContainer.Controls.Add(LabelG[i], 0, i);
NumberControlBars[i] = new System.Windows.Forms.NumericUpDown();
NumberControlBars[i].Name = "Label" + i.ToString();
NumberControlBars[i].MaximumSize = new System.Drawing.Size(40,23);
NumberControlBars[i].Text = "0";
NumberControlBars[i].Dock = DockStyle.Left;
NumberControlBars[i].Anchor = (AnchorStyles.Left | AnchorStyles.Top);
TablePanelContainer.Controls.Add(NumberControlBars[i], 1, i);
}
Properties
Bug
I have recreated your functionality in a small app. These are the settings for your TablePanelLayout control
Anchor: Top, Bottom, Left, Right
AutoScroll: True
AutoSize: False
Specially the AutoSize setting to false is important. If you don't do that the control will resize itself to the height needed to accommodate all rows. Because the container has enough space in that case to show everything it will not show the scrollbars. It doesn't care that its size doesn't fit on the form.
This is what the designer should look like:
To overcome the quirks with the first row I adapted the Style of that first row. It looks like the designer plays some tricks here. Your code will look like this.
tableLayoutPanel1.SuspendLayout();
// adapt styling of first row
if (tableLayoutPanel1.RowStyles.Count > 0)
{
tableLayoutPanel1.RowStyles[0].SizeType = SizeType.Absolute;
tableLayoutPanel1.RowStyles[0].Height = 25F;
}
for(int i=0; i<100; i++)
{
var lbl = new Label();
lbl.Text = i.ToString();
tableLayoutPanel1.Controls.Add(lbl, 0, i);
var num = new NumericUpDown();
tableLayoutPanel1.Controls.Add(num,1 ,i);
tableLayoutPanel1.RowCount++;
}
tableLayoutPanel1.ResumeLayout();
When run this is the result:
I have dynamically created an array of labels. however, when i tried to set label.text = "hahaha hehehehe hmmmm", it displays only "hahaha" and not anything after the space.
for (int i = 0; i < labelArray.Length; i++)
{
labelArray[i] = new Label();
labelArray[i].BackColor = Color.Bisque;
labelArray[i].Font = new Font(labelArray[i].Font.FontFamily, labelArray[i].Font.Size + 5, FontStyle.Bold);
labelArray[i].Location = new Point(25, temp);
labelArray[i].Name = "searchLabel" + i.ToString();
labelArray[i].Text = "hahahahaha";
labelArray[i].MouseEnter += new EventHandler(main_MouseEnter);
labelArray[i].MouseLeave += new EventHandler(main_MouseLeave);
searchPanel.Controls.Add(labelArray[i]);
temp += 40; ;
}
have I missed out any anything? btw, this is the "initialization" done in Form_load and I edited the label.text in a TextChanged event. many thanks!
edit: I have since fixed the problem by setting autosize to true.
I have tried to display e.g. "hahahahahahahahaha hmmmmmm hehehehehehehehhe" and "ha hmmmmmmm hehehehehehhe" and in both cases only the first word gets displayed so I dont think it is being truncated..
the code which i used to set the text is simply:
labelArray[11].Text = "hahahahahahahahahaha eheheheheh hmmmmm";
try setting AutoSize attribute to true
labelArray[i].AutoSize = true;
I wish to add a button for every line in a file to a panel.
My code so far is:
StreamReader menu = new StreamReader("menu.prefs");
int repetition = 0;
while(!menu.EndOfStream)
{
Button dynamicbutton = new Button();
dynamicbutton.Click += new System.EventHandler(menuItem_Click);
dynamicbutton.Text = menu.ReadLine();
dynamicbutton.Visible = true;
dynamicbutton.Location = new Point(4+repetition*307, 4);
dynamicbutton.Height = 44;
dynamicbutton.Width = 203;
dynamicbutton.BackColor = Color.FromArgb(40,40,40);
dynamicbutton.ForeColor = Color.White;
dynamicbutton.Font = new Font("Lucida Console", 16);
dynamicbutton.Show();
menuPanel.Controls.Add(dynamicbutton);
repetition++;
MessageBox.Show(dynamicbutton.Location.ToString());
}
menu.Close();
The problem is that only the first control gets created.
The code looks fine but there could be a following situations.
1.You might have only one entry in the file, so you are experiencing only One Button added to the panel.
2.Your panel width is smaller than the sum of all the dynamic buttons width.
I suspect no 2 is the main reason that is causing problem.
So, I recommend that you use FlowLayoutPanel. To add a dynamic content as it automatically layout all the child controls.
Each time it is generating the same name for dynamic controls. That's the reason why it is showing only the last one. It simply overwrites the previous control each time.
int x = 4;
int y = 4;
foreach(PhysicianData pd in listPhysicians)
{
x = 4;
y = panPhysicians.Controls.Count * 30;
RadioButton rb = new RadioButton();
rb.CheckedChanged += new System.EventHandler(rbPhysician_CheckedChanged);
rb.Text = pd.name;
rb.Visible = true;
rb.Location = new Point(x, y);
rb.Height = 40;
rb.Width = 200;
rb.BackColor = SystemColors.Control;
rb.ForeColor = Color.Black;
rb.Font = new Font("Microsoft Sans Serif", 10);
rb.Show();
rb.Name = "rb" + panPhysicians.Controls.Count;
panPhysicians.Controls.Add(rb);
}
Try this code
StreamReader menu = new StreamReader("menu.prefs");
var str = menu.ReadToEnd();
var items = str.Split(new string[] {"\r\n" } , StringSplitOptions.RemoveEmptyEntries);
foreach (var item in items)
{
Button dynamicbutton = new Button();
dynamicbutton.Click += new System.EventHandler(menuItem_Click);
dynamicbutton.Text = item;
dynamicbutton.Visible = true;
dynamicbutton.Location = new Point(4+repetition*307, 4);
dynamicbutton.Height = 44;
dynamicbutton.Width = 203;
dynamicbutton.BackColor = Color.FromArgb(40,40,40);
dynamicbutton.ForeColor = Color.White;
dynamicbutton.Font = new Font("Lucida Console", 16);
dynamicbutton.Show();
menuPanel.Controls.Add(dynamicbutton);
repetition++;
}
The problem with Panel and similar controls other than the FlowLayoutPanel is when you create a control and a second one, the second is created at the same position if you are not changing it's location dynamically or setting it according to the other already added controls. Your control is there, it's in the back of the first control.
A flowLayoutPanel is better as it will add the controls next to each other as you add them while compromising more finer control at their positioning.
I also have similar problems with panels. For what you are doing it could be useful to just add strings to a listbox rather than using labels and a panel. That should be simpler.
for (int i = 0; i < 200; i++)
{
Control control = new Control();
control = new CheckBox();
Size size = control.Size;
Point point = new Point(20, 22);
control.Location = point;
int width = size.Width + 5;
i += width;
list.Add(control);
}
foreach(Control c in list)
{
}
how do I create a new instance of checkbox? Because this way I am getting just one checkbox each time. I want to get three checkbox in each row.
Is this winforms? A first point: you don't need the new Control() each time (you simly discard it anyway when you new CheckBox(). How exactly do you want the layout to appear? Can you describe it a bit more please?
I imagine TableLayoutPanel might be a reasonable start...
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Form form = new Form();
TableLayoutPanel layout = new TableLayoutPanel();
layout.Dock = DockStyle.Fill;
form.Controls.Add(layout);
layout.AutoScroll = true;
layout.ColumnCount = 3;
// size the columns (choice just to show options, not to be pretty)
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
layout.GrowStyle = TableLayoutPanelGrowStyle.AddRows;
for (int i = 0; i < 200; i++)
{
CheckBox chk = new CheckBox();
chk.Text = "item " + i;
layout.Controls.Add(chk);
}
Application.Run(form);
}
Otherwise, you'll need to manually set the Location (or Top and Left) of each; not simple.
Your code has problems. Let's work from sample code rather than a lesson. I'll create a Panel first, nice if you want to remove the checkboxes you created. You'd probably be interested in the user clicking a checkbox so lets add an event for that. Start a new WF project and drop a button on the form. Double click it, then paste this code:
private void button1_Click(object sender, EventArgs e) {
// Give the 3 checkboxes a decent spacing
int height = this.Font.Height * 3 / 2;
// Create the panel first, add it to the form
Panel pnl = new Panel();
pnl.Size = new Size(100, 3 * height);
pnl.Location = new Point(10, 5);
this.Controls.Add(pnl);
// Make three checkboxes now
for (int ix = 0; ix < 3; ++ix) {
CheckBox box = new CheckBox();
box.Size = new Size(100, height);
// As pointed out, avoid overlapping them
box.Location = new Point(0, ix * height);
box.Text = "Option #" + (ix + 1).ToString();
box.Tag = ix;
// We want to know when the user checked it
box.CheckedChanged += new EventHandler(box_CheckedChanged);
// The panel is the container
pnl.Controls.Add(box);
}
}
void box_CheckedChanged(object sender, EventArgs e) {
// "sender" tells you which checkbox was checked
CheckBox box = sender as CheckBox;
// I used the Tag property to store contextual info, just the index here
int index = (int)box.Tag;
// Do something more interesting here...
if (box.Checked) {
MessageBox.Show(string.Format("You checked option #{0}", index + 1));
}
}
It looks like you get your 200 instances, all placed at the same point.
Instantiate 3 new checkboxes inside your loop body, set their properties accordingly and add each of them to the list. After the code above is complete, you will have 600 checkboxes.
list.Add(Control1);
list.Add(Control2);
list.Add(Control3);
I am not sure about what you are trying to do, but I cleaned up your code a bit:
for (int i = 0; i < 200; i++)
{
Control control = new CheckBox();
control.Location = new Point(20, 22);
i += control.Size.Width + 5;
list.Add(control);
}
You should not add a new instance to the list if you want to add the control you just made.
Also:
Control control = new Control();
control = new CheckBox();
Is a bit redundant. Also to not get one control at the same spot multiple times you should alter the point. Hope this helps