Filling jagged array with dynamic textboxes [closed] - c#

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I made a Linear equation solver program for school, I already found an algorithm which works, but it uses jagged arrays.
I need your help to make dynamical textboxes which are filling up a jagged array. For example: 1x+1y=3 and 2x+1y=4 would go into a {1,1,3} and into a {2,1,4} array. Here is my code, which isn't working.
TextBox[][] tb = new TextBox[n][];
for (int i = 0; i < n; i++)
for (int j = 1; j < n+1; j++) {
tb[i][j] = new TextBox();
tb[i][j].BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
tb[i][j].Left = 36 * j + 10;
tb[i][j].Top = 36 * i + 10;
tb[i][j].Width = 35;
tb[i][j].Font = new Font(tb[i][j].Font.FontFamily, 16);
tb[i][j].BackColor = Color.Cyan;
tb[i][j].TextAlign = HorizontalAlignment.Center;
}

I created a dummy project (as shown in the picture) and added a Panel. The Panel will contain the textboxes that you generate dynamically. I also updated the code behind. Although you created the textboxes, you never added it to any of the existing controls. They merely existed.
The code behind now looks like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int numVars = 2;
// You'll eventually need to obtain the values in the boxes
TextBox[][] tb;
private void button1_Click(object sender, EventArgs e)
{
// Remove existing controls
this.panel1.Controls.Clear();
// Obtain number of variables
numVars = (int)numericUpDown1.Value;
// Create the TextBoxes
tb = new TextBox[numVars][];
// Initialize each jagged array
for(int i = 0; i < numVars; i++)
tb[i] = new TextBox[numVars + 1];
// Create the Textboxes
int height = 20;
int width = 50;
int curX = 10;
int curY = 10;
for(int i = 0; i < numVars; i++)
{
for(int j = 0; j < numVars + 1; j++)
{
TextBox txtbox = new TextBox();
txtbox = new TextBox();
txtbox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
txtbox.Left = curX;
txtbox.Top = curY;
txtbox.Width = width;
txtbox.Height = height;
txtbox.Font = new Font(txtbox.Font.FontFamily, 16);
txtbox.BackColor = Color.Cyan;
txtbox.TextAlign = HorizontalAlignment.Center;
tb[i][j] = txtbox;
this.panel1.Controls.Add(tb[i][j]); // Add as a child of panel
curX += width + 15;
}
curX = 10;
curY = curY + height + 20;
}
}
}
Running it with a value of 6 gave:

Related

How can I make N label?

This doesn't work:
static int N = word.Length;
int z = 0;
for (int k = 0; k <N; k++)
{
Label l = new Label();
l.Name = string.Format("charLabel{0}", k);
l.Text = "_";
l.Height = 75;
l.Width = 25;
l.Location = new Point(300 + z, 10);
this.Controls.Add(l);
z += 10;
}
It only creates one and I would like to create more Labels, right next to the last. How can I do this?
If you set a larger number than 10 in the line z += 10; you will see the result because it needs more space to show your content. But if you set the AutoSize property like below you will get your desired result also:
l.AutoSize = true;
By setting this property the control is automatically resized to display its entire contents.
Also this is worth to mention that this property is true by default when added to a form using the designer but not when instantiated from code. Based on MSDN:
When added to a form using the designer, the default value is true. When instantiated from code, the default value is false.
Because you assign only one character to the text property of your labels and don't change vertical margin of your labels, the labels are superpositioned.
You should change the code like this :
static int N = word.Length;
int z = 0;
for (int k = 0; k <N; k++)
{
Label l = new Label();
l.Name = string.Format("charLabel{0}", k);
l.Text = "_";
l.Height = 75;
l.Width = 25;
l.Location = new Point(300, 10 + z);
this.Controls.Add(l);
z += 50;
}

How to create table of array based on textboxes?

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.

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);
}

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