C#, splitting serial data and displaying in separate textBox's - c#

I have the following code and i would like to split the incoming serial data into pieces and display the individual parts in separate textboxes. The incoming serial data is
angle1:angle2:value1:value2:value3:value4
where
angle1 has values ranging from -90 to 90
angle2 ranges from 0 to 90
value1 value2 value3 value4 from 0 to 1024
So I would like to display each of these in different textboxes.
This is what I have so far which displays the whole incoming string in a single textbox.
Any help, idea and tip is highly appreciated since I'm a complete newbie to c#.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public static System.IO.Ports.SerialPort port;
delegate void SetTextCallback(string text);
private BackgroundWorker hardWorker;
private Thread readThread = null;
public Form1()
{
InitializeComponent();
hardWorker = new BackgroundWorker();
string[] ports = SerialPort.GetPortNames();
comboBox1.Items.AddRange(ports);
}
private void Form1_Load(object sender, EventArgs e) {}
private void SetText(string text)
{
if (this.receiveText.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
//this.receiveText.Text += "";
this.receiveText.Text += text;
this.receiveText.Text += Environment.NewLine;
}
}
public void Read()
{
while (serialPort2.IsOpen)
{
try{
if (serialPort2.BytesToRead > 0)
{
Thread.Sleep(1000);
string message = serialPort2.ReadLine();
this.SetText(message);
}
}
catch (TimeoutException) { }
}
}
private void start_Click(object sender, EventArgs e)
{
System.ComponentModel.IContainer components = new System.ComponentModel.Container();
if (comboBox1.SelectedIndex > -1)
{
string port = (string)comboBox1.SelectedItem;
serialPort2.PortName = port;
serialPort2.BaudRate = 9600;
serialPort2.DtrEnable = true;
serialPort2.ReadTimeout = 1000;
serialPort2.WriteTimeout = 500;
serialPort2.Open();
readThread = new Thread(new ThreadStart(this.Read));
readThread.Start();
this.hardWorker.RunWorkerAsync();
}
}
private void receiveText_TextChanged(object sender, EventArgs e)
{
receiveText.SelectionStart = receiveText.Text.Length;
receiveText.ScrollToCaret();
receiveText.Refresh();
}
}
}
SOLVED by changing the following:
private void SetText(string text)
{
if (this.receiveText.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
string[] newData = text.Split(':');
boxLR.Text = newData[0];
boxUD.Text = newData[1];
boxldrright.Text = newData[2];
boxldrleft.Text = newData[3];
boxldrup.Text = newData[4];
boxldrdown.Text = newData[5];
}
}
Thank you everyone for your help.

First thing first, you need to split your string to get all different values as individual string.
In your SetText() function;
string[] slist = text.Split(':');
Now if you have all required text box then you can assign value for string array to different text box.
Or else
if you are creating text box runtime then you have to create new text box as per length of slist array, then assign value to new text boxes.
Hope it helps..!!!

You can use the this.receivedText.Text.Split(':') function to split the received text string into an array of string, which you then can use to assign to the different text boxes individually.
In addition to this, you could also create a method, that takes the array as a parameter, to check the various value constraints.

If the length of the values are the same you can use
public void CopyTo( int sourceIndex, char[] destination, int destinationIndex, int count )

Related

C# Windows form application how to delete selected listbox line and text file

I have problem with one function. Function "Usun" must delete both line in listbox and the same data from txt file** Can anyone help me?
using System;
namespace BazaKlientow2
{
public partial class Form1 : Form
{
private Klient[] lista = new Klient[1];
public Form1()
{
InitializeComponent();
}
private void Write(Klient obj)
{
StreamWriter sw = new StreamWriter("Klienci.txt");
sw.WriteLine(lista.Length + 1);
sw.WriteLine(obj.Imie);
sw.WriteLine(obj.Nazwisko);
sw.WriteLine(obj.Firma);
sw.WriteLine(obj.NIP);
for(int x = 0; x <lista.Length; x++)
{
sw.WriteLine(lista[x].Imie);
sw.WriteLine(lista[x].Nazwisko);
sw.WriteLine(lista[x].Firma);
sw.WriteLine(lista[x].NIP);
}
sw.Close();
}
private void Read()
{
StreamReader sr = new StreamReader("Klienci.txt");
lista = new Klient[Convert.ToInt32(sr.ReadLine())];
for (int x = 0; x < lista.Length; x++)
{
lista[x] = new Klient();
lista[x].Imie = sr.ReadLine();
lista[x].Nazwisko = sr.ReadLine();
lista[x].Firma = sr.ReadLine();
lista[x].NIP = sr.ReadLine();
}
sr.Close();
}
private void Display()
{
listaKlientow.Items.Clear();
for( int x=0; x < lista.Length; x++)
{
listaKlientow.Items.Add(lista[x].ToString());
}
}
private void ClearForm()
{
txtImie.Text = String.Empty;
txtNazwisko.Text = String.Empty;
txtFirma.Text = String.Empty;
txtNip.Text = String.Empty;
}
private void dodaj_Click(object sender, EventArgs e)
{
Klient obj = new Klient();
obj.Imie = txtImie.Text;
obj.Nazwisko = txtNazwisko.Text;
obj.Firma = txtFirma.Text;
obj.NIP = txtNip.Text;
Write(obj);
Read();
Display();
ClearForm();
}
private void Form1_Load(object sender, EventArgs e)
{
Read();
Display();
}
private void sortuj_Click(object sender, EventArgs e)
{
Sortowanie();
Display();
}
private void Sortowanie()
{
Klient temp;
bool swap;
do
{
swap = false;
for(int x=0;x<lista.Length -1;x++)
{
if(lista[x].Imie.CompareTo(lista[x+1].Nazwisko) >0)
{
temp = lista[x];
lista[x] = lista[x + 1];
lista[x + 1] = temp;
swap = true;
}
}
} while (swap == true);
}
private void usun_Click(object sender, EventArgs e)
{
Usun();
}
private void Usun()
{
**//i cant do this. this function must delete both line in listbox and the same data from txt file**
}
}
}
Function "Usun" must delete both line in listbox and the same data from txt file** Can anyone help me?
You need to read the lines from the file and store then in a List<string> memory. You also need to set the DataSource property of the ListBox to those lines. When you want to remove a line, remove it from the List<string> in memory. Then write the whole list back to the file. Then reset the DataSource property of the ListBox.
Here is an example. In this example, I create a file with "1", "2" and "3" as the lines. Then when the user clicks a button, I remove "1" from the list in memory and write the list to the file. Then I refresh the listbox.
public partial class Form1 : Form {
private List<string> linesInFile;
public Form1() {
InitializeComponent();
File.WriteAllLines( "Lines.txt", new string[] { "1", "2", "3" } );
this.linesInFile = File.ReadAllLines( "Lines.txt" ).ToList();
this.listBox1.DataSource = this.linesInFile;
}
private void Remove_Click(object sender, EventArgs e) {
this.linesInFile.Remove( "1" );
File.WriteAllLines( "Lines.txt", this.linesInFile );
this.listBox1.DataSource = null;
this.listBox1.DataSource = this.linesInFile;
}
}

Display arduino analogRead() in real time in C# using thread

I'm making a C# program to work like a poor oscilloscope. I have an Arduino which sends to serial (Serial.write(analogRead(A0)) ) and then the C# has a thread which reads each ms a sample while the main thread refreshes the Chart. My doubt is, should I use Serial.write or Serial.print ?
Is it possible to get 2kS/s ? I'm using the baud rate of 115200 and here is the code.
namespace TEST
{
public partial class Form1 : Form
{
static int buffer_size = 1024;
public static string comboBoxText;
public static int[] buffer = new int[buffer_size];
IEnumerable<int> yData;
static int[] range = Enumerable.Range(0, buffer_size).ToArray();
IEnumerable<int> xData = range;
public static bool flag = true;
public Form1()
{
Random rand = new Random();
InitializeComponent();
for (int c = 0; c<buffer_size;c++) {
buffer[c] = 0;
}
Thread thread1 = new Thread(fillBuffer);
thread1.Start();
comboBox1.Items.Add("Select");
foreach (string s in SerialPort.GetPortNames())
{
comboBox1.Items.Add(s);
}
}
static public void fillBuffer()
{
Thread.Sleep(1000);
SerialPort serialPort1 = new SerialPort();
serialPort1.PortName = "COM5";
serialPort1.BaudRate = 115200;
serialPort1.Open();
while (true)
{
}
}
private void timer1_Tick(object sender, EventArgs e)
{
yData = buffer;
chart1.Series[0].Points.DataBindY(yData);
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try {
comboBoxText = comboBox1.Text;
}
catch
{
MessageBox.Show("Porta Inválida");
return;
}
comboBox1.Enabled = false;
}
}
Is there anything I can do to sample each 0.5ms and then display the sample as a collection of points ? I'm not getting good results. If anyone can help, thank you!
At a Baudrate of 115200 and a good processor speed, your algorithm seem fast enough. But one of the things that can slow down the speed is the interval of timer1. It should be set to the lowest possible. Also for the difference between Serial.Write and Serial.Print check out this forum . Also using the .net inbuilt serial port event handler would save you a lot of stress and is also a faster and more efficient solution. You might want to check it out here

How to remove the last character typed in a textbox

I want to remove the last character someone types in a textbox.
For example if someone types in an empty textbox "abcd", i want to remove the letter "d", or if in a textbox containing "abcd", the user types a 1 like in here: "ab1cd", i want to remove that 1
Listen to the TextChanged event of the textbox, and save the change that happened:
public partial class MainWindow : Window
{
private ICollection<TextChange> _latestChange = null;
public MainWindow()
{
InitializeComponent();
myTextBox.TextChanged += (o, a) =>
{
_latestChange = a.Changes;
};
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (_latestChange != null)
{
var change = _latestChange.FirstOrDefault(); // Just take first change
if (change.AddedLength > 0) // If text was removed, ignore
{
myTextBox.Text = myTextBox.Text.Remove(change.Offset, change.AddedLength);
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
string newstring = textBox1.Text;
for(int i = 0; i<=9; i++)
{
if(newstring.Contains(i.ToString()))
{
int start = newstring.IndexOf(i.ToString());
newstring = newstring.Remove(start, 1);
}
}
textBox1.Text = newstring.Remove(newstring.Length - 1);
}
This will remove the last letter and any kind of number in the string. Hope it helps.

Where to declare queues in separate event handlers

Hi I am trying to use the queue function in my program for a mini game that receives X,Y,Z acceleration from an accelerometer.
However I don't know where I should or how I should declare the queue to make it accessible in two separate event handler.
As you can see I tried multiple attempts and declaring it in both the private event handlers was my last attempt.
Any help is appreciated. Thanks!
Here's my current code:
public Form1()
{
InitializeComponent();
ConnectedComPortUpdate();
serialPort1.DataReceived += DataReceivedHandler;
comboBox1.DropDown += comboBox1_DropDown;
}
private void comboBox1_DropDown(object sender, EventArgs e)
{
ConnectedComPortUpdate();
}
private void Clock_Tick(object sender, EventArgs e)
{
int xAccel;
int yAccel;
int zAccel;
Queue<int> myXQueue = new Queue<int>();
Queue<int> myYQueue = new Queue<int>();
Queue<int> myZQueue = new Queue<int>();
while( myXQueue.Count!=0 && myYQueue.Count!=0 && myZQueue.Count!=0 );
{
xAccel = myXQueue.Dequeue();
yAccel = myYQueue.Dequeue();
zAccel = myZQueue.Dequeue();
this.BeginInvoke(new EventHandler(delegate
{
XAccel.Text = xAccel.ToString("000");
YAccel.Text = yAccel.ToString("000");
ZAccel.Text = zAccel.ToString("000");
}));
}
}
private void ConnectedComPortUpdate()
{
//Clears COM List
comboBox1.Items.Clear();
//Accesses System Port Information and Adds it to the ComboBox
comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames().ToArray());
//Selects the last and "first" device
try
{
comboBox1.SelectedIndex = 0;
}
catch (ArgumentOutOfRangeException)
{
MessageBox.Show("Please plug in your tiny stick");
comboBox1.Text = (" ");
}
}
private void button1_Click(object sender, EventArgs e)
{
if (!serialPort1.IsOpen)
{
try
{
serialPort1.PortName = comboBox1.Text;
serialPort1.Open();
comboBox1.Enabled = false;
butPortState.Text = "Disconnect";
MessageBox.Show(String.Format("You selected port '{0}'", serialPort1.PortName));
}
catch
{
MessageBox.Show("Please select a serial port from the drop down list");
}
}
else
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
comboBox1.Enabled = true;
butPortState.Text = "Connect";
}
}
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
int currentDataByte = 0;
int byteToRead;
int xAccel = 0;
int yAccel = 0;
int zAccel = 0;
Queue<int> myXQueue = new Queue<int>();
Queue<int> myYQueue = new Queue<int>();
Queue<int> myZQueue = new Queue<int>();
while (serialPort1.IsOpen && serialPort1.BytesToRead != 0)
{
try
{
byteToRead = serialPort1.ReadByte();
}
catch
{
byteToRead = 0;
}
if (byteToRead == 255)
{
currentDataByte = 0;
}
else
{
currentDataByte++;
switch (currentDataByte)
{
case 1:
myXQueue.Enqueue(byteToRead);
xAccel = byteToRead;
break;
case 2:
myYQueue.Enqueue(byteToRead);
yAccel = byteToRead;
break;
case 3:
myZQueue.Enqueue(byteToRead);
zAccel = byteToRead;
break;
}
}
}
}
}
}
You would need the queues to be declared at the class/instance level:
// These can now be used in all event handlers...
Queue<int> myXQueue = new Queue<int>();
Queue<int> myYQueue = new Queue<int>();
Queue<int> myZQueue = new Queue<int>();
public Form1()
{
InitializeComponent();
ConnectedComPortUpdate();
serialPort1.DataReceived += DataReceivedHandler;
comboBox1.DropDown += comboBox1_DropDown;
}
private void comboBox1_DropDown(object sender, EventArgs e)
{
ConnectedComPortUpdate();
}
private void Clock_Tick(object sender, EventArgs e)
{
int xAccel;
int yAccel;
int zAccel;
I don't think the answer to this question (or even the question itself) is C# specific necessarily. Consider the question "Where should I declare variable X" The answer is almost always "In the narrowest scope possible that's accessible every place that needs to use variable X"
In your case, the answer may be "At the class level"
Alternatively, if you were to program in a more functional style the answer may be "Reconsider the structure of the program so that X can be passed as a parameter to the functions that need it". Most C# event handler have a place where you can stick a "user state" object so that it can be passed along from event source to event handler.
The answer would be the same in C, C++, java, etc.
(Perhaps this should be a comment, but I'm afraid it's a bit long)

Cannot Add Dynamically Generated Textbox's Text To A List (C#)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Mod
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int c = 0;
private void button1_Click(object sender, EventArgs e)
{
TextBox txtRun = new TextBox();
txtRun.Name = "txtDynamic" + c++;
txtRun.Location = new System.Drawing.Point(20, 18 + (20 * c));
txtRun.Size = new System.Drawing.Size(200,15);
this.Controls.Add(txtRun);
}
private void button2_Click(object sender, EventArgs e)
{
List<string>tilelocation = List<string>();
tilelocation.Add(); //What goes in this method's arguments?
}
}
}
Here is my code. Button1 creates a theoretically infinite # of textboxes, but I wish to add the text in these dynamically generated textboxes to a list. How can this be done?
[EDIT]
And how can I display them all in a messagebox, each on separate lines?
You need to keep a reference to the control.
The other secret is that you have to keep it in the ViewState so it's available between post backs.
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
int c = 0;
private List<TextBox _lstTextBoxList;
public List<TextBox> lstTextBoxList {
get {
if(_lstTextBoxList == null) {
_lstTextBoxList = ViewState["lstTextBoxList"] as List<TextBox>;
}
return _lstTextBoxList;
}
set { ViewState["lstTextBoxList"] = _lstTextBoxList = value; }
}
private void button1_Click(object sender, EventArgs e) {
TextBox txtRun = new TextBox();
txtRun.Name = "txtDynamic" + c++;
txtRun.Location = new System.Drawing.Point(20, 18 + (20 * c));
txtRun.Size = new System.Drawing.Size(200,15);
this.Controls.Add(txtRun);
lstTextBoxList.Add(txtRun);
}
private void button2_Click(object sender, EventArgs e) {
// Not sure of your goal here:
List<string> tilelocation = List<string>();
tilelocation.Add(lstTextBoxList[lstTextBoxList.Count - 1]);
// I would assume you wanted this:
List<string> strValues = lstTextBoxList.Select<TextBox,string>(t => t.Text).ToList();
}
}
but I wish to add the text in these dynamically generated textboxes to
a list. How can this be done?
You should use new List<string> like:
private void button2_Click(object sender, EventArgs e)
{
List<string> tilelocation = new List<string>();
foreach(TextBox tb in this.Controls.OfType<TextBox>().Where(r=> r.Name.StartsWith("txtDynamic"))
titlelocation.Add(tb.Text);
//if you want a string out of it.
string str = string.Join(",", titlelocation);
MessageBox.Show(str);
}
EDIT: For each text on new line use:
string str = string.Join(Environment.NewLine, titlelocation);
MessageBox.Show(str);
I don't know why you want to use a seperate button2 click event to add the text. Why don't you use a global variable tilelocation, and add the text to this list in the button1_click event? Something like:
txtRun.Text=Your Text;
tilelocation.add(Your Text);
If you want to display them in a message box, then add codes:
string str="";
foreach(text in tilelocation)
{
str+=text;
}
MessageBox.Show(str);

Categories