How to create table of array based on textboxes? - c#

I have NxM textboxes created dynamicly.
User fill textboxes with integer.
I need to create table NxM with data which was puted into Textboxes.
I need it to do matrix calculations.
How can I do that? Can I do this using for each loop?
I have this code which gives me NxM Textboxes:
for (int i = 0; i <= verticalCount; i++)
{
if (i == verticalCount)
{
for (int j = 0; j < horizontalValue; j++)
{
var xEnd = 100 + 80 * verticalCount; ;
var yEnd = 100 + 60 * j;
var textBoxNM = new TextBox();
textBoxNM.Name = string.Format("TextBox_{0}_{1}", i, j);
textBoxNM.Location = new Point(xEnd, yEnd);
textBoxNM.Size = new System.Drawing.Size(50, 25);
Step2.Controls.Add(textBoxNM);
string end = string.Format("result = ", i + 1);
newLabel(end, xEnd - 60, yEnd, Step2);
}
}
else
{
for (int j = 0; j < horizontalValue; j++) //
{
var x = 20 + 80 * i;
var y = 100 + 60 * j;
if (j < horizontalValue)
{
newTextbox(x, y, Step2);
string nbr = string.Format("x{0}", i + 1);
newLabel(nbr, x + 50, y, Step2);
}
}
}
}
I have code written in c++ and I'm trying to create windows application of it.
Thanks!
edit:
public void button2_Click(object sender, EventArgs e)
{
var verticalCount = Convert.ToInt32(comboBox1.Text);
var horizontalValue = Convert.ToInt32(comboBox2.Text);
int[,] tbArray;
tbArray = new int[,] { { horizontalValue , verticalCount } };
foreach (Control ShouldBeTextBox in this.Controls)
{
if (ShouldBeTextBox is TextBox)
{
if (ShouldBeTextBox != null)
{
int x = horizontalValue;
int y = verticalCount;
var tag = ShouldBeTextBox.Tag as int[];
string a = Convert.ToString(tag);
MessageBox.Show(a);
tbArray[tag[x], tag[y]] = Convert.ToInt32(ShouldBeTextBox.Text);
}
else
MessageBox.Show("Fill all parameters");
}
}
}

what you could do is when creating a textbox give them matrix co-ordinates as a tag. Send the i and j to your newTextbox method and do something like
theNewTextBox.Tag = new int[] {i, j};
Later when you need to get values into your matrix array you can do something like this:
foreach(Control c in Step2.Controls)
{
Textbox tb = c as TextBox;
if (tb != null)
{
var tag = tb.Tag as int[];
theMatrixArray[tag[0], tag[1]] = tb.Text; // Or parse it to int if you can't have it in text
}
}
Hope this helps. Good luck!

I really recommend you use WPF for anything new which is UI related, as it simplifies UI customization in contrast to WinForms. By using something called DataTemplates, you can tell WPF how to represent your data model as a UI element.. this means that you can make WPF create as much Textboxes as necessary. You can also receive value updates to each data model instance via a mechanism called Binding. Finally, a mechanism called ItemsPanelTemplate lets you control the layout of your items. You can use a Grid as a Panel Template for a ListView Control.

Related

how to use sender arg for access to i&j in 2D Array in C#?

i have a code like this:
Label[,] Cell = new Label[8, 8];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
Cell[i, j] = new Label();
Cell[i, j].Text = (i + 1) + "" + (j + 1);
Cell[i, j].Location = new Point(j * 50 + 25, i * 50 + 25);
this.Controls.Add(Cell[i, j]);
Cell[i, j].Click += new System.EventHandler(lbl_click);
}
}
public void lbl_click(object sender, EventArgs e)
{
//I want having i & j here and work with them.
}
How can I access i and j variables from within the click event handler?
Using the Tag property
One option could be to Tag the label with the data you need to use.
For example, create a class to hold the data...
class TagData
{
public int I { get; set; }
public int J { get; set; }
}
In your loop...
Cell[i, j].Tag = new TagData() { I = i, J = j };
In the event handler...
public void lbl_click(object sender, EventArgs e)
{
Label label = sender as Label;
TagData tagData = label.Tag as TagData;
// Do something with tagData.I and tagData.J
}
Parsing the label Text
If you can assume that neither i or j would be more than a single digit each, then you could simply parse the Text. Like so:
public void lbl_click(object sender, EventArgs e)
{
Label label = sender as Label;
int i = int.Parse(label.Text[0]) - 1;
int j = int.Parse(label.Text[1]) - 1;
}
NOTE: The danger with more than a single digit for each is that without a separator you could not know if "123" was i = 1 or i = 12. You could of course work around this by using a separator, for example "12,3" but I wouldn't suggest having code that relies on specific UI design/formatting.
Ok thanks to musefan here is the solution with storing the coordinates in the Tag of the label. Winforms controls got a Property called Tag where you can store related Information.
Label[,] Cell = new Label[8, 8];
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
Label tempLabel = new Label();
Cell[i,j] = tempLabel;
tempLabel.Text = (i + 1) + "" + (j + 1);
tempLabel.Location = new Point(j * 50 + 25, i * 50 + 25);
tempLabel.Click += new System.EventHandler(lbl_click);
tempLabel.Tag = new Tuple<int, int>(i, j);
this.Controls.Add(tempLabel);
}
}
public void lbl_click(object sender, EventArgs e)
{
Label label = sender as Label;
Tuple<int, int> position = label.Tag as Tuple<int, int>;
if(positon != null)
{
int i = position.Item1;
int j = position.Item2;
//do whatever with the coordinates
}
}

How do you retrieve inputted text from a textbox array?

I am creating a calculator where the user enters a number into a textbox specifing how many inputs (textboxes) the user wants to have (Code not shown). I have used a textbox array to create these textboxes. The problem comes when I want to get the text from these textboxes to perform the calculations, the code I have written so far for this is shown below:
int n;
TextBox[] textBoxes;
Label[] labels;
double[] values;
public void GetValue()
{
n = Convert.ToInt16(txtInputFields.Text);
values = new double[n];
textBoxes = new TextBox[n];
for (int i = 0; i < n; i++)
{
}
}
I am unsure what to put in the for loop for this; I have tried the following:
values[n] = Convert.toDouble(textBoxes[n].Text);
but it gives me the error: Index was outside the bounds of the array.
I am new to C# and programming in general so any help would be much appreciated.
Thanks.
EDIT: Code to create textboxes is shown here:
public void InstantiateTextFields()
{
n = Convert.ToInt16(txtInputFields.Text);
int posLeft = 100;
textBoxes = new TextBox[n];
labels = new Label[n];
// Creates number of inputs and labels as specified in txtInputFields (n).
for (int i = 0; i < n; i++)
{
textBoxes[i] = new TextBox();
textBoxes[i].Top = 100 + (i * 30);
textBoxes[i].Left = posLeft;
textBoxes[i].Name = "txtInput" + (i + 1);
labels[i] = new Label();
labels[i].Top = 100 + (i * 30);
labels[i].Left = posLeft - 50;
labels[i].Text = "Input " + (i + 1);
labels[i].Name = "lblInput" + (i + 1);
}
for (int i = 0; i < n; i++)
{
this.Controls.Add(textBoxes[i]);
this.Controls.Add(labels[i]);
}
}
Your code in the GetValue method recreates the array of textboxes and doing so destroys the orginal content (the textboxes dynamically created InstantiateTextFields).
In this way your loop fails with Object Reference not set.
You just need to use the global variable without reinitiaizing it
public void GetValue()
{
n = Convert.ToInt16(txtInputFields.Text);
values = new double[n];
// textBoxes = new TextBox[n];
for (int i = 0; i < n; i++)
{
values[i] = Convert.ToDouble(textBoxes[i].Text);
}
}
There is something to be said about reading the input text and converting it to double without checks. If your user types something that cannot be converted to a double your code will crash on the Convert.ToDouble line. Use instead
double temp;
for (int i = 0; i < n; i++)
{
if(double.TryParse(textBoxes[i].Text, out temp)
values[i] = temp;
else
{
// Not a double value....
// A message to your user ?
// fill the array with 0 ?
// Your choice....
}
}
values[n] = Convert.toDouble(textBoxes[n].Text); gives you error because n is outside of the array. You allocate an array with the size of n which is zero indexed aka the last element is at position n-1.
for (int i = 0; i < n; i++)
{
values[i] = Convert.toDouble(textBoxes[i].Text);
}

Get number of blank textboxes

I am writing crossWord program
First, the user must enter a number "n" , and create a n * n table with TextBoxes that are in white color and blank.
After building the table, the user clicks on several houses and the house backcolor change to black.
My question is after this steps, how many TextBoxes are in the Black color, how many are white, How can I detect the maximum number of consecutive white text box without any black on them, in horizontally or vertically columns,to paste words that match to them!
In above table, form must detect that 5 is max of white consecutive textboxes in second horizontal line or in second vertical line, after user fill them must show 4 is max in first horizontal line, and go on to end...
Here is my code snippents:
private void CreateCrossTable()
{
int count = Convert.ToInt32(textBox1.Text.Trim());
if (count > 10)
count = 10;
int x = 100, y = 100;
const int value = 100;
for (int i = 1; i <= count; i++)
{
for (int j = 1; j <= count; j++)
{
x = value + (j * 20);
TextBox tb = new TextBox();
tb.Name = "txtbox" + i + "-" + j;
tb.Location = new Point(x, y);
tb.Size = new System.Drawing.Size(20, 20);
tb.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.txtMouseDoubleClick);
Controls.Add(tb);
}
y = value + (i * 20);
}
}
private void txtMouseDoubleClick(object sender, MouseEventArgs e)
{
TextBox tb = (TextBox)sender;
tb.BackColor = Color.Black;
tb.Enabled = false;
tb.Text = "|";
}
so , now I use LINQ to get All white textbox like this:
IEnumerable<TextBox> FreeItems = frm.Controls.OfType<TextBox>().Where(I => I.BackColor != Color.Black);
how can I get items those who are white and diffrence of X location of them not more than 20!
Try following example
private void findConsecutive()
{
var vertical = (from Control cnt in pnlCrossWord.Controls
where (cnt.GetType().Name.Equals("TextBox")) && (!cnt.BackColor.Equals(Color.Black))
orderby cnt.Top
select cnt.Top).Distinct().ToArray();
var horizontal = (from Control cnt in pnlCrossWord.Controls
where (cnt.GetType().Name.Equals("TextBox")) && (!cnt.BackColor.Equals(Color.Black))
orderby cnt.Left
select cnt.Left).Distinct().ToArray();
List<int> vList = new List<int>();
int iIndex = 0;
foreach (int top in vertical)
{
vList.Add(0);
int vIndex = 0;
int iConsecutive = 0;
int iLastLeft = -1;
var Item = (from Control cnt in pnlCrossWord.Controls
where (cnt.GetType().Name.Equals("TextBox")) && (!cnt.BackColor.Equals(Color.Black))
&& (cnt.Top.Equals(top))
select (TextBox)cnt).ToArray();
foreach (TextBox txt in Item)
{
if ((iLastLeft + txt.Width) < txt.Left && iLastLeft > -1)
{
if (iConsecutive > vList[iIndex])
vList[iIndex] = iConsecutive;
iConsecutive = 0;
}
iConsecutive++;
iLastLeft = txt.Left;
vIndex++;
}
if (iConsecutive > vList[iIndex])
vList[iIndex] = iConsecutive;
iIndex++;
}
int MaxConsicutiveIndex = vList.IndexOf(vList.Max());
}
EDITED
Above code will retrieve the Line Index of Maximum Consicutive White box in Horizontal Line.
You'll need a layout container that will allow you to arrange cells dynamically. A table should work.
For each cell store the x,y position in the tag property.
When the user clicks on a specific cell it will be easy to write a method that gives you a collection of cells or text boxes that are in the same row. Or if you want to find the answer after clicking a button you'll have to loop through all the rows.
This should get you in a good place to finish the rest.

Creating and positioning an array of buttons

Hello everyone I need some help with the positioning of an array of buttons.I want to make this function so it scans the name of the previous button and it names the next one +1,afterwards I want to position these buttons on the screen having a certain space between them and them being positioned in the center of the screen.I have tried many times to modify my method but I don't know how to get this method to work.
This is how my method looks like.
UPDATED
PS.Reference not set to an instance of an object Q.Q
public Button[] ButtonCreator(byte numOfBtnsNeeded,Form1 form)
{
Button[] mybtns = new Button[numOfBtnsNeeded];
foreach (Button b in mybtns)
{
for (int i = 0; i < mybtns.Length; i++)
{
mybtns[i].Name = i.ToString();
mybtns[i].Parent = form;
mybtns[i].Height = 50;
mybtns[i].Width = 50;
for (int k = i + 1; k < mybtns.Length; k++)
{
mybtns[i].Location = new Point(190, 80);
mybtns[k].Location = Point.Add(new Point(mybtns[i].Location.X + 10,mybtns[i].Location.Y + 10),new Size(mybtns[i].Size.Width,mybtns[i].Size.Height));
}
}
}
foreach (Button b in mybtns)
{
b.Show();
}
return mybtns;
}
Play with this example...
public partial class Form1 : Form
{
private List<List<Button>> grid = new List<List<Button>>();
public Form1()
{
InitializeComponent();
byte numRows = 5;
byte numCols = 5;
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);
this.Controls.Add(btn);
btn.Click += new EventHandler(btn_Click);
}
return btns;
}
void btn_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
btn.Text = "X";
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 ...
// reset all BackColors:
foreach (List<Button> row in grid)
{
foreach (Button col in row)
{
col.BackColor = Button.DefaultBackColor;
}
}
// the below should give you some examples for the
// syntax necessary to access buttons in the grid
// highlight current row:
foreach (Button col in grid[curRow])
{
col.BackColor = Color.Yellow;
}
// highlight current col:
for (int i = 0; i < grid.Count; i++)
{
grid[i][curCol].BackColor = Color.Yellow;
}
}
}
You cannot change a foreach variable reference (ie b). If you want to initialize an array you should use for loop:
for(int i = 0; i < numOfBtnsNeeded; i++)
{
var button = mybtns[i] = new Button();
//Here you can modify the reference of button.
}
Also, mybtns will be full of nulls since Button is a reference type which means it's default value is a null.
you want something like:
public Button[] ButtonCreator(byte numOfBtnsNeeded)
{
Button[] mybtns = new Button[numOfBtnsNeeded];
for (int i = 0; i < mybtns.Length; i++)
{
mybtns[i] = new Button();
mybtns[i].Name = (i + 1).ToString();
}
return mybtns;
}
I'm not sure why you're using a byte over an int, but it works either way.
Essentially, when you create the array, you're not creating the objects within the array. And you cannot modify the thing you are looping over within a foreach loop, so you need a for loop.

Add thousands of columns into datagridview

I'm trying to add very large number of columns into datagridview and I faced a challenging problem. When column count becomes too large the code below adds columns very slowly. This depends upon size value - when it less than 10000 I get more or less good result(2-4 seconds to add this number of columns), but when size grows up to 15000 or more the time of adding is not proportional at all, for 30000 of columns it can reach 2 minutes instead of 20-30 seconds as I expect. So my question is it possible to optimize this procedure somehow?
datagridview.SuspendLayout();
int size = 10000;
var columns = new DataGridViewColumn[size];
for (int i = 0; i < size; i++)
{
columns[i] = new DataGridViewTextBoxColumn();
columns[i].Name = "col" + i;
columns[i].HeaderText = "col" + i;
columns[i].FillWeight = 0.00001f;
}
datagridview.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
Array.ForEach(columns, item => datagridview.Columns.Add(item));
datagridview.ResumeLayout();
And this is what I've done:
int visibleColumns = 20;
string[] headers;
DataGridViewColumn[] columns;
HScrollBar hbar = new HScrollBar();
public Constructor(){
...
int sizeDezired = 15000;
int size = Math.Min(sizeDezired, visibleColumns);
columns = new DataGridViewColumn[size];
headers = new string[sizeDezired];
for (int i = 0; i < size; i++)
{
columns[i] = new DataGridViewTextBoxColumn();
columns[i].Name = "col" + i;
columns[i].HeaderText = "col" + i;
columns[i].FillWeight = 0.00001f;
}
for (int i = 0; i < sizeDezired;i++ )
{
headers[i] = "col" + i;
}
if (sizeDezired > size)
{
hbar.Maximum = sizeDezired - size;
hbar.Minimum = 0;
hbar.Value = 0;
}
hbar.Scroll += hbar_Scroll;
...
}
void hbar_Scroll(object sender, ScrollEventArgs e)
{
for (int i = 0; i < datagridview.ColumnCount; i++)
{
datagridview.Columns[i].HeaderText = headers[i + e.NewValue];
}
}
I added this code:
int visibleColumns = 20;// columns that are in data grid view
string[] headers;// headers for all desired columns
DataGridViewColumn[] columns;
HScrollBar hbar = new HScrollBar();
public Constructor(){
...
int sizeDesired = 15000;
int size = Math.Min(sizeDesired, visibleColumns);
columns = new DataGridViewColumn[size];
headers = new string[sizeDesired];
for (int i = 0; i < size; i++)
{
columns[i] = new DataGridViewTextBoxColumn();
columns[i].Name = "col" + i;
columns[i].HeaderText = "col" + i;
columns[i].FillWeight = 0.00001f;
}
for (int i = 0; i < sizeDesired;i++ )
{
headers[i] = "col" + i;
}
if (sizeDesired > size)
{
hbar.Maximum = sizeDesired - size;
hbar.Minimum = 0;
hbar.Value = 0;
}
hbar.Scroll += hbar_Scroll;
...
}
void hbar_Scroll(object sender, ScrollEventArgs e)
{
for (int i = 0; i < datagridview.ColumnCount; i++)
{
datagridview.Columns[i].HeaderText = headers[i + e.NewValue];
}
}
Here horizontal scroll bar added to cycle through all invisible columns and shift column headers to visually "scroll" through all columns(15000 in this example) but in reality only 20 columns are present. This code does not use any databinding, only headers are changing so you need to modify hbar_Scroll handler to show relevant data in cells.
The technique you are looking for is called pagination. Look at the following reference
"Paging is a great way to limit the amount of data displayed to the
user at one time, but is also a very good way of stopping lots of data
being transmitted across the network, being held in memory or big
queries on databases... It solves many problems.
The most common solution is (just like on a Google search) is you get
shown a list of pages and you can navigate around pages either going
up / down a page at a time or clicking on a page number.
Another way is to make it seem like there is actually one big list but
page behind the scenes so the user feels like they are actually
viewing one big list. An example where you see this done is in TFS.
You can do this with a windows forms data grid (DataGridView).

Categories

Resources