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);
}
Related
I've created a dimensional array using two for loops, and as each inner loop completes, I'd like those values to go into textboxes on a windows form. (I realize that the values will be overwritten each time, with just the values from the final outer loop showing at the end.)
The comments in the code show what I've been trying to get to work.
Thanks!
if (IsValidData())
{
int Columns = 5;
int Rows = Convert.ToInt32(txtNumbDrawings.Text);
int[,] ball = new int[Columns, Rows];
for (int i = 0; i < Rows; i++)
{
List<int> ballsList = new List<int>();
int[] txtBall = new int[Columns];
for (int j = 0; j < Columns; j++)
{
Random number = new Random();
ball[i, j] = number.Next(1, 70);
// prevent duplicate numbers
while (ballsList.Contains(ball[i, j] ))
{
ball[i, j] = number.Next(1, 70);
}
ballsList.Add(ball[i, j]);
/*************************************************
* how do I get the current ball value
* into a textbox on a form?
*
* textboxes are named txtBall1, txtBall2, etc...
*
* I was trying something like:
*
* TextBox[] txtBall = new TextBox[5];
* for (int i = 0; i < 5; i++)
* {
* txtBall[i + 1].Text = ball[i, j].ToString();
* }
*************************************************/
}
ballsList = null;
}
}
Windows Form Image: https://1drv.ms/u/s!Ak6hxvO3Ye6Oj5I9NQy834Yk4TRLyw?e=DniwK8
If I understand what you're trying to do, and that seems to be assigning a shuffled list of integers to one of 5 list boxes, then this should do it:
if (IsValidData())
{
Random rnd = new Random();
// (1, 69) because rnd.Next(1, 70) only produces the numbers 1 to 69
int[] shuffled_balls = Enumerable.Range(1, 69).OrderBy(x => rnd.Next()).ToArray();
ListBox[] list_boxes = new [] { lstBall1, lstBall2, lstBall3, lstBall4, lstBall5 };
for (int i = 0; i < shuffled_balls.Length; i++)
{
list_boxes[i % list_boxes.Length].Items.Add(shuffled_balls[i]);
}
}
i trying to shuffle the numbers currently contained within a listbox.
However getting an error with my index
I am able to do this with an array, although now I am trying to shuffle without the use of any containers or arrays, but having problems doing so.
this.index = 0;
int a = Convert.ToInt32(lstHoldValue.Items.Count);
lstHoldValue.Items.Clear();
for (int i = 0; i < a; i++)
{
int idx = rnd.Next(i, a);
//swap elements
int tmp = Convert.ToInt32(lstHoldValue.Items[i]);
(lstHoldValue.Items[i]) = Convert.ToInt32(lstHoldValue.Items[idx]);
(lstHoldValue.Items[idx]) = Convert.ToInt32(tmp);
lstHoldValue.Items.Add("\t" + Convert.ToInt32(lstHoldValue.Items[i]));//show array in a listbox
}
this.index = 0;//what is this for?
int a = listHoldValue.Count;//Count returns an integer by default
// lstHoldValue.Items.Clear(); //remove this line,it clears the items stored
for (int i = 0; i < a; i++)
{
int idx = rnd.Next(i, a);
//swap elements
int tmp = Convert.ToInt32(lstHoldValue.Items[i]);
lstHoldVAlue.Items.Insert(i,lstHoldValue.Items[idx]);
(lstHoldValue.Items[i]) = Convert.ToInt32(lstHoldValue.Items[idx]);
(lstHoldValue.Items.Insert(idx,temp);
lstHoldValue.Items.Add("\t" + Convert.ToInt32(lstHoldValue.Items[i]));//this line is redundant because you have already added item[i] at index [idx]
}
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.
I have a code where I load up a text file and save it as an array. The array contains a list of numbers with some of the numbers being duplicated. In my code I first loop through the array and replace all duplicated numbers with a -1. Then I plan on deleting all the -1 values from my array. The remaining array values (non duplicates) are then copied on to a new array to be outputted.
However I keep getting an error when I attempt to delete the -1 values from my array (see code below). I don't know why this is happening so if anyone knows anything please let me know!
P.S. This is school project so I can only use loops and if statements, not things like LINQ or foreach, etc.
public partial class Form1 : Form
{
//Global Variable
int[] Original;
public Form1()
{
InitializeComponent();
}
//Exit Application
private void mnuExit_Click_1(object sender, EventArgs e)
{
this.Close();
}
//Load File
private void mnuLoad_Click_1(object sender, EventArgs e)
{
//Code to Load the Numbers From a File
OpenFileDialog fd = new OpenFileDialog();
//Open the File Dialog and Check If A File Was Selected
if (fd.ShowDialog() == DialogResult.OK)
{
//Open File to Read
StreamReader sr = new StreamReader(fd.OpenFile());
int Records = int.Parse(sr.ReadLine());
//Assign Array Sizes
Original = new int[Records];
//Go Through Text File
for (int i = 0; i < Records; i++)
{
Original[i] = int.Parse(sr.ReadLine());
}
}
}
private void btnOutput_Click(object sender, EventArgs e)
{
//Store Original Array
string Output = "Original \n";
//Output Original Array
for (int i = 0; i < Original.Length; i++)
{
Output = Output + Original[i] + "\n";
}
//Create TempArray
int[] TempArray = new int[Original.Length];
//Set TempArray Equal to Original Array
for (int i = 0; i < Original.Length; i++)
{
TempArray[i] = Original[i];
}
//Duplicate Number Counter
int Counter = 0;
//Loop Through Entire Array
for (int i = 0; i < TempArray.Length; i++)
{
for (int j = i + 1; j < TempArray.Length; j++)
{
//Replace Duplicate Values With '-1'
if (TempArray[i] == TempArray[j])
{
TempArray[j] = -1;
Counter++;
}
}
}
//Set Size of Original Array
Original = new int[Original.Length - Counter];
//Remove -1 Values
//Index Counter
int Index = 0;
//error starts
for (int i = 0; i < TempArray.Length; i++)
{
if (TempArray[i] != -1)
{
Original[Index] = TempArray[i];
Index++;
}
}
//error ends
//Final Output -- The New Array
Output = Output + "Original Without Duplicates\n";
for (int i = 0; i < Original.Length; i++)
{
Output = Output + Original[i] + "\n";
}
lblOutput.Text = Output;
}
}
}
Reverse the line TempArray[i] = Original[Index]; to Original[Index] = TempArray[i];
The only thing you need to do in this case would be
Original = new int[Original.Length - (Counter-1)];
and yes you need to change the code to assign the values to Original instead of TempArray.
//error starts
for (int i = 0; i < TempArray.Length; i++)
{
if (TempArray[i] != -1)
{
Original[Index] = TempArray[i];
Index++;
}
}
//error ends
Let's say you have three 3's in your array. In the outer loop when you iterate and come across a 3, you set the other two 3's to -1. Now you come across the first -1 which earlier was a 3 and you have already set the last 3 to -1. Now you search for duplicates and wrongly calculate your number of duplicates in the Duplicate Number Counter (called Counter) because for you -1 is a duplicate of -1.
So, what you can do is this:
First only set all duplicates to -1 and then count the number of -1's by looping through the array again. This way you will set correctly the size of non-duplicated array elements.
To set all dups to -1:
for (int outerIndex = 0; outerIndex < Original.Length; outerIndex++)
{
var currentElement = Original[outerIndex];
for (int innerIndex = outerIndex + 1; innerIndex < Original.Length; innerIndex++)
{
if (Original[innerIndex] == currentElement) Original[innerIndex] = -1;
}
}
To get the count of non-repeating elements now:
var counter = 0;
for (int index = 0; index < Original.Length; index++)
{
if (Original[index] != -1) counter++;
}
Creating non-duplicated elements' array:
var newArrayIndex = 0;
var newArray = new int[Original.Length - counter]; //Calculated counter above
for(int i = 0; i < Original.Length; i++)
{
if (Original[i] != -1) newArray[newArrayIndex++] = Original[i];
}
//Finally, not good programming practice, but
//you can set Original to this newArray if you like...
Original = newArray;
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).