WinForms dynamic matrix new form with button - c#

So I managed to create a dynamic array of text boxes in a new form with a button beneath, but the button is overlapping some of the text boxes as seen in the screenshot:
http://prntscr.com/l7ln4q
I'd like to add a margin and padding to the array so the button is underneath the array
This is the code that generates the array:
int LinhaText = frmDim.linhas;
int ColunText = frmDim.colunas;
const int TEXTBOX_WIDTH = 30;
const int TEXTBOX_HEIGHT = 30;
const int SPACING = 0;
List<List<TextBox>> textboxes = new List<List<TextBox>>();
private void Form2_Load(object sender, EventArgs e)
{
for (int row = 0; row < LinhaText; row++)
{
List<TextBox> newRow = new List<TextBox>();
textboxes.Add(newRow);
for (int col = 0; col < ColunText; col++)
{
TextBox newbox = new TextBox();
newbox.Width = TEXTBOX_WIDTH;
newbox.Height = TEXTBOX_HEIGHT;
newbox.Top = (row * (TEXTBOX_HEIGHT + SPACING)) + SPACING;
newbox.Left = (col * (TEXTBOX_WIDTH + SPACING)) + SPACING;
newRow.Add(newbox);
this.Controls.Add(newbox);
}
}
}
The generation of the array works just fine.

Try this if you just want a simple solution:
private void Form1_Load(object sender, EventArgs e)
{
Panel p = new Panel(); // added code
for (int row = 0; row < LinhaText; row++)
{
List<TextBox> newRow = new List<TextBox>();
textboxes.Add(newRow);
for (int col = 0; col < ColunText; col++)
{
TextBox newbox = new TextBox();
newbox.Width = TEXTBOX_WIDTH;
newbox.Height = TEXTBOX_HEIGHT;
newbox.Top = (row * (TEXTBOX_HEIGHT + SPACING)) + SPACING;
newbox.Left = (col * (TEXTBOX_WIDTH + SPACING)) + SPACING;
newRow.Add(newbox);
p.Controls.Add(newbox); // modified code (added textboxes to panel rather than form)
}
}
// added code
p.Dock = DockStyle.Fill;
this.Controls.Add(p);
this.Controls.SetChildIndex(p, 0);
Button b1 = new Button();
b1.Text = "hi";
b1.Dock = DockStyle.Bottom;
this.Controls.Add(b1);
this.Controls.SetChildIndex(b1, 1);
}

Related

C# - How can I create 2 separate button arrays with different controls without them causing problems with the other?

I am currently trying to develop a form of battleships on c# windows form.
Here is the code I am trying to use.. the trouble I have been having is how to create a second set of buttons (another 10x10) behind the other, with two sets of controls so I can switch between the two.
I have everything like AI and automated setups, I just need to have 2 button controls. I hope someone can help me out with this! Many thanks!
private List<List<Button>> grid = new List<List<Button>>();
public UserForm()
{
InitializeComponent();
byte numRows = 10;
byte numCols = 10;
for (byte i = 0; i < numRows; i++)
{
grid.Add(ButtonRowCreator(numCols, 25, (i+1) * 50));
}
}
public List<Button> ButtonRowCreator(byte numOfBtnsNeeded, int x, int y)
{
List<Button> btns = new List<Button>();
for (int i = 0; i < numOfBtnsNeeded; i++)
{
Button btn = new Button();
btn.Size = new Size(50, 50);
btn.Location = new Point(x + (i * btn.Width), y);
btns.Add(btn);
btn.Font = new Font("Georiga", 10);
this.Controls.Add(btn);
btn.Click += new EventHandler(btn_Click);
}
return btns;
}
void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
int curRow = -1, curCol = -1;
for(int i = 0; i < grid.Count; i++)
{
int index = grid[i].IndexOf(btn);
if (index != -1)
{
curRow = i;
curCol = index;
Console.WriteLine("curRow = " + curRow.ToString() + ", curCol = " + curCol.ToString());
}
}
// ... now you can use "curRow", "curCol" and "grid" to do something ...
foreach (List<Button> row in grid)
{
foreach (Button col in row)
{
col.ForeColor = Color.Gray;
}
}
if (board[curRow, curCol] == 1)
{
if (btn.Text == "Hit")
{
}
else
{
btn.Text = "Hit";
btn.BackColor = Color.Red;
hit++;
}
if (hit == 17)
{
MessageBox.Show("Congratulations, You Sunk Their Battleships!");
MessageBox.Show("Thanks For Playing!");
MessageBox.Show("Goodbye!");
}
}
else
{
btn.Text = "Miss!";
btn.BackColor = Color.Blue;
}
I think this is what you're after?
It looks like a lot of your code is used to figure out what button is clicked on. This information can be stored on the button object itself in the Tag property and greatly simplifies the code.
private Button[,] _grid1;
private Button[,] _grid2;
public UserForm()
{
InitializeComponent();
_grid1 = new Button[10, 10];
_grid2 = new Button[10, 10];
CreateGrid(_grid1, 10, 10, 25, 0, 20, true);
CreateGrid(_grid2, 10, 10, 25, 250, 20, false);
}
public void CreateGrid(Button[,] grid, int numOfRows, int numOfCols, int offsetX, int offsetY, int buttonSize, bool enabled)
{
for (byte i = 0; i < numOfRows; i++)
{
for (byte j = 0; j < numOfCols; j++)
{
grid[i,j] = ButtonCreator(i, j, offsetX, offsetY, buttonSize, enabled);
}
}
}
public Button ButtonCreator(int row, int col, int x, int y, int buttonSize, bool enabled)
{
Button btn = new Button();
btn.Size = new Size(buttonSize, buttonSize);
btn.Location = new Point(x + (col * buttonSize), y + (row * buttonSize));
btn.Font = new Font("Georiga", 10);
this.Controls.Add(btn);
btn.Click += new EventHandler(btn_Click);
btn.Tag = row + "," + col;
btn.Enabled = enabled;
return btn;
}
void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
string[] coord = btn.Tag.ToString().Split(',');
int curRow = Convert.ToInt32(coord[0]);
int curCol = Convert.ToInt32(coord[1]);
Console.WriteLine(curRow = " + curRow + ", curCol = " + curCol);
// ... now you can use "curRow", "curCol" to do something ...
_grid1[curRow, curCol].BackColor = Color.Red;
}

How to create event from control's that not yet create?

My program is the create datagridview program that user can create dynamic columns like row,column,panel(panel is quantity of the panel) so user can mark it too,
as I know I can mark the cell with CurrentCell.Style.BackColor
when I generate datagridview I have assign name of it But !!!! it cant use the new datagridvieweventhandler command so I cant do any thing with each datagridview
so this is my Datagridview Generate Code
string[] Panelname = { "One","Two","Three","Four","Five"};
for(i=0;i<Panelname.length;i++){
Generate(Panelname[i],a,b)}
DataGridView generate(string name,int columns,int rows)
{
int i;
Control Gen;
Control LB;
LB = new Label();
LB.Text = "Panel : "+name;
LB.Location = new Point(50 + 120 / (c - 1) + 900 / c , 315);
LB.BackColor = Color.Silver;
Gen = new DataGridView();
Gen.Name = name.ToString();
Gen.Size = new Size(900/c,300 );
Gen.Location = new Point(120 / (c ) + 900 / c, 0);
DataGridView CH = (DataGridView)Gen;
CH.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
CH.CellClick += new DataGridViewCellEventHandler(CH_CellClick);
CH.Location = new Point(0+locate, 0);
for (i = 1; i <= columns; i++)
{
CH.Columns.Add("", "");
}
for (i = 1; i < rows; i++)
{
CH.Rows.Add("", "");
}
dataGridView1.Controls.Add(LB);
dataGridView1.Controls.Add(CH);
return null;
}
How can I create the event handler for each datagridview that I'm create it dynamicly ?
thankyou for your kind
Create your datagridview.
for (int i = 0; i < 10; i++)
{
DataGridView d = new DataGridView();
d.MouseClick += dataGridView_MouseClick;
}
Use the add handler method.
private void dataGridView_MouseClick(object sender, MouseEventArgs e)
{
// Use sender to determine which datagridview fired the event
}
The problem that I found is when I'm create datagridview in the datagridview it hard to define it what's datagridview that you're clicking so I have stuck in this problem for a while
And now I found out the way's to through out my problem now, here it is
for(i=0;i
DataGridView generate2(string name, int columns, int rows,int form)
{
Control Gen;
Control LB;
int x = 1;
int runcolumn = columns;
int runrow = rows;
int count=0;
LB = new Label();
LB.Text = "Panel : " + name;
LB.Location = new Point(50 + 120 / (c - 1) + 900 / c, 320);
LB.BackColor = Color.Silver;
Gen = new DataGridView();
Gen.Name = name.ToString();
Gen.Location = new Point(120 / (c) + 900 / c, 0);
DataGridView CH = (DataGridView)Gen;
CH.RowTemplate.Height = 290 / rows;
CH.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
CH.Size = new Size(900 / c, 300);
CH.RowHeadersWidth = 10;
CH.ColumnHeadersHeight = 10;
CH.Location = new Point(0 + locate, 0);
And********* CH.Click += new EventHandler(control_click);********* this is my hero's
private void control_click(object sender, EventArgs e)
{
if (sender is DataGridView)
{
DataGridView A = (DataGridView)sender;
textBox2.Text = A.CurrentCell.RowIndex.ToString();
textBox1.Text = A.CurrentCell.ColumnIndex.ToString();
textBox3.Text = A.Name.ToString();
}
}
in the send control click function you can find what's kind of your control and cast it , so whatever control that you click it you can set it's function now!

Get real time input from programmatically generated elements in C# form

How to get value of checkboxes (and the textbox upon change in text) in real time with form particulars that are all generated via code?
This following code produces a form upon button press, the form has checkboxes and a richtextbox. Ideally I want any interaction to have an effect, so if I paste in a grid of ones and zeros the checkboxes update, and once a checkbox gets click, the corresponding one or zero in the textarea will update (So that I can then copy the grid (matrix) out and into another program.
I know how to get the events using the visual studio GUI maker, but not from a programmatically created form like this.
private void begin_button_Click(object sender, EventArgs e)
{
// Build the child form
Form check_box = new Form();
check_box.FormBorderStyle = FormBorderStyle.FixedSingle;
// Get the values from the textboxes
int height = Convert.ToInt16(this.height_input.Text);
int width = Convert.ToInt16(this.width_input.Text);
// Set the dimensions of the form
check_box.Width = width * 15 + 40;
check_box.Height = ( height * 15 + 40 ) * 3;
// Build checkboxes for the checkbox form
CheckBox[] chk;
chk = new CheckBox[height * width];
int count = 0;
for (int i = 1; i <= height; i++)
{
for (int j = 1; j <= width; j++)
{
chk[count] = new CheckBox();
chk[count].Name = count.ToString();
chk[count].Width = 15; // because the default is 100px for text
chk[count].Height = 15;
chk[count].Location = new Point(j * 15, i * 15);
chk[count].CheckedChanged += new EventHandler(this.CheckedChanged);
check_box.Controls.Add(chk[count]);
count += 1;
//Console.WriteLine(" i: " + i + " j: " + j + " Count: " + count);
}
}
RichTextBox output_area;
output_area = new RichTextBox();
output_area.Location = new Point(chk[0].Location.X, chk[count-1].Location.Y + 30);
check_box.Controls.Add(output_area);
output_area.Text = "hello world\n1,1,1,1,1,1,1,1,1\n0,0,0,0,0,1,0,1\nthese ones and zeros are meant to update in real time!";
output_area.Width = check_box.Width - 40;
output_area.Height = check_box.Height / 2;
// Run the form
check_box.ShowDialog();
}
EDIT:
I have added the event handler and it's working, however I can't access the checkbox form, only the main form.
private void CheckedChanged(object sender, EventArgs e)
{
//throw new NotImplementedException();
CheckBox x = (CheckBox)sender;
Console.WriteLine(x);
Console.WriteLine(x.Name.ToString());
}
Have a look at the .Designer file that the form designer generates for you!
Anyway, in your loop, try something like this:
chk[count].CheckedChanged += MyFancyHandler;
And the handler itself will look just like a normal handler:
private void MyFancyHandler( object sender, EventArgs e )
{
// ...
}
Also notice that the sender argument there will contain a reference to whichever checkbox/control the event refers to.
Below code updates matrix text in the rich text box when check box check state changed.
RichTextBox output_area;
CheckBox[] chk;
Size MatrixSize;
private void begin_button_Click()
{
// Build the child form
Form check_box = new Form();
check_box.FormBorderStyle = FormBorderStyle.FixedSingle;
check_box.StartPosition = FormStartPosition.CenterScreen;
// Get the values from the textboxes
int height = Convert.ToInt16("10");
int width = Convert.ToInt16("7");
MatrixSize = new Size(width, height);
// Set the dimensions of the form
check_box.Width = width * 15 + 40;
check_box.Height = (height * 15 + 40) * 3;
// Build checkboxes for the checkbox form
chk = new CheckBox[height * width];
int count = 0;
for (int i = 1; i <= height; i++)
{
for (int j = 1; j <= width; j++)
{
chk[count] = new CheckBox();
chk[count].Name = count.ToString();
chk[count].Width = 15; // because the default is 100px for text
chk[count].Height = 15;
chk[count].Location = new Point(j * 15, i * 15);
check_box.Controls.Add(chk[count]);
chk[count].CheckedChanged += new EventHandler(CheckBox1_CheckedChanged);
count += 1;
//Console.WriteLine(" i: " + i + " j: " + j + " Count: " + count);
}
}
output_area = new RichTextBox();
output_area.Location = new Point(chk[0].Location.X, chk[count - 1].Location.Y + 30);
check_box.Controls.Add(output_area);
output_area.Text = "hello world\n1,1,1,1,1,1,1,1,1\n0,0,0,0,0,1,0,1\nthese ones and zeros are meant to update in real time!";
output_area.Width = check_box.Width - 40;
output_area.Height = check_box.Height / 2;
// Run the form
check_box.ShowDialog();
}
private void CheckBox1_CheckedChanged(Object sender, EventArgs e)
{
CheckBox c = (CheckBox)sender;
Debug.WriteLine(c.Name);
StringBuilder sb = new StringBuilder();
int count = 0;
for (int i = 1; i <= MatrixSize.Height; i++)
{
for (int j = 1; j <= MatrixSize.Width; j++)
{
if (chk[count].Checked)
{
sb.Append("1,");
}
else
{
sb.Append("0,");
}
count += 1;
}
sb.Append("\r\n");
}
output_area.Text = sb.ToString();
}

Export dynamic label text to Excel

I have a small program that generates a few dynamic labels in a flowLayoutPanel1 I ma trying to export these labels' text to Excel but all I get is the value of the last label.
This is my Export class:
class Export
{
public Export(bool defaultBackgroundIsWhite)
{
this.defaultBackgroundIsWhite = defaultBackgroundIsWhite;
app = new Application();
app.Visible = true;
workbook = app.Workbooks.Add(1);
worksheet = (Worksheet)workbook.Sheets[1];
}
public void Do(string excelName, System.Windows.Forms.Label names)
{
for (int i = 0; i <= 5; i++)
{
AddNames(i,0,names);
}
}
private void AddNames(int row, int col, System.Windows.Forms.Label lbls)
{
if (lbls == null) return;
row++;
col++;
Range range = worksheet.Cells[row + 2, col + 2];
range.NumberFormat = "";
worksheet.Cells[row + 2, col + 2] = lbls.Text;
row--;
col--;
}
private Application app = null;
private Workbook workbook = null;
private Worksheet worksheet = null;
private bool defaultBackgroundIsWhite;
}
The form class code:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
create();
}
Label lbl;
private void create()
{
flowLayoutPanel1.Controls.Clear();
//int length = ds.Tables[0].Rows.Count;
for (int i = 0; i < 5; i++)
{
lbl = new Label();
lbl.Name = i.ToString();
lbl.Text = "Label "+i;
lbl.Font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular);
lbl.SetBounds(0, 20, 100, 25);
lbl.BorderStyle = BorderStyle.FixedSingle;
flowLayoutPanel1.Controls.Add(lbl);
}
}
private void button1_Click(object sender, EventArgs e)
{
Export ep = new Export(true);
ep.Do("test.xsl", lbl);
}
My Results:
You are always adding the text of the last created label because you are only passing its reference. You should instead pass the List with references of all the labels which Text properties you would like to export to Excel. Change these methods:
List<Label> lbls;
private void create()
{
flowLayoutPanel1.Controls.Clear();
//int length = ds.Tables[0].Rows.Count;
lbls = new List<Labels>();
for (int i = 0; i < 5; i++)
{
Label lbl = new Label();
lbl.Name = i.ToString();
lbl.Text = "Label "+i;
lbl.Font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular);
lbl.SetBounds(0, 20, 100, 25);
lbl.BorderStyle = BorderStyle.FixedSingle;
flowLayoutPanel1.Controls.Add(lbl);
lbls.Add(lbl);
}
}
Also change the method Do in the Export class to accept the List<Label> instead Label:
public void Do(string excelName, List<Label> names)
{
for (int i = 0; i <= names.Count; i++)
{
AddNames(i,0,names[i]);
}
}
List<Label> lbls = new List<Label>();
private void create()
{
flowLayoutPanel1.Controls.Clear();
//int length = ds.Tables[0].Rows.Count;
for (int i = 0; i < 5; i++)
{
lbl = new Label();
lbl.Name = i.ToString();
lbl.Text = "Label "+i;
lbl.Font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular);
lbl.SetBounds(0, 20, 100, 25);
lbl.BorderStyle = BorderStyle.FixedSingle;
lbls.Add(lbl); //< -- add the label to the local list of Labels
flowLayoutPanel1.Controls.Add(lbl);
}
}
private void button1_Click(object sender, EventArgs e)
{
int i = 0;
Export ep = new Export(true);
foreach(var lbl in lbls)
{
i++;
ep.AddNames(i,0,lbl);
}
}
public void AddNames(int row, int col, System.Windows.Forms.Label lbl)
{
if (lbl == null) return;
row++;
col++;
Range range = worksheet.Cells[row + 2, col + 2];
range.NumberFormat = "";
worksheet.Cells[row + 2, col + 2] = lbl.Text;
row--;
col--;
}
You're constructing a new label every time around the for loop in the create() method, and assigning that label to the same field (lbl). By the time you're done, lbl is the last label you created. You could instead add the labels to a List, or pass flowLayoutPanel1.Controls to the go() method, if you can be certain that will contain only the labels you wish to export.
It's a bit clunky TBH, and depending so heavily on the mechanics of the UI like that is not recommended - you'd be far better of with a well thought out model to which your UI is data bound, but if you want to just get it done, that's your problem.

Add label to Panel programmatically

So I have a form, and I want to add some Panels with some controls(labels, and radiobuttons) when the form loads.
And I want to do it from the code, of course(it's for making an application with tests, and the questions will be random)
This is what I have done till now:
List<Panel>ls=new List<Panel>();
private void VizualizareTest_Load(object sender, EventArgs e)
{
for (int i = 0; i < 4; i++)
{
Panel pan = new Panel();
pan.Name = "panel" + i;
ls.Add(pan);
Label l = new Label();
l.Text = "l"+i;
pan.Controls.Add(l);
pan.Show();
}
}
But it doesn't show anything on the form.
Add the panel just created to the Form.Controls collection
private void VizualizareTest_Load(object sender, EventArgs e)
{
for (int i = 0; i < 4; i++)
{
Panel pan = new Panel();
pan.Name = "panel" + i;
ls.Add(pan);
Label l = new Label();
l.Text = "l"+i;
pan.Location = new Point(10, i * 100);
pan.Size = new Size(200, 90); // just an example
pan.Controls.Add(l);
this.Controls.Add(pan);
}
}
enter image description here
private void button2_Click(object sender, EventArgs e)
{
int X = 153;
int Y = 34;
for (int i = 1; i < 4; i++)
{
Panel pnl = new Panel();
pnl.SuspendLayout();
pnl.Location = new Point(X, Y);
pnl.Name = "pnl"+i;
pnl.Size = new Size(200, 57);
pnl.BorderStyle = BorderStyle.FixedSingle;
Label lbl = new Label();
lbl.Location = new Point(X - 100, Y - 17);
lbl.Name = "lbl" + i;
lbl.Size = new Size(75, 23);
lbl.Text = "lable_" +i;
pnl.Controls.Add(lbl);
pnl.ResumeLayout(false);
this.Controls.Add(pnl);
Y = Y + 95;
}
}
why not display label2 & label3?

Categories