Why do i get a repeated QStringList? - c++

I am writing a Qt application that deals with scheduling employees. The header data for the main QTableView is a pointer to a QStringList. The headerData() function works correctly, but when i add a string to the list elsewhere, it appends the entire list including the new string to the end of the list.
For example, if i have the list 1,2,3 and i append 4 to it, then iterating through the list based on the pointer gives the result 1,2,3,1,2,3,4. I don't know a better way than using pointers to have multiple classes access the same data. Does anyone know how to fix the repeating list?
Example Code
//function to save a new employee in memory
bool EmployeeViewDialog::saveEmployee(Employee *e)
{
employees->insert(e->name,e);
*employeeNames << e->name;
for (int i = 0; i < employeeNames->length(); i++) {
qDebug() << employeeNames->at(i);
}
QList<QStandardItem*> items;
items << new QStandardItem(e->name);
items << new QStandardItem(e->id);
items << new QStandardItem(e->phone);
items << new QStandardItem(e->email);
model->appendRow(items);
return true;
}
The append was just changed to the << method. It is the employeeNames << e->name; line.
The for loop iterates through the list and does the same thing as what happens in the external class.

Related

Why my delete button didn't delete all widgets on QHBoxLayout

I have problem when deleting my widgets on QHBoxLayout.
i use QList for listing my layout, because i add layout at runtime.
this is my QList
QList<QHBoxLayout*> hBoxLayoutParent;
this my code when i add my widgets
hBoxLayoutParent.push_back(createNewHBoxParent());
hBoxLayoutParent.last()->addWidget(label);
hBoxLayoutParent.last()->addWidget(cmbBox);
hBoxLayoutParent.last()->addWidget(cmbJurusan);
hBoxLayoutParent.last()->addWidget(listButton.last());
ui->formLayout_2->addLayout(hBoxLayoutParent.last());
and this how i delete them
for(int i = 0; i < hBoxLayoutParent[index]->count(); i++)
{
delete hBoxLayoutParent[index]->takeAt(0)->widget();
qDebug() << "Widget Number: " << hBoxLayoutParent[index]->count();
}
hBoxLayoutParent.removeAt(index);
when i click on delete button, not all been deleted.
cmbJurusan still exists.
The problem is that your for loop isn't counting in quite the way you think it is. You have...
for (int i = 0; i < hBoxLayoutParent[index]->count(); i++)
So you're incrementing i on each iteration. But...
delete hBoxLayoutParent[index]->takeAt(0)->widget();
will remove an item from hBoxLayoutParent[index]. So you're modifying the QHBoxLayout over whose items you're iterating -- each iteration increases i by one but also decreases the number of items in the layout by one.
Instead, try...
while (!hBoxLayoutParent[index]->isEmpty()) {
delete hBoxLayoutParent[index]->takeAt(0)->widget();
qDebug() << "Widget Number: " << hBoxLayoutParent[index]->count();
}
Note also that if this code is run within the context of the event loop then you might want to use QObject::deleteLater rather than delete.

How to check if element exists in a linked list in c++?

The problem:
Imagine there is a linked list class which has multiple methods to use. The main part of the code is like this:
int main ()
{
List l;
l.push_back (86);
l.push_front (43);
l.push_front (12);
int intToSearchFor = 12;
if (l.exists (intToSearchFor))
{
cout << "(" << intToSearchFor << ") found :)";
}
else
{
cout << "(" << intToSearchFor << ") not found :(";
}
}
As you can see in this piece of code, the List class has two methods to prepend and append new items to the list. And also it has an iterator method which lets us loop over the items and check the data in each node.
The issue?
I want to create a method which check existence of an element. For example l.exists(12) should return either true or false.
My Solution:
Start to loop over the items with iterator.
Check if the item data is equal to the one you are looking for.
If it is equal then return true. Otherwise if there are more items in the list, move into the next item in the list and go to step 2.
If there are no more items in the list return false.
bool List::exists (int x)
{
Iterator it = this->get_iterator ();
do {
if (it.current->data == x) {
return true;
}
it.current = it.current->next;
} while (it.has_more_elements ());
return false;
}
Full answer:
http://cpp.sh/6cfdh
You should check whether a pointer points to nullptr before accessing data pointed by the pointer (see has_more_elements()). Better naming may avoid some confusion.
while(it.current->data!=x && it.has_more_elements())
it.current=it.current->next;
return (it.current->data==x)?true:false;
If x is not present and it reaches end of list, it.current->data will cause run time error as it may be NULL.
while(it.has_more_elements() && it.current->data!=x)
it.current = it.current->next;
return it.current!=NULL;

Visual C++ ListBox manipulation; add a string

Language: Visual C++
I have two classes. TableColumnsItemType has two variables: visibleName, and dataName (both are string).
class ColumnsSortedType is a sorted linked list.
I want to use a function called UpdateListbox to add TableColumnsItemType item to the listBox in my Form1.h (item comes from my linkedList)
public: System::Void UpdateListBox() {
//***********************************************************************
//Purpose: To add items from ColumnsSortedType::list to Form1->ListBox1
//Input: list
//Pre: list is initialized and has data.
//List gets data before Form1 initilize call, or before System::UpdateListBox call
//Output: None.
//Post: listBox is filled with data from list
//*************************************************************************
TableColumnsItemType item;
ColumnsSortedType list;
string str = "This is a sample";
item.SetDataName(str);
item.SetVisibleName();
list.InsertItem(item);
str = "This is also a sample";
item.SetDataName(str);
item.SetVisibleName();
list.InsertItem(item);
list.InsertItem(item);
int length = list.LengthIs();
int pos;
for(pos = 0; pos < length; pos++)
{
list.GetNextItem(item);
str = item.ReturnVisibleName();
//add code to insert item into listbox
this->listBox1.AddString(item); //**Here is my issue!**
}
}
I really don't want to add items to list in this function; but I want to get this function working before I start adding extra arguments to pass item and list around.
I'm having trouble adding an item to ListBox1. What is a member function that would allow me to do this? I know that Visual Basic would be something like listBox1.Items.Add
VS doesn't give me function choices when I add the dot-notation after listBox1, so I'm guessing that my syntax is incorrect. I'm having difficulty finding examples for C++ code manipulation of listboxes.

Search vector of objects by object data member attribute

I'm writing a Jukebox simulator and I'm trying to search a vector of Album objects by album title and return the index for use in other functions. The function is to be used for a number of different things such as deleting an album, printing an album etc.
I have gotten it to work in a previous application when the function was in the same Class as the data member to search for. I can however for some reason not get it to work using getters. No matter what I input as search key the idx returns 3 although the vector only contains indexes 0, 1 and 2 (only 3 albums right now).
The lambda function seem to be able to access data by using the getAlbum()-getter but somehow the comparison doesn't work.
My approach might be entirely wrong and I'd be grateful for any pointers in the right direction, or suggestions on how to accomplish the desired result using some other technique.
int Jukebox::findAlbumIdx(string key)
{
// Get search predicate
auto it = find_if(albvec.begin(), albvec.end(), [key](Album const &a)
{
return (a.getAlbum() == key);
});
int idx = it - albvec.begin();
return idx;
}
void Jukebox::delAlbum()
{
cin.get();
string key;
cout << "Input title of album to delete: ";
getline(cin, key);
int idx = findAlbumIdx(key);
if(idx > albvec.size() - 1)
cout << "No hits." << endl;
else
albvec.erase(albvec.begin() + idx);
}
getAlbum is just a simple inline getter as such:
string getAlbum() const {return album_title;}
Following Jonathan Wakely's suggestion to add std::cout << a.getAlbum() << " == " << key << std::endl; in the lambda the output is this:
Input title of album to delete: Abbey Road
== Abbey Road
== Abbey Road
== Abbey RoadLonely Hearts Club Band
No hits.
Obviously the getter isn't actually getting much to use for comparison. Not sure why it only gets the last entry and on the right hand side of the comparison.
If I add this to any of the functions above it gets and displays the Album titles correctly. The vector seems to be fine just before calling findAlbumIdx(key); and also inside the findAlbumIdx function.
for(unsigned int i = 0; i < albvec.size(); ++i)
cout << albvec[i].getAlbum() << endl;
The original playlist file that is read into the vector to be searched had dos newlines, after converting it using dos2unix (since I'm running Linux) the search, and I presume a lot of other things, is working correctly.
I suppose trimming newline characters while reading the file into the vector would be the more correct approach.

Invalid heap error when trying to copy elements from a Map to a compatible priority Queue

My program makes a frequency map of characters (which I store in , surprise surprise, a Map), I am trying to copy each element from this map into a Priority Queue so that I can have a sorted copy of these values (I plan to make further use of the Q, that's why am not sorting the map) , but whenever I try to copy these values , the program executes fine for the first two or three iterations and fails on the fourth citing an "Invalid heap" error.
I'm not sure how to proceed from here, so I am posting the code for the classes in question.
#include "srcFile.h"
#include <string>
#include <iostream>
srcFile::srcFile(std::string s_flName)
{
// Storing the file name
s_fileName= s_flName;
}
srcFile::srcFile()
{
// Default constructor (never to be used)
}
srcFile::~srcFile(void)
{
}
void srcFile::dispOverallMap ()
{
std::map<char,int>::iterator dispIterator;
dispIterator = map_charFreqDistribution.begin();
charElement *currentChar;
std::cout<<"\n Frequency distribution map \n";
while(dispIterator != map_charFreqDistribution.end())
{
std::cout<< "Character : " << (int)dispIterator->first << " Frequency : "<< dispIterator->second<<'\n';
currentChar = new charElement(dispIterator->first,dispIterator->second);
Q_freqDistribution.push(*currentChar);
dispIterator++;
// delete currentChar;
}
while(!Q_freqDistribution.empty())
{
std::cout<<'\n'<<"Queue Element : " << (int)Q_freqDistribution.top().ch_elementChar << " Frequency : " << Q_freqDistribution.top().i_frequency;
Q_freqDistribution.pop();
}
}
map_charFreqDistribution has already been populated, if I remove the line
Q_freqDistribution.push(*currentChar);
Then I can verify that the Map is indeed there.
Also , both the Q and the use charElement as the template type , its nothing except the character and its frequency, along with 2 pointers to facilitate tree generation (unused upto this point)
Adding the definition of charElement on request
#pragma once
class charElement
{
public:
// Holds the character for the element in question
char ch_elementChar;
// Holds the number of times the character appeared in the file
int i_frequency;
// Left pointer for tree
charElement* ptr_left;
// Right pointer for tree
charElement* ptr_right;
charElement(char,int);
charElement(void);
~charElement(void);
void operator=(charElement&);
};
class compareCharElt
{
public:
bool operator()(charElement &operand1,charElement &operand2)
{
// If the frequency of op1 < op2 then return true
if(operand1.i_frequency < operand2.i_frequency) return true;
// If the frequency of op1 > op2 then return false
if(operand1.i_frequency > operand2.i_frequency)return false;
// If the frequency of op1 == op2 then return true (that is priority is indicated to be less even though frequencies are equal)
if(operand1.i_frequency == operand2.i_frequency)return false;
}
};
Definition of Map and Queue
// The map which holds the frequency distribution of all characters in the file
std::map<char,int> map_charFreqDistribution;
void dispOverallMap();
// Create Q which holds character elements
std::priority_queue<charElement,std::vector<charElement>,compareCharElt> Q_freqDistribution;
P.S.This may be a noob question, but Is there an easier way to post blocks of code , putting 4 spaces in front of huge code chunks doesn't seem all that efficient to me! Are pastebin links acceptable here ?
Your vector is reallocating and invalidating your pointers. You need to use a different data structure, or an index into the vector, instead of a raw pointer. When you insert elements into a vector, then pointers to the contents become invalid.
while(dispIterator != map_charFreqDistribution.end())
{
std::cout<< "Character : " << (int)dispIterator->first << " Frequency : "<< dispIterator->second<<'\n';
currentChar = new charElement(dispIterator->first,dispIterator->second);
Q_freqDistribution.push(*currentChar);
dispIterator++;
delete currentChar;
}
Completely throws people off because it's very traditional for people to have huge problems when using new and delete directly, but there's actually no need for it whatsoever in this code, and everything is actually done by value.
You have two choices. Pick a structure (e.g. std::list) that does not invalidate pointers, or, allocate all charElements on the heap directly and use something like shared_ptr that cleans up for you.
currentChar = new charElement(dispIterator->first,dispIterator->second);
Q_freqDistribution.push(*currentChar);
dispIterator++;
delete currentChar;
In the above code, you create a new charElement object, then push it, and then delete it. When you call delete, that object no longer exists -- not even in the queue. That's probably not what you want.