How to read next line in csv file on button click - c++-cli

I have a windows form with two butttons and a text box. My start button reads the first line in the csv file and outputs the data I want into a textbox:
private: System::Void StartBtn_Click(System::Object^ sender, System::EventArgs^ e)
{
String^ fileName = "same_para_diff_uprn1.csv";
StreamReader^ din = File::OpenText(fileName);
String^ delimStr = ",";
array<Char>^ delimiter = delimStr->ToCharArray( );
array<String^>^ words;
String^ str = din->ReadLine();
words = str->Split( delimiter );
textBox1->Text += gcnew String (words[10]);
textBox1->Text += gcnew String ("\r\n");
textBox1->Text += gcnew String (words[11]);
textBox1->Text += gcnew String ("\r\n");
textBox1->Text += gcnew String (words[12]);
textBox1->Text += gcnew String ("\r\n");
textBox1->Text += gcnew String (words[13]);
Then my 'next button' I want it to clear the text box, and display the next lines data as above. Then everytime the next button is cliced, the textbox is cleared and the next line of the csv file is shown. Until I get to the end of the file. How would I manage that?
TIA

Your problem is that your button_click() function forgets the StreamReader object and all other variables after it has finished.
You need to make some of the variables (at least din) independent from the function, defining them as members of your WinForms object. Whenever you call the function, you can read the next line then. And you need to add a check whether din is nullptr (will be so at the first call), then load the file, otherwise just use it:
StreamReader^ din;
private: System::Void StartBtn_Click(System::Object^ sender, System::EventArgs^ e)
{
String^ fileName = "same_para_diff_uprn1.csv";
if (!din) // or: if (din == nullptr)
din = File::OpenText(fileName);
String^ delimStr = ",";
...

Related

Only output certain cells from .csv file into textbox windows form C++cli

I have a csv file with thousands of rows. However I want my program to read the first line on startbtn but only output certain cells. So for example my csv file has this in row 1:
test 1 test 2 test 3 1stat ignore test 1 test 2 test 3 1stat ignore
But I want my textbox to show only cells 1, 5 and 6 for example so my textbox looks like this:
test 1
ignore
test 1
The code I have so far is this:
private: System::Void StartBtn_Click(System::Object^ sender, System::EventArgs^ e) {
String^ fileName = "same_para_diff_uprn.csv";
StreamReader^ din = File::OpenText(fileName);
String^ str;
str = din->ReadLine();
array<Char>^chars = {','};
array<String^>^split = str->Split( chars );
IEnumerator^ myEnum = split->GetEnumerator();
while ( myEnum->MoveNext() )
{
String^ s = safe_cast<String^>(myEnum->Current);
if ( !s->Trim()->Equals( "" ) )
textBox1->Text += gcnew String (s);
}
}
TIA
String^ fileName = "same_para_diff_uprn1.csv";
StreamReader^ din = File::OpenText(fileName);
String^ delimStr = ",";
array<Char>^ delimiter = delimStr->ToCharArray( );
array<String^>^ words;
String^ str = din->ReadLine();
words = str->Split( delimiter );
textBox1->Text += gcnew String (words[10]);
textBox1->Text += gcnew String ("\r\n");

Why can't I get input from the ifstream?

I am trying to read in a text file for a maze program. The input is something like:
10 10
OO+E+OO+++
O++O+O+OOO
OOOOOO+O+O
+++++O++OO
OOO+OOO+O+
O+O+O+++O+
O+O+OOO+OO
++O+++O++O
O+OOOOO++O
O+O++O+OOO
When the user click on the open button, this opens a open file dialog box
{
openFileDialog1->InitialDirectory = "C:\Desktop;";
openFileDialog1->Filter = "Maze files (*.DAT)|*.DAT";
if (openFileDialog1->ShowDialog() == ::DialogResult::OK)
{
char filename[1024];
for (int i = 0; i < openFileDialog1->FileName->Length; i++)
{
filename[i] = openFileDialog1->FileName[i];
}
ifstream ifs;
ifs.open(filename); // NULL terminate this
maze = new Maze( panel1, ifs);
ifs.close();
}
}
the following is the maze constructor
Maze::Maze( Panel ^ drawingPanel, ifstream & ifs )
{
try
{
valid = false;
ifs >> width >> height;
int temp = width;
drawingPanel->Size.Width = width;
drawingPanel->Size.Height = height;
for (int i = 0; i < height; i++) // height is always nothing
for (int j = 0; j < width; j++)
{
if (orig[j][i] == DEADEND ||
orig[j][i] == OPEN ||
orig[j][i] == EXIT )
ifs >> orig[j][i]; // NULLS????
else
throw 'D'; // i had to throw something....so i threw the D /* make a slit class and throw the D there? slit.fill(D); */
}
// this should be last
panel = drawingPanel;
valid = true;
}
catch (...)
{
valid = false;
MessageBox::Show( "Not a proper maze file!" );
}
}
when the program runs: ifs >> width >> height width and height do not get set correctly.
I have searched this site for this problem and have not been able to find anything that has helped. Sorry for my inexperience, any help is greatly appreciated.
You'e program very ugly : don't know if you're programming in C or C++ or C++/CLI, or try to mix the 3...
Because you use Windows Form projet, i will give you a .Net solution for read a file, it's not the better solution but this does not mix things.
First for read the file, on a first window :
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
openFileDialog1->Filter = "Maze Files (*.dat) | *.dat";
if (openFileDialog1->ShowDialog() == ::DialogResult::OK)
{
String ^fileName = openFileDialog1->FileName;
IO::StreamReader ^myMazeFile = gcnew IO::StreamReader(fileName);
String ^content = myMazeFile->ReadToEnd();
richTextBox1->Text = content;
myMazeFile->Close();
// display button for open second form wich draw maze
button2->Visible = true;
}
}
now we have our file content, so we pass it to a second form who will draw the maze :
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e)
{
String ^content = richTextBox1->Text;
Maze ^frm = gcnew Maze(content);
frm->Show();
}
Second window, create overload constructor :
Maze(String ^contentMap)
{
InitializeComponent();
String ^dimension = getWords(contentMap, 2);
array<String ^> ^coordsString = dimension->Split(gcnew array<Char> {' '});
m_width = Convert::ToInt32(coordsString[0]);
m_height = Convert::ToInt32(coordsString[1]);
panel1->Width = m_width;
panel1->Height = m_height;
}
getWords method :
String ^getWords(String ^input, int numWords)
{
try
{
int words = numWords;
for (int i = 0; i < input->Length; ++i)
{
if (input[i] == ' ' ||input[i] == '\n')
words--;
if (words == 0)
{
return input->Substring(0, i);
}
}
}
catch (Exception ^ex)
{
// ...
}
return String::Empty;
}
You have your dimension in full .Net (private member m_width and m_height).

Edit file content

In Form1 I have 2 TextBoxes(surname and name). When I push the "register" button I write them into a file through TextWriter. Every line contains surname and name, So there are 2 fields per line.
In Form2 I want to edit them by asking a parameter. For example in Form2 I have one TextBox. If the surname I type into the TextBox is equal to one from my file, i want to show surname and name in correct TextBoxes in Form1, and after editing surname or name I want to overwrite previous line in the correct place by pushing the "register" button.
Thanks to user Medinoc I write the file like this:
ref class MyClass
{
public:
String^ cognome;
String^ nome;
};
//...
List<MyClass^>^ primo = gcnew List<MyClass^>();
//...
MyClass^ myObj = gcnew MyClass();
myObj->cognome = textBox1->Text;
myObj->nome = textBox2->Text;
primo->Add(myObj);
//...
TextWriter ^tw = gcnew StreamWriter(L"primoAnno.txt", true);
for each(MyClass^ obj in primo)
{
//You can use any character or string as separator,
//as long as it's not supposed to appear in the strings.
//Here, I used pipes.
tw->Write(obj->cognome);
tw->Write(L"|");
tw->Write(obj->nome);
}
tw->Close();
READ
MyClass^ ParseMyClass(String^ line)
{
array<String^>^ splitString = line->Split(L'|');
MyClass^ myObj = gcnew MyClass();
myObj->cognome = splitString[0];
myObj->nome = splitString[1];
return myObj;
}
Hope I was clear enough. I'm not english.
Thanks in advance!!
It's still classic text file editing behavior:
What you need is a function to search for a particular line in the file; and another function to modify a particular line. That one will be similar to the deleting code.
Find:
MyClass^ FindMyClass(String^ surnameToFind)
{
MyClass^ found = nullptr;
TextReader^ tr = gcnew StreamReader(L"primoAnno.txt");
String^ line;
while(found == nullptr && (line=tr->ReadLine()) != nullptr)
{
MyClass^ obj = ParseMyClass(line);
if(obj->cognome == surnameToFind)
found = surnameToFind;
}
tr->Close();
}
Update:
MyClass^ objToUpdate = gcnew MyClass;
objToUpdate->cognome = textBox1->Text;
objToUpdate->nome = textBox2->Text;
TextWriter^ tw = gcnew StreamWriter(L"primoAnno2.txt", true);
TextReader^ tr = gcnew StreamReader(L"primoAnno.txt");
String^ line;
bool updated = false;
while((line=tr->ReadLine()) != nullptr)
{
MyClass^ obj = ParseMyClass(line);
if(obj->cognome == objToUpdate->cognome)
{
line = objToUpdate->cognome + L"|" + objToUpdate->nome;
updated = true;
}
tw->WriteLine(line);
}
//If the surname was not in the file at all, add it.
if(!updated)
{
line = objToUpdate->cognome + L"|" + objToUpdate->nome;
tw->WriteLine(line);
}
tr->Close();
tw->Close();
File::Delete(L"primoAnno.txt");
File::Move(L"primoAnno2.txt", L"primoAnno.txt");

How to display global variable on messagebox?

This is written code,
void horizontal_calculate()
{
String ^aa = filenames[0];
std::string file1(marshal_as<std::string>(aa));
String ^bb = filenames[1];
std::string file2(marshal_as<std::string>(bb));
double Result3=horizontal_read(file1);
double Result4=horizontal_read(file2);
double result=Result3/Result4;
result1=result;
System::Diagnostics::Debug::WriteLine("{0}",result);
}
private: System::Void button4_Click(System::Object^ sender, System::EventArgs^ e) {
for (int i = 0; i < filenames->Length; i++)
System::Diagnostics::Debug::WriteLine(filenames[i]);
semicircle();
horizontal_calculate();
oblique();
MessageBox::Show("Time Ratio = "result1"","Screening Result",MessageBoxButtons::OK, MessageBoxIcon::Information);
}
I have declared double=result1 as global variable.
It comes out an error "error C2146: syntax error : missing ')' before identifier 'result1'", so how am I going to solve this?
is it needed and how's the way to convert double to string?
Thanks all.
If the problem is in MessageBox line, write it by the following way:
MessageBox::Show(
String::Format("Time Ratio = {0}", result1),
"Screening Result",
MessageBoxButtons::OK, MessageBoxIcon::Information);

StyledDocument adding extra count to indexof for each line of file

I have a strange problem (at least it appears that way) that when searching for a string in a textPane, I get an extra index for each line number that is searched and returned when using StyledDoc verses just getting the text from a textPane. I get the same text from the same pane, it's just that one is from the plain text the other is from the styled doc. Am I missing something here. I'll try to list as many of the changes between the two versions I am working with.
The plain text version:
public int displayXMLFile(String path, int target){
InputStreamReader inputStream;
FileInputStream fileStream;
BufferedReader buffReader;
if(target == 1){
try{
File file = new File(path);
fileStream = new FileInputStream(file);
inputStream = new InputStreamReader(fileStream,"UTF-8");
buffReader = new BufferedReader(inputStream);
StringBuffer content = new StringBuffer("");
String line = "";
while((line = buffReader.readLine())!=null){
content.append(line+"\n");
}
buffReader.close();
xhw.txtDisplay_1.setText(content.toString());
}
catch(Exception e){
e.printStackTrace();
return -1;
}
}
}
verses the Styled Doc (without the styles applied)
protected void openFile(String path, StyledDocument sDoc, int target)
throws BadLocationException {
FileInputStream fileStream;
String file;
if(target == 1){
file = "Openning First File";
} else {
file = "Openning Second File";
}
try {
fileStream = new FileInputStream(path);
// Get the object of DataInputStream
//DataInputStream in = new DataInputStream(fileStream);
ProgressMonitorInputStream in = new ProgressMonitorInputStream(
xw.getContentPane(), file, fileStream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
sDoc.insertString(sDoc.getLength(), strLine + "\n", sDoc.getStyle("regular"));
xw.updateProgress(target);
}
//Close the input stream
in.close();
} catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
This is how I search:
public int searchText(int sPos, int target) throws BadLocationException{
String search = xhw.textSearch.getText();
String contents;
JTextPane searchPane;
if(target == 1){
searchPane = xhw.txtDisplay_1;
} else {
searchPane = xhw.txtDisplay_2;
}
if(xhw.textSearch.getText().isEmpty()){
xhw.displayDialog("Nothing to search for");
highlight(searchPane, null, 0,0);
} else {
contents = searchPane.getText();
// Search for the desired string starting at cursor position
int newPos = contents.indexOf( search, sPos );
// cycle cursor to beginning of doc window
if (newPos == -1 && sPos > 0){
sPos = 0;
newPos = contents.indexOf( search, sPos );
}
if ( newPos >= 0 ) {
// Select occurrence if found
highlight(searchPane, contents, newPos, target);
sPos = newPos + search.length()+1;
} else {
xhw.displayDialog("\"" + search + "\"" + " was not found in File " + target);
}
}
return sPos;
}
The sample file:
<?xml version="1.0" encoding="UTF-8"?>
<AlternateDepartureRoutes>
<AlternateDepartureRoute>
<AdrName>BOIRR</AdrName>
<AdrRouteAlpha>..BROPH..</AdrRouteAlpha>
<TransitionFix>
<FixName>BROPH</FixName>
</TransitionFix>
</AlternateDepartureRoute>
<AlternateDepartureRoute>
</AlternateDepartureRoutes>
And my highlighter:
public void highlight(JTextPane tPane, String text, int position, int target) throws BadLocationException {
Highlighter highlighter = new DefaultHighlighter();
Highlighter.HighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(Color.LIGHT_GRAY);
tPane.setHighlighter(highlighter);
String searchText = xhw.textSearch.getText();
String document = tPane.getText();
int startOfSString = document.indexOf(searchText,position);
if(startOfSString >= 0){
int endOfSString = startOfSString + searchText.length();
highlighter.addHighlight(startOfSString, endOfSString, painter);
tPane.setCaretPosition(endOfSString);
int caretPos = tPane.getCaretPosition();
javax.swing.text.Element root = tPane.getDocument().getDefaultRootElement();
int lineNum = root.getElementIndex(caretPos) +1;
if (target == 1){
xhw.txtLineNum1.setText(Integer.toString(lineNum));
} else if (target == 2){
xhw.txtLineNum2.setText(Integer.toString(lineNum));
} else {
xhw.txtLineNum1.setText(null);
xhw.txtLineNum2.setText(null);
}
} else {
highlighter.removeAllHighlights();
}
}
When I do a search for Alt with the indexof() I get 40 for the plain text (which is what it should return) and 41 when searching with the styled doc. And for each additional line that Alt appears on I get and extra index (so that the indexof() call returns 2 more then needed in line 3). This happens for every additional line that it finds. Am I missing something obvious? (If I need to push this to a smaller single class to make it easier to check I can do this later when I have some more time).
Thanks in advance...
If you are on Windows, then the TextComponent text (searchPane.getText()) can contain carriage-return+newline characters (\r\n), but the TextComponent's Styled Document (sSearchPane.getText(0, sSearchPane.getLength())) contains only newline characters (\n). That's why your newPos is always larger than newPosS by the number of newlines at that point. To fix this, in your search function you can change:
contents = searchPane.getText();
to:
contents = searchPane.getText().replaceAll("\r\n","\n");
That way the search occurs with the same indices that the Styled Document is using.
OK I have found a solution (basicly). I approached this from the aspect that I am getting text from the same text componet in two different ways...
String search = xw.textSearch.getText();
String contents;
String contentsS;
JTextPane searchPane;
StyledDocument sSearchPane;
searchPane = xw.txtDisplay_left;
sSearchPane = xw.txtDisplay_left.getStyledDocument();
contents = searchPane.getText();
contentsS = sSearchPane.getText(0, sSearchPane.getLength());
// Search for the desired string starting at cursor position
int newPos = contents.indexOf( search, sPos );
int newPosS = contentsS.indexOf(search, sPos);
So when comparing the two variables "newPos" & "newPosS", newPos retruned 1 more then newPosS for each line that the search string was found on. So when looking at the sample file and searching for "Alt" the first instance is found on line 2. "newPos" returns 41 and "newPosS returns 40 (which then highlights the correct text). The next occurance (which is found in line 3) "newPos" returns 71 and "newPosS" returns 69. As you can see, every new line increases the count by the line number the occurance begins in. I would suspect that there is an extra character being added in for each new line from the textPane that is not present in the StyledDoc.
I'm sure there is a reasonable explaination but I don't have it at this time.