Why im not getting the real current char i clicked/selected? - c#

This is the code:
private void richTextBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (mouseisup == false)
{
textBox1.Text = "";
int positionToSearch = richTextBox1.GetCharIndexFromPosition(new Point(e.X, e.Y));
richTextBox1.SelectionStart = positionToSearch;
textBox1.Text = richTextBox1.Text.Substring(positionToSearch, 1);
previousChar = positionToSearch;
textBox2.Text = "";
mouseisup = true;//add this statement
}
else
{
currentChar = richTextBox1.GetCharIndexFromPosition(new Point(e.X, e.Y));
if (currentChar > previousChar + 2 || currentChar < previousChar - 2)
{
richTextBox1.SelectionStart = currentChar;
textBox2.Text = richTextBox1.Text.Substring(currentChar, 1);
button1.Enabled = true;
}
mouseisup = false;
}
}
}
private void richTextBox1_MouseUp(object sender, MouseEventArgs e)
{
if (textBox2.Text == "")
{
mouseisup = true;
button1.Enabled = false;
}
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
string[] text = Parse_Text.ParseText(richTextBox1.Text, textBox1.Text, textBox2.Text);
for (int i = 0; i < text.Length; i++)
{
richTextBox2.Text = text[i];
}
}
I created for the test a text new text file and entered the text file:
"Daniel > is smaller >< then daniel or Daniel depend on the D > but < <>"
Then in the program first click was on the first D of the first Daniel the second click was on the second D of the second Daniel.
Then in the new class in parse_text in this code :
List<string> parsedText = new List<string>();
string[] entries = null;
int startIndex = text.IndexOf(startTag);
if (startIndex >= 0)
{
int endIndex = text.IndexOf(endTag, startIndex);
startIndex is 0 but also endIndex is 0. But endTag is the second D it shouldnt be index 0.
So thats i also a problem.

Your problem is that you take an IndexOf of the character which will indeed give you the first occurence.
To avoid that, use the position of the character instead of the actual character.
You already have that information available on the line:
currentChar = richTextBox1.GetCharIndexFromPosition(new Point(e.X, e.Y));
EDIT
You should change your Parse_Text method for use with positions instead of characters.
On the top of my head you should get somehting like:
public static string[] ParseText(string text, int startPos, int endPos)
{
List<string> parsedText = new List<string>();
string[] entries = null;
if (startPos >= 0 && endPos > startPos)
{
string images = text.Substring(startPos + 1, endPos - startPos - 1);
entries = images.Split(new[] { ',' });
for (var i = 0; i < entries.Length; i++)
{
entries[i] = entries[i].Replace("\"", "");
}
for (int i = 0; i < entries.Length; i++)
{
parsedText.Add(entries[i]);
}
}
return entries;
}
Obviously you should add some extra tests regarding the allowed parameters.
For example:
text cannot be string.Empty
startPos cannot be less then zero
endPos must be greater then startPos

Related

Why doesn't my richtextbox change the color?

I'm trying to give the letters in my richtextbox different colors for my subnet calculator, but the richtextbox doesn't change the colors until the 26th letter.
How it looks:
int iValueSm = trackBarSmMask.Value;
rtbScroll.Text = "";
rtbScroll.SelectionStart = rtbScroll.TextLength;
rtbScroll.SelectionLength = 0;
for (int i = 1; i <= iValueSm; i++)
{
rtbScroll.SelectionColor = Color.Blue;
rtbScroll.AppendText("N");
if (i%8==0 && i != 32)
{
rtbScroll.Text = rtbScroll.Text + ".";
}
}
for (int i = iValueSm+1; i <= 32; i++)
{
rtbScroll.SelectionColor = Color.Red;
rtbScroll.AppendText("H");
if (i % 8 == 0 && i != 32)
{
rtbScroll.Text = rtbScroll.Text + ".";
}
}
labelAmountNetID.Text = "/" + iValueSm.ToString();
Well, can be a lot of approaches to deal with this problem but here is one suggestion:
// Track bar definitions...
private void SetTrackBarVals()
{
trackBar1.Minimum = 0;
trackBar1.Maximum = 31;
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
var counter = 0;
var dotsCounter = 0;
rtbScroll.Text = "";
int iValueSm = trackBar1.Value + 1; // +1 because we start counting from 0
for (int i = 1; i <= 32; i++)
{
if (counter > 0 && counter % 8 == 0)
{
// new octet
rtbScroll.AppendText(".");
dotsCounter++;
}
if (i > iValueSm)
{
// It is red
rtbScroll.AppendText("H");
rtbScroll.SelectionStart = (i - 1) + dotsCounter;
rtbScroll.SelectionLength = 1 ;
rtbScroll.SelectionColor = Color.Red;
}
else
{
rtbScroll.AppendText("N");
}
counter++;
}
}
Anytime you set the .Text() property, you RESET all formatting back to black and white.
Here is how I'd write it using SelectedText:
private void Form1_Load(object sender, EventArgs e)
{
updateRTB();
}
private void trackBarSmMask_ValueChanged(object sender, EventArgs e)
{
updateRTB();
}
private void trackBarSmMask_Scroll(object sender, EventArgs e)
{
updateRTB();
}
private void updateRTB()
{
rtbScroll.Text = "";
rtbScroll.SelectionStart = 0;
rtbScroll.SelectionLength = 0;
int iValueSm = trackBarSmMask.Value;
labelAmountNetID.Text = "/" + iValueSm.ToString();
for (int i = 1; i <= 32; i++)
{
rtbScroll.SelectionColor = (i <= iValueSm) ? Color.Blue : Color.Red;
rtbScroll.SelectedText = (i <= iValueSm) ? "N" : "H";
if (i % 8 == 0 && i != 32)
{
rtbScroll.SelectionColor = Color.Black;
rtbScroll.SelectedText = ".";
}
}
}

How to highliht specific word in richtextbox during writing?

Basically I want to make an autocorrect for my language. I have a RichTextBox(name: MainText), where I write. during writing, the program should every word if it exists in a dictionary file. if not then change the specific word color to red.
It has a timer. after every second it gets the written text and puts the words to an str array, and reads correct words from dictionary.txt file and puts them in a list. during comparison of the strings, it never highlights the incorrect words and it has always indexOutOfRange errors. How to fix it?
Here is the timer tick void:
void CheckTimer_Tick(object sender, EventArgs e)
{
List<string> correct_words = File.ReadAllLines(DictPath).ToList();
string text = MainText.Text;
string[] Words = text.Split(' ', '.');
for (int i = 0; i < Words.Length; i++)
{
if (correct_words.Contains(Words[i])) { }
else
{
int index = 0;
String temp = MainText.Text;
MainText.Text = "";
MainText.Text = temp;
while (index < MainText.Text.LastIndexOf(Words[i]))
{
MainText.Find(Words[i], index, MainText.TextLength, RichTextBoxFinds.None);
MainText.SelectionColor = Color.Red;
index = MainText.Text.IndexOf(Words[i], index) + 1;
}
}
}
}
I also tried this void:
void HighlightPhrase(RichTextBox box, string phrase, Color color)
{
int pos = box.SelectionStart;
string s = box.Text;
for (int ix = 0; ;)
{
int jx = s.IndexOf(phrase, ix, StringComparison.CurrentCultureIgnoreCase);
if (jx < 0) break;
box.SelectionStart = jx;
box.SelectionLength = phrase.Length;
box.SelectionColor = color;
ix = jx + 1;
}
box.SelectionStart = pos;
box.SelectionLength = 0;
box.ForeColor = Color.Black;
}
This worked if I gave it a specific string, but it couldn't recognize the phrase input from the dictionary and gave the indexOutOfRange error.
public Form1()
{
InitializeComponent();
}
private void textbox1_TextChanging(object sender, EventArgs e)
{
string[] words = textBox1.Text.Split(',');
foreach(string word in words)
{
int startindex = 0;
while(startindex < richTextBox1.TextLength)
{
int wordstartIndex = richTextBox1.Find(word, startindex, RichTextBoxFinds.None);
if (wordstartIndex != -1)
{
richTextBox1.SelectionStart = wordstartIndex;
richTextBox1.SelectionLength = word.Length;
richTextBox1.SelectionBackColor = Color.Yellow;
}
else
break;
startindex += wordstartIndex + word.Length;
}
}
}
For Clear Hightlight Use This Code
richTextBox1.SelectionStart = 0;
richTextBox1.SelectAll();
richTextBox1.SelectionBackColor = Color.White;

Why the loops wont work in my Windows Form Application? [duplicate]

This question already has an answer here:
Why do I only see some of my text output when my Window Forms application has a loop?
(1 answer)
Closed 7 years ago.
I am trying to combine prime numbers, even numbers and odd numbers and their results in a Windows Form Application. I have tested the code in Console but in Windows Form it will not loop to the next applicable number. For example: In console 1 - 10 in primes would result in "2, 3, 5, 7", however in Windows Form Application it will result in "2"
public partial class NumberCalc : Form
{
public NumberCalc()
{
InitializeComponent();
}
private void Primes_CheckedChanged(object sender, EventArgs e)
{
{
int f = Convert.ToInt32(Min.Text);
int i = Convert.ToInt32(Max.Text);
bool isPrime = true;
for (f = 0; f <= i; f++)
{
for (int j = 2; j <= i; j++)
{
if (f != j && f % j == 0)
{
isPrime = false;
break;
}
}
if (isPrime)
{
string final;
final = ("The Prime Numbers Are:" + f);
Result.Text = final;
}
isPrime = true;
}
}
}
private void Result_TextChanged(object sender, EventArgs e)
{
}
private void Min_TextChanged(object sender, EventArgs e)
{
}
private void Evens_CheckedChanged(object sender, EventArgs e)
{
int f = Convert.ToInt32(Min.Text);
int i = Convert.ToInt32(Max.Text);
for (f = 0; f >= i; f++)
{
if (f % 2 == 0)
{
{
string final;
final = ("The Even Numbers Are:" + f);
Result.Text = final;
}
}
}
}
private void Odds_CheckedChanged(object sender, EventArgs e)
{
int f = Convert.ToInt32(Min.Text);
int i = Convert.ToInt32(Max.Text);
for (f = 0; f <= i; f++)
{
if (f % 2 != 0)
{
{
string final;
final = ("The Even Numbers Are:" + f);
Result.Text = final;
}
}
}
}
}
}
Change your code to:
private void Primes_CheckedChanged(object sender, EventArgs e)
{
{
string final = "The Prime Numbers Are:";// you need to keep the result out of the loop instead of reset it everytime
int f = Convert.ToInt32(Min.Text);
int i = Convert.ToInt32(Max.Text);
bool isPrime = true;
for (f = 0; f <= i; f++)// why set f=0 here ? Does not f = min already ?
{
for (int j = 2; j <= i; j++)// maybe j < f not j <= i
{
if (f != j && f % j == 0)// then remove f != j here
{
isPrime = false;
break;
}
}
if (isPrime)
final = final + " " + f;// then add your found number to the result here
isPrime = true;
}
Result.Text = final;
}
}
Even and Odd goes the same.BTW 1 is not prime number, am I right ?
I would combine your loops/checks into one method like this:
private void Form1_Load(object sender, EventArgs e)
{
this.Primes.CheckedChanged += Options_CheckedChanged;
this.Evens.CheckedChanged += Options_CheckedChanged;
this.Odds.CheckedChanged += Options_CheckedChanged;
this.Min.TextChanged += Range_Changed;
this.Max.TextChanged += Range_Changed;
CheckNumbers();
}
private void Range_Changed(object sender, EventArgs e)
{
CheckNumbers();
}
private void Options_CheckedChanged(object sender, EventArgs e)
{
CheckNumbers();
}
private void CheckNumbers()
{
int min, max;
try
{
min = Convert.ToInt32(Min.Text);
max = Convert.ToInt32(Max.Text);
}
catch (Exception)
{
Results.Text = "Invalid Range!";
return;
}
List<int> lstPrimes = new List<int>();
List<int> lstEvens = new List<int>();
List<int> lstOdds = new List<int>();
if (Primes.Checked || Evens.Checked || Odds.Checked)
{
bool isPrime;
for (int f = min; f <= max; f++)
{
if (Primes.Checked)
{
isPrime = true;
for (int j = 2; j <= max; j++)
{
if (f != j && f % j == 0)
{
isPrime = false;
break;
}
}
if (isPrime)
{
lstPrimes.Add(f);
}
}
int modResult = f % 2;
if (Evens.Checked && modResult == 0)
{
lstEvens.Add(f);
}
if (Odds.Checked && modResult != 0)
{
lstOdds.Add(f);
}
}
}
StringBuilder sb = new StringBuilder();
if (Primes.Checked)
{
sb.AppendLine("The Prime Numbers Are:" + String.Join(",", lstPrimes));
}
if (Evens.Checked)
{
sb.AppendLine("The Even Numbers Are:" + String.Join(",", lstEvens));
}
if (Odds.Checked)
{
sb.AppendLine("The Odd Numbers Are:" + String.Join(",", lstOdds));
}
Results.Text = sb.ToString();
}
I think LINQ is more suitable here, You can try this:
int[] numbers = Enumerable.Range(f, i-f).ToArray<int>();
string oddNumbers=string.Join(",", from number in numbers
where (number % 2)!=0
select number);
string evenNumbers = string.Join(",", from number in numbers
where (number % 2) == 0
select number);
Result.Text = "The Even Numbers Are:" + evenNumbers;
Result.Text = "The Odd Numbers Are:" + oddNumbers;
Updates for Prime number:
var primeNumbers= string.Join(",",from number in numbers
where (IsPrime(number))
select number);
Where IsPrime() method is defined as follows?
private static bool IsPrime(int number)
{
for (int i = 2; i < number; i ++)
if (number % i == 0) return false;
return true;
}

Quick Search out of bounds of array and confusing array behaviour

I'm having multiple problems with my program (C#.NET) and have no idea what's causing them.
The program is intended to sort a list of names and birthdays (formatted first name,last name,DD/MM/YYYY) in ascending and descending order by first name, last name, and birthday. It is also to have other functions which have not yet been implemented.
The first problem is in the quikSortStr method. The program crashes in the first if block, stating that j is out of the bounds of the array. This happens whether or not mode == "asc".
The second, and more confusing problem is that when the values are loaded from a text file, every odd-indexed value of first and last will be null, while each odd-indexed value of bDay will be 1/1/0001.
I've included the full program below for reference, a quicksort method and the use of parallel arrays are required. My apologies for the lack of comments.
Thanks in advance for any help. I'm completely stumped.
namespace Names_Arrays
{
public partial class frmNamArrays : Form
{
System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-CA");
string[] first;
string[] last;
DateTime[] bDay;
string order = "asc";
string format = "d/M/yyyy";
public frmNamArrays()
{
InitializeComponent();
}
private void write()
{
string[] lines = new string[first.Length];
for (int i = 0; i < lines.Length; i++)
lines[i] = first[i] + ',' + last[i] + ',' + bDay[i].ToString(format);
txtbxNames.Clear();
txtbxNames.Lines = lines;
}
private void load()
{
string[] lines = txtbxNames.Lines;
first = new string[lines.Length];
last = new string[lines.Length];
bDay = new DateTime[lines.Length];
int i = 0;
foreach (string line in lines)
{
string[] data = line.Split(',');
//There aren't any lines that split to a string[] of length less than three,
//but for some reason the program kept believing there are.
//patched that leak.
if (data.Length == 3)
{
first[i] = data[0];
last[i] = data[1];
bDay[i] = Convert.ToDateTime(data[2], culture);
}
i++;
}
}
public DateTime[] quikSortTim(DateTime[] primary, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
DateTime pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (DateTime.Compare(primary[i], pivot) < 0)
i++;
while (DateTime.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (DateTime.Compare(primary[i], pivot) > 0)
i++;
while (DateTime.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
DateTime holdoverB = primary[i];
primary[i++] = primary[j];
primary[j--] = holdoverB;
string holdover = last[i - 1];
last[i] = last[j + 1];
last[j] = holdover;
holdover = first[i - 1];
first[i] = first[j + 1];
first[j] = holdover;
}
}
if (j > left)
primary = quikSortTim(primary, mode, left, j);
if (i < right)
primary = quikSortTim(primary, mode, i, right);
}
return primary;
}
public string[] quikSortStr(string[] primary, string type, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
string pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (String.Compare(primary[i], pivot) < 0)
i++;
while (String.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (String.Compare(primary[i], pivot) > 0)
i++;
while (String.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
string holdover = primary[i];
primary[i] = primary[j];
primary[j] = holdover;
if (type == "first")
{
holdover = last[i];
last[i] = last[j];
last[j] = holdover;
}
else
{
holdover = first[i];
first[i] = first[j];
first[j] = holdover;
}
DateTime holdoverBeta = bDay[i];
bDay[i] = bDay[j];
bDay[j] = holdoverBeta;
i++;
j++;
}
}
if (j > left)
primary = quikSortStr(primary, type, mode, left, j);
if (i < right)
primary = quikSortStr(primary, type, mode, i, right);
}
return primary;
}
private void frmNamArrays_SizeChanged(object sender, EventArgs e)
{
txtbxNames.Width = this.Width - 40;
txtbxNames.Height = this.Height - 157;
}
private void btnSort_Click(object sender, EventArgs e)
{
load();
switch (cbobxCategory.Text)
{
case ("First Name"):
first = quikSortStr(first, "first", order, 0, first.Length - 1);
break;
case ("Last Name"):
last = quikSortStr(last, "last", order, 0, last.Length - 1);
break;
case ("Birthday"):
bDay = quikSortTim(bDay, order, 0, bDay.Length - 1);
break;
default:
break;
}
write();
}
private void cbobxOrder_SelectedIndexChanged(object sender, EventArgs e)
{
if (cbobxOrder.Text == "Ascending")
order = "asc";
else
order = "desc";
}
private void displayfile(string name)
{
StreamReader fileData = new StreamReader(name);
txtbxNames.Lines = fileData.ReadToEnd().Split('\n');
}
private void mnuOpen_Click(object sender, EventArgs e)
{
OpenFileDialog open = new OpenFileDialog();
open.Filter = "Text Files|*.txt";
open.Title = "Select a text file...";
if (open.ShowDialog() == DialogResult.OK && open.FileName != "")
displayfile(open.FileName);
}
private void mnuExit_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
You have to change the code as below in the quikSortStr method inside the if (i <= j) loop
DateTime holdoverBeta = bDay[i];
bDay[i] = bDay[j];
bDay[j] = holdoverBeta;
i++;
j--;//was: j++;
and this will fix the issue.
Thanks to saravanan for pointing out my first mistake. The out of range error was caused by an accidental incrementation of j in the wrong direction. The fixed methods are
public DateTime[] quikSortTim(DateTime[] primary, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
DateTime pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (DateTime.Compare(primary[i], pivot) < 0)
i++;
while (DateTime.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (DateTime.Compare(primary[i], pivot) > 0)
i++;
while (DateTime.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
DateTime holdoverB = primary[i];
primary[i] = primary[j];
primary[j] = holdoverB;
string holdover = last[i];
last[i] = last[j];
last[j] = holdover;
holdover = first[i];
first[i] = first[j];
first[j] = holdover;
i++;
j--;
}
}
if (j > left)
primary = quikSortTim(primary, mode, left, j);
if (i < right)
primary = quikSortTim(primary, mode, i, right);
}
return primary;
}
public string[] quikSortStr(string[] primary, string type, string mode, int left, int right)
{
if (primary.Length > 1)
{
int i = left, j = right;
string pivot = primary[left + (right - left) / 2];
while (i <= j)
{
if (mode == "asc")
{
while (String.Compare(primary[i], pivot) < 0)
i++;
while (String.Compare(primary[j], pivot) > 0)
j--;
}
else
{
while (String.Compare(primary[i], pivot) > 0)
i++;
while (String.Compare(primary[j], pivot) < 0)
j--;
}
if (i <= j)
{
string holdover = primary[i];
primary[i] = primary[j];
primary[j] = holdover;
if (type == "first")
{
holdover = last[i];
last[i] = last[j];
last[j] = holdover;
}
else
{
holdover = first[i];
first[i] = first[j];
first[j] = holdover;
}
DateTime holdoverBeta = bDay[i];
bDay[i] = bDay[j];
bDay[j] = holdoverBeta;
i++;
j--;
}
}
if (j > left)
primary = quikSortStr(primary, type, mode, left, j);
if (i < right)
primary = quikSortStr(primary, type, mode, i, right);
}
return primary;
}
I did not find a solution for the second issue per se. I did, however, discover that all of the elements that read ",,1/1/0001" were added, and did not replace any names. Using this, I added to the array lines only the index values that did not contain "1/1/0001". I then used lines = lines.Where(s => s != null).ToArray(); to shorten lines by eliminating all of the now null-type values. The modified function is below.
private void write()
{
string[] lines = new string[first.Length];
for (int i = 0; i < lines.Length; i++)
if (bDay[i].ToString(format) != "1/1/0001")
lines[i] = first[i] + ',' + last[i] + ',' + bDay[i].ToString(format);
lines = lines.Where(s => s != null).ToArray();
txtbxNames.Clear();
txtbxNames.Lines = lines;
}
Thanks for the help. I found the resource for my solution here.
EDIT: It seems the problem is inherent in StreamReader.ReadToEnd(). I'm not sure why, but it can be completely avoided by using System.IO.File.ReadAllLines(filepath). In the original code, I would replace
StreamReader file = new StreamReader(name);
lines = file.ReadToEnd().Split('\n');
with
lines = File.ReadAllLines(name);
and add using System.IO;.

how to make a dictionary that can hold more than 1 data?

i've been trying to modify the program so that it could accept more than one data for a single alphabet character for example letter "A". there were some sort of ContainsKey function that allow only one key from keyboard to hold only one data. how to make it possible to hold more than one data?
I'm gonna make it very clear, this is an online OCR program using unsupervised neural network. when a user draw a character in the drawing space, they will have the option to add the character into the learning data to be train later. when they add a character, they have to define what character they just entered using the key on the keyboard. for example, they draw letter 'A' and a popup window will show up asking the user to enter the key from the keyboard for that letter.
the problem here, when there is already a letter 'A' in the learning data, i cannot add another letter 'A' bcause the key A is already hold the previous 'A'. i wanted to make the key A is able to hold more than one letter 'A'.
im gonna post the whole code for the program here and i hope u guys bear with me. this isnt my program, it is from Heaton Research and i just intend to modify it. thank in advance.
public partial class Form1 : Form
{
/**
* The downsample width for the application.
*/
const int DOWNSAMPLE_WIDTH = 10;
/**
* The down sample height for the application.
*/
const int DOWNSAMPLE_HEIGHT = 12;
private Bitmap entryImage;
private Graphics entryGraphics;
private int entryLastX;
private int entryLastY;
private Pen blackPen;
private bool[] downsampled;
private Dictionary<char, List<bool[]>> letterData = new Dictionary<Char, List<bool[]>>();
private double[][] trainingSet;
private SelfOrganizingMap network;
public Form1()
{
InitializeComponent();
blackPen = new Pen(Color.Black);
entryImage = new Bitmap(entry.Width, entry.Height);
entryGraphics = Graphics.FromImage(entryImage);
downsampled = new bool[Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH];
ClearEntry();
}
private void entry_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(entryImage, 0, 0);
Pen blackPen = new Pen(Color.Black);
g.DrawRectangle(blackPen, 0, 0, entry.Width - 1, entry.Height - 1);
}
private void btnDelete_Click(object sender, EventArgs e)
{
string str = (string)this.letters.Items[this.letters.SelectedIndex];
char ch = str[0];
this.letterData.Remove(ch);
this.letters.Items.Remove(str);
ClearEntry();
}
private void btnLoad_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Data File (*.dat)|*.dat";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
TextReader f = new StreamReader(openFileDialog1.FileName);
String line;
this.letterData.Clear();
this.letters.Items.Clear();
while ((line = f.ReadLine()) != null)
{
int sampleSize = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
char ch = char.ToUpper(line[0]);
bool[] sample = new bool[sampleSize];
int idx = 2;
for (int i = 0; i < sampleSize; i++)
{
if (line[idx++] == '1')
sample[i] = true;
else
sample[i] = false;
}
this.letterData.Add(ch, sample);
this.letters.Items.Add("" + ch);
}
f.Close();
}
MessageBox.Show(this, "File Loaded");
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
private void btnSave_Click(object sender, EventArgs e)
{
try
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "Data File (*.dat)|*.dat";
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
TextWriter f = new StreamWriter(saveFileDialog1.FileName);
int size = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
for (int i = 0; i < this.letters.Items.Count; i++)
{
char ch = ((string)this.letters.Items[i])[0];
bool[] data = this.letterData[ch];
f.Write(ch + ":");
for (int j = 0; j < size; j++)
{
f.Write(data[j] ? "1" : "0");
}
f.WriteLine("");
}
f.Close();
MessageBox.Show("File Saved");
}
}
catch (Exception e2)
{
MessageBox.Show("Error: " + e2.Message, "Training");
}
}
private void btnBeginTraining_Click(object sender, EventArgs e)
{
int inputCount = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
int letterCount = this.letters.Items.Count;
this.trainingSet = new double[letterCount][];
int index = 0;
foreach (char ch in this.letterData.Keys)
{
this.trainingSet[index] = new double[inputCount];
bool[] data = this.letterData[ch];
for (int i = 0; i < inputCount; i++)
{
this.trainingSet[index][i] = data[i] ? 0.5 : -0.5;
}
index++;
}
network = new SelfOrganizingMap(inputCount, letterCount, NormalizationType.Z_AXIS);
this.ThreadProc();
}
private void btnAdd_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
String Prompt = "Enter the letter you just draw (from the keyboard)";
String Title = "Letter definition Required";
String Default = " ";
Int32 XPos = ((SystemInformation.WorkingArea.Width / 2) - 200);
Int32 YPos = ((SystemInformation.WorkingArea.Height / 2) - 100);
bool valid = false;
for (int i = 0; i < this.downsampled.Length; i++)
{
if (this.downsampled[i])
{
valid = true;
}
}
if (!valid)
{
MessageBox.Show("Please draw a letter before adding it.");
return;
}
String Result = Microsoft.VisualBasic.Interaction.InputBox(Prompt, Title, Default, XPos, YPos);
if (Result != null)
{
Result = Result.ToUpper();
if (Result.Length == 0)
{
MessageBox.Show("Please enter a character.");
}
else if (Result.Length < 1)
{
MessageBox.Show("Please enter only a single character.");
}
//else if (this.letterData.ContainsKey(Result[0]))
//{
// MessageBox.Show("That letter is already defined, please delete first.");
//}
else
{
if (this.letterData.ContainsKey(Result[0]))
{
this.letterData[Result[0]].Add(this.downsampled);
}
else
{
this.letterData.Add(Result[0], new List<bool[]>() {this.downsampled});
}
this.letters.Items.Add(Result);
//this.letterData.Add(Result[0], this.downsampled);
this.ClearEntry();
}
}
}
private void btnRecognize_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
if (this.network == null)
{
MessageBox.Show("The program needs to be trained first");
return;
}
int sampleSize = Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH;
double[] input = new double[sampleSize];
for (int i = 0; i < sampleSize; i++)
{
input[i] = this.downsampled[i] ? 0.5 : -0.5;
}
int best = this.network.Winner(input);
char[] map = mapNeurons();
this.result.Text = " " + map[best];
MessageBox.Show(" " + map[best] + " (Neuron #"
+ best + " fired)", "That Letter You Enter Is");
//ClearEntry();
}
private void btnClear_Click(object sender, EventArgs e)
{
ClearEntry();
}
private void btnSample_Click(object sender, EventArgs e)
{
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
}
public void ClearEntry()
{
Brush whiteBrush = new SolidBrush(Color.White);
entryGraphics.FillRectangle(whiteBrush, 0, 0, entry.Width, entry.Height);
entry.Invalidate();
DownSample ds = new DownSample(this.entryImage);
this.downsampled = ds.downSample(Form1.DOWNSAMPLE_WIDTH, Form1.DOWNSAMPLE_HEIGHT);
this.sample.Invalidate();
}
private void entry_MouseDown(object sender, MouseEventArgs e)
{
entry.Capture = true;
entryLastX = e.X;
entryLastY = e.Y;
}
private void entry_MouseUp(object sender, MouseEventArgs e)
{
entryGraphics.DrawLine(blackPen, entryLastX, entryLastY, e.X, e.Y);
entry.Invalidate();
entry.Capture = false;
}
private void entry_MouseMove(object sender, MouseEventArgs e)
{
if (entry.Capture == true)
{
entryGraphics.DrawLine(blackPen, entryLastX, entryLastY, e.X, e.Y);
entry.Invalidate();
entryLastX = e.X;
entryLastY = e.Y;
}
}
private void sample_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
int x, y;
int vcell = sample.Height / Form1.DOWNSAMPLE_HEIGHT;
int hcell = sample.Width / Form1.DOWNSAMPLE_WIDTH;
Brush whiteBrush = new SolidBrush(Color.White);
Brush blackBrush = new SolidBrush(Color.Black);
Pen blackPen = new Pen(Color.Black);
g.FillRectangle(whiteBrush, 0, 0, sample.Width, sample.Height);
for (y = 0; y < Form1.DOWNSAMPLE_HEIGHT; y++)
{
g.DrawLine(blackPen, 0, y * vcell, sample.Width, y * vcell);
}
for (x = 0; x < Form1.DOWNSAMPLE_WIDTH; x++)
{
g.DrawLine(blackPen, x * hcell, 0, x * hcell, sample.Height);
}
int index = 0;
for (y = 0; y < Form1.DOWNSAMPLE_HEIGHT; y++)
{
for (x = 0; x < Form1.DOWNSAMPLE_WIDTH; x++)
{
if (this.downsampled[index++])
{
g.FillRectangle(blackBrush, x * hcell, y * vcell, hcell, vcell);
}
}
}
g.DrawRectangle(blackPen, 0, 0, sample.Width - 1, sample.Height - 1);
}
private void letters_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.letters.SelectedIndex >= 0)
{
string str = (string)this.letters.Items[this.letters.SelectedIndex];
char ch = str[0];
this.downsampled = this.letterData[ch];
this.sample.Invalidate();
}
}
public void ThreadProc()
{
TrainSelfOrganizingMap train = new TrainSelfOrganizingMap(
this.network, this.trainingSet, TrainSelfOrganizingMap.LearningMethod.SUBTRACTIVE, 0.5);
int tries = 1;
do
{
train.Iteration();
this.txtTries.Text = "" + tries;
this.txtBestError.Text = "" + train.BestError;
this.txtLastError.Text = "" + train.TotalError;
tries++;
Application.DoEvents();
} while (train.TotalError > 0.01 && (tries <= 100));
MessageBox.Show("Training complete.");
}
/**
* Used to map neurons to actual letters.
*
* #return The current mapping between neurons and letters as an array.
*/
public char[] mapNeurons()
{
char[] map = new char[this.letters.Items.Count];
for (int i = 0; i < map.Length; i++)
{
map[i] = '?';
}
for (int i = 0; i < this.letters.Items.Count; i++)
{
double[] input = new double[Form1.DOWNSAMPLE_HEIGHT * Form1.DOWNSAMPLE_WIDTH];
char ch = ((string)(this.letters.Items[i]))[0];
bool[] data = this.letterData[ch];
for (int j = 0; j < input.Length; j++)
{
input[j] = data[j] ? 0.5 : -0.5;
}
int best = this.network.Winner(input);
map[best] = ch;
}
return map;
}
}
Dictionary<> is created in a such way that you can access Key Value pair in most efficient way. Now in Dictionary<> you can not have two pairs with same key. To do so,
what you can do, you create a dictionary like Dictionary<char, List<bool[]>>, now in this dictionary you can store one key with more than one value.
Update
If you change the dictionary to Dictionary<char, List<bool[]>> then to store one key with more than one value you will have to as follows
private bool[] downsampled;
private Dictionary<char, List<bool[]>> letterData = new Dictionary<Char, List<bool[]>>();
//
// Your Code
//
if (Result != null)
{
Result = Result.ToUpper();
if (Result.Length == 0)
{
MessageBox.Show("Please enter a character.");
}
else if (Result.Length < 1)
{
MessageBox.Show("Please enter only a single character.");
}
else
{
if (this.letterData.ContainsKey(Result[0]))
{
this.letterData[Result[0]].Add(this.downsampled);
}
else
{
this.letterData.Add(Result[0], new List<bool[]>() { this.downsampled });
}
this.letters.Items.Add(Result);
this.ClearEntry();
}
}
If you want to string as key, instead of char, use Dictionary<string, List<bool[]>>.
Hope this answers your question.
Take a look at the Lookup class in .Net. This lets you have the same "key" value multiple times.

Categories

Resources