FLTK output showing the latest input - c++

main.cpp
void torsoOPCB(Fl_Widget *w, void* p) {
for(std::size_t i=0; i < torso.size(); i++) {
cout << "Name: " << torso[i].GetName() << endl;
cout << "Part Number: " << torso[i].GetPartNumber() << endl << endl;
} // This loop is to check if the inputs are in the vector torso
dialog = new Fl_Window(340, 300, "Robot Part");
Fl_Multiline_Output* output = new Fl_Multiline_Output(100, 10, 400, 200, "Torso list:");
for(std::size_t i = 0; i < torso.size(); i++) {
output->value(torso[i].print().c_str());
}
dialog->end();
dialog->set_non_modal();
dialog->show();
}
I'm learning how to use FLTK in C++ and I'm not sure why it keeps showing me the latest user's inputs. For example, if I entered the inputs for torso[0] and torso[1], the output will only show torso[1] which is the latest input. The inputs are stored correctly I think but I'm not sure why it won't show both torso[0] and torso[1].
Here is my print fucntion
Torso.cpp
std::string Torso::print()
{
ostringstream of;
of << "Part name: " << GetName()
<< endl << "Part #: " << GetPartNumber()
<< endl << "Weight: " << GetWeight()
<< endl << "Cost: " << GetCost()
<< endl << "Battery Comp: " << GetDescription()
<< endl << "Description: " << GetBatteryCompartmentSize() << endl;
return of.str();
}
I'm using FLTK version 1.3.4. Thank you in advanced

You are only showing the very last item in
for(std::size_t i = 0; i < torso.size(); i++) {
output->value(torso[i].print().c_str());
}
The output value is always being overwritten. If you wish to show all the output, gather it up first before putting it into the widget
std::ostringstream oss;
for(std::size_t i = 0; i < torso.size(); i++) {
oss << torso[i].print() << "\n";
}
output->value(oss.str().c_str());
If you don't mind multiple outputs on the same line, change the "\n to ". "

Related

How to successfully write to a .DAT file contents in a vector using C++?

I'm trying to write to a .DAT file my list of saved patients that are stored in a vector named PatientsInSystem. However, it won't work for some reason. Does anyone know what I might be doing wrong?
if (!PatientsInSystem.empty()) {
cout << "Error. There are still patients checked in. They must be checked out before quitting." << endl;
cout << "Printing remaining patients in the system... " << endl;
for (int i = 0; i < PatientsInSystem.size(); i++) {
cout << "Patient's ID: " << PatientsInSystem.at(i)->getID() << endl;
cout << "Patient's Name: " << PatientsInSystem.at(i)->getFirstName() << " " << PatientsInSystem.at(i)->getLastName() << endl;
cout << "Patient's Birthday: " << PatientsInSystem.at(i)->getBirthDate() << endl;
cout << "Patient's Primary Doctor's ID: " << PatientsInSystem.at(i)->getPrimaryDoctorID() << endl;
}
}
else {
outFile.open("CurrentPatients.dat", ios::out | ios::binary);
if (!outFile.is_open()) {
cout << "File not open." << endl;
}
else {
cout << "Binary file open, saving patients now...\n";
cout << "----------------------------------------\n";
for (int i = 0; i < PatientsInSystem.size(); i++) {
Patient * p;
p = PatientsInSystem.at(i);
outFile.write(reinterpret_cast<char *> (&p), sizeof(p));
}
}
outFile.close();
[This next section of code is the same as above only edited after the first amount of help received]
Here is the edited version of the code...
PatientList is my temporary vector which must be emptied for PatientsInSystem vector to write to the file
case 'q': {
if (!PatientList.empty()) {
cout << "Error. There are still patients checked in. They must be checked out before quitting." << endl;
cout << "Printing remaining patients in the system... " << endl;
for (int i = 0; i < PatientList.size(); i++) {
cout << "Patient's ID: " << PatientList.at(i)->getID() << endl;
cout << "Patient's Name: " << PatientList.at(i)->getFirstName() << " " << PatientList.at(i)->getLastName() << endl;
cout << "Patient's Birthday: " << PatientList.at(i)->getBirthDate() << endl;
cout << "Patient's Primary Doctor's ID: " << PatientList.at(i)->getPrimaryDoctorID() << endl;
}
}
else {
outFile.open("CurrentPatients.dat", ios::out | ios::binary);
if (!outFile.is_open()) {
cout << "File not open." << endl;
}
else {
cout << "Binary file open, saving patients now...\n";
cout << "----------------------------------------\n";
for (int i = 0; i < PatientsInSystem.size(); i++) {
outFile.write(reinterpret_cast<char *> (PatientsInSystem.at(i)), sizeof(Patient));
}
}
outFile.close();
Is there a reason you are using an array of pointers vs a flat array of structs?
You are writing the local pointer variable p, instead of the Patient data. You would just pass p instead of &p (or just pass .at() directly), and the bytes parameter should be sizeof(Patient).
If these are pointers to different sized derived classes, this has issues.
Also, the loop won't every be entered, because its in the block entered when .empty() is true.

C++ String Array search outputs for every item

I know it's somewhat confusing this title of question but I really need help.
I need to find a string in array with many strings. If the string is not found then the appropriate message is showed. However when I use for loop, it then shows this message for every string in array which is not found although it also shows found string... I hope you understand what I mean and sorry if i'm not making sense. here's my code:
void Store::search() {
string name;
cout << "Enter name of product you're searching: " << endl;
getline(cin, name);
for (int i = 0; i < quantity; i++) {
if (name.compare(database[i].name) == 0){
cout << "-------------<Product found!>-------------" << endl;
cout << "name: " << database[i].name << endl;
cout << "supplier: " << database[i].supplier << endl;
cout << "available quantity: " << database[i].quantity<< endl;
cout << "price per unit: " << database[i].price<< endl;
cout << "------------------------------------------" << endl;
}
else
{
cout << "Product doesn't exist in database!" << endl;
}
}
}
The code works for searching but how do I stop the output "Product doesn't exist in database!" for every item in array that is not found(even when searched item is found)?
Thank You in advance
You can use statement flag:
void Store::search()
{
string name;
bool found = false
cout << "Enter name of product you're searching: " << endl;
getline(cin, name);
for (int i = 0; i < quantity; i++)
{
if (name.compare(database[i].name) == 0){
cout << "-------------<Product found!>-------------" << endl;
cout << "name: " << database[i].name << endl;
cout << "supplier: " << database[i].supplier << endl;
cout << "available quantity: " << database[i].quantity<< endl;
cout << "price per unit: " << database[i].price<< endl;
cout << "------------------------------------------" << endl;
found = true;
break;
}
if (!found)
cout << "Product doesn't exist in database!" << endl;
}
You can also use std::find_if, which will make your code look something like:
auto it = std::find_if(databases.begin(), databases.end(), [&name](const auto &database) {return name.compare(database.name) == 0; });
if (it != databases.end())
{
cout << it->name << endl;
cout << "found" << endl;
}
else
{
cout << "not found" << endl;
}
Generally speaking, C++ offers many such features that more often than not will make your code shorter, improve readability and guarantee functionality
You can:
1. keep a bool variable to be set to true if the item is found in the for loop
2. add a break to immediately exit for loop when item is found
3. remove the else part, because it will print out "Product doesn't exist in database!" for each loop cycle if the item does not match
4. after the for loop, check if found is false to check if item does not exist in collection
bool found = false;
for (int i = 0; i < quantity; i++)
{
if (name.compare(database[i].name) == 0)
{
cout << "-------------<Product found!>-------------" << endl;
cout << "name: " << database[i].name << endl;
cout << "supplier: " << database[i].supplier << endl;
cout << "available quantity: " << database[i].quantity<< endl;
cout << "price per unit: " << database[i].price<< endl;
cout << "------------------------------------------" << endl;
found = true; // set "found" to true
break; // add a break to immediately exit for loop when item is found
}
}
if (!found)
{
cout << "Product doesn't exist in database!" << endl;
}
I assume you want to search a product in the database and print its details if found. Otherwise you want to notify user that the product was not found. If I understood you correctly, then you need to move the else statement out of 'for' loop, e.g.:
void Store::search() {
string name;
cout << "Enter name of product you're searching: " << endl;
getline(cin, name);
bool found = false;
for (int i = 0; i < quantity; i++) {
if (name.compare(database[i].name) == 0){
cout << "-------------<Product found!>-------------" << endl;
cout << "name: " << database[i].name << endl;
cout << "supplier: " << database[i].supplier << endl;
cout << "available quantity: " << database[i].quantity<< endl;
cout << "price per unit: " << database[i].price<< endl;
cout << "------------------------------------------" << endl;
found = true;
break;
}
}
if (!found)
{
cout << "Product doesn't exist in database!" << endl;
}
}
If your database may contain more products with the same name, remove 'break;' statement.
A more "modern C++" approach is to leverage the C++ algorithms (such as std::find_if), lambdas and maybe the auto specifier.
As example (assuming database is a std::vector or some kind of STL container):
auto it = std::find_if(database.begin(), database.end(), [&name](const auto& item) { return name.compare(item.name) == 0; });
if (it != database.end())
{
cout << it->name << endl;
cout << "found" << endl;
}
else
{
cout << "not found" << endl;
}

Using C++ stream for cout or text file

I have a very simple program where I ask the user if they want to print to screen or a file. Rather than create two sets of output sections, I thought I could switch a stream to either cout or an ofstream and then output to that stream. However, I'm getting screen output no matter what.
ostream &out = cout;
do
{
cout << "Write to file (f) or screen (s)?";
cin >> yes_or_no;
} while (yes_or_no != 'f' && yes_or_no !='s');
if (yes_or_no=='f')
{
ofstream out;
out.open("Report.txt");
cout << "Writing report to Report.txt" << endl;
system("pause");
}
out << "Day: Current Value ROI" << endl;
out << "------------------------------------------" << endl;
out << setw(5) << 0;
out << "$" << setw(20) << setprecision (2) << fixed << initial_value;
out << setw(12) << "1.00" << endl;
for (int day = 1 ; day < number_of_days ; day++)
{
current_value = generateNextStockValue(current_value, volatility, trend);
out << setw(5) << day;
out << setw(20) << setprecision (2) << fixed << current_value;
out << setw(12) << setprecision (2) << fixed << current_value / initial_value;
out << endl;
}
You could put all the writing logic inside a function, and let the caller decide which output stream to write to:
void do_the_stuff(std::ostream& os)
{
// write to os
os << "blah blah" ....
}
then
if (yes_or_no=='f')
{
ofstream out("Report.txt");
do_the_stuff(out);
} else {
do_the_stuff(std::cout);
}

Replace white space with another character after calling function c++

I need help getting declared string function to change white space of input file to a specific character.
if (infile.fail())
{
cout << "The file doesn't exist";
exit(-1);
}
else
{
numBooks = readFile (infile, magSub, 260);
for (i=0; i<numBooks; i++)
{
cout << "Last Name: " << magSub[i].lastName << endl;
cout << "First Name: " << magSub[i].firstName << endl;
cout << "Street Address: " << magSub[i].address << endl;
cout << "City: " << magSub[i].city << endl;
cout << "State or Province: " << magSub[i].state << endl;
cout << "Country: " << magSub[i].country << endl << endl;
cout << "Zip or Postal Code: " << magSub[i].zip << endl;
cout << "Expiration Date: " << magSub[i].expDate << endl;
cout << "Subscriber Number: " << magSub[i].subNum << endl << endl;
}
writeFile(outfile, magSub, numBooks);
}
}
void fillSpace (string &expDate)
{
for (int i=0; expDate.length(); i++)
{
if (isspace(expDate[i]))
expDate[i] = '0';
}
}
I have the function declared above main. I know I need to call the function but I can't get it to change the white spaces.
In your code for fillSpace, you are not checking for the end of string condition. You should use i<expDate.length() for checking the end of string.
You have missed the check condition in for loop of fillSpace function.
for (int i=0; i < expDate.length(); i++)
And for calling the function
you have to declare a string which will store the string from the magSub[i].expDate.
and then pass that string to the function fillSpace.
After that you will get the string with replaced char space with '0'.
cout << "Expiration Date: " << magSub[i].expDate << endl;
please use the following code:
string temp = magSub[i].expDate; // copy the string to the temp string/char array
fillSpace (temp); // Missing Line for function call
cout << "Expiration Date: " << temp << endl; // replace line with
Hope
this will Help you.

Core dump when main function returns

I have a class that's supposed to write to a gml file defined below. The class has one method that does the writing. If I call the function, I get a core dump when the main function returns. I can create objects of the class with no problem, it only happens when the write function is called. The function also returns with no error and the rest of the program runs.
GML Writer:
class GMLWriter {
public:
void write(List<User*> usr, const char* filename);
};
void GMLWriter::write(List<User*> usr, const char* filename)
{
cout << "Filename: " << filename << endl;
ofstream outfile;
outfile.open(filename);
if (!outfile.is_open())
cout << "Couldn't open the file..." << endl;
outfile << "graph [\n";
// Write user data
for (int n = 0; n < usr.size(); n++) {
cout << "Writing node..." << endl;
outfile << "node [\n";
outfile << "id " << usr[n]->getID() << "\n";
outfile << "name \"" << usr[n]->getName() << "\"\n";
outfile << "age " << usr[n]->getAge() << "\n";
outfile << "zip " << usr[n]->getZip() << "\n";
outfile << "]\n";
}
// Write associations
for (int n = 0; n < usr.size(); n++) {
List<int> tList = usr[n]->getFriends();
cout << "Writing edge..." << endl;
//List<int> tempL = usr[n]->getFriends();
for (int i = 0; i < tList.size(); i++) {
outfile << "edge [\n";
outfile << "source " << usr[n]->getID() << "\n";
outfile << "target " << tList[i] << "\n";
outfile << "]\n";
}
}
outfile << "]"; // end graph
cout << "End function" << endl;
outfile.close();
}
User simply contains the variables to write to the file, and those methods work fine.
I've spent hours with this in a debugger and haven't been able to find the problem. Any help would be greatly appreciated.
Thanks!
Try looking at the core dump: http://www.network-theory.co.uk/docs/gccintro/gccintro_38.html